aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2020-01-16 13:36:10 -0500
committerGitHub <noreply@github.com>2020-01-16 13:36:10 -0500
commit90b0a7fcc5f8c94e176c817cad75d40a82b4388a (patch)
tree9836c660230484d483b5254ee8d85412b6402568 /components/script
parent5c202ed392210ab824e16dc466e695dc0f5f7253 (diff)
parent9cf007472b364ea60445e6aaa5e91f67ef3d1894 (diff)
downloadservo-90b0a7fcc5f8c94e176c817cad75d40a82b4388a.tar.gz
servo-90b0a7fcc5f8c94e176c817cad75d40a82b4388a.zip
Auto merge of #25526 - szeged:bind_group_wgpu, r=jdm
Initial implementation of GPUBindGroupLayout for WebGPU Added WebIDL bindings for `GPUBindGroupLayout`, `GPUBindGroupLayoutDescriptor`, `GPUBindingType`, `GPUShaderStage` and `GPUBindGroupLayoutBinding` (Note: The servo's codegen doesn't like the name, because its already occupied). Implemented the `createBindGroupLayout` function of `GPUDevice`. <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes addresses a part of #24706 cc @kvark @jdm @zakorgy <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/bindings/trace.rs3
-rw-r--r--components/script/dom/gpubindgrouplayout.rs75
-rw-r--r--components/script/dom/gpudevice.rs180
-rw-r--r--components/script/dom/gpushaderstage.rs11
-rw-r--r--components/script/dom/identityhub.rs24
-rw-r--r--components/script/dom/mod.rs2
-rw-r--r--components/script/dom/navigator.rs8
-rw-r--r--components/script/dom/webidls/GPUBindGroupLayout.webidl34
-rw-r--r--components/script/dom/webidls/GPUDevice.webidl8
-rw-r--r--components/script/dom/webidls/GPUShaderStage.webidl13
10 files changed, 350 insertions, 8 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 36a12d023af..bdcf9919752 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -151,7 +151,7 @@ use tendril::stream::LossyDecoder;
use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec, Tm};
use uuid::Uuid;
-use webgpu::{WebGPU, WebGPUAdapter, WebGPUBuffer, WebGPUDevice};
+use webgpu::{WebGPU, WebGPUAdapter, WebGPUBindGroupLayout, WebGPUBuffer, WebGPUDevice};
use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
use webxr_api::SwapChainId as WebXRSwapChainId;
@@ -530,6 +530,7 @@ unsafe_no_jsmanaged_fields!(WebGPU);
unsafe_no_jsmanaged_fields!(WebGPUAdapter);
unsafe_no_jsmanaged_fields!(WebGPUDevice);
unsafe_no_jsmanaged_fields!(WebGPUBuffer);
+unsafe_no_jsmanaged_fields!(WebGPUBindGroupLayout);
unsafe_no_jsmanaged_fields!(GPUBufferState);
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
unsafe_no_jsmanaged_fields!(MediaList);
diff --git a/components/script/dom/gpubindgrouplayout.rs b/components/script/dom/gpubindgrouplayout.rs
new file mode 100644
index 00000000000..7669f0e5f2d
--- /dev/null
+++ b/components/script/dom/gpubindgrouplayout.rs
@@ -0,0 +1,75 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
+ self, GPUBindGroupLayoutBindings, GPUBindGroupLayoutMethods,
+};
+use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
+use crate::dom::bindings::root::DomRoot;
+use crate::dom::bindings::str::DOMString;
+use crate::dom::globalscope::GlobalScope;
+use dom_struct::dom_struct;
+use std::cell::Cell;
+use webgpu::{WebGPU, WebGPUBindGroupLayout};
+
+#[dom_struct]
+pub struct GPUBindGroupLayout {
+ reflector_: Reflector,
+ label: DomRefCell<Option<DOMString>>,
+ bind_group_layout: WebGPUBindGroupLayout,
+ #[ignore_malloc_size_of = "defined in webgpu"]
+ bindings: Vec<GPUBindGroupLayoutBindings>,
+ #[ignore_malloc_size_of = "defined in webgpu"]
+ channel: WebGPU,
+ valid: Cell<bool>,
+}
+
+impl GPUBindGroupLayout {
+ fn new_inherited(
+ channel: WebGPU,
+ bind_group_layout: WebGPUBindGroupLayout,
+ bindings: Vec<GPUBindGroupLayoutBindings>,
+ valid: bool,
+ ) -> GPUBindGroupLayout {
+ Self {
+ reflector_: Reflector::new(),
+ channel,
+ label: DomRefCell::new(None),
+ bind_group_layout,
+ bindings,
+ valid: Cell::new(valid),
+ }
+ }
+ pub fn new(
+ global: &GlobalScope,
+ channel: WebGPU,
+ bind_group_layout: WebGPUBindGroupLayout,
+ bindings: Vec<GPUBindGroupLayoutBindings>,
+ valid: bool,
+ ) -> DomRoot<GPUBindGroupLayout> {
+ reflect_dom_object(
+ Box::new(GPUBindGroupLayout::new_inherited(
+ channel,
+ bind_group_layout,
+ bindings,
+ valid,
+ )),
+ global,
+ GPUBindGroupLayoutBinding::Wrap,
+ )
+ }
+}
+
+impl GPUBindGroupLayoutMethods for GPUBindGroupLayout {
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn GetLabel(&self) -> Option<DOMString> {
+ self.label.borrow().clone()
+ }
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
+ fn SetLabel(&self, value: Option<DOMString>) {
+ *self.label.borrow_mut() = value;
+ }
+}
diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs
index 371643b6027..d2d2b2013d8 100644
--- a/components/script/dom/gpudevice.rs
+++ b/components/script/dom/gpudevice.rs
@@ -5,6 +5,10 @@
#![allow(unsafe_code)]
use crate::dom::bindings::cell::DomRefCell;
+use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::GPULimits;
+use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
+ GPUBindGroupLayoutBindings, GPUBindGroupLayoutDescriptor, GPUBindingType,
+};
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{self, GPUDeviceMethods};
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
@@ -15,6 +19,7 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuadapter::GPUAdapter;
+use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState};
use crate::dom::window::Window;
use crate::script_runtime::JSContext as SafeJSContext;
@@ -23,7 +28,9 @@ use ipc_channel::ipc;
use js::jsapi::{Heap, JSObject};
use js::jsval::{JSVal, ObjectValue, UndefinedValue};
use js::typedarray::{ArrayBuffer, CreateWith};
+use std::collections::{HashMap, HashSet};
use std::ptr::{self, NonNull};
+use webgpu::wgpu::binding_model::{BindGroupLayoutBinding, BindingType, ShaderStage};
use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage};
use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest};
@@ -229,4 +236,177 @@ impl GPUDeviceMethods for GPUDevice {
self.resolve_create_buffer_mapped(cx, buffer, array_buffer, wgpu_descriptor, valid)
}
}
+
+ /// https://gpuweb.github.io/gpuweb/#GPUDevice-createBindGroupLayout
+ fn CreateBindGroupLayout(
+ &self,
+ descriptor: &GPUBindGroupLayoutDescriptor,
+ ) -> DomRoot<GPUBindGroupLayout> {
+ #[derive(Clone)]
+ struct MaxLimits {
+ max_uniform_buffers_per_shader_stage: i32,
+ max_storage_buffers_per_shader_stage: i32,
+ max_sampled_textures_per_shader_stage: i32,
+ max_storage_textures_per_shader_stage: i32,
+ max_samplers_per_shader_stage: i32,
+ }
+ let mut storeBindings = HashSet::new();
+ // TODO: We should have these limits on device creation
+ let limits = GPULimits::empty();
+
+ let mut validation_map = HashMap::new();
+ let maxLimits = MaxLimits {
+ max_uniform_buffers_per_shader_stage: limits.maxUniformBuffersPerShaderStage as i32,
+ max_storage_buffers_per_shader_stage: limits.maxStorageBuffersPerShaderStage as i32,
+ max_sampled_textures_per_shader_stage: limits.maxSampledTexturesPerShaderStage as i32,
+ max_storage_textures_per_shader_stage: limits.maxStorageTexturesPerShaderStage as i32,
+ max_samplers_per_shader_stage: limits.maxSamplersPerShaderStage as i32,
+ };
+ validation_map.insert(
+ webgpu::wgpu::binding_model::ShaderStage::VERTEX,
+ maxLimits.clone(),
+ );
+ validation_map.insert(
+ webgpu::wgpu::binding_model::ShaderStage::FRAGMENT,
+ maxLimits.clone(),
+ );
+ validation_map.insert(
+ webgpu::wgpu::binding_model::ShaderStage::COMPUTE,
+ maxLimits.clone(),
+ );
+ let mut max_dynamic_uniform_buffers_per_pipeline_layout =
+ limits.maxDynamicUniformBuffersPerPipelineLayout as i32;
+ let mut max_dynamic_storage_buffers_per_pipeline_layout =
+ limits.maxDynamicStorageBuffersPerPipelineLayout as i32;
+ let mut valid = true;
+
+ let bindings = descriptor
+ .bindings
+ .iter()
+ .map(|bind| {
+ // TODO: binding must be >= 0
+ storeBindings.insert(bind.binding);
+ let visibility = match ShaderStage::from_bits(bind.visibility) {
+ Some(visibility) => visibility,
+ None => {
+ valid = false;
+ ShaderStage::from_bits(0).unwrap()
+ },
+ };
+ let ty = match bind.type_ {
+ GPUBindingType::Uniform_buffer => {
+ if let Some(limit) = validation_map.get_mut(&visibility) {
+ limit.max_uniform_buffers_per_shader_stage -= 1;
+ }
+ if bind.hasDynamicOffset {
+ max_dynamic_uniform_buffers_per_pipeline_layout -= 1;
+ };
+ BindingType::UniformBuffer
+ },
+ GPUBindingType::Storage_buffer => {
+ if let Some(limit) = validation_map.get_mut(&visibility) {
+ limit.max_storage_buffers_per_shader_stage -= 1;
+ }
+ if bind.hasDynamicOffset {
+ max_dynamic_storage_buffers_per_pipeline_layout -= 1;
+ };
+ BindingType::StorageBuffer
+ },
+ GPUBindingType::Readonly_storage_buffer => {
+ if let Some(limit) = validation_map.get_mut(&visibility) {
+ limit.max_storage_buffers_per_shader_stage -= 1;
+ }
+ if bind.hasDynamicOffset {
+ max_dynamic_storage_buffers_per_pipeline_layout -= 1;
+ };
+ BindingType::ReadonlyStorageBuffer
+ },
+ GPUBindingType::Sampled_texture => {
+ if let Some(limit) = validation_map.get_mut(&visibility) {
+ limit.max_sampled_textures_per_shader_stage -= 1;
+ }
+ if bind.hasDynamicOffset {
+ valid = false
+ };
+ BindingType::SampledTexture
+ },
+ GPUBindingType::Storage_texture => {
+ if let Some(limit) = validation_map.get_mut(&visibility) {
+ limit.max_storage_textures_per_shader_stage -= 1;
+ }
+ if bind.hasDynamicOffset {
+ valid = false
+ };
+ BindingType::StorageTexture
+ },
+ GPUBindingType::Sampler => {
+ if let Some(limit) = validation_map.get_mut(&visibility) {
+ limit.max_samplers_per_shader_stage -= 1;
+ }
+ if bind.hasDynamicOffset {
+ valid = false
+ };
+ BindingType::Sampler
+ },
+ };
+
+ BindGroupLayoutBinding {
+ binding: bind.binding,
+ visibility,
+ ty,
+ dynamic: bind.hasDynamicOffset,
+ multisampled: bind.multisampled,
+ texture_dimension: webgpu::wgpu::resource::TextureViewDimension::D2, // Use as default for now
+ }
+ })
+ .collect::<Vec<BindGroupLayoutBinding>>();
+
+ // bindings are unique
+ valid &= storeBindings.len() == bindings.len();
+
+ // Ensure that values do not exceed the max limit for each ShaderStage.
+ valid &= validation_map.values().all(|stage| {
+ stage.max_uniform_buffers_per_shader_stage >= 0 &&
+ stage.max_storage_buffers_per_shader_stage >= 0 &&
+ stage.max_sampled_textures_per_shader_stage >= 0 &&
+ stage.max_storage_textures_per_shader_stage >= 0 &&
+ stage.max_samplers_per_shader_stage >= 0
+ });
+
+ // DynamicValues does not exceed the max limit for the pipeline
+ valid &= max_dynamic_uniform_buffers_per_pipeline_layout >= 0 &&
+ max_dynamic_storage_buffers_per_pipeline_layout >= 0;
+
+ let (sender, receiver) = ipc::channel().unwrap();
+ if let Some(window) = self.global().downcast::<Window>() {
+ let id = window
+ .Navigator()
+ .create_bind_group_layout_id(self.device.0.backend());
+ self.channel
+ .0
+ .send(WebGPURequest::CreateBindGroupLayout(
+ sender,
+ self.device,
+ id,
+ bindings.clone(),
+ ))
+ .expect("Failed to create WebGPU BindGroupLayout");
+ }
+ let bgl = receiver.recv().unwrap();
+
+ let binds = descriptor
+ .bindings
+ .iter()
+ .map(|bind| GPUBindGroupLayoutBindings {
+ binding: bind.binding,
+ hasDynamicOffset: bind.hasDynamicOffset,
+ multisampled: bind.multisampled,
+ type_: bind.type_,
+ visibility: bind.visibility,
+ //texture_dimension: bind.texture_dimension
+ })
+ .collect::<Vec<_>>();
+
+ GPUBindGroupLayout::new(&self.global(), self.channel.clone(), bgl, binds, valid)
+ }
}
diff --git a/components/script/dom/gpushaderstage.rs b/components/script/dom/gpushaderstage.rs
new file mode 100644
index 00000000000..a9cd1d90589
--- /dev/null
+++ b/components/script/dom/gpushaderstage.rs
@@ -0,0 +1,11 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use crate::dom::bindings::reflector::Reflector;
+use dom_struct::dom_struct;
+
+#[dom_struct]
+pub struct GPUShaderStage {
+ reflector_: Reflector,
+}
diff --git a/components/script/dom/identityhub.rs b/components/script/dom/identityhub.rs
index 64e4cad3867..91543d2ea3f 100644
--- a/components/script/dom/identityhub.rs
+++ b/components/script/dom/identityhub.rs
@@ -5,7 +5,7 @@
use smallvec::SmallVec;
use webgpu::wgpu::{
hub::IdentityManager,
- id::{AdapterId, BufferId, DeviceId},
+ id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId},
Backend,
};
@@ -14,6 +14,7 @@ pub struct IdentityHub {
adapters: IdentityManager,
devices: IdentityManager,
buffers: IdentityManager,
+ bind_group_layouts: IdentityManager,
backend: Backend,
}
@@ -23,6 +24,7 @@ impl IdentityHub {
adapters: IdentityManager::default(),
devices: IdentityManager::default(),
buffers: IdentityManager::default(),
+ bind_group_layouts: IdentityManager::default(),
backend,
}
}
@@ -35,9 +37,13 @@ impl IdentityHub {
self.devices.alloc(self.backend)
}
- pub fn create_buffer_id(&mut self) -> BufferId {
+ fn create_buffer_id(&mut self) -> BufferId {
self.buffers.alloc(self.backend)
}
+
+ fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId {
+ self.bind_group_layouts.alloc(self.backend)
+ }
}
#[derive(Debug)]
@@ -119,4 +125,18 @@ impl Identities {
_ => self.dummy_hub.create_buffer_id(),
}
}
+
+ pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId {
+ match backend {
+ #[cfg(any(target_os = "linux", target_os = "windows"))]
+ Backend::Vulkan => self.vk_hub.create_bind_group_layout_id(),
+ #[cfg(target_os = "windows")]
+ Backend::Dx12 => self.dx12_hub.create_bind_group_layout_id(),
+ #[cfg(target_os = "windows")]
+ Backend::Dx11 => self.dx11_hub.create_bind_group_layout_id(),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ Backend::Metal => self.metal_hub.create_bind_group_layout_id(),
+ _ => self.dummy_hub.create_bind_group_layout_id(),
+ }
+ }
}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 0fdf4a80b69..08f1f0812fb 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -318,9 +318,11 @@ pub mod gamepadlist;
pub mod globalscope;
pub mod gpu;
pub mod gpuadapter;
+pub mod gpubindgrouplayout;
pub mod gpubuffer;
pub mod gpubufferusage;
pub mod gpudevice;
+pub mod gpushaderstage;
pub mod hashchangeevent;
pub mod headers;
pub mod history;
diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs
index 03c6b27d156..3d04433bfcd 100644
--- a/components/script/dom/navigator.rs
+++ b/components/script/dom/navigator.rs
@@ -28,7 +28,7 @@ use smallvec::SmallVec;
use std::cell::RefCell;
use std::rc::Rc;
use webgpu::wgpu::{
- id::{AdapterId, BufferId, DeviceId},
+ id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId},
Backend,
};
@@ -88,6 +88,12 @@ impl Navigator {
pub fn create_buffer_id(&self, backend: Backend) -> BufferId {
self.gpu_id_hub.borrow_mut().create_buffer_id(backend)
}
+
+ pub fn create_bind_group_layout_id(&self, backend: Backend) -> BindGroupLayoutId {
+ self.gpu_id_hub
+ .borrow_mut()
+ .create_bind_group_layout_id(backend)
+ }
}
impl NavigatorMethods for Navigator {
diff --git a/components/script/dom/webidls/GPUBindGroupLayout.webidl b/components/script/dom/webidls/GPUBindGroupLayout.webidl
new file mode 100644
index 00000000000..930a1dd84cc
--- /dev/null
+++ b/components/script/dom/webidls/GPUBindGroupLayout.webidl
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#gpubindgrouplayout
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUBindGroupLayout {
+};
+GPUBindGroupLayout includes GPUObjectBase;
+
+dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase {
+ required sequence<GPUBindGroupLayoutBindings> bindings;
+};
+
+// Note: Servo codegen doesn't like the name `GPUBindGroupLayoutBinding` because it's already occupied
+// dictionary GPUBindGroupLayoutBinding {
+dictionary GPUBindGroupLayoutBindings {
+ required unsigned long binding;
+ required GPUShaderStageFlags visibility;
+ required GPUBindingType type;
+ //GPUTextureViewDimension textureDimension = "2d";
+ //GPUTextureComponentType textureComponentType = "float";
+ boolean multisampled = false;
+ boolean hasDynamicOffset = false;
+};
+
+enum GPUBindingType {
+ "uniform-buffer",
+ "storage-buffer",
+ "readonly-storage-buffer",
+ "sampler",
+ "sampled-texture",
+ "storage-texture"
+};
diff --git a/components/script/dom/webidls/GPUDevice.webidl b/components/script/dom/webidls/GPUDevice.webidl
index 965f7e1b7d5..512f9bf649f 100644
--- a/components/script/dom/webidls/GPUDevice.webidl
+++ b/components/script/dom/webidls/GPUDevice.webidl
@@ -11,12 +11,12 @@ interface GPUDevice : EventTarget {
GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
- /*Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
- GPUTexture createTexture(GPUTextureDescriptor descriptor);
- GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
+ //Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
+ //GPUTexture createTexture(GPUTextureDescriptor descriptor);
+ //GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
- GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
+ /*GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
diff --git a/components/script/dom/webidls/GPUShaderStage.webidl b/components/script/dom/webidls/GPUShaderStage.webidl
new file mode 100644
index 00000000000..27fcb550cc3
--- /dev/null
+++ b/components/script/dom/webidls/GPUShaderStage.webidl
@@ -0,0 +1,13 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+// https://gpuweb.github.io/gpuweb/#typedefdef-gpushaderstageflags
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUShaderStage {
+ const GPUShaderStageFlags VERTEX = 0x1;
+ const GPUShaderStageFlags FRAGMENT = 0x2;
+ const GPUShaderStageFlags COMPUTE = 0x4;
+};
+
+typedef unsigned long GPUShaderStageFlags;