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 GPUQueue #25744

Merged
merged 1 commit into from Feb 14, 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

Initial implementation of GPUQueue

Added WebIDL bindings for `GPUQueue`.
Implemented the `submit` function of `GPUQueue` and `defaultQueue` function of `GPUDevice`.
  • Loading branch information
zakorgy authored and imiklos committed Feb 13, 2020
commit a3c6810b1850d5b8ce29af2f745058b94a39bb80
@@ -154,7 +154,7 @@ use uuid::Uuid;
use webgpu::{
WebGPU, WebGPUAdapter, WebGPUBindGroup, WebGPUBindGroupLayout, WebGPUBuffer,
WebGPUCommandBuffer, WebGPUCommandEncoder, WebGPUComputePipeline, WebGPUDevice,
WebGPUPipelineLayout, WebGPUShaderModule,
WebGPUPipelineLayout, WebGPUQueue, WebGPUShaderModule,
};
use webrender_api::{DocumentId, ImageKey};
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
@@ -537,6 +537,7 @@ unsafe_no_jsmanaged_fields!(WebGPUBindGroup);
unsafe_no_jsmanaged_fields!(WebGPUBindGroupLayout);
unsafe_no_jsmanaged_fields!(WebGPUComputePipeline);
unsafe_no_jsmanaged_fields!(WebGPUPipelineLayout);
unsafe_no_jsmanaged_fields!(WebGPUQueue);
unsafe_no_jsmanaged_fields!(WebGPUShaderModule);
unsafe_no_jsmanaged_fields!(WebGPUCommandBuffer);
unsafe_no_jsmanaged_fields!(WebGPUCommandEncoder);
@@ -107,14 +107,15 @@ impl GPUAdapterMethods for GPUAdapter {
impl AsyncWGPUListener for GPUAdapter {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
match response {
WebGPUResponse::RequestDevice(device_id, _descriptor) => {
WebGPUResponse::RequestDevice(device_id, queue_id, _descriptor) => {
let device = GPUDevice::new(
&self.global(),
self.channel.clone(),
&self,
Heap::default(),
Heap::default(),
device_id,
queue_id,
);
promise.resolve_native(&device);
},
@@ -2,7 +2,7 @@
* 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::cell::{DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::{
self, GPUBufferMethods, GPUBufferSize,
};
@@ -91,6 +91,10 @@ impl GPUBuffer {
pub fn usage(&self) -> u32 {
self.usage
}

pub fn state(&self) -> Ref<GPUBufferState> {
self.state.borrow()
}
}

impl Drop for GPUBuffer {
@@ -106,6 +110,7 @@ impl GPUBufferMethods for GPUBuffer {
.0
.send(WebGPURequest::UnmapBuffer(self.buffer))
.unwrap();
*self.state.borrow_mut() = GPUBufferState::Unmapped;
}

/// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-destroy
@@ -2,49 +2,81 @@
* 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::cell::{DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::GPUCommandBufferBinding::{
self, GPUCommandBufferMethods,
};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::Dom;
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubuffer::GPUBuffer;
use dom_struct::dom_struct;
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use webgpu::{WebGPU, WebGPUCommandBuffer};

impl Eq for DomRoot<GPUBuffer> {}
impl Hash for DomRoot<GPUBuffer> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id().hash(state);
}
}

#[dom_struct]
pub struct GPUCommandBuffer {
reflector_: Reflector,
#[ignore_malloc_size_of = "defined in webgpu"]
channel: WebGPU,
label: DomRefCell<Option<DOMString>>,
command_buffer: WebGPUCommandBuffer,
buffers: DomRefCell<HashSet<Dom<GPUBuffer>>>,
}

impl GPUCommandBuffer {
pub fn new_inherited(channel: WebGPU, command_buffer: WebGPUCommandBuffer) -> GPUCommandBuffer {
fn new_inherited(
channel: WebGPU,
command_buffer: WebGPUCommandBuffer,
buffers: HashSet<DomRoot<GPUBuffer>>,
) -> GPUCommandBuffer {
GPUCommandBuffer {
channel,
reflector_: Reflector::new(),
label: DomRefCell::new(None),
command_buffer,
buffers: DomRefCell::new(buffers.into_iter().map(|b| Dom::from_ref(&*b)).collect()),
}
}

pub fn new(
global: &GlobalScope,
channel: WebGPU,
command_buffer: WebGPUCommandBuffer,
buffers: HashSet<DomRoot<GPUBuffer>>,
) -> DomRoot<GPUCommandBuffer> {
reflect_dom_object(
Box::new(GPUCommandBuffer::new_inherited(channel, command_buffer)),
Box::new(GPUCommandBuffer::new_inherited(
channel,
command_buffer,
buffers,
)),
global,
GPUCommandBufferBinding::Wrap,
)
}
}

impl GPUCommandBuffer {
pub fn id(&self) -> WebGPUCommandBuffer {
self.command_buffer
}

pub fn buffers(&self) -> Ref<HashSet<Dom<GPUBuffer>>> {
self.buffers.borrow()
}
}

impl GPUCommandBufferMethods for GPUCommandBuffer {
/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<DOMString> {
@@ -16,6 +16,7 @@ use crate::dom::gpucommandbuffer::GPUCommandBuffer;
use crate::dom::gpucomputepassencoder::GPUComputePassEncoder;
use dom_struct::dom_struct;
use ipc_channel::ipc;
use std::collections::HashSet;
use webgpu::{wgpu::command::RawPass, WebGPU, WebGPUCommandEncoder, WebGPURequest};

#[dom_struct]
@@ -25,6 +26,7 @@ pub struct GPUCommandEncoder {
channel: WebGPU,
label: DomRefCell<Option<DOMString>>,
encoder: WebGPUCommandEncoder,
buffers: DomRefCell<HashSet<DomRoot<GPUBuffer>>>,
}

impl GPUCommandEncoder {
@@ -34,6 +36,7 @@ impl GPUCommandEncoder {
reflector_: Reflector::new(),
label: DomRefCell::new(None),
encoder,
buffers: DomRefCell::new(HashSet::new()),
}
}

@@ -82,6 +85,10 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
destination_offset: u64,
size: u64,
) {
self.buffers.borrow_mut().insert(DomRoot::from_ref(source));
self.buffers
.borrow_mut()
.insert(DomRoot::from_ref(destination));
self.channel
.0
.send(WebGPURequest::CopyBufferToBuffer(
@@ -106,9 +113,14 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
// TODO(zakorgy): We should use `_descriptor` here after it's not empty
// and the underlying wgpu-core struct is serializable
))
.expect("Failed to send CopyBufferToBuffer");
.expect("Failed to send Finish");

let buffer = receiver.recv().unwrap();
GPUCommandBuffer::new(&self.global(), self.channel.clone(), buffer)
GPUCommandBuffer::new(
&self.global(),
self.channel.clone(),
buffer,
self.buffers.borrow_mut().drain().collect(),

This comment has been minimized.

Copy link
@jdm

jdm Feb 12, 2020

Member

Let's do this instead: self.buffers.borrow_mut().drain().map(|b| DomRoot::from_ref(&**b)).collect()

This comment has been minimized.

Copy link
@imiklos

imiklos Feb 13, 2020

Author Contributor

To pass as DomRoot here, I had to implement the Eq and Hash for DomRoot<GPUBuffer>.
I've also changed the buffers type in the GPUCommandEncoder from Dom to DomRoot<GPUBuffer> to be able to use in the finish function without using the unrooted_must_root annotation.

)
}
}
@@ -31,6 +31,7 @@ use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState};
use crate::dom::gpucommandencoder::GPUCommandEncoder;
use crate::dom::gpucomputepipeline::GPUComputePipeline;
use crate::dom::gpupipelinelayout::GPUPipelineLayout;
use crate::dom::gpuqueue::GPUQueue;
use crate::dom::gpushadermodule::GPUShaderModule;
use crate::script_runtime::JSContext as SafeJSContext;
use dom_struct::dom_struct;
@@ -45,7 +46,7 @@ use webgpu::wgpu::binding_model::{
ShaderStage,
};
use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage};
use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest};
use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPUQueue, WebGPURequest};

#[dom_struct]
pub struct GPUDevice {
@@ -59,6 +60,7 @@ pub struct GPUDevice {
limits: Heap<*mut JSObject>,
label: DomRefCell<Option<DOMString>>,
device: WebGPUDevice,
default_queue: Dom<GPUQueue>,
}

impl GPUDevice {
@@ -68,6 +70,7 @@ impl GPUDevice {
extensions: Heap<*mut JSObject>,
limits: Heap<*mut JSObject>,
device: WebGPUDevice,
queue: &GPUQueue,
) -> GPUDevice {
Self {
eventtarget: EventTarget::new_inherited(),
@@ -77,6 +80,7 @@ impl GPUDevice {
limits,
label: DomRefCell::new(None),
device,
default_queue: Dom::from_ref(queue),
}
}

@@ -88,10 +92,12 @@ impl GPUDevice {
extensions: Heap<*mut JSObject>,
limits: Heap<*mut JSObject>,
device: WebGPUDevice,
queue: WebGPUQueue,
) -> DomRoot<GPUDevice> {
let queue = GPUQueue::new(global, channel.clone(), queue);
reflect_dom_object(
Box::new(GPUDevice::new_inherited(
channel, adapter, extensions, limits, device,
channel, adapter, extensions, limits, device, &queue,
)),
global,
GPUDeviceBinding::Wrap,
@@ -176,6 +182,11 @@ impl GPUDeviceMethods for GPUDevice {
NonNull::new(self.extensions.get()).unwrap()
}

/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-defaultqueue
fn DefaultQueue(&self) -> DomRoot<GPUQueue> {
DomRoot::from_ref(&self.default_queue)
}

/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<DOMString> {
self.label.borrow().clone()
@@ -0,0 +1,73 @@
/* 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::GPUQueueBinding::{self, GPUQueueMethods};
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::gpubuffer::GPUBufferState;
use crate::dom::gpucommandbuffer::GPUCommandBuffer;
use dom_struct::dom_struct;
use webgpu::{WebGPU, WebGPUQueue, WebGPURequest};

#[dom_struct]
pub struct GPUQueue {
reflector_: Reflector,
#[ignore_malloc_size_of = "defined in webgpu"]
channel: WebGPU,
label: DomRefCell<Option<DOMString>>,
queue: WebGPUQueue,
}

impl GPUQueue {
fn new_inherited(channel: WebGPU, queue: WebGPUQueue) -> GPUQueue {
GPUQueue {
channel,
reflector_: Reflector::new(),
label: DomRefCell::new(None),
queue,
}
}

pub fn new(global: &GlobalScope, channel: WebGPU, queue: WebGPUQueue) -> DomRoot<GPUQueue> {
reflect_dom_object(
Box::new(GPUQueue::new_inherited(channel, queue)),
global,
GPUQueueBinding::Wrap,
)
}
}

impl GPUQueueMethods for GPUQueue {
/// 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;
}

/// https://gpuweb.github.io/gpuweb/#dom-gpuqueue-submit
fn Submit(&self, command_buffers: Vec<DomRoot<GPUCommandBuffer>>) {
let valid = command_buffers.iter().all(|cb| {
cb.buffers().iter().all(|b| match *b.state() {
GPUBufferState::Unmapped => true,
_ => false,
})
});
if !valid {
// TODO: Generate error to the ErrorScope
return;
}
let buffer_ids = command_buffers.iter().map(|cb| cb.id().0).collect();
self.channel
.0
.send(WebGPURequest::Submit(self.queue.0, buffer_ids))
.unwrap();
}
}
@@ -328,6 +328,7 @@ pub mod gpucomputepassencoder;
pub mod gpucomputepipeline;
pub mod gpudevice;
pub mod gpupipelinelayout;
pub mod gpuqueue;
pub mod gpushadermodule;
pub mod gpushaderstage;
pub mod hashchangeevent;
@@ -5,13 +5,14 @@
// https://gpuweb.github.io/gpuweb/#gpudevice
[Exposed=(Window, DedicatedWorker)/*, Serializable */, Pref="dom.webgpu.enabled"]
interface GPUDevice : EventTarget {
readonly attribute GPUAdapter adapter;
/*[SameObject]*/ readonly attribute GPUAdapter adapter;
readonly attribute object extensions;
readonly attribute object limits;

[SameObject] readonly attribute GPUQueue defaultQueue;

GPUBuffer createBuffer(GPUBufferDescriptor descriptor);
GPUMappedBuffer createBufferMapped(GPUBufferDescriptor descriptor);
// Promise<GPUMappedBuffer> createBufferMappedAsync(GPUBufferDescriptor descriptor);
// GPUTexture createTexture(GPUTextureDescriptor descriptor);
// GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});

@@ -25,8 +26,6 @@ interface GPUDevice : EventTarget {

GPUCommandEncoder createCommandEncoder(optional GPUCommandEncoderDescriptor descriptor = {});
// GPURenderBundleEncoder createRenderBundleEncoder(GPURenderBundleEncoderDescriptor descriptor);

// GPUQueue getQueue();
};
GPUDevice includes GPUObjectBase;

@@ -0,0 +1,18 @@
/* 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/#gpuqueue
[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
interface GPUQueue {
void submit(sequence<GPUCommandBuffer> commandBuffers);

// GPUFence createFence(optional GPUFenceDescriptor descriptor = {});
// void signal(GPUFence fence, unsigned long long signalValue);

// void copyImageBitmapToTexture(
// GPUImageBitmapCopyView source,
// GPUTextureCopyView destination,
// GPUExtent3D copySize);
};
GPUQueue includes GPUObjectBase;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.