Initial implementation of GPUDevice for WebGPU

Added the WebIDL bindigs for GPUDevice, GPUObjectDescriptorBase, GPUDeviceDescriptor, GPUObjectBase
Implemented the `requestDevice` function of `GPUAdapter`
This commit is contained in:
Istvan Miklos 2019-11-12 12:56:57 +01:00
parent 7aa68c8fe7
commit b15d2bb7d7
11 changed files with 270 additions and 16 deletions

View file

@ -138,6 +138,10 @@ DOMInterfaces = {
'GPU': { 'GPU': {
'inCompartments': ['RequestAdapter'], 'inCompartments': ['RequestAdapter'],
},
'GPUAdapter': {
'inCompartments': ['RequestDevice'],
} }
} }

View file

@ -146,7 +146,7 @@ use tendril::stream::LossyDecoder;
use tendril::{StrTendril, TendrilSink}; use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec}; use time::{Duration, Timespec};
use uuid::Uuid; use uuid::Uuid;
use webgpu::{WebGPU, WebGPUAdapter}; use webgpu::{WebGPU, WebGPUAdapter, WebGPUDevice};
use webrender_api::{DocumentId, ImageKey}; use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
use webxr_api::SwapChainId as WebXRSwapChainId; use webxr_api::SwapChainId as WebXRSwapChainId;
@ -504,9 +504,10 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId);
unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
unsafe_no_jsmanaged_fields!(WebGLVersion); unsafe_no_jsmanaged_fields!(WebGLVersion);
unsafe_no_jsmanaged_fields!(WebGLSLVersion); unsafe_no_jsmanaged_fields!(WebGLSLVersion);
unsafe_no_jsmanaged_fields!(WebGPU);
unsafe_no_jsmanaged_fields!(RefCell<Identities>); unsafe_no_jsmanaged_fields!(RefCell<Identities>);
unsafe_no_jsmanaged_fields!(WebGPU);
unsafe_no_jsmanaged_fields!(WebGPUAdapter); unsafe_no_jsmanaged_fields!(WebGPUAdapter);
unsafe_no_jsmanaged_fields!(WebGPUDevice);
unsafe_no_jsmanaged_fields!(WebXRSwapChainId); unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(MediaList);
unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand);

View file

@ -2,16 +2,29 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::{self, GPUAdapterMethods}; use crate::compartments::InCompartment;
use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::{
self, GPUAdapterMethods, GPUDeviceDescriptor,
};
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpu::response_async;
use crate::dom::gpu::AsyncWGPUListener;
use crate::dom::gpudevice::GPUDevice;
use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::script_runtime::JSContext as SafeJSContext; use crate::script_runtime::JSContext as SafeJSContext;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject}; use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull; use std::ptr::NonNull;
use webgpu::WebGPUAdapter; use std::rc::Rc;
use webgpu::{wgpu, WebGPUAdapter, WebGPURequest, WebGPUResponse};
#[dom_struct] #[dom_struct]
pub struct GPUAdapter { pub struct GPUAdapter {
@ -60,4 +73,51 @@ impl GPUAdapterMethods for GPUAdapter {
fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> { fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> {
NonNull::new(self.extensions.get()).unwrap() NonNull::new(self.extensions.get()).unwrap()
} }
/// https://gpuweb.github.io/gpuweb/#dom-gpuadapter-requestdevice
fn RequestDevice(&self, descriptor: &GPUDeviceDescriptor, comp: InCompartment) -> Rc<Promise> {
let promise = Promise::new_in_current_compartment(&self.global(), comp);
let sender = response_async(&promise, self);
let desc = wgpu::DeviceDescriptor {
extensions: wgpu::Extensions {
anisotropic_filtering: descriptor.extensions.anisotropicFiltering,
},
limits: wgpu::Limits {
max_bind_groups: descriptor.limits.maxBindGroups,
},
};
if let Some(window) = self.global().downcast::<Window>() {
let id = window.Navigator().create_device_id();
match window.webgpu_channel() {
Some(thread) => thread
.0
.send(WebGPURequest::RequestDevice(sender, self.adapter, desc, id))
.unwrap(),
None => promise.reject_error(Error::Type("No WebGPU thread...".to_owned())),
}
} else {
promise.reject_error(Error::Type("No WebGPU thread...".to_owned()))
};
promise
}
}
impl AsyncWGPUListener for GPUAdapter {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
match response {
WebGPUResponse::RequestDevice(device_id, _descriptor) => {
let device = GPUDevice::new(
&self.global(),
&self,
Heap::default(),
Heap::default(),
device_id,
);
promise.resolve_native(&device);
},
_ => promise.reject_error(Error::Type(
"Wrong response type from WebGPU thread...".to_owned(),
)),
}
}
} }

View file

@ -0,0 +1,91 @@
/* 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::GPUDeviceBinding::{self, GPUDeviceMethods};
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuadapter::GPUAdapter;
use crate::script_runtime::JSContext as SafeJSContext;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull;
use webgpu::WebGPUDevice;
#[dom_struct]
pub struct GPUDevice {
eventtarget: EventTarget,
adapter: Dom<GPUAdapter>,
#[ignore_malloc_size_of = "mozjs"]
extensions: Heap<*mut JSObject>,
#[ignore_malloc_size_of = "mozjs"]
limits: Heap<*mut JSObject>,
label: DomRefCell<Option<DOMString>>,
device: WebGPUDevice,
}
impl GPUDevice {
fn new_inherited(
adapter: &GPUAdapter,
extensions: Heap<*mut JSObject>,
limits: Heap<*mut JSObject>,
device: WebGPUDevice,
) -> GPUDevice {
Self {
eventtarget: EventTarget::new_inherited(),
adapter: Dom::from_ref(adapter),
extensions,
limits,
label: DomRefCell::new(None),
device,
}
}
#[allow(unsafe_code)]
pub fn new(
global: &GlobalScope,
adapter: &GPUAdapter,
extensions: Heap<*mut JSObject>,
limits: Heap<*mut JSObject>,
device: WebGPUDevice,
) -> DomRoot<GPUDevice> {
reflect_dom_object(
Box::new(GPUDevice::new_inherited(
adapter, extensions, limits, device,
)),
global,
GPUDeviceBinding::Wrap,
)
}
}
impl GPUDeviceMethods for GPUDevice {
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-adapter
fn Adapter(&self) -> DomRoot<GPUAdapter> {
DomRoot::from_ref(&self.adapter)
}
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-extensions
fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> {
NonNull::new(self.extensions.get()).unwrap()
}
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-limits
fn Limits(&self, _cx: SafeJSContext) -> NonNull<JSObject> {
NonNull::new(self.extensions.get()).unwrap()
}
/// 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

@ -44,4 +44,8 @@ impl Identities {
pub fn create_adapter_id(&mut self) -> AdapterId { pub fn create_adapter_id(&mut self) -> AdapterId {
self.hub.adapters.alloc() self.hub.adapters.alloc()
} }
pub fn create_device_id(&mut self) -> DeviceId {
self.hub.devices.alloc()
}
} }

View file

@ -317,6 +317,7 @@ pub mod gamepadlist;
pub mod globalscope; pub mod globalscope;
pub mod gpu; pub mod gpu;
pub mod gpuadapter; pub mod gpuadapter;
pub mod gpudevice;
pub mod hashchangeevent; pub mod hashchangeevent;
pub mod headers; pub mod headers;
pub mod history; pub mod history;

View file

@ -26,7 +26,7 @@ use crate::dom::xr::XR;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use webgpu::wgpu::AdapterId; use webgpu::wgpu::{AdapterId, DeviceId};
#[dom_struct] #[dom_struct]
pub struct Navigator { pub struct Navigator {
@ -76,6 +76,10 @@ impl Navigator {
pub fn create_adapter_id(&self) -> AdapterId { pub fn create_adapter_id(&self) -> AdapterId {
self.gpu_id_hub.borrow_mut().create_adapter_id() self.gpu_id_hub.borrow_mut().create_adapter_id()
} }
pub fn create_device_id(&self) -> DeviceId {
self.gpu_id_hub.borrow_mut().create_device_id()
}
} }
impl NavigatorMethods for Navigator { impl NavigatorMethods for Navigator {

View file

@ -10,5 +10,25 @@ interface GPUAdapter {
//readonly attribute GPULimits limits; Dont expose higher limits for now. //readonly attribute GPULimits limits; Dont expose higher limits for now.
// May reject with DOMException // TODO: DOMException("OperationError")? // May reject with DOMException // TODO: DOMException("OperationError")?
// Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {}); Promise<GPUDevice> requestDevice(optional GPUDeviceDescriptor descriptor = {});
};
dictionary GPUDeviceDescriptor : GPUObjectDescriptorBase {
GPUExtensions extensions = {};
GPULimits limits = {};
};
dictionary GPUExtensions {
boolean anisotropicFiltering = false;
};
dictionary GPULimits {
unsigned long maxBindGroups = 4;
unsigned long maxDynamicUniformBuffersPerPipelineLayout = 8;
unsigned long maxDynamicStorageBuffersPerPipelineLayout = 4;
unsigned long maxSampledTexturesPerShaderStage = 16;
unsigned long maxSamplersPerShaderStage = 16;
unsigned long maxStorageBuffersPerShaderStage = 4;
unsigned long maxStorageTexturesPerShaderStage = 4;
unsigned long maxUniformBuffersPerShaderStage = 12;
}; };

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/#gpudevice
[Exposed=(Window, DedicatedWorker)/*, Serializable */, Pref="dom.webgpu.enabled"]
interface GPUDevice : EventTarget {
readonly attribute GPUAdapter adapter;
readonly attribute object extensions;
readonly attribute object limits;
/*GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
GPUTexture createTexture(GPUTextureDescriptor descriptor);
GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {});
GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);
GPUQueue getQueue();*/
};
GPUDevice includes GPUObjectBase;

View file

@ -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/#gpuobjectbase
[Exposed=(Window)]
interface mixin GPUObjectBase {
attribute DOMString? label;
};
dictionary GPUObjectDescriptorBase {
DOMString? label;
};

View file

@ -12,12 +12,12 @@ pub extern crate wgpu_native as wgpu;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use servo_config::pref; use servo_config::pref;
use wgpu::adapter_get_info; use wgpu::{adapter_get_info, adapter_request_device};
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum WebGPUResponse { pub enum WebGPUResponse {
RequestAdapter(String, WebGPUAdapter), RequestAdapter(String, WebGPUAdapter),
RequestDevice, RequestDevice(WebGPUDevice, wgpu::DeviceDescriptor),
} }
pub type WebGPUResponseResult = Result<WebGPUResponse, String>; pub type WebGPUResponseResult = Result<WebGPUResponse, String>;
@ -29,7 +29,12 @@ pub enum WebGPURequest {
wgpu::RequestAdapterOptions, wgpu::RequestAdapterOptions,
wgpu::AdapterId, wgpu::AdapterId,
), ),
RequestDevice, RequestDevice(
IpcSender<WebGPUResponseResult>,
WebGPUAdapter,
wgpu::DeviceDescriptor,
wgpu::DeviceId,
),
Exit(IpcSender<()>), Exit(IpcSender<()>),
} }
@ -124,7 +129,18 @@ impl WGPU {
) )
} }
}, },
WebGPURequest::RequestDevice => {}, WebGPURequest::RequestDevice(sender, adapter, descriptor, id) => {
let _output = gfx_select!(id => adapter_request_device(&self.global, adapter.0, &descriptor, id));
let device = WebGPUDevice(id);
if let Err(e) =
sender.send(Ok(WebGPUResponse::RequestDevice(device, descriptor)))
{
warn!(
"Failed to send response to WebGPURequest::RequestDevice ({})",
e
)
}
},
WebGPURequest::Exit(sender) => { WebGPURequest::Exit(sender) => {
self.deinit(); self.deinit();
if let Err(e) = sender.send(()) { if let Err(e) = sender.send(()) {
@ -137,11 +153,20 @@ impl WGPU {
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)] macro_rules! webgpu_resource {
pub struct WebGPUAdapter(pub wgpu::AdapterId); ($name:ident, $id:ty) => {
#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
pub struct $name(pub $id);
impl MallocSizeOf for WebGPUAdapter { impl MallocSizeOf for $name {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
0 0
} }
}
impl Eq for $name {}
};
} }
webgpu_resource!(WebGPUAdapter, wgpu::AdapterId);
webgpu_resource!(WebGPUDevice, wgpu::DeviceId);