aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKunal Mohan <kunalmohan99@gmail.com>2020-08-07 22:36:05 +0530
committerKunal Mohan <kunalmohan99@gmail.com>2020-08-07 22:36:05 +0530
commit1d80f57aab0a11e6138b360391900666303244f3 (patch)
tree1a38c380c6995a44d673d97b906b06e3e3b3dcc0
parent78c9466fdb98435dc4829b3c2e0a0a3a85b79b5f (diff)
downloadservo-1d80f57aab0a11e6138b360391900666303244f3.tar.gz
servo-1d80f57aab0a11e6138b360391900666303244f3.zip
Record errors in GPUCommandEncoder.BeginPass() and EncoderPass.endPass()
-rw-r--r--components/script/dom/gpucommandencoder.rs217
-rw-r--r--components/script/dom/gpucomputepassencoder.rs44
-rw-r--r--components/script/dom/gpurenderpassencoder.rs79
-rw-r--r--components/webgpu/lib.rs60
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 {