use std::collections::BTreeMap;
use alpha2_gpu::CapabilityTier;
use alpha2_render::Renderer;
use serde::Serialize;
use crate::PlaybackPolicy;
pub const CAPABILITY_SCHEMA: &str = "alpha2-capabilities";
pub const CAPABILITY_VERSION: u32 = 1;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum Runtime {
Native,
Browser,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CapabilityReport {
pub schema: &'static str,
pub version: u32,
pub runtime: Runtime,
pub gpu: GpuReport,
pub color: ColorReport,
pub playback: PlaybackReport,
pub decode: serde_json::Value,
pub encode: serde_json::Value,
pub features: BTreeMap<String, Feature>,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GpuReport {
pub adapter: String,
pub backend: String,
pub driver: String,
pub driver_info: String,
pub tier: &'static str,
pub intermediate_format: &'static str,
pub max_texture_dimension_2d: u32,
pub timestamp_queries: bool,
pub texture_budget_bytes: u64,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ColorReport {
pub working_space: &'static str,
pub hdr_sources: bool,
pub hdr_output: bool,
pub extended_range_sources: bool,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PlaybackReport {
pub policies: Vec<PlaybackPolicy>,
pub default_policy: PlaybackPolicy,
pub audio_at_non_unit_rate: bool,
}
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct Feature {
pub available: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
}
impl Feature {
#[must_use]
pub const fn available() -> Self {
Self {
available: true,
reason: None,
}
}
#[must_use]
pub fn unavailable(reason: impl Into<String>) -> Self {
Self {
available: false,
reason: Some(reason.into()),
}
}
}
impl CapabilityReport {
#[must_use]
pub fn new(runtime: Runtime, renderer: &Renderer) -> Self {
let capabilities = renderer.gpu_capabilities();
let half = matches!(
capabilities.intermediate_format,
alpha2_gpu::IntermediateFormat::Rgba16Float
);
Self {
schema: CAPABILITY_SCHEMA,
version: CAPABILITY_VERSION,
runtime,
gpu: GpuReport {
adapter: capabilities.adapter_name.clone(),
backend: capabilities.backend.clone(),
driver: capabilities.driver.clone(),
driver_info: capabilities.driver_info.clone(),
tier: match capabilities.tier {
CapabilityTier::TierA => "a",
CapabilityTier::TierB => "b",
_ => "unknown",
},
intermediate_format: if half { "rgba16float" } else { "rgba8unorm" },
max_texture_dimension_2d: capabilities.max_texture_dimension_2d,
timestamp_queries: capabilities.timestamp_queries,
texture_budget_bytes: renderer.diagnostics().textures.budget_bytes,
},
color: ColorReport {
working_space: "linear_bt709_sdr",
hdr_sources: true,
hdr_output: false,
extended_range_sources: half,
},
playback: PlaybackReport {
policies: PlaybackPolicy::ALL.to_vec(),
default_policy: PlaybackPolicy::default(),
audio_at_non_unit_rate: false,
},
decode: serde_json::Value::Null,
encode: serde_json::Value::Null,
features: BTreeMap::new(),
}
}
#[must_use]
pub fn with_feature(mut self, name: &str, feature: Feature) -> Self {
self.features.insert(name.to_owned(), feature);
self
}
}