diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 5 | ||||
-rw-r--r-- | components/script/dom/gpuadapter.rs | 3 | ||||
-rw-r--r-- | components/script/dom/gpubuffer.rs | 120 | ||||
-rw-r--r-- | components/script/dom/gpubufferusage.rs | 11 | ||||
-rw-r--r-- | components/script/dom/gpudevice.rs | 164 | ||||
-rw-r--r-- | components/script/dom/identityhub.rs | 22 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 2 | ||||
-rw-r--r-- | components/script/dom/navigator.rs | 6 | ||||
-rw-r--r-- | components/script/dom/webidls/GPUBuffer.webidl | 25 | ||||
-rw-r--r-- | components/script/dom/webidls/GPUBufferUsage.webidl | 17 | ||||
-rw-r--r-- | components/script/dom/webidls/GPUDevice.webidl | 4 | ||||
-rw-r--r-- | components/webgpu/lib.rs | 56 |
12 files changed, 425 insertions, 10 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 8f019f9a37f..96ef909ea8f 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -37,6 +37,7 @@ use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::{DOMString, USVString}; use crate::dom::bindings::utils::WindowProxyHandler; use crate::dom::document::PendingRestyle; +use crate::dom::gpubuffer::GPUBufferState; use crate::dom::htmlimageelement::SourceSet; use crate::dom::htmlmediaelement::{HTMLMediaElementFetchContext, MediaFrameRenderer}; use crate::dom::identityhub::Identities; @@ -147,7 +148,7 @@ use tendril::stream::LossyDecoder; use tendril::{StrTendril, TendrilSink}; use time::{Duration, Timespec, Tm}; use uuid::Uuid; -use webgpu::{WebGPU, WebGPUAdapter, WebGPUDevice}; +use webgpu::{WebGPU, WebGPUAdapter, WebGPUBuffer, WebGPUDevice}; use webrender_api::{DocumentId, ImageKey}; use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; use webxr_api::SwapChainId as WebXRSwapChainId; @@ -511,6 +512,8 @@ 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!(WebGPUBuffer); +unsafe_no_jsmanaged_fields!(GPUBufferState); unsafe_no_jsmanaged_fields!(WebXRSwapChainId); unsafe_no_jsmanaged_fields!(MediaList); unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); diff --git a/components/script/dom/gpuadapter.rs b/components/script/dom/gpuadapter.rs index 937b9103321..cbb24917ebe 100644 --- a/components/script/dom/gpuadapter.rs +++ b/components/script/dom/gpuadapter.rs @@ -9,8 +9,7 @@ use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::{ 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, DomObject, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; use crate::dom::globalscope::GlobalScope; diff --git a/components/script/dom/gpubuffer.rs b/components/script/dom/gpubuffer.rs new file mode 100644 index 00000000000..a2a3e3b62eb --- /dev/null +++ b/components/script/dom/gpubuffer.rs @@ -0,0 +1,120 @@ +/* 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::GPUBufferBinding::{ + self, GPUBufferMethods, GPUBufferSize, +}; +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 ipc_channel::ipc::IpcSender; +use std::cell::Cell; +use webgpu::{WebGPUBuffer, WebGPUDevice, WebGPURequest}; + +#[derive(MallocSizeOf)] +pub enum GPUBufferState { + Mapped, + Unmapped, + Destroyed, +} + +#[dom_struct] +pub struct GPUBuffer { + reflector_: Reflector, + #[ignore_malloc_size_of = "channels are hard"] + channel: IpcSender<WebGPURequest>, + label: DomRefCell<Option<DOMString>>, + size: GPUBufferSize, + usage: u32, + state: DomRefCell<GPUBufferState>, + buffer: WebGPUBuffer, + device: WebGPUDevice, + valid: Cell<bool>, +} + +impl GPUBuffer { + fn new_inherited( + channel: IpcSender<WebGPURequest>, + buffer: WebGPUBuffer, + device: WebGPUDevice, + state: GPUBufferState, + size: GPUBufferSize, + usage: u32, + valid: bool, + ) -> GPUBuffer { + Self { + reflector_: Reflector::new(), + channel, + label: DomRefCell::new(None), + state: DomRefCell::new(state), + size: size, + usage: usage, + valid: Cell::new(valid), + device, + buffer, + } + } + + #[allow(unsafe_code)] + pub fn new( + global: &GlobalScope, + channel: IpcSender<WebGPURequest>, + buffer: WebGPUBuffer, + device: WebGPUDevice, + state: GPUBufferState, + size: GPUBufferSize, + usage: u32, + valid: bool, + ) -> DomRoot<GPUBuffer> { + reflect_dom_object( + Box::new(GPUBuffer::new_inherited( + channel, buffer, device, state, size, usage, valid, + )), + global, + GPUBufferBinding::Wrap, + ) + } +} + +impl Drop for GPUBuffer { + fn drop(&mut self) { + self.Destroy() + } +} + +impl GPUBufferMethods for GPUBuffer { + /// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-unmap + fn Unmap(&self) { + self.channel + .send(WebGPURequest::UnmapBuffer(self.buffer)) + .unwrap(); + } + + /// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-destroy + fn Destroy(&self) { + match *self.state.borrow() { + GPUBufferState::Mapped => { + self.Unmap(); + }, + _ => {}, + }; + self.channel + .send(WebGPURequest::DestroyBuffer(self.buffer)) + .unwrap(); + *self.state.borrow_mut() = GPUBufferState::Destroyed; + } + + /// 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; + } +} diff --git a/components/script/dom/gpubufferusage.rs b/components/script/dom/gpubufferusage.rs new file mode 100644 index 00000000000..9b3a97d26fd --- /dev/null +++ b/components/script/dom/gpubufferusage.rs @@ -0,0 +1,11 @@ +/* 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::reflector::Reflector; +use dom_struct::dom_struct; + +#[dom_struct] +pub struct GPUBufferUsage { + reflector_: Reflector, +} diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs index d04ae97483a..81974735b55 100644 --- a/components/script/dom/gpudevice.rs +++ b/components/script/dom/gpudevice.rs @@ -2,19 +2,30 @@ * 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/. */ +#![allow(unsafe_code)] + use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor; use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{self, GPUDeviceMethods}; -use crate::dom::bindings::reflector::reflect_dom_object; +use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods; +use crate::dom::bindings::inheritance::Castable; +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::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::gpuadapter::GPUAdapter; +use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState}; +use crate::dom::window::Window; use crate::script_runtime::JSContext as SafeJSContext; use dom_struct::dom_struct; +use ipc_channel::ipc; use js::jsapi::{Heap, JSObject}; -use std::ptr::NonNull; -use webgpu::WebGPUDevice; +use js::jsval::{JSVal, ObjectValue, UndefinedValue}; +use js::typedarray::{ArrayBuffer, CreateWith}; +use std::ptr::{self, NonNull}; +use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage}; +use webgpu::{WebGPUBuffer, WebGPUDevice, WebGPURequest}; #[dom_struct] pub struct GPUDevice { @@ -63,6 +74,68 @@ impl GPUDevice { } } +impl GPUDevice { + unsafe fn resolve_create_buffer_mapped( + &self, + cx: SafeJSContext, + channel: ipc_channel::ipc::IpcSender<WebGPURequest>, + gpu_buffer: WebGPUBuffer, + array_buffer: Vec<u8>, + descriptor: BufferDescriptor, + valid: bool, + ) -> Vec<JSVal> { + rooted!(in(*cx) let mut js_array_buffer = ptr::null_mut::<JSObject>()); + let mut out = Vec::new(); + assert!(ArrayBuffer::create( + *cx, + CreateWith::Slice(array_buffer.as_slice()), + js_array_buffer.handle_mut(), + ) + .is_ok()); + + let buff = GPUBuffer::new( + &self.global(), + channel, + gpu_buffer, + self.device, + GPUBufferState::Mapped, + descriptor.size, + descriptor.usage.bits(), + valid, + ); + out.push(ObjectValue(buff.reflector().get_jsobject().get())); + out.push(ObjectValue(js_array_buffer.get())); + out + } + + fn validate_buffer_descriptor( + &self, + descriptor: &GPUBufferDescriptor, + ) -> (bool, BufferDescriptor) { + // TODO: Record a validation error in the current scope if the descriptor is invalid. + let wgpu_usage = BufferUsage::from_bits(descriptor.usage); + let valid = wgpu_usage.is_some() && descriptor.size > 0; + + if valid { + ( + true, + BufferDescriptor { + size: descriptor.size, + usage: wgpu_usage.unwrap(), + }, + ) + } else { + ( + false, + BufferDescriptor { + size: 0, + usage: BufferUsage::STORAGE, + }, + ) + } + } +} + impl GPUDeviceMethods for GPUDevice { /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-adapter fn Adapter(&self) -> DomRoot<GPUAdapter> { @@ -88,4 +161,89 @@ impl GPUDeviceMethods for GPUDevice { fn SetLabel(&self, value: Option<DOMString>) { *self.label.borrow_mut() = value; } + + /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer + fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> DomRoot<GPUBuffer> { + let (valid, wgpu_descriptor) = self.validate_buffer_descriptor(descriptor); + let channel; + let (sender, receiver) = ipc::channel().unwrap(); + if let Some(window) = self.global().downcast::<Window>() { + let id = window.Navigator().create_buffer_id(self.device.0.backend()); + match window.webgpu_channel() { + Some(thread) => { + channel = thread.0.clone(); + thread + .0 + .send(WebGPURequest::CreateBuffer( + sender, + self.device, + id, + wgpu_descriptor, + )) + .unwrap(); + }, + None => unimplemented!(), + } + } else { + unimplemented!() + }; + + let buffer = receiver.recv().unwrap(); + + GPUBuffer::new( + &self.global(), + channel, + buffer, + self.device, + GPUBufferState::Unmapped, + descriptor.size, + descriptor.usage, + valid, + ) + } + + /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffermapped + fn CreateBufferMapped( + &self, + cx: SafeJSContext, + descriptor: &GPUBufferDescriptor, + ) -> Vec<JSVal> { + let (valid, wgpu_descriptor) = self.validate_buffer_descriptor(descriptor); + let channel; + let (sender, receiver) = ipc::channel().unwrap(); + rooted!(in(*cx) let js_val = UndefinedValue()); + if let Some(window) = self.global().downcast::<Window>() { + let id = window.Navigator().create_buffer_id(self.device.0.backend()); + match window.webgpu_channel() { + Some(thread) => { + channel = thread.0.clone(); + thread + .0 + .send(WebGPURequest::CreateBufferMapped( + sender, + self.device, + id, + wgpu_descriptor.clone(), + )) + .unwrap() + }, + None => return vec![js_val.get()], + } + } else { + return vec![js_val.get()]; + }; + + let (buffer, array_buffer) = receiver.recv().unwrap(); + + unsafe { + self.resolve_create_buffer_mapped( + cx, + channel, + buffer, + array_buffer, + wgpu_descriptor, + valid, + ) + } + } } diff --git a/components/script/dom/identityhub.rs b/components/script/dom/identityhub.rs index b2f310330e9..64e4cad3867 100644 --- a/components/script/dom/identityhub.rs +++ b/components/script/dom/identityhub.rs @@ -5,7 +5,7 @@ use smallvec::SmallVec; use webgpu::wgpu::{ hub::IdentityManager, - id::{AdapterId, DeviceId}, + id::{AdapterId, BufferId, DeviceId}, Backend, }; @@ -13,6 +13,7 @@ use webgpu::wgpu::{ pub struct IdentityHub { adapters: IdentityManager, devices: IdentityManager, + buffers: IdentityManager, backend: Backend, } @@ -21,6 +22,7 @@ impl IdentityHub { IdentityHub { adapters: IdentityManager::default(), devices: IdentityManager::default(), + buffers: IdentityManager::default(), backend, } } @@ -32,6 +34,10 @@ impl IdentityHub { fn create_device_id(&mut self) -> DeviceId { self.devices.alloc(self.backend) } + + pub fn create_buffer_id(&mut self) -> BufferId { + self.buffers.alloc(self.backend) + } } #[derive(Debug)] @@ -99,4 +105,18 @@ impl Identities { } ids } + + pub fn create_buffer_id(&mut self, backend: Backend) -> BufferId { + match backend { + #[cfg(any(target_os = "linux", target_os = "windows"))] + Backend::Vulkan => self.vk_hub.create_buffer_id(), + #[cfg(target_os = "windows")] + Backend::Dx12 => self.dx12_hub.create_buffer_id(), + #[cfg(target_os = "windows")] + Backend::Dx11 => self.dx11_hub.create_buffer_id(), + #[cfg(any(target_os = "ios", target_os = "macos"))] + Backend::Metal => self.metal_hub.create_buffer_id(), + _ => self.dummy_hub.create_buffer_id(), + } + } } diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index bb1110389c6..b8bdc638c17 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -317,6 +317,8 @@ pub mod gamepadlist; pub mod globalscope; pub mod gpu; pub mod gpuadapter; +pub mod gpubuffer; +pub mod gpubufferusage; pub mod gpudevice; pub mod hashchangeevent; pub mod headers; diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 491ae034f31..03c6b27d156 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -28,7 +28,7 @@ use smallvec::SmallVec; use std::cell::RefCell; use std::rc::Rc; use webgpu::wgpu::{ - id::{AdapterId, DeviceId}, + id::{AdapterId, BufferId, DeviceId}, Backend, }; @@ -84,6 +84,10 @@ impl Navigator { pub fn create_device_id(&self, backend: Backend) -> DeviceId { self.gpu_id_hub.borrow_mut().create_device_id(backend) } + + pub fn create_buffer_id(&self, backend: Backend) -> BufferId { + self.gpu_id_hub.borrow_mut().create_buffer_id(backend) + } } impl NavigatorMethods for Navigator { diff --git a/components/script/dom/webidls/GPUBuffer.webidl b/components/script/dom/webidls/GPUBuffer.webidl new file mode 100644 index 00000000000..0b327bdcbd2 --- /dev/null +++ b/components/script/dom/webidls/GPUBuffer.webidl @@ -0,0 +1,25 @@ +/* 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/#gpubuffer +[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"] +interface GPUBuffer { + // Promise<ArrayBuffer> mapReadAsync(); + // Promise<ArrayBuffer> mapWriteAsync(); + void unmap(); + + void destroy(); +}; +GPUBuffer includes GPUObjectBase; + +dictionary GPUBufferDescriptor : GPUObjectDescriptorBase { + required GPUBufferSize size; + required GPUBufferUsageFlags usage; +}; + +typedef unsigned long long GPUBufferSize; + +typedef unsigned long GPUBufferUsageFlags; + +typedef sequence<any> GPUMappedBuffer; diff --git a/components/script/dom/webidls/GPUBufferUsage.webidl b/components/script/dom/webidls/GPUBufferUsage.webidl new file mode 100644 index 00000000000..549f6652d1f --- /dev/null +++ b/components/script/dom/webidls/GPUBufferUsage.webidl @@ -0,0 +1,17 @@ +/* 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/#buffer-usage +[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] +interface GPUBufferUsage { + const GPUBufferUsageFlags MAP_READ = 0x0001; + const GPUBufferUsageFlags MAP_WRITE = 0x0002; + const GPUBufferUsageFlags COPY_SRC = 0x0004; + const GPUBufferUsageFlags COPY_DST = 0x0008; + const GPUBufferUsageFlags INDEX = 0x0010; + const GPUBufferUsageFlags VERTEX = 0x0020; + const GPUBufferUsageFlags UNIFORM = 0x0040; + const GPUBufferUsageFlags STORAGE = 0x0080; + const GPUBufferUsageFlags INDIRECT = 0x0100; +}; diff --git a/components/script/dom/webidls/GPUDevice.webidl b/components/script/dom/webidls/GPUDevice.webidl index 1cd441e6ef3..965f7e1b7d5 100644 --- a/components/script/dom/webidls/GPUDevice.webidl +++ b/components/script/dom/webidls/GPUDevice.webidl @@ -9,9 +9,9 @@ interface GPUDevice : EventTarget { readonly attribute object extensions; readonly attribute object limits; - /*GPUBuffer createBuffer(GPUBufferDescriptor descriptor); + GPUBuffer createBuffer(GPUBufferDescriptor descriptor); GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor); - Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor); + /*Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor); GPUTexture createTexture(GPUTextureDescriptor descriptor); GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {}); diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs index bfd68ccc611..156beeb040b 100644 --- a/components/webgpu/lib.rs +++ b/components/webgpu/lib.rs @@ -36,6 +36,20 @@ pub enum WebGPURequest { wgpu::id::DeviceId, ), Exit(IpcSender<()>), + CreateBuffer( + IpcSender<WebGPUBuffer>, + WebGPUDevice, + wgpu::id::BufferId, + wgpu::resource::BufferDescriptor, + ), + CreateBufferMapped( + IpcSender<(WebGPUBuffer, Vec<u8>)>, + WebGPUDevice, + wgpu::id::BufferId, + wgpu::resource::BufferDescriptor, + ), + UnmapBuffer(WebGPUBuffer), + DestroyBuffer(WebGPUBuffer), } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -152,6 +166,47 @@ impl WGPU { ) } }, + WebGPURequest::CreateBuffer(sender, device, id, descriptor) => { + let global = &self.global; + let _output = + gfx_select!(id => global.device_create_buffer(device.0, &descriptor, id)); + let buffer = WebGPUBuffer(id); + if let Err(e) = sender.send(buffer) { + warn!( + "Failed to send response to WebGPURequest::CreateBuffer ({})", + e + ) + } + }, + WebGPURequest::CreateBufferMapped(sender, device, id, descriptor) => { + let global = &self.global; + let mut arr_buff_ptr: *mut u8 = std::ptr::null_mut(); + let buffer_size = descriptor.size as usize; + + let _output = gfx_select!(id => + global.device_create_buffer_mapped(device.0, &descriptor, &mut arr_buff_ptr, id)); + let buffer = WebGPUBuffer(id); + + let mut array_buffer = Vec::with_capacity(buffer_size); + unsafe { + array_buffer.set_len(buffer_size); + std::ptr::copy(arr_buff_ptr, array_buffer.as_mut_ptr(), buffer_size); + }; + if let Err(e) = sender.send((buffer, array_buffer)) { + warn!( + "Failed to send response to WebGPURequest::CreateBufferMapped ({})", + e + ) + } + }, + WebGPURequest::UnmapBuffer(buffer) => { + let global = &self.global; + let _output = gfx_select!(buffer.0 => global.buffer_unmap(buffer.0)); + }, + WebGPURequest::DestroyBuffer(buffer) => { + let global = &self.global; + let _output = gfx_select!(buffer.0 => global.buffer_destroy(buffer.0)); + }, WebGPURequest::Exit(sender) => { self.deinit(); if let Err(e) = sender.send(()) { @@ -181,3 +236,4 @@ macro_rules! webgpu_resource { webgpu_resource!(WebGPUAdapter, wgpu::id::AdapterId); webgpu_resource!(WebGPUDevice, wgpu::id::DeviceId); +webgpu_resource!(WebGPUBuffer, wgpu::id::BufferId); |