Record errors in GPUCommandEncoder.BeginPass() and EncoderPass.endPass()

This commit is contained in:
Kunal Mohan 2020-08-07 22:36:05 +05:30
parent 78c9466fdb
commit 1d80f57aab
4 changed files with 230 additions and 168 deletions

View file

@ -125,14 +125,32 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
&self, &self,
descriptor: &GPUComputePassDescriptor, descriptor: &GPUComputePassDescriptor,
) -> DomRoot<GPUComputePassEncoder> { ) -> DomRoot<GPUComputePassEncoder> {
let scope_id = self.device.use_current_scope();
self.set_state( self.set_state(
GPUCommandEncoderState::EncodingComputePass, GPUCommandEncoderState::EncodingComputePass,
GPUCommandEncoderState::Open, GPUCommandEncoderState::Open,
); );
let (compute_pass, res) = if !self.valid.get() {
(
None,
WebGPUOpResult::ValidationError(String::from(
"CommandEncoder is not in Open State",
)),
)
} else {
(
Some(wgpu_com::ComputePass::new(self.encoder.0)),
WebGPUOpResult::Success,
)
};
self.device.handle_server_msg(scope_id, res);
GPUComputePassEncoder::new( GPUComputePassEncoder::new(
&self.global(), &self.global(),
self.channel.clone(), self.channel.clone(),
&self, &self,
compute_pass,
descriptor.parent.label.as_ref().cloned(), descriptor.parent.label.as_ref().cloned(),
) )
} }
@ -142,11 +160,20 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
&self, &self,
descriptor: &GPURenderPassDescriptor, descriptor: &GPURenderPassDescriptor,
) -> DomRoot<GPURenderPassEncoder> { ) -> DomRoot<GPURenderPassEncoder> {
let scope_id = self.device.use_current_scope();
self.set_state( self.set_state(
GPUCommandEncoderState::EncodingRenderPass, GPUCommandEncoderState::EncodingRenderPass,
GPUCommandEncoderState::Open, GPUCommandEncoderState::Open,
); );
let (render_pass, res) = if !self.valid.get() {
(
None,
WebGPUOpResult::ValidationError(String::from(
"CommandEncoder is not in Open State",
)),
)
} else {
let depth_stencil = descriptor.depthStencilAttachment.as_ref().map(|depth| { let depth_stencil = descriptor.depthStencilAttachment.as_ref().map(|depth| {
let (depth_load_op, clear_depth) = match depth.depthLoadValue { let (depth_load_op, clear_depth) = match depth.depthLoadValue {
GPULoadOpOrFloat::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0.0f32), GPULoadOpOrFloat::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0.0f32),
@ -154,7 +181,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
}; };
let (stencil_load_op, clear_stencil) = match depth.stencilLoadValue { let (stencil_load_op, clear_stencil) = match depth.stencilLoadValue {
GPUStencilLoadValue::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0u32), GPUStencilLoadValue::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0u32),
GPUStencilLoadValue::RangeEnforcedUnsignedLong(l) => (wgpu_com::LoadOp::Clear, l), GPUStencilLoadValue::RangeEnforcedUnsignedLong(l) => {
(wgpu_com::LoadOp::Clear, l)
},
}; };
let depth_channel = wgpu_com::PassChannel { let depth_channel = wgpu_com::PassChannel {
load_op: depth_load_op, load_op: depth_load_op,
@ -236,8 +265,13 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
), ),
depth_stencil_attachment: depth_stencil.as_ref(), depth_stencil_attachment: depth_stencil.as_ref(),
}; };
(
Some(wgpu_com::RenderPass::new(self.encoder.0, desc)),
WebGPUOpResult::Success,
)
};
let render_pass = wgpu_com::RenderPass::new(self.encoder.0, desc); self.device.handle_server_msg(scope_id, res);
GPURenderPassEncoder::new( GPURenderPassEncoder::new(
&self.global(), &self.global(),
@ -257,10 +291,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
destination_offset: GPUSize64, destination_offset: GPUSize64,
size: GPUSize64, size: GPUSize64,
) { ) {
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
let scope_id = self.device.use_current_scope(); let scope_id = self.device.use_current_scope();
if !valid { if !(*self.state.borrow() == GPUCommandEncoderState::Open) {
self.device.handle_server_msg( self.device.handle_server_msg(
scope_id, scope_id,
WebGPUOpResult::ValidationError(String::from( WebGPUOpResult::ValidationError(String::from(
@ -299,10 +332,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
destination: &GPUTextureCopyView, destination: &GPUTextureCopyView,
copy_size: GPUExtent3D, copy_size: GPUExtent3D,
) { ) {
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
let scope_id = self.device.use_current_scope(); let scope_id = self.device.use_current_scope();
if !valid { if !(*self.state.borrow() == GPUCommandEncoderState::Open) {
self.device.handle_server_msg( self.device.handle_server_msg(
scope_id, scope_id,
WebGPUOpResult::ValidationError(String::from( WebGPUOpResult::ValidationError(String::from(
@ -341,10 +373,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
destination: &GPUBufferCopyView, destination: &GPUBufferCopyView,
copy_size: GPUExtent3D, copy_size: GPUExtent3D,
) { ) {
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
let scope_id = self.device.use_current_scope(); let scope_id = self.device.use_current_scope();
if !valid { if !(*self.state.borrow() == GPUCommandEncoderState::Open) {
self.device.handle_server_msg( self.device.handle_server_msg(
scope_id, scope_id,
WebGPUOpResult::ValidationError(String::from( WebGPUOpResult::ValidationError(String::from(
@ -383,10 +414,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
destination: &GPUTextureCopyView, destination: &GPUTextureCopyView,
copy_size: GPUExtent3D, copy_size: GPUExtent3D,
) { ) {
let valid = *self.state.borrow() == GPUCommandEncoderState::Open;
let scope_id = self.device.use_current_scope(); let scope_id = self.device.use_current_scope();
if !valid { if !(*self.state.borrow() == GPUCommandEncoderState::Open) {
self.device.handle_server_msg( self.device.handle_server_msg(
scope_id, scope_id,
WebGPUOpResult::ValidationError(String::from( WebGPUOpResult::ValidationError(String::from(
@ -423,6 +453,7 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
WebGPURequest::CommandEncoderFinish { WebGPURequest::CommandEncoderFinish {
command_encoder_id: self.encoder.0, command_encoder_id: self.encoder.0,
device_id: self.device.id().0, device_id: self.device.id().0,
is_error: !self.valid.get(),
// TODO(zakorgy): We should use `_descriptor` here after it's not empty // TODO(zakorgy): We should use `_descriptor` here after it's not empty
// and the underlying wgpu-core struct is serializable // and the underlying wgpu-core struct is serializable
}, },

View file

@ -33,13 +33,14 @@ impl GPUComputePassEncoder {
fn new_inherited( fn new_inherited(
channel: WebGPU, channel: WebGPU,
parent: &GPUCommandEncoder, parent: &GPUCommandEncoder,
compute_pass: Option<ComputePass>,
label: Option<USVString>, label: Option<USVString>,
) -> Self { ) -> Self {
Self { Self {
channel, channel,
reflector_: Reflector::new(), reflector_: Reflector::new(),
label: DomRefCell::new(label), label: DomRefCell::new(label),
compute_pass: DomRefCell::new(Some(ComputePass::new(parent.id().0))), compute_pass: DomRefCell::new(compute_pass),
command_encoder: Dom::from_ref(parent), command_encoder: Dom::from_ref(parent),
} }
} }
@ -48,10 +49,16 @@ impl GPUComputePassEncoder {
global: &GlobalScope, global: &GlobalScope,
channel: WebGPU, channel: WebGPU,
parent: &GPUCommandEncoder, parent: &GPUCommandEncoder,
compute_pass: Option<ComputePass>,
label: Option<USVString>, label: Option<USVString>,
) -> DomRoot<Self> { ) -> DomRoot<Self> {
reflect_dom_object( reflect_dom_object(
Box::new(GPUComputePassEncoder::new_inherited(channel, parent, label)), Box::new(GPUComputePassEncoder::new_inherited(
channel,
parent,
compute_pass,
label,
)),
global, global,
) )
} }
@ -88,7 +95,7 @@ impl GPUComputePassEncoderMethods for GPUComputePassEncoder {
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass /// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass
fn EndPass(&self) { fn EndPass(&self) {
if let Some(compute_pass) = self.compute_pass.borrow_mut().take() { let compute_pass = self.compute_pass.borrow_mut().take();
self.channel self.channel
.0 .0
.send(( .send((
@ -106,7 +113,6 @@ impl GPUComputePassEncoderMethods for GPUComputePassEncoder {
GPUCommandEncoderState::EncodingComputePass, GPUCommandEncoderState::EncodingComputePass,
); );
} }
}
/// https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup /// https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup
#[allow(unsafe_code)] #[allow(unsafe_code)]

View file

@ -35,7 +35,7 @@ pub struct GPURenderPassEncoder {
impl GPURenderPassEncoder { impl GPURenderPassEncoder {
fn new_inherited( fn new_inherited(
channel: WebGPU, channel: WebGPU,
render_pass: RenderPass, render_pass: Option<RenderPass>,
parent: &GPUCommandEncoder, parent: &GPUCommandEncoder,
label: Option<USVString>, label: Option<USVString>,
) -> Self { ) -> Self {
@ -43,7 +43,7 @@ impl GPURenderPassEncoder {
channel, channel,
reflector_: Reflector::new(), reflector_: Reflector::new(),
label: DomRefCell::new(label), label: DomRefCell::new(label),
render_pass: DomRefCell::new(Some(render_pass)), render_pass: DomRefCell::new(render_pass),
command_encoder: Dom::from_ref(parent), command_encoder: Dom::from_ref(parent),
} }
} }
@ -51,7 +51,7 @@ impl GPURenderPassEncoder {
pub fn new( pub fn new(
global: &GlobalScope, global: &GlobalScope,
channel: WebGPU, channel: WebGPU,
render_pass: RenderPass, render_pass: Option<RenderPass>,
parent: &GPUCommandEncoder, parent: &GPUCommandEncoder,
label: Option<USVString>, label: Option<USVString>,
) -> DomRoot<Self> { ) -> DomRoot<Self> {
@ -126,6 +126,7 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder {
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setblendcolor /// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setblendcolor
fn SetBlendColor(&self, color: GPUColor) { fn SetBlendColor(&self, color: GPUColor) {
if let Some(render_pass) = self.render_pass.borrow_mut().as_mut() {
let colors = match color { let colors = match color {
GPUColor::GPUColorDict(d) => wgt::Color { GPUColor::GPUColorDict(d) => wgt::Color {
r: *d.r, r: *d.r,
@ -146,7 +147,6 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder {
} }
}, },
}; };
if let Some(render_pass) = self.render_pass.borrow_mut().as_mut() {
wgpu_render::wgpu_render_pass_set_blend_color(render_pass, &colors); wgpu_render::wgpu_render_pass_set_blend_color(render_pass, &colors);
} }
} }
@ -160,7 +160,7 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder {
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass /// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass
fn EndPass(&self) { fn EndPass(&self) {
if let Some(render_pass) = self.render_pass.borrow_mut().take() { let render_pass = self.render_pass.borrow_mut().take();
self.channel self.channel
.0 .0
.send(( .send((
@ -178,7 +178,6 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder {
GPUCommandEncoderState::EncodingRenderPass, GPUCommandEncoderState::EncodingRenderPass,
); );
} }
}
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setpipeline /// https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setpipeline
fn SetPipeline(&self, pipeline: &GPURenderPipeline) { fn SetPipeline(&self, pipeline: &GPURenderPipeline) {

View file

@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize};
use servo_config::pref; use servo_config::pref;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::ffi::CString; use std::ffi::CString;
use std::num::NonZeroU64; use std::num::NonZeroU64;
use std::ptr; use std::ptr;
@ -77,6 +77,7 @@ pub enum WebGPURequest {
CommandEncoderFinish { CommandEncoderFinish {
command_encoder_id: id::CommandEncoderId, command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId, device_id: id::DeviceId,
is_error: bool,
// TODO(zakorgy): Serialize CommandBufferDescriptor in wgpu-core // TODO(zakorgy): Serialize CommandBufferDescriptor in wgpu-core
// wgpu::command::CommandBufferDescriptor, // wgpu::command::CommandBufferDescriptor,
}, },
@ -207,12 +208,12 @@ pub enum WebGPURequest {
RunComputePass { RunComputePass {
command_encoder_id: id::CommandEncoderId, command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId, device_id: id::DeviceId,
compute_pass: ComputePass, compute_pass: Option<ComputePass>,
}, },
RunRenderPass { RunRenderPass {
command_encoder_id: id::CommandEncoderId, command_encoder_id: id::CommandEncoderId,
device_id: id::DeviceId, device_id: id::DeviceId,
render_pass: RenderPass, render_pass: Option<RenderPass>,
}, },
Submit { Submit {
queue_id: id::QueueId, queue_id: id::QueueId,
@ -337,6 +338,8 @@ struct WGPU<'a> {
// Presentation Buffers with pending mapping // Presentation Buffers with pending mapping
present_buffer_maps: present_buffer_maps:
HashMap<id::BufferId, Rc<BufferMapInfo<'a, (Option<ErrorScopeId>, WebGPURequest)>>>, HashMap<id::BufferId, Rc<BufferMapInfo<'a, (Option<ErrorScopeId>, WebGPURequest)>>>,
//TODO: Remove this (https://github.com/gfx-rs/wgpu/issues/867)
error_command_buffers: HashSet<id::CommandBufferId>,
webrender_api: webrender_api::RenderApi, webrender_api: webrender_api::RenderApi,
webrender_document: webrender_api::DocumentId, webrender_document: webrender_api::DocumentId,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
@ -368,6 +371,7 @@ impl<'a> WGPU<'a> {
_invalid_adapters: Vec::new(), _invalid_adapters: Vec::new(),
buffer_maps: HashMap::new(), buffer_maps: HashMap::new(),
present_buffer_maps: HashMap::new(), present_buffer_maps: HashMap::new(),
error_command_buffers: HashSet::new(),
webrender_api: webrender_api_sender.create_api(), webrender_api: webrender_api_sender.create_api(),
webrender_document, webrender_document,
external_images, external_images,
@ -450,14 +454,20 @@ impl<'a> WGPU<'a> {
WebGPURequest::CommandEncoderFinish { WebGPURequest::CommandEncoderFinish {
command_encoder_id, command_encoder_id,
device_id, device_id,
is_error,
} => { } => {
let global = &self.global; let global = &self.global;
let result = gfx_select!(command_encoder_id => global.command_encoder_finish( let result = if is_error {
Err(String::from("Invalid GPUCommandEncoder"))
} else {
gfx_select!(command_encoder_id => global.command_encoder_finish(
command_encoder_id, command_encoder_id,
&wgt::CommandBufferDescriptor::default() &wgt::CommandBufferDescriptor::default()
)); ))
.map_err(|e| format!("{:?}", e))
};
if result.is_err() { if result.is_err() {
let _ = gfx_select!(command_encoder_id => global.command_buffer_error(command_encoder_id)); self.error_command_buffers.insert(command_encoder_id);
} }
self.send_result(device_id, scope_id, result); self.send_result(device_id, scope_id, result);
}, },
@ -967,10 +977,14 @@ impl<'a> WGPU<'a> {
compute_pass, compute_pass,
} => { } => {
let global = &self.global; let global = &self.global;
let result = gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass( let result = if let Some(pass) = compute_pass {
gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass(
command_encoder_id, command_encoder_id,
&compute_pass &pass
)); )).map_err(|e| format!("{:?}", e))
} else {
Err(String::from("Invalid ComputePass"))
};
self.send_result(device_id, scope_id, result); self.send_result(device_id, scope_id, result);
}, },
WebGPURequest::RunRenderPass { WebGPURequest::RunRenderPass {
@ -979,10 +993,14 @@ impl<'a> WGPU<'a> {
render_pass, render_pass,
} => { } => {
let global = &self.global; let global = &self.global;
let result = gfx_select!(command_encoder_id => global.command_encoder_run_render_pass( let result = if let Some(pass) = render_pass {
gfx_select!(command_encoder_id => global.command_encoder_run_render_pass(
command_encoder_id, command_encoder_id,
&render_pass &pass
)); )).map_err(|e| format!("{:?}", e))
} else {
Err(String::from("Invalid RenderPass"))
};
self.send_result(device_id, scope_id, result); self.send_result(device_id, scope_id, result);
}, },
WebGPURequest::Submit { WebGPURequest::Submit {
@ -990,7 +1008,15 @@ impl<'a> WGPU<'a> {
command_buffers, command_buffers,
} => { } => {
let global = &self.global; let global = &self.global;
let result = gfx_select!(queue_id => global.queue_submit(queue_id, &command_buffers)); let cmd_id = command_buffers
.iter()
.find(|id| self.error_command_buffers.contains(id));
let result = if cmd_id.is_some() {
Err(String::from("Invalid command buffer submitted"))
} else {
gfx_select!(queue_id => global.queue_submit(queue_id, &command_buffers))
.map_err(|e| format!("{:?}", e))
};
self.send_result(queue_id, scope_id, result); self.send_result(queue_id, scope_id, result);
}, },
WebGPURequest::SwapChainPresent { WebGPURequest::SwapChainPresent {