diff options
author | Kunal Mohan <kunalmohan99@gmail.com> | 2020-08-07 22:36:05 +0530 |
---|---|---|
committer | Kunal Mohan <kunalmohan99@gmail.com> | 2020-08-07 22:36:05 +0530 |
commit | 1d80f57aab0a11e6138b360391900666303244f3 (patch) | |
tree | 1a38c380c6995a44d673d97b906b06e3e3b3dcc0 | |
parent | 78c9466fdb98435dc4829b3c2e0a0a3a85b79b5f (diff) | |
download | servo-1d80f57aab0a11e6138b360391900666303244f3.tar.gz servo-1d80f57aab0a11e6138b360391900666303244f3.zip |
Record errors in GPUCommandEncoder.BeginPass() and EncoderPass.endPass()
-rw-r--r-- | components/script/dom/gpucommandencoder.rs | 217 | ||||
-rw-r--r-- | components/script/dom/gpucomputepassencoder.rs | 44 | ||||
-rw-r--r-- | components/script/dom/gpurenderpassencoder.rs | 79 | ||||
-rw-r--r-- | components/webgpu/lib.rs | 60 |
4 files changed, 231 insertions, 169 deletions
diff --git a/components/script/dom/gpucommandencoder.rs b/components/script/dom/gpucommandencoder.rs index 9fabd77a6fa..7d0a4153289 100644 --- a/components/script/dom/gpucommandencoder.rs +++ b/components/script/dom/gpucommandencoder.rs @@ -125,14 +125,32 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { &self, descriptor: &GPUComputePassDescriptor, ) -> DomRoot<GPUComputePassEncoder> { + let scope_id = self.device.use_current_scope(); self.set_state( GPUCommandEncoderState::EncodingComputePass, 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( &self.global(), self.channel.clone(), &self, + compute_pass, descriptor.parent.label.as_ref().cloned(), ) } @@ -142,102 +160,118 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { &self, descriptor: &GPURenderPassDescriptor, ) -> DomRoot<GPURenderPassEncoder> { + let scope_id = self.device.use_current_scope(); self.set_state( GPUCommandEncoderState::EncodingRenderPass, GPUCommandEncoderState::Open, ); - let depth_stencil = descriptor.depthStencilAttachment.as_ref().map(|depth| { - let (depth_load_op, clear_depth) = match depth.depthLoadValue { - GPULoadOpOrFloat::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0.0f32), - GPULoadOpOrFloat::Float(f) => (wgpu_com::LoadOp::Clear, *f), - }; - let (stencil_load_op, clear_stencil) = match depth.stencilLoadValue { - GPUStencilLoadValue::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0u32), - GPUStencilLoadValue::RangeEnforcedUnsignedLong(l) => (wgpu_com::LoadOp::Clear, l), - }; - let depth_channel = wgpu_com::PassChannel { - load_op: depth_load_op, - store_op: match depth.depthStoreOp { - GPUStoreOp::Store => wgpu_com::StoreOp::Store, - GPUStoreOp::Clear => wgpu_com::StoreOp::Clear, - }, - clear_value: clear_depth, - read_only: depth.depthReadOnly, - }; - let stencil_channel = wgpu_com::PassChannel { - load_op: stencil_load_op, - store_op: match depth.stencilStoreOp { - GPUStoreOp::Store => wgpu_com::StoreOp::Store, - GPUStoreOp::Clear => wgpu_com::StoreOp::Clear, - }, - clear_value: clear_stencil, - read_only: depth.stencilReadOnly, - }; - wgpu_com::DepthStencilAttachmentDescriptor { - attachment: depth.attachment.id().0, - depth: depth_channel, - stencil: stencil_channel, - } - }); - - let desc = wgpu_com::RenderPassDescriptor { - color_attachments: Cow::Owned( - descriptor - .colorAttachments - .iter() - .map(|color| { - let (load_op, clear_value) = match color.loadValue { - GPUColorLoad::GPULoadOp(_) => { - (wgpu_com::LoadOp::Load, wgt::Color::TRANSPARENT) - }, - GPUColorLoad::DoubleSequence(ref s) => { - let mut w = s.clone(); - if w.len() < 3 { - w.resize(3, Finite::wrap(0.0f64)); - } - w.resize(4, Finite::wrap(1.0f64)); - ( + 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_load_op, clear_depth) = match depth.depthLoadValue { + GPULoadOpOrFloat::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0.0f32), + GPULoadOpOrFloat::Float(f) => (wgpu_com::LoadOp::Clear, *f), + }; + let (stencil_load_op, clear_stencil) = match depth.stencilLoadValue { + GPUStencilLoadValue::GPULoadOp(_) => (wgpu_com::LoadOp::Load, 0u32), + GPUStencilLoadValue::RangeEnforcedUnsignedLong(l) => { + (wgpu_com::LoadOp::Clear, l) + }, + }; + let depth_channel = wgpu_com::PassChannel { + load_op: depth_load_op, + store_op: match depth.depthStoreOp { + GPUStoreOp::Store => wgpu_com::StoreOp::Store, + GPUStoreOp::Clear => wgpu_com::StoreOp::Clear, + }, + clear_value: clear_depth, + read_only: depth.depthReadOnly, + }; + let stencil_channel = wgpu_com::PassChannel { + load_op: stencil_load_op, + store_op: match depth.stencilStoreOp { + GPUStoreOp::Store => wgpu_com::StoreOp::Store, + GPUStoreOp::Clear => wgpu_com::StoreOp::Clear, + }, + clear_value: clear_stencil, + read_only: depth.stencilReadOnly, + }; + wgpu_com::DepthStencilAttachmentDescriptor { + attachment: depth.attachment.id().0, + depth: depth_channel, + stencil: stencil_channel, + } + }); + + let desc = wgpu_com::RenderPassDescriptor { + color_attachments: Cow::Owned( + descriptor + .colorAttachments + .iter() + .map(|color| { + let (load_op, clear_value) = match color.loadValue { + GPUColorLoad::GPULoadOp(_) => { + (wgpu_com::LoadOp::Load, wgt::Color::TRANSPARENT) + }, + GPUColorLoad::DoubleSequence(ref s) => { + let mut w = s.clone(); + if w.len() < 3 { + w.resize(3, Finite::wrap(0.0f64)); + } + w.resize(4, Finite::wrap(1.0f64)); + ( + wgpu_com::LoadOp::Clear, + wgt::Color { + r: *w[0], + g: *w[1], + b: *w[2], + a: *w[3], + }, + ) + }, + GPUColorLoad::GPUColorDict(ref d) => ( wgpu_com::LoadOp::Clear, wgt::Color { - r: *w[0], - g: *w[1], - b: *w[2], - a: *w[3], + r: *d.r, + g: *d.g, + b: *d.b, + a: *d.a, }, - ) - }, - GPUColorLoad::GPUColorDict(ref d) => ( - wgpu_com::LoadOp::Clear, - wgt::Color { - r: *d.r, - g: *d.g, - b: *d.b, - a: *d.a, + ), + }; + let channel = wgpu_com::PassChannel { + load_op, + store_op: match color.storeOp { + GPUStoreOp::Store => wgpu_com::StoreOp::Store, + GPUStoreOp::Clear => wgpu_com::StoreOp::Clear, }, - ), - }; - let channel = wgpu_com::PassChannel { - load_op, - store_op: match color.storeOp { - GPUStoreOp::Store => wgpu_com::StoreOp::Store, - GPUStoreOp::Clear => wgpu_com::StoreOp::Clear, - }, - clear_value, - read_only: false, - }; - wgpu_com::ColorAttachmentDescriptor { - attachment: color.attachment.id().0, - resolve_target: color.resolveTarget.as_ref().map(|t| t.id().0), - channel, - } - }) - .collect::<Vec<_>>(), - ), - depth_stencil_attachment: depth_stencil.as_ref(), + clear_value, + read_only: false, + }; + wgpu_com::ColorAttachmentDescriptor { + attachment: color.attachment.id().0, + resolve_target: color.resolveTarget.as_ref().map(|t| t.id().0), + channel, + } + }) + .collect::<Vec<_>>(), + ), + 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( &self.global(), @@ -257,10 +291,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { destination_offset: GPUSize64, size: GPUSize64, ) { - let valid = *self.state.borrow() == GPUCommandEncoderState::Open; let scope_id = self.device.use_current_scope(); - if !valid { + if !(*self.state.borrow() == GPUCommandEncoderState::Open) { self.device.handle_server_msg( scope_id, WebGPUOpResult::ValidationError(String::from( @@ -299,10 +332,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { destination: &GPUTextureCopyView, copy_size: GPUExtent3D, ) { - let valid = *self.state.borrow() == GPUCommandEncoderState::Open; let scope_id = self.device.use_current_scope(); - if !valid { + if !(*self.state.borrow() == GPUCommandEncoderState::Open) { self.device.handle_server_msg( scope_id, WebGPUOpResult::ValidationError(String::from( @@ -341,10 +373,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { destination: &GPUBufferCopyView, copy_size: GPUExtent3D, ) { - let valid = *self.state.borrow() == GPUCommandEncoderState::Open; let scope_id = self.device.use_current_scope(); - if !valid { + if !(*self.state.borrow() == GPUCommandEncoderState::Open) { self.device.handle_server_msg( scope_id, WebGPUOpResult::ValidationError(String::from( @@ -383,10 +414,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { destination: &GPUTextureCopyView, copy_size: GPUExtent3D, ) { - let valid = *self.state.borrow() == GPUCommandEncoderState::Open; let scope_id = self.device.use_current_scope(); - if !valid { + if !(*self.state.borrow() == GPUCommandEncoderState::Open) { self.device.handle_server_msg( scope_id, WebGPUOpResult::ValidationError(String::from( @@ -423,6 +453,7 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { WebGPURequest::CommandEncoderFinish { command_encoder_id: self.encoder.0, device_id: self.device.id().0, + is_error: !self.valid.get(), // TODO(zakorgy): We should use `_descriptor` here after it's not empty // and the underlying wgpu-core struct is serializable }, diff --git a/components/script/dom/gpucomputepassencoder.rs b/components/script/dom/gpucomputepassencoder.rs index c55eaf86fe2..a73ee8bde34 100644 --- a/components/script/dom/gpucomputepassencoder.rs +++ b/components/script/dom/gpucomputepassencoder.rs @@ -33,13 +33,14 @@ impl GPUComputePassEncoder { fn new_inherited( channel: WebGPU, parent: &GPUCommandEncoder, + compute_pass: Option<ComputePass>, label: Option<USVString>, ) -> Self { Self { channel, reflector_: Reflector::new(), 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), } } @@ -48,10 +49,16 @@ impl GPUComputePassEncoder { global: &GlobalScope, channel: WebGPU, parent: &GPUCommandEncoder, + compute_pass: Option<ComputePass>, label: Option<USVString>, ) -> DomRoot<Self> { reflect_dom_object( - Box::new(GPUComputePassEncoder::new_inherited(channel, parent, label)), + Box::new(GPUComputePassEncoder::new_inherited( + channel, + parent, + compute_pass, + label, + )), global, ) } @@ -88,24 +95,23 @@ impl GPUComputePassEncoderMethods for GPUComputePassEncoder { /// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass fn EndPass(&self) { - if let Some(compute_pass) = self.compute_pass.borrow_mut().take() { - self.channel - .0 - .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"); + let compute_pass = self.compute_pass.borrow_mut().take(); + self.channel + .0 + .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( - GPUCommandEncoderState::Open, - GPUCommandEncoderState::EncodingComputePass, - ); - } + self.command_encoder.set_state( + GPUCommandEncoderState::Open, + GPUCommandEncoderState::EncodingComputePass, + ); } /// https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup diff --git a/components/script/dom/gpurenderpassencoder.rs b/components/script/dom/gpurenderpassencoder.rs index 0e68b384ac5..9d1abf12511 100644 --- a/components/script/dom/gpurenderpassencoder.rs +++ b/components/script/dom/gpurenderpassencoder.rs @@ -35,7 +35,7 @@ pub struct GPURenderPassEncoder { impl GPURenderPassEncoder { fn new_inherited( channel: WebGPU, - render_pass: RenderPass, + render_pass: Option<RenderPass>, parent: &GPUCommandEncoder, label: Option<USVString>, ) -> Self { @@ -43,7 +43,7 @@ impl GPURenderPassEncoder { channel, reflector_: Reflector::new(), label: DomRefCell::new(label), - render_pass: DomRefCell::new(Some(render_pass)), + render_pass: DomRefCell::new(render_pass), command_encoder: Dom::from_ref(parent), } } @@ -51,7 +51,7 @@ impl GPURenderPassEncoder { pub fn new( global: &GlobalScope, channel: WebGPU, - render_pass: RenderPass, + render_pass: Option<RenderPass>, parent: &GPUCommandEncoder, label: Option<USVString>, ) -> DomRoot<Self> { @@ -126,27 +126,27 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder { /// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setblendcolor fn SetBlendColor(&self, color: GPUColor) { - let colors = match color { - GPUColor::GPUColorDict(d) => wgt::Color { - r: *d.r, - g: *d.g, - b: *d.b, - a: *d.a, - }, - GPUColor::DoubleSequence(mut s) => { - if s.len() < 3 { - s.resize(3, Finite::wrap(0.0f64)); - } - s.resize(4, Finite::wrap(1.0f64)); - wgt::Color { - r: *s[0], - g: *s[1], - b: *s[2], - a: *s[3], - } - }, - }; if let Some(render_pass) = self.render_pass.borrow_mut().as_mut() { + let colors = match color { + GPUColor::GPUColorDict(d) => wgt::Color { + r: *d.r, + g: *d.g, + b: *d.b, + a: *d.a, + }, + GPUColor::DoubleSequence(mut s) => { + if s.len() < 3 { + s.resize(3, Finite::wrap(0.0f64)); + } + s.resize(4, Finite::wrap(1.0f64)); + wgt::Color { + r: *s[0], + g: *s[1], + b: *s[2], + a: *s[3], + } + }, + }; wgpu_render::wgpu_render_pass_set_blend_color(render_pass, &colors); } } @@ -160,24 +160,23 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder { /// https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass fn EndPass(&self) { - if let Some(render_pass) = self.render_pass.borrow_mut().take() { - self.channel - .0 - .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"); + let render_pass = self.render_pass.borrow_mut().take(); + self.channel + .0 + .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( - GPUCommandEncoderState::Open, - GPUCommandEncoderState::EncodingRenderPass, - ); - } + self.command_encoder.set_state( + GPUCommandEncoderState::Open, + GPUCommandEncoderState::EncodingRenderPass, + ); } /// https://gpuweb.github.io/gpuweb/#dom-gpurenderencoderbase-setpipeline diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs index 11ae4f29d6a..944edcfa461 100644 --- a/components/webgpu/lib.rs +++ b/components/webgpu/lib.rs @@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize}; use servo_config::pref; use smallvec::SmallVec; use std::borrow::Cow; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::ffi::CString; use std::num::NonZeroU64; use std::ptr; @@ -77,6 +77,7 @@ pub enum WebGPURequest { CommandEncoderFinish { command_encoder_id: id::CommandEncoderId, device_id: id::DeviceId, + is_error: bool, // TODO(zakorgy): Serialize CommandBufferDescriptor in wgpu-core // wgpu::command::CommandBufferDescriptor, }, @@ -207,12 +208,12 @@ pub enum WebGPURequest { RunComputePass { command_encoder_id: id::CommandEncoderId, device_id: id::DeviceId, - compute_pass: ComputePass, + compute_pass: Option<ComputePass>, }, RunRenderPass { command_encoder_id: id::CommandEncoderId, device_id: id::DeviceId, - render_pass: RenderPass, + render_pass: Option<RenderPass>, }, Submit { queue_id: id::QueueId, @@ -337,6 +338,8 @@ struct WGPU<'a> { // Presentation Buffers with pending mapping present_buffer_maps: 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_document: webrender_api::DocumentId, external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, @@ -368,6 +371,7 @@ impl<'a> WGPU<'a> { _invalid_adapters: Vec::new(), buffer_maps: HashMap::new(), present_buffer_maps: HashMap::new(), + error_command_buffers: HashSet::new(), webrender_api: webrender_api_sender.create_api(), webrender_document, external_images, @@ -450,14 +454,20 @@ impl<'a> WGPU<'a> { WebGPURequest::CommandEncoderFinish { command_encoder_id, device_id, + is_error, } => { let global = &self.global; - let result = gfx_select!(command_encoder_id => global.command_encoder_finish( - command_encoder_id, - &wgt::CommandBufferDescriptor::default() - )); + let result = if is_error { + Err(String::from("Invalid GPUCommandEncoder")) + } else { + gfx_select!(command_encoder_id => global.command_encoder_finish( + command_encoder_id, + &wgt::CommandBufferDescriptor::default() + )) + .map_err(|e| format!("{:?}", e)) + }; 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); }, @@ -967,10 +977,14 @@ impl<'a> WGPU<'a> { compute_pass, } => { let global = &self.global; - let result = gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass( - command_encoder_id, - &compute_pass - )); + let result = if let Some(pass) = compute_pass { + gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass( + command_encoder_id, + &pass + )).map_err(|e| format!("{:?}", e)) + } else { + Err(String::from("Invalid ComputePass")) + }; self.send_result(device_id, scope_id, result); }, WebGPURequest::RunRenderPass { @@ -979,10 +993,14 @@ impl<'a> WGPU<'a> { render_pass, } => { let global = &self.global; - let result = gfx_select!(command_encoder_id => global.command_encoder_run_render_pass( - command_encoder_id, - &render_pass - )); + let result = if let Some(pass) = render_pass { + gfx_select!(command_encoder_id => global.command_encoder_run_render_pass( + command_encoder_id, + &pass + )).map_err(|e| format!("{:?}", e)) + } else { + Err(String::from("Invalid RenderPass")) + }; self.send_result(device_id, scope_id, result); }, WebGPURequest::Submit { @@ -990,7 +1008,15 @@ impl<'a> WGPU<'a> { command_buffers, } => { 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); }, WebGPURequest::SwapChainPresent { |