Implement GPUPipelineBase for implicit pipeline layouts

This commit is contained in:
Kunal Mohan 2020-08-19 16:44:26 +05:30
parent 8c576bb02b
commit f082a507da
7 changed files with 176 additions and 25 deletions

View file

@ -3,28 +3,37 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::GPULimits;
use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::GPUComputePipelineMethods; use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::GPUComputePipelineMethods;
use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::Reflector; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use webgpu::WebGPUComputePipeline; use std::string::String;
use webgpu::{WebGPUBindGroupLayout, WebGPUComputePipeline};
#[dom_struct] #[dom_struct]
pub struct GPUComputePipeline { pub struct GPUComputePipeline {
reflector_: Reflector, reflector_: Reflector,
label: DomRefCell<Option<USVString>>, label: DomRefCell<Option<USVString>>,
compute_pipeline: WebGPUComputePipeline, compute_pipeline: WebGPUComputePipeline,
bind_group_layouts: Vec<WebGPUBindGroupLayout>,
} }
impl GPUComputePipeline { impl GPUComputePipeline {
fn new_inherited(compute_pipeline: WebGPUComputePipeline, label: Option<USVString>) -> Self { fn new_inherited(
compute_pipeline: WebGPUComputePipeline,
label: Option<USVString>,
bgls: Vec<WebGPUBindGroupLayout>,
) -> Self {
Self { Self {
reflector_: Reflector::new(), reflector_: Reflector::new(),
label: DomRefCell::new(label), label: DomRefCell::new(label),
compute_pipeline, compute_pipeline,
bind_group_layouts: bgls,
} }
} }
@ -32,9 +41,14 @@ impl GPUComputePipeline {
global: &GlobalScope, global: &GlobalScope,
compute_pipeline: WebGPUComputePipeline, compute_pipeline: WebGPUComputePipeline,
label: Option<USVString>, label: Option<USVString>,
bgls: Vec<WebGPUBindGroupLayout>,
) -> DomRoot<Self> { ) -> DomRoot<Self> {
reflect_dom_object( reflect_dom_object(
Box::new(GPUComputePipeline::new_inherited(compute_pipeline, label)), Box::new(GPUComputePipeline::new_inherited(
compute_pipeline,
label,
bgls,
)),
global, global,
) )
} }
@ -56,4 +70,17 @@ impl GPUComputePipelineMethods for GPUComputePipeline {
fn SetLabel(&self, value: Option<USVString>) { fn SetLabel(&self, value: Option<USVString>) {
*self.label.borrow_mut() = value; *self.label.borrow_mut() = value;
} }
/// https://gpuweb.github.io/gpuweb/#dom-gpupipelinebase-getbindgrouplayout
fn GetBindGroupLayout(&self, index: u32) -> Fallible<DomRoot<GPUBindGroupLayout>> {
if index > self.bind_group_layouts.len() as u32 || index > GPULimits::empty().maxBindGroups
{
return Err(Error::Range(String::from("Index out of bounds")));
}
return Ok(GPUBindGroupLayout::new(
&self.global(),
self.bind_group_layouts[index as usize],
None,
));
}
} }

View file

@ -7,6 +7,7 @@
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit; use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit;
use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::GPULimits;
use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::{ use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::{
GPUBindGroupDescriptor, GPUBindingResource, GPUBindGroupDescriptor, GPUBindingResource,
}; };
@ -74,7 +75,9 @@ use std::collections::HashMap;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::rc::Rc; use std::rc::Rc;
use webgpu::wgpu::{ use webgpu::wgpu::{
binding_model as wgpu_bind, command as wgpu_com, pipeline as wgpu_pipe, resource as wgpu_res, binding_model as wgpu_bind, command as wgpu_com,
id::{BindGroupLayoutId, PipelineLayoutId},
pipeline as wgpu_pipe, resource as wgpu_res,
}; };
use webgpu::{self, identity::WebGPUOpResult, wgt, ErrorScopeId, WebGPU, WebGPURequest}; use webgpu::{self, identity::WebGPUOpResult, wgt, ErrorScopeId, WebGPU, WebGPURequest};
@ -279,6 +282,38 @@ impl GPUDevice {
}) })
}) })
} }
fn get_pipeline_layout_data(
&self,
layout: &Option<DomRoot<GPUPipelineLayout>>,
) -> (
Option<PipelineLayoutId>,
Option<(PipelineLayoutId, Vec<BindGroupLayoutId>)>,
Vec<webgpu::WebGPUBindGroupLayout>,
) {
if let Some(ref layout) = layout {
(Some(layout.id().0), None, layout.bind_group_layouts())
} else {
let layout_id = self
.global()
.wgpu_id_hub()
.lock()
.create_pipeline_layout_id(self.device.0.backend());
let max_bind_grps = GPULimits::empty().maxBindGroups;
let mut bgls = Vec::with_capacity(max_bind_grps as usize);
let mut bgl_ids = Vec::with_capacity(max_bind_grps as usize);
for _ in 0..max_bind_grps {
let bgl = self
.global()
.wgpu_id_hub()
.lock()
.create_bind_group_layout_id(self.device.0.backend());
bgls.push(webgpu::WebGPUBindGroupLayout(bgl));
bgl_ids.push(bgl);
}
(None, Some((layout_id, bgl_ids)), bgls)
}
}
} }
impl GPUDeviceMethods for GPUDevice { impl GPUDeviceMethods for GPUDevice {
@ -552,11 +587,17 @@ impl GPUDeviceMethods for GPUDevice {
)) ))
.expect("Failed to create WebGPU PipelineLayout"); .expect("Failed to create WebGPU PipelineLayout");
let bgls = descriptor
.bindGroupLayouts
.iter()
.map(|each| each.id())
.collect::<Vec<_>>();
let pipeline_layout = webgpu::WebGPUPipelineLayout(pipeline_layout_id); let pipeline_layout = webgpu::WebGPUPipelineLayout(pipeline_layout_id);
GPUPipelineLayout::new( GPUPipelineLayout::new(
&self.global(), &self.global(),
pipeline_layout, pipeline_layout,
descriptor.parent.label.as_ref().cloned(), descriptor.parent.label.as_ref().cloned(),
bgls,
) )
} }
@ -671,10 +712,11 @@ impl GPUDeviceMethods for GPUDevice {
.create_compute_pipeline_id(self.device.0.backend()); .create_compute_pipeline_id(self.device.0.backend());
let scope_id = self.use_current_scope(); let scope_id = self.use_current_scope();
let (layout, implicit_ids, bgls) = self.get_pipeline_layout_data(&descriptor.parent.layout);
let desc = wgpu_pipe::ComputePipelineDescriptor { let desc = wgpu_pipe::ComputePipelineDescriptor {
label: convert_label(&descriptor.parent.parent), label: convert_label(&descriptor.parent.parent),
layout: Some(descriptor.parent.layout.id().0), layout,
compute_stage: wgpu_pipe::ProgrammableStageDescriptor { compute_stage: wgpu_pipe::ProgrammableStageDescriptor {
module: descriptor.computeStage.module.id().0, module: descriptor.computeStage.module.id().0,
entry_point: Cow::Owned(descriptor.computeStage.entryPoint.to_string()), entry_point: Cow::Owned(descriptor.computeStage.entryPoint.to_string()),
@ -689,6 +731,7 @@ impl GPUDeviceMethods for GPUDevice {
device_id: self.device.0, device_id: self.device.0,
compute_pipeline_id, compute_pipeline_id,
descriptor: desc, descriptor: desc,
implicit_ids,
}, },
)) ))
.expect("Failed to create WebGPU ComputePipeline"); .expect("Failed to create WebGPU ComputePipeline");
@ -698,6 +741,7 @@ impl GPUDeviceMethods for GPUDevice {
&self.global(), &self.global(),
compute_pipeline, compute_pipeline,
descriptor.parent.parent.label.as_ref().cloned(), descriptor.parent.parent.label.as_ref().cloned(),
bgls,
) )
} }
@ -872,11 +916,12 @@ impl GPUDeviceMethods for GPUDevice {
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
let (layout, implicit_ids, bgls) = self.get_pipeline_layout_data(&descriptor.parent.layout);
let desc = if valid { let desc = if valid {
Some(wgpu_pipe::RenderPipelineDescriptor { Some(wgpu_pipe::RenderPipelineDescriptor {
label: convert_label(&descriptor.parent.parent), label: convert_label(&descriptor.parent.parent),
layout: Some(descriptor.parent.layout.id().0), layout,
vertex_stage: wgpu_pipe::ProgrammableStageDescriptor { vertex_stage: wgpu_pipe::ProgrammableStageDescriptor {
module: descriptor.vertexStage.module.id().0, module: descriptor.vertexStage.module.id().0,
entry_point: Cow::Owned(descriptor.vertexStage.entryPoint.to_string()), entry_point: Cow::Owned(descriptor.vertexStage.entryPoint.to_string()),
@ -991,6 +1036,7 @@ impl GPUDeviceMethods for GPUDevice {
device_id: self.device.0, device_id: self.device.0,
render_pipeline_id, render_pipeline_id,
descriptor: desc, descriptor: desc,
implicit_ids,
}, },
)) ))
.expect("Failed to create WebGPU render pipeline"); .expect("Failed to create WebGPU render pipeline");
@ -1000,8 +1046,8 @@ impl GPUDeviceMethods for GPUDevice {
GPURenderPipeline::new( GPURenderPipeline::new(
&self.global(), &self.global(),
render_pipeline, render_pipeline,
self.device,
descriptor.parent.parent.label.as_ref().cloned(), descriptor.parent.parent.label.as_ref().cloned(),
bgls,
) )
} }

View file

@ -9,21 +9,27 @@ use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use webgpu::WebGPUPipelineLayout; use webgpu::{WebGPUBindGroupLayout, WebGPUPipelineLayout};
#[dom_struct] #[dom_struct]
pub struct GPUPipelineLayout { pub struct GPUPipelineLayout {
reflector_: Reflector, reflector_: Reflector,
label: DomRefCell<Option<USVString>>, label: DomRefCell<Option<USVString>>,
pipeline_layout: WebGPUPipelineLayout, pipeline_layout: WebGPUPipelineLayout,
bind_group_layouts: Vec<WebGPUBindGroupLayout>,
} }
impl GPUPipelineLayout { impl GPUPipelineLayout {
fn new_inherited(pipeline_layout: WebGPUPipelineLayout, label: Option<USVString>) -> Self { fn new_inherited(
pipeline_layout: WebGPUPipelineLayout,
label: Option<USVString>,
bgls: Vec<WebGPUBindGroupLayout>,
) -> Self {
Self { Self {
reflector_: Reflector::new(), reflector_: Reflector::new(),
label: DomRefCell::new(label), label: DomRefCell::new(label),
pipeline_layout, pipeline_layout,
bind_group_layouts: bgls,
} }
} }
@ -31,9 +37,14 @@ impl GPUPipelineLayout {
global: &GlobalScope, global: &GlobalScope,
pipeline_layout: WebGPUPipelineLayout, pipeline_layout: WebGPUPipelineLayout,
label: Option<USVString>, label: Option<USVString>,
bgls: Vec<WebGPUBindGroupLayout>,
) -> DomRoot<Self> { ) -> DomRoot<Self> {
reflect_dom_object( reflect_dom_object(
Box::new(GPUPipelineLayout::new_inherited(pipeline_layout, label)), Box::new(GPUPipelineLayout::new_inherited(
pipeline_layout,
label,
bgls,
)),
global, global,
) )
} }
@ -43,6 +54,10 @@ impl GPUPipelineLayout {
pub fn id(&self) -> WebGPUPipelineLayout { pub fn id(&self) -> WebGPUPipelineLayout {
self.pipeline_layout self.pipeline_layout
} }
pub fn bind_group_layouts(&self) -> Vec<WebGPUBindGroupLayout> {
self.bind_group_layouts.clone()
}
} }
impl GPUPipelineLayoutMethods for GPUPipelineLayout { impl GPUPipelineLayoutMethods for GPUPipelineLayout {

View file

@ -3,48 +3,51 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::GPULimits;
use crate::dom::bindings::codegen::Bindings::GPURenderPipelineBinding::GPURenderPipelineMethods; use crate::dom::bindings::codegen::Bindings::GPURenderPipelineBinding::GPURenderPipelineMethods;
use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::Reflector; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::USVString; use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use webgpu::{WebGPUDevice, WebGPURenderPipeline}; use std::string::String;
use webgpu::{WebGPUBindGroupLayout, WebGPURenderPipeline};
#[dom_struct] #[dom_struct]
pub struct GPURenderPipeline { pub struct GPURenderPipeline {
reflector_: Reflector, reflector_: Reflector,
label: DomRefCell<Option<USVString>>, label: DomRefCell<Option<USVString>>,
render_pipeline: WebGPURenderPipeline, render_pipeline: WebGPURenderPipeline,
device: WebGPUDevice, bind_group_layouts: Vec<WebGPUBindGroupLayout>,
} }
impl GPURenderPipeline { impl GPURenderPipeline {
fn new_inherited( fn new_inherited(
render_pipeline: WebGPURenderPipeline, render_pipeline: WebGPURenderPipeline,
device: WebGPUDevice,
label: Option<USVString>, label: Option<USVString>,
bgls: Vec<WebGPUBindGroupLayout>,
) -> Self { ) -> Self {
Self { Self {
reflector_: Reflector::new(), reflector_: Reflector::new(),
label: DomRefCell::new(label), label: DomRefCell::new(label),
render_pipeline, render_pipeline,
device, bind_group_layouts: bgls,
} }
} }
pub fn new( pub fn new(
global: &GlobalScope, global: &GlobalScope,
render_pipeline: WebGPURenderPipeline, render_pipeline: WebGPURenderPipeline,
device: WebGPUDevice,
label: Option<USVString>, label: Option<USVString>,
bgls: Vec<WebGPUBindGroupLayout>,
) -> DomRoot<Self> { ) -> DomRoot<Self> {
reflect_dom_object( reflect_dom_object(
Box::new(GPURenderPipeline::new_inherited( Box::new(GPURenderPipeline::new_inherited(
render_pipeline, render_pipeline,
device,
label, label,
bgls,
)), )),
global, global,
) )
@ -67,4 +70,17 @@ impl GPURenderPipelineMethods for GPURenderPipeline {
fn SetLabel(&self, value: Option<USVString>) { fn SetLabel(&self, value: Option<USVString>) {
*self.label.borrow_mut() = value; *self.label.borrow_mut() = value;
} }
/// https://gpuweb.github.io/gpuweb/#dom-gpupipelinebase-getbindgrouplayout
fn GetBindGroupLayout(&self, index: u32) -> Fallible<DomRoot<GPUBindGroupLayout>> {
if index > self.bind_group_layouts.len() as u32 || index > GPULimits::empty().maxBindGroups
{
return Err(Error::Range(String::from("Index out of bounds")));
}
return Ok(GPUBindGroupLayout::new(
&self.global(),
self.bind_group_layouts[index as usize],
None,
));
}
} }

View file

@ -7,9 +7,10 @@
interface GPUComputePipeline { interface GPUComputePipeline {
}; };
GPUComputePipeline includes GPUObjectBase; GPUComputePipeline includes GPUObjectBase;
GPUComputePipeline includes GPUPipelineBase;
dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase { dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
required GPUPipelineLayout layout; GPUPipelineLayout layout;
}; };
dictionary GPUProgrammableStageDescriptor { dictionary GPUProgrammableStageDescriptor {
@ -20,3 +21,7 @@ dictionary GPUProgrammableStageDescriptor {
dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase { dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
required GPUProgrammableStageDescriptor computeStage; required GPUProgrammableStageDescriptor computeStage;
}; };
interface mixin GPUPipelineBase {
[Throws] GPUBindGroupLayout getBindGroupLayout(unsigned long index);
};

View file

@ -7,6 +7,7 @@
interface GPURenderPipeline { interface GPURenderPipeline {
}; };
GPURenderPipeline includes GPUObjectBase; GPURenderPipeline includes GPUObjectBase;
GPURenderPipeline includes GPUPipelineBase;
dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase { dictionary GPURenderPipelineDescriptor : GPUPipelineDescriptorBase {
required GPUProgrammableStageDescriptor vertexStage; required GPUProgrammableStageDescriptor vertexStage;

View file

@ -36,7 +36,7 @@ use wgpu::{
BufferCopyView, ComputePass, RenderBundleDescriptor, RenderBundleEncoder, RenderPass, BufferCopyView, ComputePass, RenderBundleDescriptor, RenderBundleEncoder, RenderPass,
TextureCopyView, TextureCopyView,
}, },
device::HostMap, device::{HostMap, ImplicitPipelineIds},
id, id,
instance::RequestAdapterOptions, instance::RequestAdapterOptions,
pipeline::{ComputePipelineDescriptor, RenderPipelineDescriptor}, pipeline::{ComputePipelineDescriptor, RenderPipelineDescriptor},
@ -141,6 +141,7 @@ pub enum WebGPURequest {
device_id: id::DeviceId, device_id: id::DeviceId,
compute_pipeline_id: id::ComputePipelineId, compute_pipeline_id: id::ComputePipelineId,
descriptor: ComputePipelineDescriptor<'static>, descriptor: ComputePipelineDescriptor<'static>,
implicit_ids: Option<(id::PipelineLayoutId, Vec<id::BindGroupLayoutId>)>,
}, },
CreateContext(IpcSender<webrender_api::ExternalImageId>), CreateContext(IpcSender<webrender_api::ExternalImageId>),
CreatePipelineLayout { CreatePipelineLayout {
@ -152,6 +153,7 @@ pub enum WebGPURequest {
device_id: id::DeviceId, device_id: id::DeviceId,
render_pipeline_id: id::RenderPipelineId, render_pipeline_id: id::RenderPipelineId,
descriptor: Option<RenderPipelineDescriptor<'static>>, descriptor: Option<RenderPipelineDescriptor<'static>>,
implicit_ids: Option<(id::PipelineLayoutId, Vec<id::BindGroupLayoutId>)>,
}, },
CreateSampler { CreateSampler {
device_id: id::DeviceId, device_id: id::DeviceId,
@ -611,13 +613,34 @@ impl<'a> WGPU<'a> {
device_id, device_id,
compute_pipeline_id, compute_pipeline_id,
descriptor, descriptor,
implicit_ids,
} => { } => {
let global = &self.global; let global = &self.global;
let result = gfx_select!(compute_pipeline_id => let bgls = implicit_ids
global.device_create_compute_pipeline(device_id, &descriptor, compute_pipeline_id, None)); .as_ref()
.map_or(Vec::with_capacity(0), |(_, bgls)| bgls.clone());
let implicit =
implicit_ids
.as_ref()
.map(|(layout, _)| ImplicitPipelineIds {
root_id: *layout,
group_ids: bgls.as_slice(),
});
let result = gfx_select!(compute_pipeline_id => global.device_create_compute_pipeline(
device_id,
&descriptor,
compute_pipeline_id,
implicit
));
if result.is_err() { if result.is_err() {
let _ = gfx_select!(compute_pipeline_id => let _ = gfx_select!(compute_pipeline_id =>
global.compute_pipeline_error(compute_pipeline_id)); global.compute_pipeline_error(compute_pipeline_id));
if let Some((layout, bgls)) = implicit_ids {
let _ = gfx_select!(layout => global.pipeline_layout_error(layout));
bgls.iter().for_each(|&bgl| {
let _ = gfx_select!(bgl => global.bind_group_layout_error(bgl));
});
}
} }
self.send_result(device_id, scope_id, result); self.send_result(device_id, scope_id, result);
}, },
@ -648,14 +671,32 @@ impl<'a> WGPU<'a> {
device_id, device_id,
render_pipeline_id, render_pipeline_id,
descriptor, descriptor,
implicit_ids,
} => { } => {
let global = &self.global; let global = &self.global;
let bgls = implicit_ids
.as_ref()
.map_or(Vec::with_capacity(0), |(_, bgls)| bgls.clone());
let implicit =
implicit_ids
.as_ref()
.map(|(layout, _)| ImplicitPipelineIds {
root_id: *layout,
group_ids: bgls.as_slice(),
});
if let Some(desc) = descriptor { if let Some(desc) = descriptor {
let result = gfx_select!(render_pipeline_id => let result = gfx_select!(render_pipeline_id =>
global.device_create_render_pipeline(device_id, &desc, render_pipeline_id, None)); global.device_create_render_pipeline(device_id, &desc, render_pipeline_id, implicit));
if result.is_err() { if result.is_err() {
let _ = gfx_select!(render_pipeline_id => let _ = gfx_select!(render_pipeline_id =>
global.render_pipeline_error(render_pipeline_id)); global.render_pipeline_error(render_pipeline_id));
if let Some((layout, bgls)) = implicit_ids {
let _ =
gfx_select!(layout => global.pipeline_layout_error(layout));
bgls.iter().for_each(|&bgl| {
let _ = gfx_select!(bgl => global.bind_group_layout_error(bgl));
});
}
} }
self.send_result(device_id, scope_id, result); self.send_result(device_id, scope_id, result);
} else { } else {