diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/gpucommandencoder.rs | 217 | ||||
-rw-r--r-- | components/script/dom/gpucomputepassencoder.rs | 44 | ||||
-rw-r--r-- | components/script/dom/gpudevice.rs | 343 | ||||
-rw-r--r-- | components/script/dom/gpurenderpassencoder.rs | 79 | ||||
-rw-r--r-- | components/script/dom/gputexture.rs | 67 |
5 files changed, 430 insertions, 320 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/gpudevice.rs b/components/script/dom/gpudevice.rs index 9e3e6d4976d..e54c0d1540a 100644 --- a/components/script/dom/gpudevice.rs +++ b/components/script/dom/gpudevice.rs @@ -64,7 +64,7 @@ use crate::script_runtime::JSContext as SafeJSContext; use dom_struct::dom_struct; use js::jsapi::{Heap, JSObject}; use std::borrow::Cow; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::ptr::NonNull; use std::rc::Rc; @@ -83,9 +83,16 @@ struct ErrorScopeInfo { } #[derive(JSTraceable, MallocSizeOf)] +struct ErrorScopeMetadata { + id: ErrorScopeId, + filter: GPUErrorFilter, + popped: Cell<bool>, +} + +#[derive(JSTraceable, MallocSizeOf)] struct ScopeContext { error_scopes: HashMap<ErrorScopeId, ErrorScopeInfo>, - scope_stack: Vec<(ErrorScopeId, GPUErrorFilter)>, + scope_stack: Vec<ErrorScopeMetadata>, next_scope_id: ErrorScopeId, } @@ -189,8 +196,8 @@ impl GPUDevice { .scope_stack .iter() .rev() - .find(|&&(id, fil)| id <= s_id && fil == filter) - .map(|(id, _)| *id); + .find(|meta| meta.id <= s_id && meta.filter == filter) + .map(|meta| meta.id); if let Some(s) = scop { self.handle_error(s, err); } else { @@ -237,14 +244,19 @@ impl GPUDevice { }; if remove { let _ = context.error_scopes.remove(&scope); - context.scope_stack.retain(|(id, _)| *id != scope); + context.scope_stack.retain(|meta| meta.id != scope); } } pub fn use_current_scope(&self) -> Option<ErrorScopeId> { let mut context = self.scope_context.borrow_mut(); - let scope_id = context.scope_stack.last().copied(); - scope_id.and_then(|(s_id, _)| { + let scope_id = context + .scope_stack + .iter() + .rev() + .find(|meta| !meta.popped.get()) + .map(|meta| meta.id); + scope_id.and_then(|s_id| { context.error_scopes.get_mut(&s_id).map(|mut scope| { scope.op_count += 1; s_id @@ -293,15 +305,12 @@ impl GPUDeviceMethods for GPUDevice { /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> DomRoot<GPUBuffer> { - let wgpu_descriptor = wgt::BufferDescriptor { + let desc = wgt::BufferUsage::from_bits(descriptor.usage).map(|usg| wgt::BufferDescriptor { label: descriptor.parent.label.as_ref().map(|s| s.to_string()), size: descriptor.size, - usage: match wgt::BufferUsage::from_bits(descriptor.usage) { - Some(u) => u, - None => wgt::BufferUsage::empty(), - }, + usage: usg, mapped_at_creation: descriptor.mappedAtCreation, - }; + }); let id = self .global() .wgpu_id_hub() @@ -309,6 +318,13 @@ impl GPUDeviceMethods for GPUDevice { .create_buffer_id(self.device.0.backend()); let scope_id = self.use_current_scope(); + if desc.is_none() { + self.handle_server_msg( + scope_id, + WebGPUOpResult::ValidationError(String::from("Invalid GPUBufferUsage")), + ); + } + self.channel .0 .send(( @@ -316,7 +332,7 @@ impl GPUDeviceMethods for GPUDevice { WebGPURequest::CreateBuffer { device_id: self.device.0, buffer_id: id, - descriptor: wgpu_descriptor, + descriptor: desc, }, )) .expect("Failed to create WebGPU buffer"); @@ -357,13 +373,17 @@ impl GPUDeviceMethods for GPUDevice { &self, descriptor: &GPUBindGroupLayoutDescriptor, ) -> DomRoot<GPUBindGroupLayout> { + let mut valid = true; let entries = descriptor .entries .iter() .map(|bind| { let visibility = match wgt::ShaderStage::from_bits(bind.visibility) { Some(visibility) => visibility, - None => wgt::ShaderStage::from_bits(0).unwrap(), + None => { + valid = false; + wgt::ShaderStage::empty() + }, }; let ty = match bind.type_ { GPUBindingType::Uniform_buffer => wgt::BindingType::UniformBuffer { @@ -435,13 +455,21 @@ impl GPUDeviceMethods for GPUDevice { let scope_id = self.use_current_scope(); - let desc = wgt::BindGroupLayoutDescriptor { - label: descriptor - .parent - .label - .as_ref() - .map(|s| Cow::Owned(s.to_string())), - entries: Cow::Owned(entries), + let desc = if valid { + Some(wgt::BindGroupLayoutDescriptor { + label: descriptor + .parent + .label + .as_ref() + .map(|s| Cow::Owned(s.to_string())), + entries: Cow::Owned(entries), + }) + } else { + self.handle_server_msg( + scope_id, + WebGPUOpResult::ValidationError(String::from("Invalid GPUShaderStage")), + ); + None }; let bind_group_layout_id = self @@ -695,22 +723,20 @@ impl GPUDeviceMethods for GPUDevice { /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createtexture fn CreateTexture(&self, descriptor: &GPUTextureDescriptor) -> DomRoot<GPUTexture> { let size = convert_texture_size_to_dict(&descriptor.size); - let desc = wgt::TextureDescriptor { - label: descriptor.parent.label.as_ref().map(|s| s.to_string()), - size: convert_texture_size_to_wgt(&size), - mip_level_count: descriptor.mipLevelCount, - sample_count: descriptor.sampleCount, - dimension: match descriptor.dimension { - GPUTextureDimension::_1d => wgt::TextureDimension::D1, - GPUTextureDimension::_2d => wgt::TextureDimension::D2, - GPUTextureDimension::_3d => wgt::TextureDimension::D3, - }, - format: convert_texture_format(descriptor.format), - usage: match wgt::TextureUsage::from_bits(descriptor.usage) { - Some(t) => t, - None => wgt::TextureUsage::empty(), - }, - }; + let desc = + wgt::TextureUsage::from_bits(descriptor.usage).map(|usg| wgt::TextureDescriptor { + label: descriptor.parent.label.as_ref().map(|s| s.to_string()), + size: convert_texture_size_to_wgt(&size), + mip_level_count: descriptor.mipLevelCount, + sample_count: descriptor.sampleCount, + dimension: match descriptor.dimension { + GPUTextureDimension::_1d => wgt::TextureDimension::D1, + GPUTextureDimension::_2d => wgt::TextureDimension::D2, + GPUTextureDimension::_3d => wgt::TextureDimension::D3, + }, + format: convert_texture_format(descriptor.format), + usage: usg, + }); let texture_id = self .global() @@ -719,7 +745,12 @@ impl GPUDeviceMethods for GPUDevice { .create_texture_id(self.device.0.backend()); let scope_id = self.use_current_scope(); - + if desc.is_none() { + self.handle_server_msg( + scope_id, + WebGPUOpResult::ValidationError(String::from("Invalid GPUTextureUsage")), + ); + } self.channel .0 .send(( @@ -803,110 +834,124 @@ impl GPUDeviceMethods for GPUDevice { ) -> DomRoot<GPURenderPipeline> { let ref rs_desc = descriptor.rasterizationState; let ref vs_desc = descriptor.vertexState; + let scope_id = self.use_current_scope(); + let mut valid = true; + let color_states = Cow::Owned( + descriptor + .colorStates + .iter() + .map(|state| wgt::ColorStateDescriptor { + format: convert_texture_format(state.format), + alpha_blend: convert_blend_descriptor(&state.alphaBlend), + color_blend: convert_blend_descriptor(&state.colorBlend), + write_mask: match wgt::ColorWrite::from_bits(state.writeMask) { + Some(mask) => mask, + None => { + valid = false; + wgt::ColorWrite::empty() + }, + }, + }) + .collect::<Vec<_>>(), + ); - let desc = wgpu_pipe::RenderPipelineDescriptor { - layout: descriptor.parent.layout.id().0, - vertex_stage: wgpu_pipe::ProgrammableStageDescriptor { - module: descriptor.vertexStage.module.id().0, - entry_point: Cow::Owned(descriptor.vertexStage.entryPoint.to_string()), - }, - fragment_stage: descriptor.fragmentStage.as_ref().map(|stage| { - wgpu_pipe::ProgrammableStageDescriptor { - module: stage.module.id().0, - entry_point: Cow::Owned(stage.entryPoint.to_string()), - } - }), - rasterization_state: Some(wgt::RasterizationStateDescriptor { - front_face: match rs_desc.frontFace { - GPUFrontFace::Ccw => wgt::FrontFace::Ccw, - GPUFrontFace::Cw => wgt::FrontFace::Cw, + let desc = if valid { + Some(wgpu_pipe::RenderPipelineDescriptor { + layout: descriptor.parent.layout.id().0, + vertex_stage: wgpu_pipe::ProgrammableStageDescriptor { + module: descriptor.vertexStage.module.id().0, + entry_point: Cow::Owned(descriptor.vertexStage.entryPoint.to_string()), }, - cull_mode: match rs_desc.cullMode { - GPUCullMode::None => wgt::CullMode::None, - GPUCullMode::Front => wgt::CullMode::Front, - GPUCullMode::Back => wgt::CullMode::Back, + fragment_stage: descriptor.fragmentStage.as_ref().map(|stage| { + wgpu_pipe::ProgrammableStageDescriptor { + module: stage.module.id().0, + entry_point: Cow::Owned(stage.entryPoint.to_string()), + } + }), + rasterization_state: Some(wgt::RasterizationStateDescriptor { + front_face: match rs_desc.frontFace { + GPUFrontFace::Ccw => wgt::FrontFace::Ccw, + GPUFrontFace::Cw => wgt::FrontFace::Cw, + }, + cull_mode: match rs_desc.cullMode { + GPUCullMode::None => wgt::CullMode::None, + GPUCullMode::Front => wgt::CullMode::Front, + GPUCullMode::Back => wgt::CullMode::Back, + }, + clamp_depth: rs_desc.clampDepth, + depth_bias: rs_desc.depthBias, + depth_bias_slope_scale: *rs_desc.depthBiasSlopeScale, + depth_bias_clamp: *rs_desc.depthBiasClamp, + }), + primitive_topology: match descriptor.primitiveTopology { + GPUPrimitiveTopology::Point_list => wgt::PrimitiveTopology::PointList, + GPUPrimitiveTopology::Line_list => wgt::PrimitiveTopology::LineList, + GPUPrimitiveTopology::Line_strip => wgt::PrimitiveTopology::LineStrip, + GPUPrimitiveTopology::Triangle_list => wgt::PrimitiveTopology::TriangleList, + GPUPrimitiveTopology::Triangle_strip => wgt::PrimitiveTopology::TriangleStrip, }, - clamp_depth: rs_desc.clampDepth, - depth_bias: rs_desc.depthBias, - depth_bias_slope_scale: *rs_desc.depthBiasSlopeScale, - depth_bias_clamp: *rs_desc.depthBiasClamp, - }), - primitive_topology: match descriptor.primitiveTopology { - GPUPrimitiveTopology::Point_list => wgt::PrimitiveTopology::PointList, - GPUPrimitiveTopology::Line_list => wgt::PrimitiveTopology::LineList, - GPUPrimitiveTopology::Line_strip => wgt::PrimitiveTopology::LineStrip, - GPUPrimitiveTopology::Triangle_list => wgt::PrimitiveTopology::TriangleList, - GPUPrimitiveTopology::Triangle_strip => wgt::PrimitiveTopology::TriangleStrip, - }, - color_states: Cow::Owned( - descriptor - .colorStates - .iter() - .map(|state| wgt::ColorStateDescriptor { - format: convert_texture_format(state.format), - alpha_blend: convert_blend_descriptor(&state.alphaBlend), - color_blend: convert_blend_descriptor(&state.colorBlend), - write_mask: match wgt::ColorWrite::from_bits(state.writeMask) { - Some(mask) => mask, - None => wgt::ColorWrite::empty(), + color_states, + depth_stencil_state: descriptor.depthStencilState.as_ref().map(|dss_desc| { + wgt::DepthStencilStateDescriptor { + format: convert_texture_format(dss_desc.format), + depth_write_enabled: dss_desc.depthWriteEnabled, + depth_compare: convert_compare_function(dss_desc.depthCompare), + stencil_front: wgt::StencilStateFaceDescriptor { + compare: convert_compare_function(dss_desc.stencilFront.compare), + fail_op: convert_stencil_op(dss_desc.stencilFront.failOp), + depth_fail_op: convert_stencil_op(dss_desc.stencilFront.depthFailOp), + pass_op: convert_stencil_op(dss_desc.stencilFront.passOp), }, - }) - .collect::<Vec<_>>(), - ), - depth_stencil_state: descriptor.depthStencilState.as_ref().map(|dss_desc| { - wgt::DepthStencilStateDescriptor { - format: convert_texture_format(dss_desc.format), - depth_write_enabled: dss_desc.depthWriteEnabled, - depth_compare: convert_compare_function(dss_desc.depthCompare), - stencil_front: wgt::StencilStateFaceDescriptor { - compare: convert_compare_function(dss_desc.stencilFront.compare), - fail_op: convert_stencil_op(dss_desc.stencilFront.failOp), - depth_fail_op: convert_stencil_op(dss_desc.stencilFront.depthFailOp), - pass_op: convert_stencil_op(dss_desc.stencilFront.passOp), - }, - stencil_back: wgt::StencilStateFaceDescriptor { - compare: convert_compare_function(dss_desc.stencilBack.compare), - fail_op: convert_stencil_op(dss_desc.stencilBack.failOp), - depth_fail_op: convert_stencil_op(dss_desc.stencilBack.depthFailOp), - pass_op: convert_stencil_op(dss_desc.stencilBack.passOp), + stencil_back: wgt::StencilStateFaceDescriptor { + compare: convert_compare_function(dss_desc.stencilBack.compare), + fail_op: convert_stencil_op(dss_desc.stencilBack.failOp), + depth_fail_op: convert_stencil_op(dss_desc.stencilBack.depthFailOp), + pass_op: convert_stencil_op(dss_desc.stencilBack.passOp), + }, + stencil_read_mask: dss_desc.stencilReadMask, + stencil_write_mask: dss_desc.stencilWriteMask, + } + }), + vertex_state: wgt::VertexStateDescriptor { + index_format: match vs_desc.indexFormat { + GPUIndexFormat::Uint16 => wgt::IndexFormat::Uint16, + GPUIndexFormat::Uint32 => wgt::IndexFormat::Uint32, }, - stencil_read_mask: dss_desc.stencilReadMask, - stencil_write_mask: dss_desc.stencilWriteMask, - } - }), - vertex_state: wgt::VertexStateDescriptor { - index_format: match vs_desc.indexFormat { - GPUIndexFormat::Uint16 => wgt::IndexFormat::Uint16, - GPUIndexFormat::Uint32 => wgt::IndexFormat::Uint32, + vertex_buffers: Cow::Owned( + vs_desc + .vertexBuffers + .iter() + .map(|buffer| wgt::VertexBufferDescriptor { + stride: buffer.arrayStride, + step_mode: match buffer.stepMode { + GPUInputStepMode::Vertex => wgt::InputStepMode::Vertex, + GPUInputStepMode::Instance => wgt::InputStepMode::Instance, + }, + attributes: Cow::Owned( + buffer + .attributes + .iter() + .map(|att| wgt::VertexAttributeDescriptor { + format: convert_vertex_format(att.format), + offset: att.offset, + shader_location: att.shaderLocation, + }) + .collect::<Vec<_>>(), + ), + }) + .collect::<Vec<_>>(), + ), }, - vertex_buffers: Cow::Owned( - vs_desc - .vertexBuffers - .iter() - .map(|buffer| wgt::VertexBufferDescriptor { - stride: buffer.arrayStride, - step_mode: match buffer.stepMode { - GPUInputStepMode::Vertex => wgt::InputStepMode::Vertex, - GPUInputStepMode::Instance => wgt::InputStepMode::Instance, - }, - attributes: Cow::Owned( - buffer - .attributes - .iter() - .map(|att| wgt::VertexAttributeDescriptor { - format: convert_vertex_format(att.format), - offset: att.offset, - shader_location: att.shaderLocation, - }) - .collect::<Vec<_>>(), - ), - }) - .collect::<Vec<_>>(), - ), - }, - sample_count: descriptor.sampleCount, - sample_mask: descriptor.sampleMask, - alpha_to_coverage_enabled: descriptor.alphaToCoverageEnabled, + sample_count: descriptor.sampleCount, + sample_mask: descriptor.sampleMask, + alpha_to_coverage_enabled: descriptor.alphaToCoverageEnabled, + }) + } else { + self.handle_server_msg( + scope_id, + WebGPUOpResult::ValidationError(String::from("Invalid GPUColorWriteFlags")), + ); + None }; let render_pipeline_id = self @@ -915,8 +960,6 @@ impl GPUDeviceMethods for GPUDevice { .lock() .create_render_pipeline_id(self.device.0.backend()); - let scope_id = self.use_current_scope(); - self.channel .0 .send(( @@ -986,7 +1029,11 @@ impl GPUDeviceMethods for GPUDevice { promise: None, }; let res = context.error_scopes.insert(scope_id, err_scope); - context.scope_stack.push((scope_id, filter)); + context.scope_stack.push(ErrorScopeMetadata { + id: scope_id, + filter, + popped: Cell::new(false), + }); assert!(res.is_none()); } @@ -994,12 +1041,14 @@ impl GPUDeviceMethods for GPUDevice { fn PopErrorScope(&self, comp: InRealm) -> Rc<Promise> { let mut context = self.scope_context.borrow_mut(); let promise = Promise::new_in_current_realm(&self.global(), comp); - let scope_id = if let Some((e, _)) = context.scope_stack.last() { - *e - } else { - promise.reject_error(Error::Operation); - return promise; - }; + let scope_id = + if let Some(meta) = context.scope_stack.iter().rev().find(|m| !m.popped.get()) { + meta.popped.set(true); + meta.id + } else { + promise.reject_error(Error::Operation); + return promise; + }; let remove = if let Some(mut err_scope) = context.error_scopes.get_mut(&scope_id) { if let Some(ref e) = err_scope.error { match e { @@ -1017,7 +1066,7 @@ impl GPUDeviceMethods for GPUDevice { }; if remove { let _ = context.error_scopes.remove(&scope_id); - let _ = context.scope_stack.pop(); + context.scope_stack.retain(|meta| meta.id != scope_id); } promise } 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/script/dom/gputexture.rs b/components/script/dom/gputexture.rs index 64b56e82607..a7137d1bd61 100644 --- a/components/script/dom/gputexture.rs +++ b/components/script/dom/gputexture.rs @@ -16,8 +16,11 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::gpudevice::{convert_texture_format, convert_texture_view_dimension, GPUDevice}; use crate::dom::gputextureview::GPUTextureView; use dom_struct::dom_struct; +use std::num::NonZeroU32; use std::string::String; -use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView}; +use webgpu::{ + identity::WebGPUOpResult, wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView, +}; #[dom_struct] pub struct GPUTexture { @@ -137,24 +140,48 @@ impl GPUTextureMethods for GPUTexture { }; let format = descriptor.format.unwrap_or(self.format); - - let desc = wgt::TextureViewDescriptor { - label: descriptor - .parent - .label - .as_ref() - .map(|s| String::from(s.as_ref())), - format: convert_texture_format(format), - dimension: convert_texture_view_dimension(dimension), - aspect: match descriptor.aspect { - GPUTextureAspect::All => wgt::TextureAspect::All, - GPUTextureAspect::Stencil_only => wgt::TextureAspect::StencilOnly, - GPUTextureAspect::Depth_only => wgt::TextureAspect::DepthOnly, - }, - base_mip_level: descriptor.baseMipLevel, - level_count: descriptor.mipLevelCount.as_ref().copied(), - base_array_layer: descriptor.baseArrayLayer, - array_layer_count: descriptor.arrayLayerCount.as_ref().copied(), + let scope_id = self.device.use_current_scope(); + let mut valid = true; + let level_count = descriptor.mipLevelCount.and_then(|count| { + if count == 0 { + valid = false; + } + NonZeroU32::new(count) + }); + let array_layer_count = descriptor.arrayLayerCount.and_then(|count| { + if count == 0 { + valid = false; + } + NonZeroU32::new(count) + }); + + let desc = if valid { + Some(wgt::TextureViewDescriptor { + label: descriptor + .parent + .label + .as_ref() + .map(|s| String::from(s.as_ref())), + format: convert_texture_format(format), + dimension: convert_texture_view_dimension(dimension), + aspect: match descriptor.aspect { + GPUTextureAspect::All => wgt::TextureAspect::All, + GPUTextureAspect::Stencil_only => wgt::TextureAspect::StencilOnly, + GPUTextureAspect::Depth_only => wgt::TextureAspect::DepthOnly, + }, + base_mip_level: descriptor.baseMipLevel, + level_count, + base_array_layer: descriptor.baseArrayLayer, + array_layer_count, + }) + } else { + self.device.handle_server_msg( + scope_id, + WebGPUOpResult::ValidationError(String::from( + "arrayLayerCount and mipLevelCount cannot be 0", + )), + ); + None }; let texture_view_id = self @@ -163,8 +190,6 @@ impl GPUTextureMethods for GPUTexture { .lock() .create_texture_view_id(self.device.id().0.backend()); - let scope_id = self.device.use_current_scope(); - self.channel .0 .send(( |