alpha2_gpu/
capabilities.rs1#[derive(Copy, Clone, Debug, Eq, PartialEq)]
3#[non_exhaustive]
4pub enum CapabilityTier {
5 TierA,
7 TierB,
9}
10
11#[derive(Copy, Clone, Debug, Eq, PartialEq)]
13#[non_exhaustive]
14pub enum IntermediateFormat {
15 Rgba16Float,
17 Rgba8Unorm,
19}
20
21#[derive(Clone, Debug)]
23#[non_exhaustive]
24pub struct Capabilities {
25 pub tier: CapabilityTier,
27 pub intermediate_format: IntermediateFormat,
29 pub adapter_name: String,
31 pub max_texture_dimension_2d: u32,
33 pub timestamp_queries: bool,
35 pub backend: String,
37 pub driver: String,
39 pub driver_info: String,
41 pub software_rasterizer: bool,
45}
46
47impl Capabilities {
48 #[must_use]
50 #[allow(clippy::too_many_arguments)]
51 pub fn new(
52 tier: CapabilityTier,
53 intermediate_format: IntermediateFormat,
54 adapter_name: impl Into<String>,
55 max_texture_dimension_2d: u32,
56 timestamp_queries: bool,
57 backend: impl Into<String>,
58 driver: impl Into<String>,
59 driver_info: impl Into<String>,
60 ) -> Self {
61 Self {
62 tier,
63 intermediate_format,
64 adapter_name: adapter_name.into(),
65 max_texture_dimension_2d,
66 timestamp_queries,
67 backend: backend.into(),
68 driver: driver.into(),
69 driver_info: driver_info.into(),
70 software_rasterizer: false,
71 }
72 }
73
74 pub(crate) fn from_adapter(adapter: &wgpu::Adapter) -> Self {
75 let info = adapter.get_info();
76 Self {
77 tier: tier_for(&adapter.get_downlevel_capabilities()),
78 intermediate_format: intermediate_format_for(
79 adapter.get_texture_format_features(wgpu::TextureFormat::Rgba16Float),
80 ),
81 adapter_name: info.name,
82 max_texture_dimension_2d: adapter.limits().max_texture_dimension_2d,
83 timestamp_queries: adapter.features().contains(wgpu::Features::TIMESTAMP_QUERY),
84 backend: format!("{:?}", info.backend),
85 driver: info.driver,
86 driver_info: info.driver_info,
87 software_rasterizer: info.device_type == wgpu::DeviceType::Cpu,
88 }
89 }
90}
91
92fn intermediate_format_for(half_float: wgpu::TextureFormatFeatures) -> IntermediateFormat {
99 let required = wgpu::TextureUsages::RENDER_ATTACHMENT
100 | wgpu::TextureUsages::TEXTURE_BINDING
101 | wgpu::TextureUsages::COPY_SRC;
102 if half_float.allowed_usages.contains(required)
103 && half_float
104 .flags
105 .contains(wgpu::TextureFormatFeatureFlags::FILTERABLE)
106 {
107 IntermediateFormat::Rgba16Float
108 } else {
109 IntermediateFormat::Rgba8Unorm
110 }
111}
112
113fn tier_for(downlevel: &wgpu::DownlevelCapabilities) -> CapabilityTier {
116 if downlevel.is_webgpu_compliant() {
117 CapabilityTier::TierA
118 } else {
119 CapabilityTier::TierB
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use wgpu::{TextureFormatFeatureFlags as Flags, TextureUsages as Usages};
127
128 fn half_float(allowed_usages: Usages, flags: Flags) -> wgpu::TextureFormatFeatures {
129 wgpu::TextureFormatFeatures {
130 allowed_usages,
131 flags,
132 }
133 }
134
135 #[test]
136 fn half_float_is_the_intermediate_only_where_it_renders_filters_and_copies() {
137 let required = Usages::RENDER_ATTACHMENT | Usages::TEXTURE_BINDING | Usages::COPY_SRC;
138 assert_eq!(
139 intermediate_format_for(half_float(required | Usages::COPY_DST, Flags::FILTERABLE)),
140 IntermediateFormat::Rgba16Float
141 );
142 for missing in [
143 Usages::RENDER_ATTACHMENT,
144 Usages::TEXTURE_BINDING,
145 Usages::COPY_SRC,
146 ] {
147 assert_eq!(
148 intermediate_format_for(half_float(required - missing, Flags::FILTERABLE)),
149 IntermediateFormat::Rgba8Unorm,
150 "without {missing:?}"
151 );
152 }
153 assert_eq!(
154 intermediate_format_for(half_float(required, Flags::empty())),
155 IntermediateFormat::Rgba8Unorm,
156 "without filtering"
157 );
158 assert_eq!(
160 intermediate_format_for(half_float(Usages::empty(), Flags::empty())),
161 IntermediateFormat::Rgba8Unorm
162 );
163 }
164
165 #[test]
166 fn the_tier_follows_webgpu_compliance_alone() {
167 assert_eq!(
168 tier_for(&wgpu::DownlevelCapabilities::default()),
169 CapabilityTier::TierA
170 );
171 let mut downlevel = wgpu::DownlevelCapabilities::default();
172 downlevel
173 .flags
174 .remove(wgpu::DownlevelFlags::COMPUTE_SHADERS);
175 assert_eq!(tier_for(&downlevel), CapabilityTier::TierB);
176 let shader_model = wgpu::DownlevelCapabilities {
177 shader_model: wgpu::ShaderModel::Sm4,
178 ..Default::default()
179 };
180 assert_eq!(tier_for(&shader_model), CapabilityTier::TierB);
181 }
182}