Auto merge of #25637 - szeged:wgpu_crete_bind_group, r=jdm

Initial implementation of GPUBindGroup for WebGPU

Added WebIDL bindings for `GPUBindGroup`.
Implemented the `createBindGroup` function of `GPUDevice`
Renamed `GPUBindGroupBinding` to `GPUBindGroupBindings` and `GPUBufferBinding` to `GPUBufferBindings` in the WebIDL, because these names are already occupied.

<!-- 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. -->
This commit is contained in:
bors-servo 2020-01-30 12:34:26 -05:00 committed by GitHub
commit 1352e7188a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 227 additions and 9 deletions

2
Cargo.lock generated
View file

@ -6764,7 +6764,7 @@ dependencies = [
[[package]] [[package]]
name = "wgpu-core" name = "wgpu-core"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/gfx-rs/wgpu#881222a9477036e9e3504045452d88abfe5ae177" source = "git+https://github.com/gfx-rs/wgpu#d4a46cb60e71d6b108e9052cc581e52e44a16a44"
dependencies = [ dependencies = [
"arrayvec 0.5.1", "arrayvec 0.5.1",
"battery", "battery",

View file

@ -152,7 +152,8 @@ use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec, Tm}; use time::{Duration, Timespec, Tm};
use uuid::Uuid; use uuid::Uuid;
use webgpu::{ use webgpu::{
WebGPU, WebGPUAdapter, WebGPUBindGroupLayout, WebGPUBuffer, WebGPUDevice, WebGPUPipelineLayout, WebGPU, WebGPUAdapter, WebGPUBindGroup, WebGPUBindGroupLayout, WebGPUBuffer, WebGPUDevice,
WebGPUPipelineLayout,
}; };
use webrender_api::{DocumentId, ImageKey}; use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
@ -532,6 +533,7 @@ unsafe_no_jsmanaged_fields!(WebGPU);
unsafe_no_jsmanaged_fields!(WebGPUAdapter); unsafe_no_jsmanaged_fields!(WebGPUAdapter);
unsafe_no_jsmanaged_fields!(WebGPUDevice); unsafe_no_jsmanaged_fields!(WebGPUDevice);
unsafe_no_jsmanaged_fields!(WebGPUBuffer); unsafe_no_jsmanaged_fields!(WebGPUBuffer);
unsafe_no_jsmanaged_fields!(WebGPUBindGroup);
unsafe_no_jsmanaged_fields!(WebGPUBindGroupLayout); unsafe_no_jsmanaged_fields!(WebGPUBindGroupLayout);
unsafe_no_jsmanaged_fields!(WebGPUPipelineLayout); unsafe_no_jsmanaged_fields!(WebGPUPipelineLayout);
unsafe_no_jsmanaged_fields!(GPUBufferState); unsafe_no_jsmanaged_fields!(GPUBufferState);

View file

@ -98,7 +98,7 @@ use std::sync::Arc;
use time::{get_time, Timespec}; use time::{get_time, Timespec};
use uuid::Uuid; use uuid::Uuid;
use webgpu::wgpu::{ use webgpu::wgpu::{
id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId}, id::{AdapterId, BindGroupId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
Backend, Backend,
}; };
@ -2105,6 +2105,10 @@ impl GlobalScope {
self.gpu_id_hub.borrow_mut().create_adapter_ids() self.gpu_id_hub.borrow_mut().create_adapter_ids()
} }
pub fn wgpu_create_bind_group_id(&self, backend: Backend) -> BindGroupId {
self.gpu_id_hub.borrow_mut().create_bind_group_id(backend)
}
pub fn wgpu_create_bind_group_layout_id(&self, backend: Backend) -> BindGroupLayoutId { pub fn wgpu_create_bind_group_layout_id(&self, backend: Backend) -> BindGroupLayoutId {
self.gpu_id_hub self.gpu_id_hub
.borrow_mut() .borrow_mut()

View file

@ -0,0 +1,58 @@
/* 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::GPUBindGroupBinding::{
GPUBindGroupBinding, GPUBindGroupMethods,
};
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::WebGPUBindGroup;
#[dom_struct]
pub struct GPUBindGroup {
reflector_: Reflector,
label: DomRefCell<Option<DOMString>>,
bind_group: WebGPUBindGroup,
valid: Cell<bool>,
}
impl GPUBindGroup {
fn new_inherited(bind_group: WebGPUBindGroup, valid: bool) -> GPUBindGroup {
Self {
reflector_: Reflector::new(),
label: DomRefCell::new(None),
bind_group,
valid: Cell::new(valid),
}
}
pub fn new(
global: &GlobalScope,
bind_group: WebGPUBindGroup,
valid: bool,
) -> DomRoot<GPUBindGroup> {
reflect_dom_object(
Box::new(GPUBindGroup::new_inherited(bind_group, valid)),
global,
GPUBindGroupBinding::Wrap,
)
}
}
impl GPUBindGroupMethods for GPUBindGroup {
/// 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;
}
}

View file

@ -79,6 +79,20 @@ impl GPUBuffer {
} }
} }
impl GPUBuffer {
pub fn id(&self) -> WebGPUBuffer {
self.buffer
}
pub fn size(&self) -> GPUBufferSize {
self.size
}
pub fn usage(&self) -> u32 {
self.usage
}
}
impl Drop for GPUBuffer { impl Drop for GPUBuffer {
fn drop(&mut self) { fn drop(&mut self) {
self.Destroy() self.Destroy()

View file

@ -6,6 +6,7 @@
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::GPUAdapterBinding::GPULimits;
use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::GPUBindGroupDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{ use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
GPUBindGroupLayoutBindings, GPUBindGroupLayoutDescriptor, GPUBindingType, GPUBindGroupLayoutBindings, GPUBindGroupLayoutDescriptor, GPUBindingType,
}; };
@ -18,6 +19,7 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuadapter::GPUAdapter; use crate::dom::gpuadapter::GPUAdapter;
use crate::dom::gpubindgroup::GPUBindGroup;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout; use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState}; use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState};
use crate::dom::gpupipelinelayout::GPUPipelineLayout; use crate::dom::gpupipelinelayout::GPUPipelineLayout;
@ -29,7 +31,10 @@ use js::jsval::{JSVal, ObjectValue};
use js::typedarray::{ArrayBuffer, CreateWith}; use js::typedarray::{ArrayBuffer, CreateWith};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ptr::{self, NonNull}; use std::ptr::{self, NonNull};
use webgpu::wgpu::binding_model::{BindGroupLayoutBinding, BindingType, ShaderStage}; use webgpu::wgpu::binding_model::{
BindGroupBinding, BindGroupLayoutBinding, BindingResource, BindingType, BufferBinding,
ShaderStage,
};
use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage}; use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage};
use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest}; use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest};
@ -463,4 +468,64 @@ impl GPUDeviceMethods for GPUDevice {
let pipeline_layout = receiver.recv().unwrap(); let pipeline_layout = receiver.recv().unwrap();
GPUPipelineLayout::new(&self.global(), bind_group_layouts, pipeline_layout, valid) GPUPipelineLayout::new(&self.global(), bind_group_layouts, pipeline_layout, valid)
} }
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbindgroup
fn CreateBindGroup(&self, descriptor: &GPUBindGroupDescriptor) -> DomRoot<GPUBindGroup> {
let alignment: u64 = 256;
let mut valid = descriptor.layout.bindings().len() == descriptor.bindings.len();
valid &= descriptor.bindings.iter().all(|bind| {
let buffer_size = bind.resource.buffer.size();
let resource_size = bind.resource.size.unwrap_or(buffer_size);
let length = bind.resource.offset.checked_add(resource_size);
let usage = BufferUsage::from_bits(bind.resource.buffer.usage()).unwrap();
length.is_some() &&
buffer_size >= length.unwrap() && // check buffer OOB
bind.resource.offset % alignment == 0 && // check alignment
bind.resource.offset < buffer_size && // on Vulkan offset must be less than size of buffer
descriptor.layout.bindings().iter().any(|layout_bind| {
let ty = match layout_bind.type_ {
GPUBindingType::Storage_buffer => BufferUsage::STORAGE,
// GPUBindingType::Readonly_storage_buffer => BufferUsage::STORAGE_READ,
GPUBindingType::Uniform_buffer => BufferUsage::UNIFORM,
_ => unimplemented!(),
};
// binding must be present in layout
layout_bind.binding == bind.binding &&
// binding must contain one buffer of its type
usage.contains(ty)
})
});
let bindings = descriptor
.bindings
.iter()
.map(|bind| BindGroupBinding {
binding: bind.binding,
resource: BindingResource::Buffer(BufferBinding {
buffer: bind.resource.buffer.id().0,
offset: bind.resource.offset,
size: bind.resource.size.unwrap_or(bind.resource.buffer.size()),
}),
})
.collect::<Vec<_>>();
let (sender, receiver) = ipc::channel().unwrap();
let id = self
.global()
.wgpu_create_bind_group_id(self.device.0.backend());
self.channel
.0
.send(WebGPURequest::CreateBindGroup(
sender,
self.device,
id,
descriptor.layout.id(),
bindings,
))
.expect("Failed to create WebGPU PipelineLayout");
let bind_group = receiver.recv().unwrap();
GPUBindGroup::new(&self.global(), bind_group, valid)
}
} }

View file

@ -5,7 +5,7 @@
use smallvec::SmallVec; use smallvec::SmallVec;
use webgpu::wgpu::{ use webgpu::wgpu::{
hub::IdentityManager, hub::IdentityManager,
id::{AdapterId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId}, id::{AdapterId, BindGroupId, BindGroupLayoutId, BufferId, DeviceId, PipelineLayoutId},
Backend, Backend,
}; };
@ -14,6 +14,7 @@ pub struct IdentityHub {
adapters: IdentityManager, adapters: IdentityManager,
devices: IdentityManager, devices: IdentityManager,
buffers: IdentityManager, buffers: IdentityManager,
bind_groups: IdentityManager,
bind_group_layouts: IdentityManager, bind_group_layouts: IdentityManager,
pipeline_layouts: IdentityManager, pipeline_layouts: IdentityManager,
backend: Backend, backend: Backend,
@ -25,6 +26,7 @@ impl IdentityHub {
adapters: IdentityManager::default(), adapters: IdentityManager::default(),
devices: IdentityManager::default(), devices: IdentityManager::default(),
buffers: IdentityManager::default(), buffers: IdentityManager::default(),
bind_groups: IdentityManager::default(),
bind_group_layouts: IdentityManager::default(), bind_group_layouts: IdentityManager::default(),
pipeline_layouts: IdentityManager::default(), pipeline_layouts: IdentityManager::default(),
backend, backend,
@ -43,6 +45,10 @@ impl IdentityHub {
self.buffers.alloc(self.backend) self.buffers.alloc(self.backend)
} }
fn create_bind_group_id(&mut self) -> BindGroupId {
self.bind_groups.alloc(self.backend)
}
fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId { fn create_bind_group_layout_id(&mut self) -> BindGroupLayoutId {
self.bind_group_layouts.alloc(self.backend) self.bind_group_layouts.alloc(self.backend)
} }
@ -126,6 +132,20 @@ impl Identities {
self.select(backend).create_buffer_id() self.select(backend).create_buffer_id()
} }
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(),
}
}
pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId { pub fn create_bind_group_layout_id(&mut self, backend: Backend) -> BindGroupLayoutId {
self.select(backend).create_bind_group_layout_id() self.select(backend).create_bind_group_layout_id()
} }

View file

@ -318,6 +318,7 @@ pub mod gamepadlist;
pub mod globalscope; pub mod globalscope;
pub mod gpu; pub mod gpu;
pub mod gpuadapter; pub mod gpuadapter;
pub mod gpubindgroup;
pub mod gpubindgrouplayout; pub mod gpubindgrouplayout;
pub mod gpubuffer; pub mod gpubuffer;
pub mod gpubufferusage; pub mod gpubufferusage;

View file

@ -0,0 +1,31 @@
/* 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 GPUBindGroup {
};
GPUBindGroup includes GPUObjectBase;
dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {
required GPUBindGroupLayout layout;
required sequence<GPUBindGroupBindings> bindings;
};
typedef /*(GPUSampler or GPUTextureView or*/ GPUBufferBindings/*)*/ GPUBindingResource;
// Note: Servo codegen doesn't like the name `GPUBindGroupBinding` because it's already occupied
// dictionary GPUBindGroupBinding {
dictionary GPUBindGroupBindings {
required unsigned long binding;
required GPUBindingResource resource;
};
// Note: Servo codegen doesn't like the name `GPUBufferBinding` because it's already occupied
// dictionary GPUBufferBinding {
dictionary GPUBufferBindings {
required GPUBuffer buffer;
GPUBufferSize offset = 0;
GPUBufferSize size;
};

View file

@ -17,9 +17,9 @@ interface GPUDevice : EventTarget {
GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor); GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor); GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
/*GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor); GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor); /*GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor); GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor); GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);

View file

@ -5,8 +5,6 @@
#[macro_use] #[macro_use]
extern crate log; extern crate log;
#[macro_use] #[macro_use]
extern crate serde;
#[macro_use]
pub extern crate wgpu_core as wgpu; pub extern crate wgpu_core as wgpu;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
@ -48,6 +46,13 @@ pub enum WebGPURequest {
wgpu::id::BufferId, wgpu::id::BufferId,
wgpu::resource::BufferDescriptor, wgpu::resource::BufferDescriptor,
), ),
CreateBindGroup(
IpcSender<WebGPUBindGroup>,
WebGPUDevice,
wgpu::id::BindGroupId,
WebGPUBindGroupLayout,
Vec<wgpu::binding_model::BindGroupBinding>,
),
CreateBindGroupLayout( CreateBindGroupLayout(
IpcSender<WebGPUBindGroupLayout>, IpcSender<WebGPUBindGroupLayout>,
WebGPUDevice, WebGPUDevice,
@ -232,6 +237,23 @@ impl WGPU {
let global = &self.global; let global = &self.global;
gfx_select!(buffer.0 => global.buffer_destroy(buffer.0)); gfx_select!(buffer.0 => global.buffer_destroy(buffer.0));
}, },
WebGPURequest::CreateBindGroup(sender, device, id, layout_id, bindings) => {
let global = &self.global;
let descriptor = wgpu_core::binding_model::BindGroupDescriptor {
layout: layout_id.0,
bindings: bindings.as_ptr(),
bindings_length: bindings.len(),
};
let bg_id = gfx_select!(id => global.device_create_bind_group(device.0, &descriptor, id));
let bind_group = WebGPUBindGroup(bg_id);
if let Err(e) = sender.send(bind_group) {
warn!(
"Failed to send response to WebGPURequest::CreateBindGroup ({})",
e
)
}
},
WebGPURequest::CreateBindGroupLayout(sender, device, id, bindings) => { WebGPURequest::CreateBindGroupLayout(sender, device, id, bindings) => {
let global = &self.global; let global = &self.global;
let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor { let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor {
@ -294,5 +316,6 @@ macro_rules! webgpu_resource {
webgpu_resource!(WebGPUAdapter, wgpu::id::AdapterId); webgpu_resource!(WebGPUAdapter, wgpu::id::AdapterId);
webgpu_resource!(WebGPUDevice, wgpu::id::DeviceId); webgpu_resource!(WebGPUDevice, wgpu::id::DeviceId);
webgpu_resource!(WebGPUBuffer, wgpu::id::BufferId); webgpu_resource!(WebGPUBuffer, wgpu::id::BufferId);
webgpu_resource!(WebGPUBindGroup, wgpu::id::BindGroupId);
webgpu_resource!(WebGPUBindGroupLayout, wgpu::id::BindGroupLayoutId); webgpu_resource!(WebGPUBindGroupLayout, wgpu::id::BindGroupLayoutId);
webgpu_resource!(WebGPUPipelineLayout, wgpu::id::PipelineLayoutId); webgpu_resource!(WebGPUPipelineLayout, wgpu::id::PipelineLayoutId);