Auto merge of #27480 - kunalmohan:gpu-void-error, r=kvark

WebGPU-Report errors in Promise or void returning operations

<!-- Please describe your changes on the following line: -->
This also updates GPUBuffer mapping to match latest spec.

r?@kvark

---
<!-- 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

<!-- 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-08-04 16:37:16 -04:00 committed by GitHub
commit 549179bbd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 489 additions and 305 deletions

6
Cargo.lock generated
View file

@ -3701,7 +3701,7 @@ checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204"
[[package]]
name = "naga"
version = "0.1.0"
source = "git+https://github.com/gfx-rs/naga?rev=94802078c3bc5d138f497419ea3e7a869f10916d#94802078c3bc5d138f497419ea3e7a869f10916d"
source = "git+https://github.com/gfx-rs/naga?rev=1eb637038dd15fc1dad770eca8e6943424dbc122#1eb637038dd15fc1dad770eca8e6943424dbc122"
dependencies = [
"bitflags",
"fxhash",
@ -6911,7 +6911,7 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "0.5.0"
source = "git+https://github.com/gfx-rs/wgpu#9e4839eb049707629fa8a91e3603085433f352a4"
source = "git+https://github.com/gfx-rs/wgpu#872a6c4c2bab5591838219c34e0cbf5fa9c2ec85"
dependencies = [
"arrayvec 0.5.1",
"bitflags",
@ -6938,7 +6938,7 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "0.5.0"
source = "git+https://github.com/gfx-rs/wgpu#9e4839eb049707629fa8a91e3603085433f352a4"
source = "git+https://github.com/gfx-rs/wgpu#872a6c4c2bab5591838219c34e0cbf5fa9c2ec85"
dependencies = [
"bitflags",
"serde",

View file

@ -2169,7 +2169,7 @@ where
options,
ids,
};
if webgpu_chan.0.send(adapter_request).is_err() {
if webgpu_chan.0.send((None, adapter_request)).is_err() {
return warn!("Failed to send request adapter message on WebGPU channel");
}
},

View file

@ -831,6 +831,7 @@ malloc_size_of_is_0!(bool, char, str);
malloc_size_of_is_0!(u8, u16, u32, u64, u128, usize);
malloc_size_of_is_0!(i8, i16, i32, i64, i128, isize);
malloc_size_of_is_0!(f32, f64);
malloc_size_of_is_0!(std::num::NonZeroU64);
malloc_size_of_is_0!(std::sync::atomic::AtomicBool);
malloc_size_of_is_0!(std::sync::atomic::AtomicIsize);

View file

@ -138,6 +138,7 @@ use std::cell::{Cell, RefCell, UnsafeCell};
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::hash::{BuildHasher, Hash};
use std::mem;
use std::num::NonZeroU64;
use std::ops::{Deref, DerefMut, Range};
use std::path::PathBuf;
use std::rc::Rc;
@ -524,6 +525,7 @@ unsafe_no_jsmanaged_fields!(ActiveUniformBlockInfo);
unsafe_no_jsmanaged_fields!(bool, f32, f64, String, AtomicBool, AtomicUsize, Uuid, char);
unsafe_no_jsmanaged_fields!(usize, u8, u16, u32, u64);
unsafe_no_jsmanaged_fields!(isize, i8, i16, i32, i64);
unsafe_no_jsmanaged_fields!(NonZeroU64);
unsafe_no_jsmanaged_fields!(Error);
unsafe_no_jsmanaged_fields!(ServoUrl, ImmutableOrigin, MutableOrigin);
unsafe_no_jsmanaged_fields!(Image, ImageMetadata, dyn ImageCache, PendingImageId);

View file

@ -127,7 +127,7 @@ use std::sync::Arc;
use std::thread::JoinHandle;
use time::{get_time, Timespec};
use uuid::Uuid;
use webgpu::{identity::WebGPUOpResult, WebGPUDevice};
use webgpu::{identity::WebGPUOpResult, ErrorScopeId, WebGPUDevice};
#[derive(JSTraceable)]
pub struct AutoCloseWorker {
@ -3023,7 +3023,7 @@ impl GlobalScope {
pub fn handle_wgpu_msg(
&self,
device: WebGPUDevice,
scope: Option<u64>,
scope: Option<ErrorScopeId>,
result: WebGPUOpResult,
) {
self.gpu_devices

View file

@ -41,7 +41,7 @@ impl GPU {
}
pub trait AsyncWGPUListener {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>);
fn handle_response(&self, response: WebGPUResponseResult, promise: &Rc<Promise>);
}
struct WGPUResponse<T: AsyncWGPUListener + DomObject> {
@ -53,13 +53,7 @@ impl<T: AsyncWGPUListener + DomObject> WGPUResponse<T> {
#[allow(unrooted_must_root)]
fn response(self, response: WebGPUResponseResult) {
let promise = self.trusted.root();
match response {
Ok(response) => self.receiver.root().handle_response(response, &promise),
Err(error) => promise.reject_error(Error::Type(format!(
"Received error from WebGPU thread: {}",
error
))),
}
self.receiver.root().handle_response(response, &promise);
}
}
@ -134,13 +128,13 @@ impl GPUMethods for GPU {
}
impl AsyncWGPUListener for GPU {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: WebGPUResponseResult, promise: &Rc<Promise>) {
match response {
WebGPUResponse::RequestAdapter {
Ok(WebGPUResponse::RequestAdapter {
adapter_name,
adapter_id,
channel,
} => {
}) => {
let adapter = GPUAdapter::new(
&self.global(),
channel,
@ -150,7 +144,14 @@ impl AsyncWGPUListener for GPU {
);
promise.resolve_native(&adapter);
},
_ => promise.reject_error(Error::Operation),
Err(e) => {
warn!("Could not get GPUAdapter ({:?})", e);
promise.resolve_native(&None::<GPUAdapter>);
},
_ => {
warn!("GPU received wrong WebGPUResponse");
promise.reject_error(Error::Operation);
},
}
}
}

View file

@ -20,7 +20,7 @@ use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull;
use std::rc::Rc;
use webgpu::{wgt, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse};
use webgpu::{wgt, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse, WebGPUResponseResult};
#[dom_struct]
pub struct GPUAdapter {
@ -97,14 +97,17 @@ impl GPUAdapterMethods for GPUAdapter {
if self
.channel
.0
.send(WebGPURequest::RequestDevice {
sender,
adapter_id: self.adapter,
descriptor: desc,
device_id: id,
pipeline_id,
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
})
.send((
None,
WebGPURequest::RequestDevice {
sender,
adapter_id: self.adapter,
descriptor: desc,
device_id: id,
pipeline_id,
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
},
))
.is_err()
{
promise.reject_error(Error::Operation);
@ -114,14 +117,14 @@ impl GPUAdapterMethods for GPUAdapter {
}
impl AsyncWGPUListener for GPUAdapter {
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: WebGPUResponseResult, promise: &Rc<Promise>) {
match response {
WebGPUResponse::RequestDevice {
Ok(WebGPUResponse::RequestDevice {
device_id,
queue_id,
_descriptor,
label,
} => {
}) => {
let device = GPUDevice::new(
&self.global(),
self.channel.clone(),
@ -135,7 +138,14 @@ impl AsyncWGPUListener for GPUAdapter {
self.global().add_gpu_device(&device);
promise.resolve_native(&device);
},
_ => promise.reject_error(Error::Operation),
Err(e) => {
warn!("Could not get GPUDevice({:?})", e);
promise.reject_error(Error::Operation);
},
_ => {
warn!("GPUAdapter received wrong WebGPUResponse");
promise.reject_error(Error::Operation);
},
}
}
}

View file

@ -8,10 +8,11 @@ use crate::dom::bindings::codegen::Bindings::GPUMapModeBinding::GPUMapModeConsta
use crate::dom::bindings::error::{Error, Fallible};
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::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::gpu::{response_async, AsyncWGPUListener};
use crate::dom::gpudevice::GPUDevice;
use crate::dom::promise::Promise;
use crate::realms::InRealm;
use crate::script_runtime::JSContext;
@ -25,8 +26,10 @@ use std::ffi::c_void;
use std::ops::Range;
use std::ptr::NonNull;
use std::rc::Rc;
use std::string::String;
use webgpu::{
wgpu::device::HostMap, WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest, WebGPUResponse,
identity::WebGPUOpResult, wgpu::device::HostMap, WebGPU, WebGPUBuffer, WebGPURequest,
WebGPUResponse, WebGPUResponseResult,
};
const RANGE_OFFSET_ALIGN_MASK: u64 = 8;
@ -61,7 +64,7 @@ pub struct GPUBuffer {
label: DomRefCell<Option<USVString>>,
state: Cell<GPUBufferState>,
buffer: WebGPUBuffer,
device: WebGPUDevice,
device: Dom<GPUDevice>,
size: GPUSize64,
#[ignore_malloc_size_of = "promises are hard"]
map_promise: DomRefCell<Option<Rc<Promise>>>,
@ -72,7 +75,7 @@ impl GPUBuffer {
fn new_inherited(
channel: WebGPU,
buffer: WebGPUBuffer,
device: WebGPUDevice,
device: &GPUDevice,
state: GPUBufferState,
size: GPUSize64,
map_info: DomRefCell<Option<GPUBufferMapInfo>>,
@ -83,7 +86,7 @@ impl GPUBuffer {
channel,
label: DomRefCell::new(label),
state: Cell::new(state),
device,
device: Dom::from_ref(device),
buffer,
map_promise: DomRefCell::new(None),
size,
@ -96,7 +99,7 @@ impl GPUBuffer {
global: &GlobalScope,
channel: WebGPU,
buffer: WebGPUBuffer,
device: WebGPUDevice,
device: &GPUDevice,
state: GPUBufferState,
size: GPUSize64,
map_info: DomRefCell<Option<GPUBufferMapInfo>>,
@ -143,13 +146,19 @@ impl GPUBufferMethods for GPUBuffer {
let mut info = self.map_info.borrow_mut();
let m_info = info.as_mut().unwrap();
let m_range = m_info.mapping_range.clone();
if let Err(e) = self.channel.0.send(WebGPURequest::UnmapBuffer {
buffer_id: self.id().0,
array_buffer: IpcSharedMemory::from_bytes(m_info.mapping.borrow().as_slice()),
is_map_read: m_info.map_mode == Some(GPUMapModeConstants::READ),
offset: m_range.start,
size: m_range.end - m_range.start,
}) {
if let Err(e) = self.channel.0.send((
self.device.use_current_scope(),
WebGPURequest::UnmapBuffer {
buffer_id: self.id().0,
device_id: self.device.id().0,
array_buffer: IpcSharedMemory::from_bytes(
m_info.mapping.borrow().as_slice(),
),
is_map_read: m_info.map_mode == Some(GPUMapModeConstants::READ),
offset: m_range.start,
size: m_range.end - m_range.start,
},
)) {
warn!("Failed to send Buffer unmap ({:?}) ({})", self.buffer.0, e);
}
// Step 3.3
@ -180,7 +189,7 @@ impl GPUBufferMethods for GPUBuffer {
if let Err(e) = self
.channel
.0
.send(WebGPURequest::DestroyBuffer(self.buffer.0))
.send((None, WebGPURequest::DestroyBuffer(self.buffer.0)))
{
warn!(
"Failed to send WebGPURequest::DestroyBuffer({:?}) ({})",
@ -196,40 +205,53 @@ impl GPUBufferMethods for GPUBuffer {
&self,
mode: u32,
offset: GPUSize64,
size: GPUSize64,
size: Option<GPUSize64>,
comp: InRealm,
) -> Rc<Promise> {
let promise = Promise::new_in_current_realm(&self.global(), comp);
let map_range = if size == 0 {
offset..self.size
let range_size = if let Some(s) = size {
s
} else if offset >= self.size {
promise.reject_error(Error::Operation);
return promise;
} else {
if offset + size > self.size {
warn!("Requested mapping size is greated than buffer size");
promise.reject_error(Error::Abort);
return promise;
}
offset..offset + size
self.size - offset
};
let scope_id = self.device.use_current_scope();
if self.state.get() != GPUBufferState::Unmapped {
self.device.handle_server_msg(
scope_id,
WebGPUOpResult::ValidationError(String::from("Buffer is not Unmapped")),
);
promise.reject_error(Error::Abort);
return promise;
}
let host_map = match mode {
GPUMapModeConstants::READ => HostMap::Read,
GPUMapModeConstants::WRITE => HostMap::Write,
_ => {
self.device.handle_server_msg(
scope_id,
WebGPUOpResult::ValidationError(String::from("Invalid MapModeFlags")),
);
promise.reject_error(Error::Abort);
return promise;
},
};
if self.state.get() != GPUBufferState::Unmapped {
promise.reject_error(Error::Abort);
return promise;
}
let map_range = offset..offset + range_size;
let sender = response_async(&promise, self);
if let Err(e) = self.channel.0.send(WebGPURequest::BufferMapAsync {
sender,
buffer_id: self.buffer.0,
host_map,
map_range: map_range.clone(),
}) {
if let Err(e) = self.channel.0.send((
scope_id,
WebGPURequest::BufferMapAsync {
sender,
buffer_id: self.buffer.0,
device_id: self.device.id().0,
host_map,
map_range: map_range.clone(),
},
)) {
warn!(
"Failed to send BufferMapAsync ({:?}) ({})",
self.buffer.0, e
@ -256,9 +278,16 @@ impl GPUBufferMethods for GPUBuffer {
&self,
cx: JSContext,
offset: GPUSize64,
size: GPUSize64,
size: Option<GPUSize64>,
) -> Fallible<NonNull<JSObject>> {
let m_end = if size == 0 { self.size } else { offset + size };
let range_size = if let Some(s) = size {
s
} else if offset >= self.size {
return Err(Error::Operation);
} else {
self.size - offset
};
let m_end = offset + range_size;
let mut info = self.map_info.borrow_mut();
let m_info = info.as_mut().unwrap();
@ -267,7 +296,7 @@ impl GPUBufferMethods for GPUBuffer {
_ => false,
};
valid &= offset % RANGE_OFFSET_ALIGN_MASK == 0 &&
(m_end - offset) % RANGE_SIZE_ALIGN_MASK == 0 &&
range_size % RANGE_SIZE_ALIGN_MASK == 0 &&
offset >= m_info.mapping_range.start &&
m_end <= m_info.mapping_range.end;
valid &= m_info
@ -285,7 +314,7 @@ impl GPUBufferMethods for GPUBuffer {
let array_buffer = unsafe {
NewExternalArrayBuffer(
*cx,
(m_end - offset) as usize,
range_size as usize,
m_info.mapping.borrow_mut()[offset as usize..m_end as usize].as_mut_ptr() as _,
Some(free_func),
Rc::into_raw(m_info.mapping.clone()) as _,
@ -311,9 +340,9 @@ impl GPUBufferMethods for GPUBuffer {
impl AsyncWGPUListener for GPUBuffer {
#[allow(unsafe_code)]
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
fn handle_response(&self, response: WebGPUResponseResult, promise: &Rc<Promise>) {
match response {
WebGPUResponse::BufferMapAsync(bytes) => {
Ok(WebGPUResponse::BufferMapAsync(bytes)) => {
*self
.map_info
.borrow_mut()
@ -324,8 +353,12 @@ impl AsyncWGPUListener for GPUBuffer {
promise.resolve_native(&());
self.state.set(GPUBufferState::Mapped);
},
Err(e) => {
warn!("Could not map buffer({:?})", e);
promise.reject_error(Error::Abort);
},
_ => {
warn!("Wrong WebGPUResponse received");
warn!("GPUBuffer received wrong WebGPUResponse");
promise.reject_error(Error::Operation);
},
}
@ -333,7 +366,7 @@ impl AsyncWGPUListener for GPUBuffer {
if let Err(e) = self
.channel
.0
.send(WebGPURequest::BufferMapComplete(self.buffer.0))
.send((None, WebGPURequest::BufferMapComplete(self.buffer.0)))
{
warn!(
"Failed to send BufferMapComplete({:?}) ({})",

View file

@ -45,7 +45,9 @@ pub struct GPUCanvasContext {
impl GPUCanvasContext {
fn new_inherited(canvas: &HTMLCanvasElement, size: Size2D<u32>, channel: WebGPU) -> Self {
let (sender, receiver) = ipc::channel().unwrap();
let _ = channel.0.send(WebGPURequest::CreateContext(sender));
if let Err(e) = channel.0.send((None, WebGPURequest::CreateContext(sender))) {
warn!("Failed to send CreateContext ({:?})", e);
}
let external_id = receiver.recv().unwrap();
Self {
reflector_: Reflector::new(),
@ -88,11 +90,14 @@ impl GPUCanvasContext {
.wgpu_id_hub()
.lock()
.create_command_encoder_id(texture_id.backend());
if let Err(e) = self.channel.0.send(WebGPURequest::SwapChainPresent {
external_id: self.context_id.0,
texture_id,
encoder_id,
}) {
if let Err(e) = self.channel.0.send((
None,
WebGPURequest::SwapChainPresent {
external_id: self.context_id.0,
texture_id,
encoder_id,
},
)) {
warn!(
"Failed to send UpdateWebrenderData({:?}) ({})",
self.context_id, e
@ -168,14 +173,17 @@ impl GPUCanvasContextMethods for GPUCanvasContext {
self.channel
.0
.send(WebGPURequest::CreateSwapChain {
device_id: descriptor.device.id().0,
buffer_ids,
external_id: self.context_id.0,
sender,
image_desc,
image_data,
})
.send((
None,
WebGPURequest::CreateSwapChain {
device_id: descriptor.device.id().0,
buffer_ids,
external_id: self.context_id.0,
sender,
image_desc,
image_data,
},
))
.expect("Failed to create WebGPU SwapChain");
let usage = if descriptor.usage % 2 == 0 {

View file

@ -29,7 +29,7 @@ use std::borrow::Cow;
use std::cell::Cell;
use std::collections::HashSet;
use webgpu::wgpu::command as wgpu_com;
use webgpu::{self, wgt, WebGPU, WebGPURequest};
use webgpu::{self, identity::WebGPUOpResult, wgt, WebGPU, WebGPURequest};
// https://gpuweb.github.io/gpuweb/#enumdef-encoder-state
#[derive(MallocSizeOf, PartialEq)]
@ -103,6 +103,10 @@ impl GPUCommandEncoder {
*self.state.borrow_mut() = GPUCommandEncoderState::Closed;
}
}
pub fn device(&self) -> &GPUDevice {
&*self.device
}
}
impl GPUCommandEncoderMethods for GPUCommandEncoder {
@ -254,9 +258,15 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
size: GPUSize64,
) {
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
let scope_id = self.device.use_current_scope();
if !valid {
// TODO: Record an error in the current scope.
self.device.handle_server_msg(
scope_id,
WebGPUOpResult::ValidationError(String::from(
"CommandEncoder is not in Open State",
)),
);
self.valid.set(false);
return;
}
@ -267,14 +277,18 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
.insert(DomRoot::from_ref(destination));
self.channel
.0
.send(WebGPURequest::CopyBufferToBuffer {
command_encoder_id: self.encoder.0,
source_id: source.id().0,
source_offset,
destination_id: destination.id().0,
destination_offset,
size,
})
.send((
scope_id,
WebGPURequest::CopyBufferToBuffer {
command_encoder_id: self.encoder.0,
device_id: self.device.id().0,
source_id: source.id().0,
source_offset,
destination_id: destination.id().0,
destination_offset,
size,
},
))
.expect("Failed to send CopyBufferToBuffer");
}
@ -286,9 +300,15 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
copy_size: GPUExtent3D,
) {
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
let scope_id = self.device.use_current_scope();
if !valid {
// TODO: Record an error in the current scope.
self.device.handle_server_msg(
scope_id,
WebGPUOpResult::ValidationError(String::from(
"CommandEncoder is not in Open State",
)),
);
self.valid.set(false);
return;
}
@ -299,12 +319,18 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
self.channel
.0
.send(WebGPURequest::CopyBufferToTexture {
command_encoder_id: self.encoder.0,
source: convert_buffer_cv(source),
destination: convert_texture_cv(destination),
copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(&copy_size)),
})
.send((
scope_id,
WebGPURequest::CopyBufferToTexture {
command_encoder_id: self.encoder.0,
device_id: self.device.id().0,
source: convert_buffer_cv(source),
destination: convert_texture_cv(destination),
copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(
&copy_size,
)),
},
))
.expect("Failed to send CopyBufferToTexture");
}
@ -316,9 +342,15 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
copy_size: GPUExtent3D,
) {
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
let scope_id = self.device.use_current_scope();
if !valid {
// TODO: Record an error in the current scope.
self.device.handle_server_msg(
scope_id,
WebGPUOpResult::ValidationError(String::from(
"CommandEncoder is not in Open State",
)),
);
self.valid.set(false);
return;
}
@ -329,12 +361,18 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
self.channel
.0
.send(WebGPURequest::CopyTextureToBuffer {
command_encoder_id: self.encoder.0,
source: convert_texture_cv(source),
destination: convert_buffer_cv(destination),
copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(&copy_size)),
})
.send((
scope_id,
WebGPURequest::CopyTextureToBuffer {
command_encoder_id: self.encoder.0,
device_id: self.device.id().0,
source: convert_texture_cv(source),
destination: convert_buffer_cv(destination),
copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(
&copy_size,
)),
},
))
.expect("Failed to send CopyTextureToBuffer");
}
@ -346,21 +384,33 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
copy_size: GPUExtent3D,
) {
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
let scope_id = self.device.use_current_scope();
if !valid {
// TODO: Record an error in the current scope.
self.device.handle_server_msg(
scope_id,
WebGPUOpResult::ValidationError(String::from(
"CommandEncoder is not in Open State",
)),
);
self.valid.set(false);
return;
}
self.channel
.0
.send(WebGPURequest::CopyTextureToTexture {
command_encoder_id: self.encoder.0,
source: convert_texture_cv(source),
destination: convert_texture_cv(destination),
copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(&copy_size)),
})
.send((
scope_id,
WebGPURequest::CopyTextureToTexture {
command_encoder_id: self.encoder.0,
device_id: self.device.id().0,
source: convert_texture_cv(source),
destination: convert_texture_cv(destination),
copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(
&copy_size,
)),
},
))
.expect("Failed to send CopyTextureToTexture");
}
@ -368,13 +418,15 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
fn Finish(&self, descriptor: &GPUCommandBufferDescriptor) -> DomRoot<GPUCommandBuffer> {
self.channel
.0
.send(WebGPURequest::CommandEncoderFinish {
command_encoder_id: self.encoder.0,
device_id: self.device.id().0,
scope_id: self.device.use_current_scope(),
// TODO(zakorgy): We should use `_descriptor` here after it's not empty
// and the underlying wgpu-core struct is serializable
})
.send((
self.device.use_current_scope(),
WebGPURequest::CommandEncoderFinish {
command_encoder_id: self.encoder.0,
device_id: self.device.id().0,
// TODO(zakorgy): We should use `_descriptor` here after it's not empty
// and the underlying wgpu-core struct is serializable
},
))
.expect("Failed to send Finish");
*self.state.borrow_mut() = GPUCommandEncoderState::Closed;

View file

@ -91,10 +91,14 @@ impl GPUComputePassEncoderMethods for GPUComputePassEncoder {
if let Some(compute_pass) = self.compute_pass.borrow_mut().take() {
self.channel
.0
.send(WebGPURequest::RunComputePass {
command_encoder_id: self.command_encoder.id().0,
compute_pass,
})
.send((
self.command_encoder.device().use_current_scope(),
WebGPURequest::RunComputePass {
command_encoder_id: self.command_encoder.id().0,
device_id: self.command_encoder.device().id().0,
compute_pass,
},
))
.expect("Failed to send RunComputePass");
self.command_encoder.set_state(

View file

@ -71,9 +71,7 @@ use std::rc::Rc;
use webgpu::wgpu::{
binding_model as wgpu_bind, command::RenderBundleEncoder, pipeline as wgpu_pipe,
};
use webgpu::{self, identity::WebGPUOpResult, wgt, WebGPU, WebGPURequest};
type ErrorScopeId = u64;
use webgpu::{self, identity::WebGPUOpResult, wgt, ErrorScopeId, WebGPU, WebGPURequest};
#[derive(JSTraceable, MallocSizeOf)]
struct ErrorScopeInfo {
@ -131,7 +129,7 @@ impl GPUDevice {
scope_context: DomRefCell::new(ScopeContext {
error_scopes: HashMap::new(),
scope_stack: Vec::new(),
next_scope_id: 0,
next_scope_id: ErrorScopeId::new(1).unwrap(),
}),
lost_promise: DomRefCell::new(None),
}
@ -148,12 +146,14 @@ impl GPUDevice {
label: Option<String>,
) -> DomRoot<Self> {
let queue = GPUQueue::new(global, channel.clone(), queue);
reflect_dom_object(
let device = reflect_dom_object(
Box::new(GPUDevice::new_inherited(
channel, adapter, extensions, limits, device, &queue, label,
)),
global,
)
);
queue.set_device(&*device);
device
}
}
@ -311,12 +311,14 @@ impl GPUDeviceMethods for GPUDevice {
let scope_id = self.use_current_scope();
self.channel
.0
.send(WebGPURequest::CreateBuffer {
device_id: self.device.0,
.send((
scope_id,
buffer_id: id,
descriptor: wgpu_descriptor,
})
WebGPURequest::CreateBuffer {
device_id: self.device.0,
buffer_id: id,
descriptor: wgpu_descriptor,
},
))
.expect("Failed to create WebGPU buffer");
let buffer = webgpu::WebGPUBuffer(id);
@ -341,7 +343,7 @@ impl GPUDeviceMethods for GPUDevice {
&self.global(),
self.channel.clone(),
buffer,
self.device,
&self,
state,
descriptor.size,
map_info,
@ -449,12 +451,14 @@ impl GPUDeviceMethods for GPUDevice {
.create_bind_group_layout_id(self.device.0.backend());
self.channel
.0
.send(WebGPURequest::CreateBindGroupLayout {
device_id: self.device.0,
bind_group_layout_id,
.send((
scope_id,
descriptor: desc,
})
WebGPURequest::CreateBindGroupLayout {
device_id: self.device.0,
bind_group_layout_id,
descriptor: desc,
},
))
.expect("Failed to create WebGPU BindGroupLayout");
let bgl = webgpu::WebGPUBindGroupLayout(bind_group_layout_id);
@ -491,12 +495,14 @@ impl GPUDeviceMethods for GPUDevice {
.create_pipeline_layout_id(self.device.0.backend());
self.channel
.0
.send(WebGPURequest::CreatePipelineLayout {
device_id: self.device.0,
pipeline_layout_id,
descriptor: desc,
.send((
scope_id,
})
WebGPURequest::CreatePipelineLayout {
device_id: self.device.0,
pipeline_layout_id,
descriptor: desc,
},
))
.expect("Failed to create WebGPU PipelineLayout");
let pipeline_layout = webgpu::WebGPUPipelineLayout(pipeline_layout_id);
@ -551,12 +557,14 @@ impl GPUDeviceMethods for GPUDevice {
.create_bind_group_id(self.device.0.backend());
self.channel
.0
.send(WebGPURequest::CreateBindGroup {
device_id: self.device.0,
bind_group_id,
descriptor: desc,
.send((
scope_id,
})
WebGPURequest::CreateBindGroup {
device_id: self.device.0,
bind_group_id,
descriptor: desc,
},
))
.expect("Failed to create WebGPU BindGroup");
let bind_group = webgpu::WebGPUBindGroup(bind_group_id);
@ -590,12 +598,14 @@ impl GPUDeviceMethods for GPUDevice {
let scope_id = self.use_current_scope();
self.channel
.0
.send(WebGPURequest::CreateShaderModule {
device_id: self.device.0,
.send((
scope_id,
program_id,
program,
})
WebGPURequest::CreateShaderModule {
device_id: self.device.0,
program_id,
program,
},
))
.expect("Failed to create WebGPU ShaderModule");
let shader_module = webgpu::WebGPUShaderModule(program_id);
@ -629,12 +639,14 @@ impl GPUDeviceMethods for GPUDevice {
self.channel
.0
.send(WebGPURequest::CreateComputePipeline {
device_id: self.device.0,
.send((
scope_id,
compute_pipeline_id,
descriptor: desc,
})
WebGPURequest::CreateComputePipeline {
device_id: self.device.0,
compute_pipeline_id,
descriptor: desc,
},
))
.expect("Failed to create WebGPU ComputePipeline");
let compute_pipeline = webgpu::WebGPUComputePipeline(compute_pipeline_id);
@ -658,12 +670,14 @@ impl GPUDeviceMethods for GPUDevice {
let scope_id = self.use_current_scope();
self.channel
.0
.send(WebGPURequest::CreateCommandEncoder {
device_id: self.device.0,
.send((
scope_id,
command_encoder_id,
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
})
WebGPURequest::CreateCommandEncoder {
device_id: self.device.0,
command_encoder_id,
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
},
))
.expect("Failed to create WebGPU command encoder");
let encoder = webgpu::WebGPUCommandEncoder(command_encoder_id);
@ -708,12 +722,14 @@ impl GPUDeviceMethods for GPUDevice {
self.channel
.0
.send(WebGPURequest::CreateTexture {
device_id: self.device.0,
texture_id,
descriptor: desc,
.send((
scope_id,
})
WebGPURequest::CreateTexture {
device_id: self.device.0,
texture_id,
descriptor: desc,
},
))
.expect("Failed to create WebGPU Texture");
let texture = webgpu::WebGPUTexture(texture_id);
@ -759,12 +775,14 @@ impl GPUDeviceMethods for GPUDevice {
let scope_id = self.use_current_scope();
self.channel
.0
.send(WebGPURequest::CreateSampler {
device_id: self.device.0,
.send((
scope_id,
sampler_id,
descriptor: desc,
})
WebGPURequest::CreateSampler {
device_id: self.device.0,
sampler_id,
descriptor: desc,
},
))
.expect("Failed to create WebGPU sampler");
let sampler = webgpu::WebGPUSampler(sampler_id);
@ -901,12 +919,14 @@ impl GPUDeviceMethods for GPUDevice {
self.channel
.0
.send(WebGPURequest::CreateRenderPipeline {
device_id: self.device.0,
render_pipeline_id,
.send((
scope_id,
descriptor: desc,
})
WebGPURequest::CreateRenderPipeline {
device_id: self.device.0,
render_pipeline_id,
descriptor: desc,
},
))
.expect("Failed to create WebGPU render pipeline");
let render_pipeline = webgpu::WebGPURenderPipeline(render_pipeline_id);
@ -959,7 +979,7 @@ impl GPUDeviceMethods for GPUDevice {
fn PushErrorScope(&self, filter: GPUErrorFilter) {
let mut context = self.scope_context.borrow_mut();
let scope_id = context.next_scope_id;
context.next_scope_id += 1;
context.next_scope_id = ErrorScopeId::new(scope_id.get() + 1).unwrap();
let err_scope = ErrorScopeInfo {
op_count: 0,
error: None,

View file

@ -11,24 +11,25 @@ use crate::dom::bindings::codegen::Bindings::GPUQueueBinding::GPUQueueMethods;
use crate::dom::bindings::codegen::Bindings::GPUTextureBinding::GPUExtent3D;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubuffer::{GPUBuffer, GPUBufferState};
use crate::dom::gpucommandbuffer::GPUCommandBuffer;
use crate::dom::gpucommandencoder::{convert_texture_cv, convert_texture_data_layout};
use crate::dom::gpudevice::{convert_texture_size_to_dict, convert_texture_size_to_wgt};
use crate::dom::gpudevice::{convert_texture_size_to_dict, convert_texture_size_to_wgt, GPUDevice};
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSharedMemory;
use js::rust::CustomAutoRooterGuard;
use js::typedarray::ArrayBuffer;
use webgpu::{wgt, WebGPU, WebGPUQueue, WebGPURequest};
use webgpu::{identity::WebGPUOpResult, wgt, WebGPU, WebGPUQueue, WebGPURequest};
#[dom_struct]
pub struct GPUQueue {
reflector_: Reflector,
#[ignore_malloc_size_of = "defined in webgpu"]
channel: WebGPU,
device: DomRefCell<Option<Dom<GPUDevice>>>,
label: DomRefCell<Option<USVString>>,
queue: WebGPUQueue,
}
@ -38,6 +39,7 @@ impl GPUQueue {
GPUQueue {
channel,
reflector_: Reflector::new(),
device: DomRefCell::new(None),
label: DomRefCell::new(None),
queue,
}
@ -48,6 +50,12 @@ impl GPUQueue {
}
}
impl GPUQueue {
pub fn set_device(&self, device: &GPUDevice) {
*self.device.borrow_mut() = Some(Dom::from_ref(device));
}
}
impl GPUQueueMethods for GPUQueue {
/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<USVString> {
@ -67,17 +75,26 @@ impl GPUQueueMethods for GPUQueue {
_ => false,
})
});
let scope_id = self.device.borrow().as_ref().unwrap().use_current_scope();
if !valid {
// TODO: Generate error to the ErrorScope
self.device.borrow().as_ref().unwrap().handle_server_msg(
scope_id,
WebGPUOpResult::ValidationError(String::from(
"Referenced GPUBuffer(s) are not Unmapped",
)),
);
return;
}
let command_buffers = command_buffers.iter().map(|cb| cb.id().0).collect();
self.channel
.0
.send(WebGPURequest::Submit {
queue_id: self.queue.0,
command_buffers,
})
.send((
scope_id,
WebGPURequest::Submit {
queue_id: self.queue.0,
command_buffers,
},
))
.unwrap();
}
@ -109,12 +126,15 @@ impl GPUQueueMethods for GPUQueue {
let final_data = IpcSharedMemory::from_bytes(
&bytes[data_offset as usize..(data_offset + content_size) as usize],
);
if let Err(e) = self.channel.0.send(WebGPURequest::WriteBuffer {
queue_id: self.queue.0,
buffer_id: buffer.id().0,
buffer_offset,
data: final_data,
}) {
if let Err(e) = self.channel.0.send((
self.device.borrow().as_ref().unwrap().use_current_scope(),
WebGPURequest::WriteBuffer {
queue_id: self.queue.0,
buffer_id: buffer.id().0,
buffer_offset,
data: final_data,
},
)) {
warn!("Failed to send WriteBuffer({:?}) ({})", buffer.id(), e);
return Err(Error::Operation);
}
@ -142,13 +162,16 @@ impl GPUQueueMethods for GPUQueue {
let write_size = convert_texture_size_to_wgt(&convert_texture_size_to_dict(&size));
let final_data = IpcSharedMemory::from_bytes(&bytes);
if let Err(e) = self.channel.0.send(WebGPURequest::WriteTexture {
queue_id: self.queue.0,
texture_cv,
data_layout: texture_layout,
size: write_size,
data: final_data,
}) {
if let Err(e) = self.channel.0.send((
self.device.borrow().as_ref().unwrap().use_current_scope(),
WebGPURequest::WriteTexture {
queue_id: self.queue.0,
texture_cv,
data_layout: texture_layout,
size: write_size,
data: final_data,
},
)) {
warn!(
"Failed to send WriteTexture({:?}) ({})",
destination.texture.id().0,

View file

@ -195,13 +195,15 @@ impl GPURenderBundleEncoderMethods for GPURenderBundleEncoder {
self.channel
.0
.send(WebGPURequest::RenderBundleEncoderFinish {
render_bundle_encoder: encoder,
descriptor: desc,
render_bundle_id,
device_id: self.device.id().0,
scope_id: self.device.use_current_scope(),
})
.send((
self.device.use_current_scope(),
WebGPURequest::RenderBundleEncoderFinish {
render_bundle_encoder: encoder,
descriptor: desc,
render_bundle_id,
device_id: self.device.id().0,
},
))
.expect("Failed to send RenderBundleEncoderFinish");
let render_bundle = WebGPURenderBundle(render_bundle_id);

View file

@ -163,10 +163,14 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder {
if let Some(render_pass) = self.render_pass.borrow_mut().take() {
self.channel
.0
.send(WebGPURequest::RunRenderPass {
command_encoder_id: self.command_encoder.id().0,
render_pass,
})
.send((
self.command_encoder.device().use_current_scope(),
WebGPURequest::RunRenderPass {
command_encoder_id: self.command_encoder.id().0,
device_id: self.command_encoder.device().id().0,
render_pass,
},
))
.expect("Failed to send RunRenderPass");
self.command_encoder.set_state(

View file

@ -57,10 +57,13 @@ impl GPUSwapChain {
impl GPUSwapChain {
pub fn destroy(&self, external_id: u64, image_key: webrender_api::ImageKey) {
if let Err(e) = self.channel.0.send(WebGPURequest::DestroySwapChain {
external_id,
image_key,
}) {
if let Err(e) = self.channel.0.send((
None,
WebGPURequest::DestroySwapChain {
external_id,
image_key,
},
)) {
warn!(
"Failed to send DestroySwapChain-ImageKey({:?}) ({})",
image_key, e

View file

@ -167,13 +167,15 @@ impl GPUTextureMethods for GPUTexture {
self.channel
.0
.send(WebGPURequest::CreateTextureView {
texture_id: self.texture.0,
texture_view_id,
device_id: self.device.id().0,
descriptor: desc,
.send((
scope_id,
})
WebGPURequest::CreateTextureView {
texture_id: self.texture.0,
texture_view_id,
device_id: self.device.id().0,
descriptor: desc,
},
))
.expect("Failed to create WebGPU texture view");
let texture_view = WebGPUTextureView(texture_view_id);
@ -191,7 +193,7 @@ impl GPUTextureMethods for GPUTexture {
if let Err(e) = self
.channel
.0
.send(WebGPURequest::DestroyTexture(self.texture.0))
.send((None, WebGPURequest::DestroyTexture(self.texture.0)))
{
warn!(
"Failed to send WebGPURequest::DestroyTexture({:?}) ({})",

View file

@ -5,8 +5,7 @@
// https://gpuweb.github.io/gpuweb/#gpu-interface
[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
interface GPU {
// May reject with DOMException // TODO: DOMException("OperationError")?
Promise<GPUAdapter> requestAdapter(optional GPURequestAdapterOptions options = {});
Promise<GPUAdapter?> requestAdapter(optional GPURequestAdapterOptions options = {});
};
// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions

View file

@ -9,8 +9,7 @@ interface GPUAdapter {
readonly attribute object extensions;
//readonly attribute GPULimits limits; Dont 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 {

View file

@ -5,8 +5,8 @@
// https://gpuweb.github.io/gpuweb/#gpubuffer
[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
interface GPUBuffer {
Promise<void> mapAsync(GPUMapModeFlags mode, optional GPUSize64 offset = 0, optional GPUSize64 size = 0);
[Throws] ArrayBuffer getMappedRange(optional GPUSize64 offset = 0, optional GPUSize64 size = 0);
Promise<void> mapAsync(GPUMapModeFlags mode, optional GPUSize64 offset = 0, optional GPUSize64 size);
[Throws] ArrayBuffer getMappedRange(optional GPUSize64 offset = 0, optional GPUSize64 size);
void unmap();
void destroy();

View file

@ -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::{WebGPUDevice, WebGPURequest};
use crate::{ErrorScopeId, WebGPUDevice, WebGPURequest};
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId;
use serde::{Deserialize, Serialize};
@ -43,7 +43,7 @@ pub enum WebGPUMsg {
FreeRenderBundle(RenderBundleId),
WebGPUOpResult {
device: WebGPUDevice,
scope_id: Option<u64>,
scope_id: Option<ErrorScopeId>,
pipeline_id: PipelineId,
result: WebGPUOpResult,
},
@ -57,12 +57,12 @@ pub enum WebGPUMsg {
#[derive(Debug)]
pub struct IdentityRecycler {
sender: IpcSender<WebGPUMsg>,
self_sender: IpcSender<WebGPURequest>,
self_sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>,
}
pub struct IdentityRecyclerFactory {
pub sender: IpcSender<WebGPUMsg>,
pub self_sender: IpcSender<WebGPURequest>,
pub self_sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>,
}
macro_rules! impl_identity_handler {
@ -130,12 +130,14 @@ impl IdentityHandler<DeviceId> for IdentityRecycler {
}
fn free(&self, id: DeviceId) {
log::debug!("free device {:?}", id);
let msg = WebGPUMsg::FreeDevice(id);
if self.sender.send(msg).is_err() {
if self.sender.send(WebGPUMsg::FreeDevice(id)).is_err() {
log::error!("Failed to send FreeDevice({:?}) to script", id);
}
let msg_to_self = WebGPURequest::FreeDevice(id);
if self.self_sender.send(msg_to_self).is_err() {
if self
.self_sender
.send((None, WebGPURequest::FreeDevice(id)))
.is_err()
{
log::error!("Failed to send FreeDevice({:?}) to server", id);
}
}

View file

@ -22,6 +22,7 @@ use smallvec::SmallVec;
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::CString;
use std::num::NonZeroU64;
use std::ptr;
use std::rc::Rc;
use std::slice;
@ -41,6 +42,7 @@ use wgpu::{
resource::{BufferMapAsyncStatus, BufferMapOperation},
};
pub type ErrorScopeId = NonZeroU64;
const DEVICE_POLL_INTERVAL: u64 = 100;
pub const PRESENTATION_BUFFER_COUNT: usize = 10;
@ -67,6 +69,7 @@ pub enum WebGPURequest {
BufferMapAsync {
sender: IpcSender<WebGPUResponseResult>,
buffer_id: id::BufferId,
device_id: id::DeviceId,
host_map: HostMap,
map_range: std::ops::Range<u64>,
},
@ -74,12 +77,12 @@ pub enum WebGPURequest {
CommandEncoderFinish {
command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId,
scope_id: Option<u64>,
// TODO(zakorgy): Serialize CommandBufferDescriptor in wgpu-core
// wgpu::command::CommandBufferDescriptor,
},
CopyBufferToBuffer {
command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId,
source_id: id::BufferId,
source_offset: wgt::BufferAddress,
destination_id: id::BufferId,
@ -88,44 +91,42 @@ pub enum WebGPURequest {
},
CopyBufferToTexture {
command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId,
source: BufferCopyView,
destination: TextureCopyView,
copy_size: wgt::Extent3d,
},
CopyTextureToBuffer {
command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId,
source: TextureCopyView,
destination: BufferCopyView,
copy_size: wgt::Extent3d,
},
CopyTextureToTexture {
command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId,
source: TextureCopyView,
destination: TextureCopyView,
copy_size: wgt::Extent3d,
},
CreateBindGroup {
device_id: id::DeviceId,
// TODO: Consider using NonZeroU64 to reduce enum size
scope_id: Option<u64>,
bind_group_id: id::BindGroupId,
descriptor: BindGroupDescriptor<'static>,
},
CreateBindGroupLayout {
device_id: id::DeviceId,
scope_id: Option<u64>,
bind_group_layout_id: id::BindGroupLayoutId,
descriptor: wgt::BindGroupLayoutDescriptor<'static>,
},
CreateBuffer {
device_id: id::DeviceId,
scope_id: Option<u64>,
buffer_id: id::BufferId,
descriptor: wgt::BufferDescriptor<Option<String>>,
},
CreateCommandEncoder {
device_id: id::DeviceId,
scope_id: Option<u64>,
// TODO(zakorgy): Serialize CommandEncoderDescriptor in wgpu-core
// wgpu::command::CommandEncoderDescriptor,
command_encoder_id: id::CommandEncoderId,
@ -133,32 +134,27 @@ pub enum WebGPURequest {
},
CreateComputePipeline {
device_id: id::DeviceId,
scope_id: Option<u64>,
compute_pipeline_id: id::ComputePipelineId,
descriptor: ComputePipelineDescriptor<'static>,
},
CreateContext(IpcSender<webrender_api::ExternalImageId>),
CreatePipelineLayout {
device_id: id::DeviceId,
scope_id: Option<u64>,
pipeline_layout_id: id::PipelineLayoutId,
descriptor: wgt::PipelineLayoutDescriptor<'static, id::BindGroupLayoutId>,
},
CreateRenderPipeline {
device_id: id::DeviceId,
scope_id: Option<u64>,
render_pipeline_id: id::RenderPipelineId,
descriptor: RenderPipelineDescriptor<'static>,
},
CreateSampler {
device_id: id::DeviceId,
scope_id: Option<u64>,
sampler_id: id::SamplerId,
descriptor: wgt::SamplerDescriptor<Option<String>>,
},
CreateShaderModule {
device_id: id::DeviceId,
scope_id: Option<u64>,
program_id: id::ShaderModuleId,
program: Vec<u32>,
},
@ -172,7 +168,6 @@ pub enum WebGPURequest {
},
CreateTexture {
device_id: id::DeviceId,
scope_id: Option<u64>,
texture_id: id::TextureId,
descriptor: wgt::TextureDescriptor<Option<String>>,
},
@ -180,7 +175,6 @@ pub enum WebGPURequest {
texture_id: id::TextureId,
texture_view_id: id::TextureViewId,
device_id: id::DeviceId,
scope_id: Option<u64>,
descriptor: wgt::TextureViewDescriptor<Option<String>>,
},
DestroyBuffer(id::BufferId),
@ -196,7 +190,6 @@ pub enum WebGPURequest {
descriptor: wgt::RenderBundleDescriptor<Option<String>>,
render_bundle_id: id::RenderBundleId,
device_id: id::DeviceId,
scope_id: Option<u64>,
},
RequestAdapter {
sender: IpcSender<WebGPUResponseResult>,
@ -213,10 +206,12 @@ pub enum WebGPURequest {
},
RunComputePass {
command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId,
compute_pass: ComputePass,
},
RunRenderPass {
command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId,
render_pass: RenderPass,
},
Submit {
@ -230,6 +225,7 @@ pub enum WebGPURequest {
},
UnmapBuffer {
buffer_id: id::BufferId,
device_id: id::DeviceId,
array_buffer: IpcSharedMemory,
is_map_read: bool,
offset: u64,
@ -264,7 +260,7 @@ struct BufferMapInfo<'a, T> {
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WebGPU(pub IpcSender<WebGPURequest>);
pub struct WebGPU(pub IpcSender<(Option<ErrorScopeId>, WebGPURequest)>);
impl WebGPU {
pub fn new(
@ -322,14 +318,14 @@ impl WebGPU {
pub fn exit(&self, sender: IpcSender<()>) -> Result<(), &'static str> {
self.0
.send(WebGPURequest::Exit(sender))
.send((None, WebGPURequest::Exit(sender)))
.map_err(|_| "Failed to send Exit message")
}
}
struct WGPU<'a> {
receiver: IpcReceiver<WebGPURequest>,
sender: IpcSender<WebGPURequest>,
receiver: IpcReceiver<(Option<ErrorScopeId>, WebGPURequest)>,
sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>,
script_sender: IpcSender<WebGPUMsg>,
global: wgpu::hub::Global<IdentityRecyclerFactory>,
adapters: Vec<WebGPUAdapter>,
@ -339,7 +335,8 @@ struct WGPU<'a> {
// Buffers with pending mapping
buffer_maps: HashMap<id::BufferId, Rc<BufferMapInfo<'a, WebGPUResponseResult>>>,
// Presentation Buffers with pending mapping
present_buffer_maps: HashMap<id::BufferId, Rc<BufferMapInfo<'a, WebGPURequest>>>,
present_buffer_maps:
HashMap<id::BufferId, Rc<BufferMapInfo<'a, (Option<ErrorScopeId>, WebGPURequest)>>>,
webrender_api: webrender_api::RenderApi,
webrender_document: webrender_api::DocumentId,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
@ -349,8 +346,8 @@ struct WGPU<'a> {
impl<'a> WGPU<'a> {
fn new(
receiver: IpcReceiver<WebGPURequest>,
sender: IpcSender<WebGPURequest>,
receiver: IpcReceiver<(Option<ErrorScopeId>, WebGPURequest)>,
sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>,
script_sender: IpcSender<WebGPUMsg>,
webrender_api_sender: webrender_api::RenderApiSender,
webrender_document: webrender_api::DocumentId,
@ -385,17 +382,18 @@ impl<'a> WGPU<'a> {
let _ = self.global.poll_all_devices(false);
self.last_poll = Instant::now();
}
if let Ok(msg) = self.receiver.try_recv() {
if let Ok((scope_id, msg)) = self.receiver.try_recv() {
match msg {
WebGPURequest::BufferMapAsync {
sender,
buffer_id,
device_id,
host_map,
map_range,
} => {
let map_info = BufferMapInfo {
buffer_id,
sender,
sender: sender.clone(),
global: &self.global,
size: (map_range.end - map_range.start) as usize,
external_id: None,
@ -409,22 +407,24 @@ impl<'a> WGPU<'a> {
let info = Rc::from_raw(
userdata as *const BufferMapInfo<WebGPUResponseResult>,
);
match status {
let msg = match status {
BufferMapAsyncStatus::Success => {
let global = &info.global;
let data_pt = gfx_select!(info.buffer_id =>
global.buffer_get_mapped_range(info.buffer_id, 0, None))
.unwrap();
let data = slice::from_raw_parts(data_pt, info.size);
if let Err(e) =
info.sender.send(Ok(WebGPUResponse::BufferMapAsync(
IpcSharedMemory::from_bytes(data),
)))
{
warn!("Could not send BufferMapAsync Response ({})", e);
}
Ok(WebGPUResponse::BufferMapAsync(IpcSharedMemory::from_bytes(
data,
)))
},
_ => error!("Could not map buffer({:?})", info.buffer_id),
_ => {
warn!("Could not map buffer({:?})", info.buffer_id);
Err(String::from("Failed to map Buffer"))
},
};
if let Err(e) = info.sender.send(msg) {
warn!("Could not send BufferMapAsync Response ({})", e);
}
}
@ -436,7 +436,13 @@ impl<'a> WGPU<'a> {
),
};
let global = &self.global;
let _ = gfx_select!(buffer_id => global.buffer_map_async(buffer_id, map_range, operation));
let result = gfx_select!(buffer_id => global.buffer_map_async(buffer_id, map_range, operation));
if let Err(ref e) = result {
if let Err(w) = sender.send(Err(format!("{:?}", e))) {
warn!("Failed to send BufferMapAsync Response ({:?})", w);
}
}
self.send_result(device_id, scope_id, result);
},
WebGPURequest::BufferMapComplete(buffer_id) => {
self.buffer_maps.remove(&buffer_id);
@ -444,7 +450,6 @@ impl<'a> WGPU<'a> {
WebGPURequest::CommandEncoderFinish {
command_encoder_id,
device_id,
scope_id,
} => {
let global = &self.global;
let result = gfx_select!(command_encoder_id => global.command_encoder_finish(
@ -455,6 +460,7 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CopyBufferToBuffer {
command_encoder_id,
device_id,
source_id,
source_offset,
destination_id,
@ -462,7 +468,7 @@ impl<'a> WGPU<'a> {
size,
} => {
let global = &self.global;
let _ = gfx_select!(command_encoder_id => global.command_encoder_copy_buffer_to_buffer(
let result = gfx_select!(command_encoder_id => global.command_encoder_copy_buffer_to_buffer(
command_encoder_id,
source_id,
source_offset,
@ -470,52 +476,58 @@ impl<'a> WGPU<'a> {
destination_offset,
size
));
self.send_result(device_id, scope_id, result);
},
WebGPURequest::CopyBufferToTexture {
command_encoder_id,
device_id,
source,
destination,
copy_size,
} => {
let global = &self.global;
let _ = gfx_select!(command_encoder_id => global.command_encoder_copy_buffer_to_texture(
let result = gfx_select!(command_encoder_id => global.command_encoder_copy_buffer_to_texture(
command_encoder_id,
&source,
&destination,
&copy_size
));
self.send_result(device_id, scope_id, result);
},
WebGPURequest::CopyTextureToBuffer {
command_encoder_id,
device_id,
source,
destination,
copy_size,
} => {
let global = &self.global;
let _ = gfx_select!(command_encoder_id => global.command_encoder_copy_texture_to_buffer(
let result = gfx_select!(command_encoder_id => global.command_encoder_copy_texture_to_buffer(
command_encoder_id,
&source,
&destination,
&copy_size
));
self.send_result(device_id, scope_id, result);
},
WebGPURequest::CopyTextureToTexture {
command_encoder_id,
device_id,
source,
destination,
copy_size,
} => {
let global = &self.global;
let _ = gfx_select!(command_encoder_id => global.command_encoder_copy_texture_to_texture(
let result = gfx_select!(command_encoder_id => global.command_encoder_copy_texture_to_texture(
command_encoder_id,
&source,
&destination,
&copy_size
));
self.send_result(device_id, scope_id, result);
},
WebGPURequest::CreateBindGroup {
device_id,
scope_id,
bind_group_id,
descriptor,
} => {
@ -526,7 +538,6 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreateBindGroupLayout {
device_id,
scope_id,
bind_group_layout_id,
descriptor,
} => {
@ -537,7 +548,6 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreateBuffer {
device_id,
scope_id,
buffer_id,
descriptor,
} => {
@ -556,7 +566,6 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreateCommandEncoder {
device_id,
scope_id,
command_encoder_id,
label,
} => {
@ -576,7 +585,6 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreateComputePipeline {
device_id,
scope_id,
compute_pipeline_id,
descriptor,
} => {
@ -597,7 +605,6 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreatePipelineLayout {
device_id,
scope_id,
pipeline_layout_id,
descriptor,
} => {
@ -609,7 +616,6 @@ impl<'a> WGPU<'a> {
//TODO: consider https://github.com/gfx-rs/wgpu/issues/684
WebGPURequest::CreateRenderPipeline {
device_id,
scope_id,
render_pipeline_id,
descriptor,
} => {
@ -620,7 +626,6 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreateSampler {
device_id,
scope_id,
sampler_id,
descriptor,
} => {
@ -642,7 +647,6 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreateShaderModule {
device_id,
scope_id,
program_id,
program,
} => {
@ -697,7 +701,6 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreateTexture {
device_id,
scope_id,
texture_id,
descriptor,
} => {
@ -721,7 +724,6 @@ impl<'a> WGPU<'a> {
texture_id,
texture_view_id,
device_id,
scope_id,
descriptor,
} => {
let global = &self.global;
@ -799,7 +801,6 @@ impl<'a> WGPU<'a> {
descriptor,
render_bundle_id,
device_id,
scope_id,
} => {
let global = &self.global;
let st;
@ -863,14 +864,23 @@ impl<'a> WGPU<'a> {
label,
} => {
let global = &self.global;
let result = gfx_select!(device_id => global.adapter_request_device(
let id = match gfx_select!(device_id => global.adapter_request_device(
adapter_id.0,
&descriptor,
None,
device_id
));
// TODO: Handle error gracefully acc. to spec.
let id = result.unwrap();
)) {
Ok(id) => id,
Err(e) => {
if let Err(w) = sender.send(Err(format!("{:?}", e))) {
warn!(
"Failed to send response to WebGPURequest::RequestDevice ({})",
w
)
}
return;
},
};
let device = WebGPUDevice(id);
// Note: (zakorgy) Note sure if sending the queue is needed at all,
// since wgpu-core uses the same id for the device and the queue
@ -890,30 +900,35 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::RunComputePass {
command_encoder_id,
device_id,
compute_pass,
} => {
let global = &self.global;
let _ = gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass(
let result = gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass(
command_encoder_id,
&compute_pass
));
self.send_result(device_id, scope_id, result);
},
WebGPURequest::RunRenderPass {
command_encoder_id,
device_id,
render_pass,
} => {
let global = &self.global;
let _ = gfx_select!(command_encoder_id => global.command_encoder_run_render_pass(
let result = gfx_select!(command_encoder_id => global.command_encoder_run_render_pass(
command_encoder_id,
&render_pass
));
self.send_result(device_id, scope_id, result);
},
WebGPURequest::Submit {
queue_id,
command_buffers,
} => {
let global = &self.global;
let _ = gfx_select!(queue_id => global.queue_submit(queue_id, &command_buffers));
let result = gfx_select!(queue_id => global.queue_submit(queue_id, &command_buffers));
self.send_result(queue_id, scope_id, result);
},
WebGPURequest::SwapChainPresent {
external_id,
@ -1052,6 +1067,7 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::UnmapBuffer {
buffer_id,
device_id,
array_buffer,
is_map_read,
offset,
@ -1068,7 +1084,8 @@ impl<'a> WGPU<'a> {
unsafe { slice::from_raw_parts_mut(map_ptr, size as usize) }
.copy_from_slice(&array_buffer);
}
let _ = gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
let result = gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
self.send_result(device_id, scope_id, result);
},
WebGPURequest::UpdateWebRenderData {
buffer_id,
@ -1111,12 +1128,13 @@ impl<'a> WGPU<'a> {
} => {
let global = &self.global;
//TODO: Report result to content process
let _ = gfx_select!(queue_id => global.queue_write_buffer(
let result = gfx_select!(queue_id => global.queue_write_buffer(
queue_id,
buffer_id,
buffer_offset as wgt::BufferAddress,
&data
));
self.send_result(queue_id, scope_id, result);
},
WebGPURequest::WriteTexture {
queue_id,
@ -1127,23 +1145,24 @@ impl<'a> WGPU<'a> {
} => {
let global = &self.global;
//TODO: Report result to content process
let _ = gfx_select!(queue_id => global.queue_write_texture(
let result = gfx_select!(queue_id => global.queue_write_texture(
queue_id,
&texture_cv,
&data,
&data_layout,
&size
));
self.send_result(queue_id, scope_id, result);
},
}
}
}
}
fn send_result<U: id::TypedId, T: std::fmt::Debug>(
fn send_result<U, T: std::fmt::Debug>(
&self,
device_id: id::DeviceId,
scope_id: Option<u64>,
scope_id: Option<ErrorScopeId>,
result: Result<U, T>,
) {
let &pipeline_id = self.devices.get(&WebGPUDevice(device_id)).unwrap();