Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of GPUComputePipeline #25700

Merged
merged 2 commits into from Feb 11, 2020
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -152,8 +152,8 @@ use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec, Tm};
use uuid::Uuid;
use webgpu::{
WebGPU, WebGPUAdapter, WebGPUBindGroup, WebGPUBindGroupLayout, WebGPUBuffer, WebGPUDevice,
WebGPUPipelineLayout,
WebGPU, WebGPUAdapter, WebGPUBindGroup, WebGPUBindGroupLayout, WebGPUBuffer,
WebGPUComputePipeline, WebGPUDevice, WebGPUPipelineLayout, WebGPUShaderModule,
};
use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
@@ -535,7 +535,9 @@ unsafe_no_jsmanaged_fields!(WebGPUDevice);
unsafe_no_jsmanaged_fields!(WebGPUBuffer);
unsafe_no_jsmanaged_fields!(WebGPUBindGroup);
unsafe_no_jsmanaged_fields!(WebGPUBindGroupLayout);
unsafe_no_jsmanaged_fields!(WebGPUComputePipeline);
unsafe_no_jsmanaged_fields!(WebGPUPipelineLayout);
unsafe_no_jsmanaged_fields!(WebGPUShaderModule);
unsafe_no_jsmanaged_fields!(GPUBufferState);
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
unsafe_no_jsmanaged_fields!(MediaList);
@@ -98,7 +98,10 @@ use std::sync::Arc;
use time::{get_time, Timespec};
use uuid::Uuid;
use webgpu::wgpu::{
id::{AdapterId, BindGroupId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
id::{
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, ComputePipelineId, DeviceId,
PipelineLayoutId, ShaderModuleId,
},
Backend,
};

@@ -2128,6 +2131,17 @@ impl GlobalScope {
.borrow_mut()
.create_pipeline_layout_id(backend)
}

pub fn wgpu_create_shader_module_id(&self, backend: Backend) -> ShaderModuleId {

This comment has been minimized.

Copy link
@kvark

kvark Feb 8, 2020

Member

nit: perhaps it would be simpler to just have a function returning &mut GpuIdHub and let the users call the methods appropriately?

self.gpu_id_hub
.borrow_mut()
.create_shader_module_id(backend)
}
pub fn wgpu_create_compute_pipeline_id(&self, backend: Backend) -> ComputePipelineId {
self.gpu_id_hub

This comment has been minimized.

Copy link
@kvark

kvark Feb 8, 2020

Member

A bit surprised you are able to use the RefCell here. In Gecko implementation, multiple threads in the same content process may want to create their own resource IDs.

This comment has been minimized.

Copy link
@jdm

jdm Feb 10, 2020

Member

@imiklos Please file an issue about this - it sounds like when we create an ID, we could have multiple threads that end up creating the same ID independently. Possible we need to share a single gpu_id_hub between all threads using Arc & Mutex?

.borrow_mut()
.create_compute_pipeline_id(backend)
}
}

fn timestamp_in_ms(time: Timespec) -> u64 {
@@ -0,0 +1,55 @@
/* 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::GPUComputePipelineBinding::{
GPUComputePipelineBinding, GPUComputePipelineMethods,
};
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::reflector::Reflector;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
use webgpu::WebGPUComputePipeline;

#[dom_struct]
pub struct GPUComputePipeline {
reflector_: Reflector,
label: DomRefCell<Option<DOMString>>,
compute_pipeline: WebGPUComputePipeline,
}

impl GPUComputePipeline {
fn new_inherited(compute_pipeline: WebGPUComputePipeline) -> GPUComputePipeline {
Self {
reflector_: Reflector::new(),
label: DomRefCell::new(None),
compute_pipeline,
}
}

pub fn new(
global: &GlobalScope,
compute_pipeline: WebGPUComputePipeline,
) -> DomRoot<GPUComputePipeline> {
reflect_dom_object(
Box::new(GPUComputePipeline::new_inherited(compute_pipeline)),
global,
GPUComputePipelineBinding::Wrap,
)
}
}

impl GPUComputePipelineMethods for GPUComputePipeline {
/// 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;
}
}
@@ -11,18 +11,24 @@ use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
GPUBindGroupLayoutBindings, GPUBindGroupLayoutDescriptor, GPUBindingType,
};
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::GPUComputePipelineDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{self, GPUDeviceMethods};
use crate::dom::bindings::codegen::Bindings::GPUPipelineLayoutBinding::GPUPipelineLayoutDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUShaderModuleBinding::GPUShaderModuleDescriptor;
use crate::dom::bindings::codegen::UnionTypes::Uint32ArrayOrString::{String, Uint32Array};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuadapter::GPUAdapter;
use crate::dom::gpubindgroup::GPUBindGroup;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState};
use crate::dom::gpucomputepipeline::GPUComputePipeline;
use crate::dom::gpupipelinelayout::GPUPipelineLayout;
use crate::dom::gpushadermodule::GPUShaderModule;
use crate::script_runtime::JSContext as SafeJSContext;
use dom_struct::dom_struct;
use ipc_channel::ipc;
@@ -523,9 +529,64 @@ impl GPUDeviceMethods for GPUDevice {
descriptor.layout.id(),
bindings,
))
.expect("Failed to create WebGPU PipelineLayout");
.expect("Failed to create WebGPU BindGroup");

let bind_group = receiver.recv().unwrap();
GPUBindGroup::new(&self.global(), bind_group, valid)
}

/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule
fn CreateShaderModule(
&self,
descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
) -> DomRoot<GPUShaderModule> {
let (sender, receiver) = ipc::channel().unwrap();
let program: Vec<u32> = match &descriptor.code {
Uint32Array(program) => program.to_vec(),
String(program) => program.chars().map(|c| c as u32).collect::<Vec<u32>>(),
};
let id = self
.global()
.wgpu_create_shader_module_id(self.device.0.backend());
self.channel
.0
.send(WebGPURequest::CreateShaderModule(
sender,
self.device,
id,
program,
))
.expect("Failed to create WebGPU ShaderModule");

let shader_module = receiver.recv().unwrap();

This comment has been minimized.

Copy link
@kvark

kvark Feb 8, 2020

Member

In all of the creation methods, we aren't expected to block on anything. Here, therefore, we can't recv(). Instead, we'd be creating a new ID and asking the GPU server side to create something associated with this ID, but never wait for it to do so.

This comment has been minimized.

Copy link
@imiklos

imiklos Feb 10, 2020

Author Contributor

Yes, We have an issue ( #25472 ) for this, we would like to address this in a separate pull request for all the call which has to be non-blocking.

GPUShaderModule::new(&self.global(), shader_module)
}

/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcomputepipeline
fn CreateComputePipeline(
&self,
descriptor: &GPUComputePipelineDescriptor,
) -> DomRoot<GPUComputePipeline> {
let pipeline = descriptor.parent.layout.id();
let program = descriptor.computeStage.module.id();
let entry_point = descriptor.computeStage.entryPoint.to_string();
let id = self
.global()
.wgpu_create_compute_pipeline_id(self.device.0.backend());
let (sender, receiver) = ipc::channel().unwrap();
self.channel
.0
.send(WebGPURequest::CreateComputePipeline(
sender,
self.device,
id,
pipeline.0,
program.0,
entry_point,
))
.expect("Failed to create WebGPU ComputePipeline");

let compute_pipeline = receiver.recv().unwrap();
GPUComputePipeline::new(&self.global(), compute_pipeline)
}
}
@@ -56,6 +56,12 @@ impl GPUPipelineLayout {
}
}

impl GPUPipelineLayout {
pub fn id(&self) -> WebGPUPipelineLayout {
self.pipeline_layout
}
}

impl GPUPipelineLayoutMethods for GPUPipelineLayout {
/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<DOMString> {
@@ -0,0 +1,60 @@
/* 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::GPUShaderModuleBinding::{
self, GPUShaderModuleMethods,
};
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 webgpu::WebGPUShaderModule;

#[dom_struct]
pub struct GPUShaderModule {
reflector_: Reflector,
label: DomRefCell<Option<DOMString>>,
shader_module: WebGPUShaderModule,
}

impl GPUShaderModule {
fn new_inherited(shader_module: WebGPUShaderModule) -> GPUShaderModule {
Self {
reflector_: Reflector::new(),
label: DomRefCell::new(None),
shader_module,
}
}

pub fn new(
global: &GlobalScope,
shader_module: WebGPUShaderModule,
) -> DomRoot<GPUShaderModule> {
reflect_dom_object(
Box::new(GPUShaderModule::new_inherited(shader_module)),
global,
GPUShaderModuleBinding::Wrap,
)
}
}

impl GPUShaderModule {
pub fn id(&self) -> WebGPUShaderModule {
self.shader_module
}
}

impl GPUShaderModuleMethods for GPUShaderModule {
/// 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;
}
}
@@ -5,7 +5,10 @@
use smallvec::SmallVec;
use webgpu::wgpu::{
hub::IdentityManager,
id::{AdapterId, BindGroupId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
id::{
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, ComputePipelineId, DeviceId,
PipelineLayoutId, ShaderModuleId,
},
Backend,
};

@@ -16,7 +19,9 @@ pub struct IdentityHub {
buffers: IdentityManager,
bind_groups: IdentityManager,
bind_group_layouts: IdentityManager,
compute_pipelines: IdentityManager,
pipeline_layouts: IdentityManager,
shader_modules: IdentityManager,
backend: Backend,
}

@@ -28,7 +33,9 @@ impl IdentityHub {
buffers: IdentityManager::default(),
bind_groups: IdentityManager::default(),
bind_group_layouts: IdentityManager::default(),
compute_pipelines: IdentityManager::default(),
pipeline_layouts: IdentityManager::default(),
shader_modules: IdentityManager::default(),
backend,
}
}
@@ -53,9 +60,17 @@ impl IdentityHub {
self.bind_group_layouts.alloc(self.backend)
}

fn create_compute_pipeline_id(&mut self) -> ComputePipelineId {
self.compute_pipelines.alloc(self.backend)
}

fn create_pipeline_layout_id(&mut self) -> PipelineLayoutId {
self.pipeline_layouts.alloc(self.backend)
}

fn create_shader_module_id(&mut self) -> ShaderModuleId {
self.shader_modules.alloc(self.backend)
}
}

#[derive(Debug)]
@@ -133,24 +148,22 @@ impl Identities {
}

pub fn create_bind_group_id(&mut self, backend: Backend) -> BindGroupId {
match backend {
#[cfg(any(target_os = "linux", target_os = "windows"))]
Backend::Vulkan => self.vk_hub.create_bind_group_id(),
#[cfg(target_os = "windows")]
Backend::Dx12 => self.dx12_hub.create_bind_group_id(),
#[cfg(target_os = "windows")]
Backend::Dx11 => self.dx11_hub.create_bind_group_id(),
#[cfg(any(target_os = "ios", target_os = "macos"))]
Backend::Metal => self.metal_hub.create_bind_group_id(),
_ => self.dummy_hub.create_bind_group_id(),
}
self.select(backend).create_bind_group_id()
}

pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId {
self.select(backend).create_bind_group_layout_id()
}

pub fn create_compute_pipeline_id(&mut self, backend: Backend) -> ComputePipelineId {
self.select(backend).create_compute_pipeline_id()
}

pub fn create_pipeline_layout_id(&mut self, backend: Backend) -> PipelineLayoutId {
self.select(backend).create_pipeline_layout_id()
}

pub fn create_shader_module_id(&mut self, backend: Backend) -> ShaderModuleId {
self.select(backend).create_shader_module_id()
}
}
@@ -322,8 +322,10 @@ pub mod gpubindgroup;
pub mod gpubindgrouplayout;
pub mod gpubuffer;
pub mod gpubufferusage;
pub mod gpucomputepipeline;
pub mod gpudevice;
pub mod gpupipelinelayout;
pub mod gpushadermodule;
pub mod gpushaderstage;
pub mod hashchangeevent;
pub mod headers;
@@ -0,0 +1,22 @@
/* 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/#gpucomputepipeline
[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
interface GPUComputePipeline {
};
GPUComputePipeline includes GPUObjectBase;

dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
required GPUPipelineLayout layout;
};

dictionary GPUProgrammableStageDescriptor {
required GPUShaderModule module;
required DOMString entryPoint;
};

dictionary GPUComputePipelineDescriptor : GPUPipelineDescriptorBase {
required GPUProgrammableStageDescriptor computeStage;
};
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.