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;
27use crate::traits::Equivalence;
28
29#[dom_struct]
30pub struct GPUSupportedFeatures<D: DomTypes> {
31 reflector: Reflector,
32 #[custom_trace]
34 internal: DomRefCell<IndexSet<GPUFeatureName>>,
35 #[ignore_malloc_size_of = "defined in wgpu-types"]
36 #[no_trace]
37 features: Features,
38 #[no_trace = "PhantomData does not exist"]
39 phantom: PhantomData<D>,
40}
41
42impl<D: Equivalence> GPUSupportedFeatures<D> {
43 fn new(
44 cx: &mut JSContext,
45 global: &D::GlobalScope,
46 proto: Option<HandleObject>,
47 features: Features,
48 ) -> DomRoot<GPUSupportedFeatures<D>> {
49 let mut set = IndexSet::new();
50 set.insert(GPUFeatureName::Core_features_and_limits);
52 if features.contains(Features::DEPTH_CLIP_CONTROL) {
53 set.insert(GPUFeatureName::Depth_clip_control);
54 }
55 if features.contains(Features::DEPTH32FLOAT_STENCIL8) {
56 set.insert(GPUFeatureName::Depth32float_stencil8);
57 }
58 if features.contains(Features::TEXTURE_COMPRESSION_BC) {
59 set.insert(GPUFeatureName::Texture_compression_bc);
60 }
61 if features.contains(Features::TEXTURE_COMPRESSION_ETC2) {
63 set.insert(GPUFeatureName::Texture_compression_etc2);
64 }
65 if features.contains(Features::TEXTURE_COMPRESSION_ASTC) {
66 set.insert(GPUFeatureName::Texture_compression_astc);
67 }
68 if features.contains(Features::TIMESTAMP_QUERY) {
69 set.insert(GPUFeatureName::Timestamp_query);
70 }
71 if features.contains(Features::INDIRECT_FIRST_INSTANCE) {
72 set.insert(GPUFeatureName::Indirect_first_instance);
73 }
74 if features.contains(Features::RG11B10UFLOAT_RENDERABLE) {
82 set.insert(GPUFeatureName::Rg11b10ufloat_renderable);
83 }
84 if features.contains(Features::BGRA8UNORM_STORAGE) {
85 set.insert(GPUFeatureName::Bgra8unorm_storage);
86 }
87 if features.contains(Features::FLOAT32_FILTERABLE) {
88 set.insert(GPUFeatureName::Float32_filterable);
89 }
90 if features.contains(Features::DUAL_SOURCE_BLENDING) {
92 set.insert(GPUFeatureName::Dual_source_blending);
93 }
94 reflect_dom_object_with_proto_and_wrap::<D, _, _>(
103 Box::new(GPUSupportedFeatures {
104 reflector: Reflector::new(),
105 internal: DomRefCell::new(set),
106 features,
107 phantom: PhantomData,
108 }),
109 global,
110 proto,
111 cx,
112 GPUSupportedFeaturesWrap::<D>,
113 )
114 }
115
116 #[expect(non_snake_case)]
117 pub fn Constructor(
118 cx: &mut JSContext,
119 global: &D::GlobalScope,
120 proto: Option<HandleObject>,
121 features: Features,
122 ) -> Fallible<DomRoot<GPUSupportedFeatures<D>>> {
123 Ok(GPUSupportedFeatures::new(cx, global, proto, features))
124 }
125}
126
127impl<D: DomTypes> GPUSupportedFeatures<D> {
128 pub fn wgpu_features(&self) -> &Features {
129 &self.features
130 }
131}
132
133impl<D: DomTypes> GPUSupportedFeaturesMethods<D> for GPUSupportedFeatures<D> {
134 fn Size(&self) -> u32 {
135 self.internal.borrow().len() as u32
136 }
137}
138
139pub(crate) fn gpu_to_wgt_feature(feature: GPUFeatureName) -> Option<Features> {
140 match feature {
141 GPUFeatureName::Core_features_and_limits => Some(Features::empty()),
143 GPUFeatureName::Depth_clip_control => Some(Features::DEPTH_CLIP_CONTROL),
144 GPUFeatureName::Depth32float_stencil8 => Some(Features::DEPTH32FLOAT_STENCIL8),
145 GPUFeatureName::Texture_compression_bc => Some(Features::TEXTURE_COMPRESSION_BC),
146 GPUFeatureName::Texture_compression_etc2 => Some(Features::TEXTURE_COMPRESSION_ETC2),
147 GPUFeatureName::Texture_compression_astc => Some(Features::TEXTURE_COMPRESSION_ASTC),
148 GPUFeatureName::Timestamp_query => Some(Features::TIMESTAMP_QUERY),
149 GPUFeatureName::Indirect_first_instance => Some(Features::INDIRECT_FIRST_INSTANCE),
150 GPUFeatureName::Shader_f16 => None,
153 GPUFeatureName::Rg11b10ufloat_renderable => Some(Features::RG11B10UFLOAT_RENDERABLE),
154 GPUFeatureName::Bgra8unorm_storage => Some(Features::BGRA8UNORM_STORAGE),
155 GPUFeatureName::Float32_filterable => Some(Features::FLOAT32_FILTERABLE),
156 GPUFeatureName::Dual_source_blending => Some(Features::DUAL_SOURCE_BLENDING),
157 GPUFeatureName::Texture_compression_bc_sliced_3d => None,
158 GPUFeatureName::Clip_distances => None,
159 GPUFeatureName::Subgroups => None,
162 }
163}
164
165impl<D: DomTypes> Setlike for GPUSupportedFeatures<D> {
166 type Key = DOMString;
167
168 #[inline(always)]
169 fn get_index(&self, cx: &mut JSContext, index: u32) -> Option<Self::Key> {
170 self.internal
171 .get_index(cx, index)
172 .map(|key| key.as_str().into())
173 }
174 #[inline(always)]
175 fn size(&self, cx: &mut JSContext) -> u32 {
176 self.internal.size(cx)
177 }
178 #[inline(always)]
179 fn add(&self, _cx: &mut JSContext, _key: Self::Key) {
180 unreachable!("readonly");
181 }
182 #[inline(always)]
183 fn has(&self, cx: &mut JSContext, key: Self::Key) -> bool {
184 if let Ok(key) = key.parse() {
185 self.internal.has(cx, key)
186 } else {
187 false
188 }
189 }
190 #[inline(always)]
191 fn clear(&self, _cx: &mut JSContext) {
192 unreachable!("readonly");
193 }
194 #[inline(always)]
195 fn delete(&self, _cx: &mut JSContext, _key: Self::Key) -> bool {
196 unreachable!("readonly");
197 }
198}