Skip to content

Commit

Permalink
Initial implementation of GPUPipelineLayout for WebGPU
Browse files Browse the repository at this point in the history
Added WebIDL bindings for `GPUPipelineLayout`.
Implemented the createPipelineLayout function of `GPUDevice`.
  • Loading branch information
Istvan Miklos committed Jan 21, 2020
1 parent 0dccfd1 commit d33a4d2
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 6 deletions.
5 changes: 4 additions & 1 deletion components/script/dom/bindings/trace.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
15 changes: 15 additions & 0 deletions components/script/dom/gpubindgrouplayout.rs
Expand Up @@ -42,6 +42,7 @@ impl GPUBindGroupLayout {
valid: Cell::new(valid),
}
}

pub fn new(
global: &GlobalScope,
channel: WebGPU,
Expand All @@ -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> {
Expand Down
67 changes: 67 additions & 0 deletions components/script/dom/gpudevice.rs
Expand Up @@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -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)
}
}
69 changes: 69 additions & 0 deletions 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;
}
}
22 changes: 21 additions & 1 deletion components/script/dom/identityhub.rs
Expand Up @@ -5,7 +5,7 @@
use smallvec::SmallVec;
use webgpu::wgpu::{
hub::IdentityManager,
id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId},
id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
Backend,
};

Expand All @@ -15,6 +15,7 @@ pub struct IdentityHub {
devices: IdentityManager,
buffers: IdentityManager,
bind_group_layouts: IdentityManager,
pipeline_layouts: IdentityManager,
backend: Backend,
}

Expand All @@ -25,6 +26,7 @@ impl IdentityHub {
devices: IdentityManager::default(),
buffers: IdentityManager::default(),
bind_group_layouts: IdentityManager::default(),
pipeline_layouts: IdentityManager::default(),
backend,
}
}
Expand All @@ -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)]
Expand Down Expand Up @@ -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(),
}
}
}
1 change: 1 addition & 0 deletions components/script/dom/mod.rs
Expand Up @@ -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;
Expand Down
8 changes: 7 additions & 1 deletion components/script/dom/navigator.rs
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions components/script/dom/webidls/GPUDevice.webidl
Expand Up @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions 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;
};
25 changes: 24 additions & 1 deletion components/webgpu/lib.rs
Expand Up @@ -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),
}
Expand Down Expand Up @@ -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
)
}
Expand Down Expand Up @@ -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);

0 comments on commit d33a4d2

Please sign in to comment.