aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIstvan Miklos <istvan.miklos@h-lab.eu>2020-01-15 12:16:32 +0100
committerIstvan Miklos <istvan.miklos@h-lab.eu>2020-01-21 14:47:38 +0100
commitd33a4d29a0d8467531a3beb722dfdb3e15df12ae (patch)
tree43d722bb7cf730337ef875ee55b36757fca6a3ae
parent0dccfd148a62807d1d962aaef5321f4ce6d9dbc9 (diff)
downloadservo-d33a4d29a0d8467531a3beb722dfdb3e15df12ae.tar.gz
servo-d33a4d29a0d8467531a3beb722dfdb3e15df12ae.zip
Initial implementation of GPUPipelineLayout for WebGPU
Added WebIDL bindings for `GPUPipelineLayout`. Implemented the createPipelineLayout function of `GPUDevice`.
-rw-r--r--components/script/dom/bindings/trace.rs5
-rw-r--r--components/script/dom/gpubindgrouplayout.rs15
-rw-r--r--components/script/dom/gpudevice.rs67
-rw-r--r--components/script/dom/gpupipelinelayout.rs69
-rw-r--r--components/script/dom/identityhub.rs22
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/navigator.rs8
-rw-r--r--components/script/dom/webidls/GPUDevice.webidl4
-rw-r--r--components/script/dom/webidls/GPUPipelineLayout.webidl13
-rw-r--r--components/webgpu/lib.rs25
10 files changed, 223 insertions, 6 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index bdcf9919752..ffd4a4952d0 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -151,7 +151,9 @@ use tendril::stream::LossyDecoder;
use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec, Tm};
use uuid::Uuid;
-use webgpu::{WebGPU, WebGPUAdapter, WebGPUBindGroupLayout, WebGPUBuffer, WebGPUDevice};
+use webgpu::{
+ WebGPU, WebGPUAdapter, WebGPUBindGroupLayout, WebGPUBuffer, WebGPUDevice, WebGPUPipelineLayout,
+};
use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
use webxr_api::SwapChainId as WebXRSwapChainId;
@@ -531,6 +533,7 @@ unsafe_no_jsmanaged_fields!(WebGPUAdapter);
unsafe_no_jsmanaged_fields!(WebGPUDevice);
unsafe_no_jsmanaged_fields!(WebGPUBuffer);
unsafe_no_jsmanaged_fields!(WebGPUBindGroupLayout);
+unsafe_no_jsmanaged_fields!(WebGPUPipelineLayout);
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
index 7669f0e5f2d..7651d16b52b 100644
--- a/components/script/dom/gpubindgrouplayout.rs
+++ b/components/script/dom/gpubindgrouplayout.rs
@@ -42,6 +42,7 @@ impl GPUBindGroupLayout {
valid: Cell::new(valid),
}
}
+
pub fn new(
global: &GlobalScope,
channel: WebGPU,
@@ -62,6 +63,20 @@ impl GPUBindGroupLayout {
}
}
+impl GPUBindGroupLayout {
+ pub fn is_valid(&self) -> bool {
+ self.valid.get()
+ }
+
+ pub fn id(&self) -> WebGPUBindGroupLayout {
+ self.bind_group_layout
+ }
+
+ pub fn bindings(&self) -> &[GPUBindGroupLayoutBindings] {
+ &self.bindings
+ }
+}
+
impl GPUBindGroupLayoutMethods for GPUBindGroupLayout {
/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<DOMString> {
diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs
index 1cc00110146..0ebefda60a0 100644
--- a/components/script/dom/gpudevice.rs
+++ b/components/script/dom/gpudevice.rs
@@ -11,6 +11,7 @@ use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
};
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{self, GPUDeviceMethods};
+use crate::dom::bindings::codegen::Bindings::GPUPipelineLayoutBinding::GPUPipelineLayoutDescriptor;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
@@ -21,6 +22,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuadapter::GPUAdapter;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState};
+use crate::dom::gpupipelinelayout::GPUPipelineLayout;
use crate::dom::window::Window;
use crate::script_runtime::JSContext as SafeJSContext;
use dom_struct::dom_struct;
@@ -410,4 +412,69 @@ impl GPUDeviceMethods for GPUDevice {
GPUBindGroupLayout::new(&self.global(), self.channel.clone(), bgl, binds, valid)
}
+
+ /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createpipelinelayout
+ fn CreatePipelineLayout(
+ &self,
+ descriptor: &GPUPipelineLayoutDescriptor,
+ ) -> DomRoot<GPUPipelineLayout> {
+ // TODO: We should have these limits on device creation
+ let limits = GPULimits::empty();
+ let mut bind_group_layouts = Vec::new();
+ let mut bgl_ids = Vec::new();
+ 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;
+ descriptor.bindGroupLayouts.iter().for_each(|each| {
+ if each.is_valid() {
+ let id = each.id();
+ bind_group_layouts.push(id);
+ bgl_ids.push(id.0);
+ }
+ each.bindings().iter().for_each(|bind| {
+ match bind.type_ {
+ GPUBindingType::Uniform_buffer => {
+ if bind.hasDynamicOffset {
+ max_dynamic_uniform_buffers_per_pipeline_layout -= 1;
+ };
+ },
+ GPUBindingType::Storage_buffer => {
+ if bind.hasDynamicOffset {
+ max_dynamic_storage_buffers_per_pipeline_layout -= 1;
+ };
+ },
+ GPUBindingType::Readonly_storage_buffer => {
+ if bind.hasDynamicOffset {
+ max_dynamic_storage_buffers_per_pipeline_layout -= 1;
+ };
+ },
+ _ => {},
+ };
+ });
+ });
+
+ let valid = descriptor.bindGroupLayouts.len() <= limits.maxBindGroups as usize &&
+ descriptor.bindGroupLayouts.len() == bind_group_layouts.len() &&
+ 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_pipeline_layout_id(self.device.0.backend());
+ self.channel
+ .0
+ .send(WebGPURequest::CreatePipelineLayout(
+ sender,
+ self.device,
+ id,
+ bgl_ids,
+ ))
+ .expect("Failed to create WebGPU PipelineLayout");
+ }
+ let pipeline_layout = receiver.recv().unwrap();
+ GPUPipelineLayout::new(&self.global(), bind_group_layouts, pipeline_layout, valid)
+ }
}
diff --git a/components/script/dom/gpupipelinelayout.rs b/components/script/dom/gpupipelinelayout.rs
new file mode 100644
index 00000000000..a52bbedb7b5
--- /dev/null
+++ b/components/script/dom/gpupipelinelayout.rs
@@ -0,0 +1,69 @@
+/* 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::GPUPipelineLayoutBinding::{
+ self, GPUPipelineLayoutMethods,
+};
+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::{WebGPUBindGroupLayout, WebGPUPipelineLayout};
+
+#[dom_struct]
+pub struct GPUPipelineLayout {
+ reflector_: Reflector,
+ bind_group_layouts: Vec<WebGPUBindGroupLayout>,
+ label: DomRefCell<Option<DOMString>>,
+ pipeline_layout: WebGPUPipelineLayout,
+ valid: Cell<bool>,
+}
+
+impl GPUPipelineLayout {
+ fn new_inherited(
+ bind_group_layouts: Vec<WebGPUBindGroupLayout>,
+ pipeline_layout: WebGPUPipelineLayout,
+ valid: bool,
+ ) -> GPUPipelineLayout {
+ Self {
+ reflector_: Reflector::new(),
+ bind_group_layouts,
+ label: DomRefCell::new(None),
+ pipeline_layout,
+ valid: Cell::new(valid),
+ }
+ }
+
+ pub fn new(
+ global: &GlobalScope,
+ bind_group_layouts: Vec<WebGPUBindGroupLayout>,
+ pipeline_layout: WebGPUPipelineLayout,
+ valid: bool,
+ ) -> DomRoot<GPUPipelineLayout> {
+ reflect_dom_object(
+ Box::new(GPUPipelineLayout::new_inherited(
+ bind_group_layouts,
+ pipeline_layout,
+ valid,
+ )),
+ global,
+ GPUPipelineLayoutBinding::Wrap,
+ )
+ }
+}
+
+impl GPUPipelineLayoutMethods for GPUPipelineLayout {
+ /// 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/identityhub.rs b/components/script/dom/identityhub.rs
index 91543d2ea3f..91ead1acf0a 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, BindGroupLayoutId, BufferId, DeviceId},
+ id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
Backend,
};
@@ -15,6 +15,7 @@ pub struct IdentityHub {
devices: IdentityManager,
buffers: IdentityManager,
bind_group_layouts: IdentityManager,
+ pipeline_layouts: IdentityManager,
backend: Backend,
}
@@ -25,6 +26,7 @@ impl IdentityHub {
devices: IdentityManager::default(),
buffers: IdentityManager::default(),
bind_group_layouts: IdentityManager::default(),
+ pipeline_layouts: IdentityManager::default(),
backend,
}
}
@@ -44,6 +46,10 @@ impl IdentityHub {
fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId {
self.bind_group_layouts.alloc(self.backend)
}
+
+ fn create_pipeline_layout_id(&mut self) -> PipelineLayoutId {
+ self.pipeline_layouts.alloc(self.backend)
+ }
}
#[derive(Debug)]
@@ -139,4 +145,18 @@ impl Identities {
_ => self.dummy_hub.create_bind_group_layout_id(),
}
}
+
+ pub fn create_pipeline_layout_id(&mut self, backend: Backend) -> PipelineLayoutId {
+ match backend {
+ #[cfg(any(target_os = "linux", target_os = "windows"))]
+ Backend::Vulkan => self.vk_hub.create_pipeline_layout_id(),
+ #[cfg(target_os = "windows")]
+ Backend::Dx12 => self.dx12_hub.create_pipeline_layout_id(),
+ #[cfg(target_os = "windows")]
+ Backend::Dx11 => self.dx11_hub.create_pipeline_layout_id(),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ Backend::Metal => self.metal_hub.create_pipeline_layout_id(),
+ _ => self.dummy_hub.create_pipeline_layout_id(),
+ }
+ }
}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 08f1f0812fb..a39143c845b 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -322,6 +322,7 @@ pub mod gpubindgrouplayout;
pub mod gpubuffer;
pub mod gpubufferusage;
pub mod gpudevice;
+pub mod gpupipelinelayout;
pub mod gpushaderstage;
pub mod hashchangeevent;
pub mod headers;
diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs
index 3d04433bfcd..1c96907cb31 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, BindGroupLayoutId, BufferId, DeviceId},
+ id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
Backend,
};
@@ -94,6 +94,12 @@ impl Navigator {
.borrow_mut()
.create_bind_group_layout_id(backend)
}
+
+ pub fn create_pipeline_layout_id(&self, backend: Backend) -> PipelineLayoutId {
+ self.gpu_id_hub
+ .borrow_mut()
+ .create_pipeline_layout_id(backend)
+ }
}
impl NavigatorMethods for Navigator {
diff --git a/components/script/dom/webidls/GPUDevice.webidl b/components/script/dom/webidls/GPUDevice.webidl
index 512f9bf649f..85e8a3ea633 100644
--- a/components/script/dom/webidls/GPUDevice.webidl
+++ b/components/script/dom/webidls/GPUDevice.webidl
@@ -16,8 +16,8 @@ interface GPUDevice : EventTarget {
//GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
- /*GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
- GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
+ GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
+ /*GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
diff --git a/components/script/dom/webidls/GPUPipelineLayout.webidl b/components/script/dom/webidls/GPUPipelineLayout.webidl
new file mode 100644
index 00000000000..a50c2c60f40
--- /dev/null
+++ b/components/script/dom/webidls/GPUPipelineLayout.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/#pipeline-layout
+[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
+interface GPUPipelineLayout {
+};
+GPUPipelineLayout includes GPUObjectBase;
+
+dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
+ required sequence<GPUBindGroupLayout> bindGroupLayouts;
+};
diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs
index 92d99f8a90e..8d223a12366 100644
--- a/components/webgpu/lib.rs
+++ b/components/webgpu/lib.rs
@@ -54,6 +54,12 @@ pub enum WebGPURequest {
wgpu::id::BindGroupLayoutId,
Vec<wgpu::binding_model::BindGroupLayoutBinding>,
),
+ CreatePipelineLayout(
+ IpcSender<WebGPUPipelineLayout>,
+ WebGPUDevice,
+ wgpu::id::PipelineLayoutId,
+ Vec<wgpu::id::BindGroupLayoutId>,
+ ),
UnmapBuffer(WebGPUBuffer),
DestroyBuffer(WebGPUBuffer),
}
@@ -237,7 +243,23 @@ impl WGPU {
if let Err(e) = sender.send(bgl) {
warn!(
- "Failed to send response to WebGPURequest::CreateBufferMapped ({})",
+ "Failed to send response to WebGPURequest::CreateBindGroupLayout ({})",
+ e
+ )
+ }
+ },
+ WebGPURequest::CreatePipelineLayout(sender, device, id, bind_group_layouts) => {
+ let global = &self.global;
+ let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor {
+ bind_group_layouts: bind_group_layouts.as_ptr(),
+ bind_group_layouts_length: bind_group_layouts.len(),
+ };
+ let pl_id = gfx_select!(id => global.device_create_pipeline_layout(device.0, &descriptor, id));
+ let pipeline_layout = WebGPUPipelineLayout(pl_id);
+
+ if let Err(e) = sender.send(pipeline_layout) {
+ warn!(
+ "Failed to send response to WebGPURequest::CreatePipelineLayout ({})",
e
)
}
@@ -273,3 +295,4 @@ webgpu_resource!(WebGPUAdapter, wgpu::id::AdapterId);
webgpu_resource!(WebGPUDevice, wgpu::id::DeviceId);
webgpu_resource!(WebGPUBuffer, wgpu::id::BufferId);
webgpu_resource!(WebGPUBindGroupLayout, wgpu::id::BindGroupLayoutId);
+webgpu_resource!(WebGPUPipelineLayout, wgpu::id::PipelineLayoutId);