script_webgpu/
gpusupportedfeatures.rs1use std::marker::PhantomData;
8
9use dom_struct::dom_struct;
10use indexmap::IndexSet;
11use js::context::JSContext;
12use js::rust::HandleObject;
13use malloc_size_of_derive::MallocSizeOf;
14use script_bindings::DomTypes;
15use script_bindings::cell::DomRefCell;
16use script_bindings::codegen::GenericBindings::WebGPUBinding::{
17 GPUFeatureName, GPUSupportedFeaturesMethods, GPUSupportedFeaturesWrap,
18};
19use script_bindings::like::Setlike;
20use script_bindings::reflector::{Reflector, reflect_dom_object_with_proto_and_wrap};
21use wgpu_types::Features;
22
23use crate::JSTraceable;
24use crate::dom::bindings::error::Fallible;
25use crate::dom::bindings::root::DomRoot;
26use crate::dom::bindings::str::DOMString;
27
28#[dom_struct]
29pub struct GPUSupportedFeatures<D: DomTypes> {
30 reflector: Reflector,
31 #[custom_trace]
33 internal: DomRefCell<IndexSet<GPUFeatureName>>,
34 #[ignore_malloc_size_of = "defined in wgpu-types"]
35 #[no_trace]
36 features: Features,
37 #[no_trace = "PhantomData does not exist"]
38 phantom: PhantomData<D>,
39}
40
41impl<D> GPUSupportedFeatures<D>
42where
43 D: DomTypes<GPUSupportedFeatures = GPUSupportedFeatures<D>>,
44{
45 fn new(
46 cx: &mut JSContext,
47 global: &D::GlobalScope,
48 proto: Option<HandleObject>,
49 features: Features,
50 ) -> DomRoot<GPUSupportedFeatures<D>> {
51 let mut set = IndexSet::new();
52 set.insert(GPUFeatureName::Core_features_and_limits);
54 if features.contains(Features::DEPTH_CLIP_CONTROL) {
55 set.insert(GPUFeatureName::Depth_clip_control);
56 }
57 if features.contains(Features::DEPTH32FLOAT_STENCIL8) {
58 set.insert(GPUFeatureName::Depth32float_stencil8);
59 }
60 if features.contains(Features::TEXTURE_COMPRESSION_BC) {
61 set.insert(GPUFeatureName::Texture_compression_bc);
62 }
63 if features.contains(Features::TEXTURE_COMPRESSION_ETC2) {
65 set.insert(GPUFeatureName::Texture_compression_etc2);
66 }
67 if features.contains(Features::TEXTURE_COMPRESSION_ASTC) {
68 set.insert(GPUFeatureName::Texture_compression_astc);
69 }
70 if features.contains(Features::TIMESTAMP_QUERY) {
71 set.insert(GPUFeatureName::Timestamp_query);
72 }
73 if features.contains(Features::INDIRECT_FIRST_INSTANCE) {
74 set.insert(GPUFeatureName::Indirect_first_instance);
75 }
76 if features.contains(Features::RG11B10UFLOAT_RENDERABLE) {
84 set.insert(GPUFeatureName::Rg11b10ufloat_renderable);
85 }
86 if features.contains(Features::BGRA8UNORM_STORAGE) {
87 set.insert(GPUFeatureName::Bgra8unorm_storage);
88 }
89 if features.contains(Features::FLOAT32_FILTERABLE) {
90 set.insert(GPUFeatureName::Float32_filterable);
91 }
92 if features.contains(Features::DUAL_SOURCE_BLENDING) {
94 set.insert(GPUFeatureName::Dual_source_blending);
95 }
96 reflect_dom_object_with_proto_and_wrap::<D, _, _>(
105 Box::new(GPUSupportedFeatures {
106 reflector: Reflector::new(),
107 internal: DomRefCell::new(set),
108 features,
109 phantom: PhantomData,
110 }),
111 global,
112 proto,
113 cx,
114 GPUSupportedFeaturesWrap::<D>,
115 )
116 }
117
118 #[expect(non_snake_case)]
119 pub fn Constructor(
120 cx: &mut JSContext,
121 global: &D::GlobalScope,
122 proto: Option<HandleObject>,
123 features: Features,
124 ) -> Fallible<DomRoot<GPUSupportedFeatures<D>>> {
125 Ok(GPUSupportedFeatures::new(cx, global, proto, features))
126 }
127}
128
129impl<D: DomTypes> GPUSupportedFeatures<D> {
130 pub fn wgpu_features(&self) -> &Features {
131 &self.features
132 }
133}
134
135impl<D: DomTypes> GPUSupportedFeaturesMethods<D> for GPUSupportedFeatures<D> {
136 fn Size(&self) -> u32 {
137 self.internal.borrow().len() as u32
138 }
139}
140
141pub(crate) fn gpu_to_wgt_feature(feature: GPUFeatureName) -> Option<Features> {
142 match feature {
143 GPUFeatureName::Core_features_and_limits => Some(Features::empty()),
145 GPUFeatureName::Depth_clip_control => Some(Features::DEPTH_CLIP_CONTROL),
146 GPUFeatureName::Depth32float_stencil8 => Some(Features::DEPTH32FLOAT_STENCIL8),
147 GPUFeatureName::Texture_compression_bc => Some(Features::TEXTURE_COMPRESSION_BC),
148 GPUFeatureName::Texture_compression_etc2 => Some(Features::TEXTURE_COMPRESSION_ETC2),
149 GPUFeatureName::Texture_compression_astc => Some(Features::TEXTURE_COMPRESSION_ASTC),
150 GPUFeatureName::Timestamp_query => Some(Features::TIMESTAMP_QUERY),
151 GPUFeatureName::Indirect_first_instance => Some(Features::INDIRECT_FIRST_INSTANCE),
152 GPUFeatureName::Shader_f16 => None,
155 GPUFeatureName::Rg11b10ufloat_renderable => Some(Features::RG11B10UFLOAT_RENDERABLE),
156 GPUFeatureName::Bgra8unorm_storage => Some(Features::BGRA8UNORM_STORAGE),
157 GPUFeatureName::Float32_filterable => Some(Features::FLOAT32_FILTERABLE),
158 GPUFeatureName::Dual_source_blending => Some(Features::DUAL_SOURCE_BLENDING),
159 GPUFeatureName::Texture_compression_bc_sliced_3d => None,
160 GPUFeatureName::Clip_distances => None,
161 GPUFeatureName::Subgroups => None,
164 }
165}
166
167impl<D: DomTypes> Setlike for GPUSupportedFeatures<D> {
168 type Key = DOMString;
169
170 #[inline(always)]
171 fn get_index(&self, cx: &mut JSContext, index: u32) -> Option<Self::Key> {
172 self.internal
173 .get_index(cx, index)
174 .map(|key| key.as_str().into())
175 }
176 #[inline(always)]
177 fn size(&self, cx: &mut JSContext) -> u32 {
178 self.internal.size(cx)
179 }
180 #[inline(always)]
181 fn add(&self, _cx: &mut JSContext, _key: Self::Key) {
182 unreachable!("readonly");
183 }
184 #[inline(always)]
185 fn has(&self, cx: &mut JSContext, key: Self::Key) -> bool {
186 if let Ok(key) = key.parse() {
187 self.internal.has(cx, key)
188 } else {
189 false
190 }
191 }
192 #[inline(always)]
193 fn clear(&self, _cx: &mut JSContext) {
194 unreachable!("readonly");
195 }
196 #[inline(always)]
197 fn delete(&self, _cx: &mut JSContext, _key: Self::Key) -> bool {
198 unreachable!("readonly");
199 }
200}