mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
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:
parent
7aa68c8fe7
commit
b15d2bb7d7
11 changed files with 270 additions and 16 deletions
|
@ -138,6 +138,10 @@ DOMInterfaces = {
|
|||
|
||||
'GPU': {
|
||||
'inCompartments': ['RequestAdapter'],
|
||||
},
|
||||
|
||||
'GPUAdapter': {
|
||||
'inCompartments': ['RequestDevice'],
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ use tendril::stream::LossyDecoder;
|
|||
use tendril::{StrTendril, TendrilSink};
|
||||
use time::{Duration, Timespec};
|
||||
use uuid::Uuid;
|
||||
use webgpu::{WebGPU, WebGPUAdapter};
|
||||
use webgpu::{WebGPU, WebGPUAdapter, WebGPUDevice};
|
||||
use webrender_api::{DocumentId, ImageKey};
|
||||
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
|
||||
use webxr_api::SwapChainId as WebXRSwapChainId;
|
||||
|
@ -504,9 +504,10 @@ unsafe_no_jsmanaged_fields!(WebGLTextureId);
|
|||
unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
|
||||
unsafe_no_jsmanaged_fields!(WebGLVersion);
|
||||
unsafe_no_jsmanaged_fields!(WebGLSLVersion);
|
||||
unsafe_no_jsmanaged_fields!(WebGPU);
|
||||
unsafe_no_jsmanaged_fields!(RefCell<Identities>);
|
||||
unsafe_no_jsmanaged_fields!(WebGPU);
|
||||
unsafe_no_jsmanaged_fields!(WebGPUAdapter);
|
||||
unsafe_no_jsmanaged_fields!(WebGPUDevice);
|
||||
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
|
||||
unsafe_no_jsmanaged_fields!(MediaList);
|
||||
unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand);
|
||||
|
|
|
@ -2,16 +2,29 @@
|
|||
* 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::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::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
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 dom_struct::dom_struct;
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use std::ptr::NonNull;
|
||||
use webgpu::WebGPUAdapter;
|
||||
use std::rc::Rc;
|
||||
use webgpu::{wgpu, WebGPUAdapter, WebGPURequest, WebGPUResponse};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct GPUAdapter {
|
||||
|
@ -60,4 +73,51 @@ impl GPUAdapterMethods for GPUAdapter {
|
|||
fn Extensions(&self, _cx: SafeJSContext) -> NonNull<JSObject> {
|
||||
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(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
91
components/script/dom/gpudevice.rs
Normal file
91
components/script/dom/gpudevice.rs
Normal 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;
|
||||
}
|
||||
}
|
|
@ -44,4 +44,8 @@ impl Identities {
|
|||
pub fn create_adapter_id(&mut self) -> AdapterId {
|
||||
self.hub.adapters.alloc()
|
||||
}
|
||||
|
||||
pub fn create_device_id(&mut self) -> DeviceId {
|
||||
self.hub.devices.alloc()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -317,6 +317,7 @@ pub mod gamepadlist;
|
|||
pub mod globalscope;
|
||||
pub mod gpu;
|
||||
pub mod gpuadapter;
|
||||
pub mod gpudevice;
|
||||
pub mod hashchangeevent;
|
||||
pub mod headers;
|
||||
pub mod history;
|
||||
|
|
|
@ -26,7 +26,7 @@ use crate::dom::xr::XR;
|
|||
use dom_struct::dom_struct;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use webgpu::wgpu::AdapterId;
|
||||
use webgpu::wgpu::{AdapterId, DeviceId};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct Navigator {
|
||||
|
@ -76,6 +76,10 @@ impl Navigator {
|
|||
pub fn create_adapter_id(&self) -> AdapterId {
|
||||
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 {
|
||||
|
|
|
@ -10,5 +10,25 @@ interface GPUAdapter {
|
|||
//readonly attribute GPULimits limits; Don’t expose higher limits for now.
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
|
31
components/script/dom/webidls/GPUDevice.webidl
Normal file
31
components/script/dom/webidls/GPUDevice.webidl
Normal 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;
|
13
components/script/dom/webidls/GPUObjectBase.webidl
Normal file
13
components/script/dom/webidls/GPUObjectBase.webidl
Normal 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;
|
||||
};
|
|
@ -12,12 +12,12 @@ pub extern crate wgpu_native as wgpu;
|
|||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use servo_config::pref;
|
||||
use wgpu::adapter_get_info;
|
||||
use wgpu::{adapter_get_info, adapter_request_device};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum WebGPUResponse {
|
||||
RequestAdapter(String, WebGPUAdapter),
|
||||
RequestDevice,
|
||||
RequestDevice(WebGPUDevice, wgpu::DeviceDescriptor),
|
||||
}
|
||||
|
||||
pub type WebGPUResponseResult = Result<WebGPUResponse, String>;
|
||||
|
@ -29,7 +29,12 @@ pub enum WebGPURequest {
|
|||
wgpu::RequestAdapterOptions,
|
||||
wgpu::AdapterId,
|
||||
),
|
||||
RequestDevice,
|
||||
RequestDevice(
|
||||
IpcSender<WebGPUResponseResult>,
|
||||
WebGPUAdapter,
|
||||
wgpu::DeviceDescriptor,
|
||||
wgpu::DeviceId,
|
||||
),
|
||||
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) => {
|
||||
self.deinit();
|
||||
if let Err(e) = sender.send(()) {
|
||||
|
@ -137,11 +153,20 @@ impl WGPU {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
pub struct WebGPUAdapter(pub wgpu::AdapterId);
|
||||
macro_rules! webgpu_resource {
|
||||
($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 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for $name {}
|
||||
};
|
||||
}
|
||||
|
||||
webgpu_resource!(WebGPUAdapter, wgpu::AdapterId);
|
||||
webgpu_resource!(WebGPUDevice, wgpu::DeviceId);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue