diff --git a/components/script/dom/gpucommandbuffer.rs b/components/script/dom/gpucommandbuffer.rs index be0edf8f2c8..7bcff2d9000 100644 --- a/components/script/dom/gpucommandbuffer.rs +++ b/components/script/dom/gpucommandbuffer.rs @@ -2,26 +2,15 @@ * 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 std::collections::HashSet; -use std::hash::{Hash, Hasher}; - use dom_struct::dom_struct; use webgpu::{WebGPU, WebGPUCommandBuffer, WebGPURequest}; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUCommandBufferMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::USVString; use crate::dom::globalscope::GlobalScope; -use crate::dom::gpubuffer::GPUBuffer; - -impl Eq for DomRoot {} -impl Hash for DomRoot { - fn hash(&self, state: &mut H) { - self.id().hash(state); - } -} #[dom_struct] pub struct GPUCommandBuffer { @@ -32,14 +21,12 @@ pub struct GPUCommandBuffer { label: DomRefCell, #[no_trace] command_buffer: WebGPUCommandBuffer, - buffers: DomRefCell>>, } impl GPUCommandBuffer { fn new_inherited( channel: WebGPU, command_buffer: WebGPUCommandBuffer, - buffers: HashSet>, label: USVString, ) -> Self { Self { @@ -47,7 +34,6 @@ impl GPUCommandBuffer { reflector_: Reflector::new(), label: DomRefCell::new(label), command_buffer, - buffers: DomRefCell::new(buffers.into_iter().map(|b| Dom::from_ref(&*b)).collect()), } } @@ -55,14 +41,12 @@ impl GPUCommandBuffer { global: &GlobalScope, channel: WebGPU, command_buffer: WebGPUCommandBuffer, - buffers: HashSet>, label: USVString, ) -> DomRoot { reflect_dom_object( Box::new(GPUCommandBuffer::new_inherited( channel, command_buffer, - buffers, label, )), global, diff --git a/components/script/dom/gpucommandencoder.rs b/components/script/dom/gpucommandencoder.rs index 9cd5af180a8..dfa0849b204 100644 --- a/components/script/dom/gpucommandencoder.rs +++ b/components/script/dom/gpucommandencoder.rs @@ -2,21 +2,17 @@ * 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 std::cell::Cell; -use std::collections::HashSet; - use dom_struct::dom_struct; use webgpu::wgc::command as wgpu_com; use webgpu::{self, wgt, WebGPU, WebGPUComputePass, WebGPURenderPass, WebGPURequest}; -use super::gpuconvert::convert_label; +use super::bindings::error::Fallible; +use super::gpuconvert::{convert_color, convert_label}; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ GPUCommandBufferDescriptor, GPUCommandEncoderMethods, GPUComputePassDescriptor, GPUExtent3D, GPUImageCopyBuffer, GPUImageCopyTexture, GPURenderPassDescriptor, GPUSize64, }; -use crate::dom::bindings::codegen::UnionTypes::DoubleSequenceOrGPUColorDict; -use crate::dom::bindings::num::Finite; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::USVString; @@ -25,8 +21,7 @@ use crate::dom::gpubuffer::GPUBuffer; use crate::dom::gpucommandbuffer::GPUCommandBuffer; use crate::dom::gpucomputepassencoder::GPUComputePassEncoder; use crate::dom::gpuconvert::{ - convert_ic_buffer, convert_ic_texture, convert_load_op, convert_store_op, - convert_texture_size_to_dict, convert_texture_size_to_wgt, + convert_ic_buffer, convert_ic_texture, convert_load_op, convert_store_op, convert_texture_size, }; use crate::dom::gpudevice::GPUDevice; use crate::dom::gpurenderpassencoder::GPURenderPassEncoder; @@ -40,9 +35,7 @@ pub struct GPUCommandEncoder { label: DomRefCell, #[no_trace] encoder: webgpu::WebGPUCommandEncoder, - buffers: DomRefCell>>, device: Dom, - valid: Cell, } impl GPUCommandEncoder { @@ -58,8 +51,6 @@ impl GPUCommandEncoder { label: DomRefCell::new(label), device: Dom::from_ref(device), encoder, - buffers: DomRefCell::new(HashSet::new()), - valid: Cell::new(true), } } @@ -132,7 +123,7 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { fn BeginRenderPass( &self, descriptor: &GPURenderPassDescriptor, - ) -> DomRoot { + ) -> Fallible> { let depth_stencil_attachment = descriptor.depthStencilAttachment.as_ref().map(|depth| { wgpu_com::RenderPassDepthStencilAttachment { depth: wgpu_com::PassChannel { @@ -154,44 +145,25 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { let color_attachments = descriptor .colorAttachments .iter() - .map(|color| { + .map(|color| -> Fallible<_> { let channel = wgpu_com::PassChannel { load_op: convert_load_op(Some(color.loadOp)), store_op: convert_store_op(Some(color.storeOp)), - clear_value: if let Some(clear_val) = &color.clearValue { - match clear_val { - DoubleSequenceOrGPUColorDict::DoubleSequence(s) => { - let mut w = s.clone(); - if w.len() < 3 { - w.resize(3, Finite::wrap(0.0f64)); - } - w.resize(4, Finite::wrap(1.0f64)); - wgt::Color { - r: *w[0], - g: *w[1], - b: *w[2], - a: *w[3], - } - }, - DoubleSequenceOrGPUColorDict::GPUColorDict(d) => wgt::Color { - r: *d.r, - g: *d.g, - b: *d.b, - a: *d.a, - }, - } - } else { - wgt::Color::TRANSPARENT - }, + clear_value: color + .clearValue + .as_ref() + .map(|color| convert_color(color)) + .transpose()? + .unwrap_or_default(), read_only: false, }; - Some(wgpu_com::RenderPassColorAttachment { + Ok(Some(wgpu_com::RenderPassColorAttachment { resolve_target: color.resolveTarget.as_ref().map(|t| t.id().0), channel, view: color.view.id().0, - }) + })) }) - .collect::>(); + .collect::>>()?; let render_pass_id = self .global() .wgpu_id_hub() @@ -208,13 +180,13 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { warn!("Failed to send WebGPURequest::BeginRenderPass {e:?}"); } - GPURenderPassEncoder::new( + Ok(GPURenderPassEncoder::new( &self.global(), self.channel.clone(), WebGPURenderPass(render_pass_id), self, descriptor.parent.label.clone(), - ) + )) } /// @@ -226,10 +198,6 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { destination_offset: GPUSize64, size: GPUSize64, ) { - self.buffers.borrow_mut().insert(DomRoot::from_ref(source)); - self.buffers - .borrow_mut() - .insert(DomRoot::from_ref(destination)); self.channel .0 .send(WebGPURequest::CopyBufferToBuffer { @@ -249,20 +217,18 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { source: &GPUImageCopyBuffer, destination: &GPUImageCopyTexture, copy_size: GPUExtent3D, - ) { - self.buffers - .borrow_mut() - .insert(DomRoot::from_ref(&*source.buffer)); - + ) -> Fallible<()> { self.channel .0 .send(WebGPURequest::CopyBufferToTexture { command_encoder_id: self.encoder.0, source: convert_ic_buffer(source), - destination: convert_ic_texture(destination), - copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(©_size)), + destination: convert_ic_texture(destination)?, + copy_size: convert_texture_size(©_size)?, }) .expect("Failed to send CopyBufferToTexture"); + + Ok(()) } /// @@ -271,20 +237,18 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { source: &GPUImageCopyTexture, destination: &GPUImageCopyBuffer, copy_size: GPUExtent3D, - ) { - self.buffers - .borrow_mut() - .insert(DomRoot::from_ref(&*destination.buffer)); - + ) -> Fallible<()> { self.channel .0 .send(WebGPURequest::CopyTextureToBuffer { command_encoder_id: self.encoder.0, - source: convert_ic_texture(source), + source: convert_ic_texture(source)?, destination: convert_ic_buffer(destination), - copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(©_size)), + copy_size: convert_texture_size(©_size)?, }) .expect("Failed to send CopyTextureToBuffer"); + + Ok(()) } /// @@ -293,16 +257,18 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { source: &GPUImageCopyTexture, destination: &GPUImageCopyTexture, copy_size: GPUExtent3D, - ) { + ) -> Fallible<()> { self.channel .0 .send(WebGPURequest::CopyTextureToTexture { command_encoder_id: self.encoder.0, - source: convert_ic_texture(source), - destination: convert_ic_texture(destination), - copy_size: convert_texture_size_to_wgt(&convert_texture_size_to_dict(©_size)), + source: convert_ic_texture(source)?, + destination: convert_ic_texture(destination)?, + copy_size: convert_texture_size(©_size)?, }) .expect("Failed to send CopyTextureToTexture"); + + Ok(()) } /// @@ -312,9 +278,9 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { .send(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 + desc: wgt::CommandBufferDescriptor { + label: convert_label(&descriptor.parent), + }, }) .expect("Failed to send Finish"); @@ -323,7 +289,6 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder { &self.global(), self.channel.clone(), buffer, - self.buffers.borrow_mut().drain().collect(), descriptor.parent.label.clone(), ) } diff --git a/components/script/dom/gpuconvert.rs b/components/script/dom/gpuconvert.rs index 05b0bcc510b..ca580f613fc 100644 --- a/components/script/dom/gpuconvert.rs +++ b/components/script/dom/gpuconvert.rs @@ -3,17 +3,23 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::borrow::Cow; +use std::num::NonZeroU64; use webgpu::wgc::command as wgpu_com; use webgpu::wgt::{self, AstcBlock, AstcChannel}; +use super::bindings::error::Error; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ - GPUAddressMode, GPUBlendComponent, GPUBlendFactor, GPUBlendOperation, GPUCompareFunction, - GPUCullMode, GPUExtent3D, GPUExtent3DDict, GPUFilterMode, GPUFrontFace, GPUImageCopyBuffer, - GPUImageCopyTexture, GPUImageDataLayout, GPUIndexFormat, GPULoadOp, GPUObjectDescriptorBase, - GPUOrigin3D, GPUPrimitiveState, GPUPrimitiveTopology, GPUStencilOperation, GPUStoreOp, - GPUTextureAspect, GPUTextureFormat, GPUTextureViewDimension, GPUVertexFormat, + GPUAddressMode, GPUBindGroupLayoutEntry, GPUBlendComponent, GPUBlendFactor, GPUBlendOperation, + GPUBufferBindingType, GPUColor, GPUCompareFunction, GPUCullMode, GPUExtent3D, GPUFilterMode, + GPUFrontFace, GPUImageCopyBuffer, GPUImageCopyTexture, GPUImageDataLayout, GPUIndexFormat, + GPULoadOp, GPUObjectDescriptorBase, GPUOrigin3D, GPUPrimitiveState, GPUPrimitiveTopology, + GPUSamplerBindingType, GPUStencilOperation, GPUStorageTextureAccess, GPUStoreOp, + GPUTextureAspect, GPUTextureFormat, GPUTextureSampleType, GPUTextureViewDimension, + GPUVertexFormat, }; +use crate::dom::bindings::error::Fallible; +use crate::dom::types::GPUDevice; pub fn convert_texture_format(format: GPUTextureFormat) -> wgt::TextureFormat { match format { @@ -212,33 +218,30 @@ pub fn convert_texture_view_dimension( } } -pub fn convert_texture_size_to_dict(size: &GPUExtent3D) -> GPUExtent3DDict { +pub fn convert_texture_size(size: &GPUExtent3D) -> Fallible { match *size { - GPUExtent3D::GPUExtent3DDict(ref dict) => GPUExtent3DDict { + GPUExtent3D::GPUExtent3DDict(ref dict) => Ok(wgt::Extent3d { width: dict.width, height: dict.height, - depthOrArrayLayers: dict.depthOrArrayLayers, - }, + depth_or_array_layers: dict.depthOrArrayLayers, + }), GPUExtent3D::RangeEnforcedUnsignedLongSequence(ref v) => { - let mut w = v.clone(); - w.resize(3, 1); - GPUExtent3DDict { - width: w[0], - height: w[1], - depthOrArrayLayers: w[2], + // https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpuextent3d-shape + if v.len() < 1 || v.len() > 3 { + Err(Error::Type( + "GPUExtent3D size must be between 1 and 3 (inclusive)".to_string(), + )) + } else { + Ok(wgt::Extent3d { + width: v[0], + height: v.get(1).copied().unwrap_or(1), + depth_or_array_layers: v.get(2).copied().unwrap_or(1), + }) } }, } } -pub fn convert_texture_size_to_wgt(size: &GPUExtent3DDict) -> wgt::Extent3d { - wgt::Extent3d { - width: size.width, - height: size.height, - depth_or_array_layers: size.depthOrArrayLayers, - } -} - pub fn convert_image_data_layout(data_layout: &GPUImageDataLayout) -> wgt::ImageDataLayout { wgt::ImageDataLayout { offset: data_layout.offset as wgt::BufferAddress, @@ -426,33 +429,48 @@ pub fn convert_ic_buffer(ic_buffer: &GPUImageCopyBuffer) -> wgpu_com::ImageCopyB } } -pub fn convert_ic_texture(ic_texture: &GPUImageCopyTexture) -> wgpu_com::ImageCopyTexture { - wgpu_com::ImageCopyTexture { +pub fn convert_origin3d(origin: &GPUOrigin3D) -> Fallible { + match origin { + GPUOrigin3D::RangeEnforcedUnsignedLongSequence(v) => { + // https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpuorigin3d-shape + if v.len() > 3 { + Err(Error::Type( + "sequence is too long for GPUOrigin3D".to_string(), + )) + } else { + Ok(wgt::Origin3d { + x: v.get(0).copied().unwrap_or(0), + y: v.get(1).copied().unwrap_or(0), + z: v.get(2).copied().unwrap_or(0), + }) + } + }, + GPUOrigin3D::GPUOrigin3DDict(d) => Ok(wgt::Origin3d { + x: d.x, + y: d.y, + z: d.z, + }), + } +} + +pub fn convert_ic_texture( + ic_texture: &GPUImageCopyTexture, +) -> Fallible { + Ok(wgpu_com::ImageCopyTexture { texture: ic_texture.texture.id().0, mip_level: ic_texture.mipLevel, - origin: match ic_texture.origin { - Some(GPUOrigin3D::RangeEnforcedUnsignedLongSequence(ref v)) => { - let mut w = v.clone(); - w.resize(3, 0); - wgt::Origin3d { - x: w[0], - y: w[1], - z: w[2], - } - }, - Some(GPUOrigin3D::GPUOrigin3DDict(ref d)) => wgt::Origin3d { - x: d.x, - y: d.y, - z: d.z, - }, - None => wgt::Origin3d::default(), - }, + origin: ic_texture + .origin + .as_ref() + .map(|origin| convert_origin3d(origin)) + .transpose()? + .unwrap_or_default(), aspect: match ic_texture.aspect { GPUTextureAspect::All => wgt::TextureAspect::All, GPUTextureAspect::Stencil_only => wgt::TextureAspect::StencilOnly, GPUTextureAspect::Depth_only => wgt::TextureAspect::DepthOnly, }, - } + }) } pub fn convert_label(parent: &GPUObjectDescriptorBase) -> Option> { @@ -462,3 +480,102 @@ pub fn convert_label(parent: &GPUObjectDescriptorBase) -> Option Fallible> { + let number_of_provided_bindings = bgle.buffer.is_some() as u8 + + bgle.sampler.is_some() as u8 + + bgle.storageTexture.is_some() as u8 + + bgle.texture.is_some() as u8; + let ty = if let Some(buffer) = &bgle.buffer { + Some(wgt::BindingType::Buffer { + ty: match buffer.type_ { + GPUBufferBindingType::Uniform => wgt::BufferBindingType::Uniform, + GPUBufferBindingType::Storage => { + wgt::BufferBindingType::Storage { read_only: false } + }, + GPUBufferBindingType::Read_only_storage => { + wgt::BufferBindingType::Storage { read_only: true } + }, + }, + has_dynamic_offset: buffer.hasDynamicOffset, + min_binding_size: NonZeroU64::new(buffer.minBindingSize), + }) + } else if let Some(sampler) = &bgle.sampler { + Some(wgt::BindingType::Sampler(match sampler.type_ { + GPUSamplerBindingType::Filtering => wgt::SamplerBindingType::Filtering, + GPUSamplerBindingType::Non_filtering => wgt::SamplerBindingType::NonFiltering, + GPUSamplerBindingType::Comparison => wgt::SamplerBindingType::Comparison, + })) + } else if let Some(storage) = &bgle.storageTexture { + Some(wgt::BindingType::StorageTexture { + access: match storage.access { + GPUStorageTextureAccess::Write_only => wgt::StorageTextureAccess::WriteOnly, + GPUStorageTextureAccess::Read_only => wgt::StorageTextureAccess::ReadOnly, + GPUStorageTextureAccess::Read_write => wgt::StorageTextureAccess::ReadWrite, + }, + format: device.validate_texture_format_required_features(&storage.format)?, + view_dimension: convert_view_dimension(storage.viewDimension), + }) + } else if let Some(texture) = &bgle.texture { + Some(wgt::BindingType::Texture { + sample_type: match texture.sampleType { + GPUTextureSampleType::Float => wgt::TextureSampleType::Float { filterable: true }, + GPUTextureSampleType::Unfilterable_float => { + wgt::TextureSampleType::Float { filterable: false } + }, + GPUTextureSampleType::Depth => wgt::TextureSampleType::Depth, + GPUTextureSampleType::Sint => wgt::TextureSampleType::Sint, + GPUTextureSampleType::Uint => wgt::TextureSampleType::Uint, + }, + view_dimension: convert_view_dimension(texture.viewDimension), + multisampled: texture.multisampled, + }) + } else { + assert_eq!(number_of_provided_bindings, 0); + None + }; + // Check for number of bindings should actually be done in device-timeline, + // but we do it last on content-timeline to have some visible effect + let ty = if number_of_provided_bindings != 1 { + None + } else { + ty + } + .ok_or(webgpu::Error::Validation( + "Exactly on entry type must be provided".to_string(), + )); + + Ok(ty.map(|ty| wgt::BindGroupLayoutEntry { + binding: bgle.binding, + visibility: wgt::ShaderStages::from_bits_retain(bgle.visibility), + ty, + count: None, + })) +} + +pub fn convert_color(color: &GPUColor) -> Fallible { + match color { + GPUColor::DoubleSequence(s) => { + // https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpucolor-shape + if s.len() != 4 { + Err(Error::Type("GPUColor sequence must be len 4".to_string())) + } else { + Ok(wgt::Color { + r: *s[0], + g: *s[1], + b: *s[2], + a: *s[3], + }) + } + }, + GPUColor::GPUColorDict(d) => Ok(wgt::Color { + r: *d.r, + g: *d.g, + b: *d.b, + a: *d.a, + }), + } +} diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs index 47ab1e29fac..a07a00d65c7 100644 --- a/components/script/dom/gpudevice.rs +++ b/components/script/dom/gpudevice.rs @@ -7,7 +7,6 @@ use std::borrow::Cow; use std::cell::Cell; use std::collections::HashMap; -use std::num::NonZeroU64; use std::rc::Rc; use dom_struct::dom_struct; @@ -29,6 +28,7 @@ use super::bindings::codegen::Bindings::WebGPUBinding::{ use super::bindings::codegen::UnionTypes::GPUPipelineLayoutOrGPUAutoLayoutMode; use super::bindings::error::Fallible; use super::gpu::AsyncWGPUListener; +use super::gpuconvert::convert_bind_group_layout_entry; use super::gpudevicelostinfo::GPUDeviceLostInfo; use super::gpupipelineerror::GPUPipelineError; use super::gpusupportedlimits::GPUSupportedLimits; @@ -37,13 +37,12 @@ use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::EventBinding::EventInit; use crate::dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ - GPUBindGroupDescriptor, GPUBindGroupLayoutDescriptor, GPUBindingResource, GPUBufferBindingType, - GPUBufferDescriptor, GPUCommandEncoderDescriptor, GPUComputePipelineDescriptor, - GPUDeviceLostReason, GPUDeviceMethods, GPUErrorFilter, GPUPipelineLayoutDescriptor, - GPURenderBundleEncoderDescriptor, GPURenderPipelineDescriptor, GPUSamplerBindingType, - GPUSamplerDescriptor, GPUShaderModuleDescriptor, GPUStorageTextureAccess, - GPUSupportedLimitsMethods, GPUTextureDescriptor, GPUTextureDimension, GPUTextureSampleType, - GPUUncapturedErrorEventInit, GPUVertexStepMode, + GPUBindGroupDescriptor, GPUBindGroupLayoutDescriptor, GPUBindingResource, GPUBufferDescriptor, + GPUCommandEncoderDescriptor, GPUComputePipelineDescriptor, GPUDeviceLostReason, + GPUDeviceMethods, GPUErrorFilter, GPUPipelineLayoutDescriptor, + GPURenderBundleEncoderDescriptor, GPURenderPipelineDescriptor, GPUSamplerDescriptor, + GPUShaderModuleDescriptor, GPUSupportedLimitsMethods, GPUTextureDescriptor, + GPUTextureDimension, GPUUncapturedErrorEventInit, GPUVertexStepMode, }; use crate::dom::bindings::error::Error; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; @@ -62,8 +61,7 @@ use crate::dom::gpucomputepipeline::GPUComputePipeline; use crate::dom::gpuconvert::{ convert_address_mode, convert_blend_component, convert_compare_function, convert_filter_mode, convert_label, convert_primitive_state, convert_stencil_op, convert_texture_format, - convert_texture_size_to_dict, convert_texture_size_to_wgt, convert_vertex_format, - convert_view_dimension, + convert_texture_size, convert_vertex_format, }; use crate::dom::gpupipelinelayout::GPUPipelineLayout; use crate::dom::gpuqueue::GPUQueue; @@ -484,91 +482,21 @@ impl GPUDeviceMethods for GPUDevice { &self, descriptor: &GPUBindGroupLayoutDescriptor, ) -> Fallible> { - // TODO(sagudev): pass invalid bits to wgpu - let mut valid = true; let entries = descriptor .entries .iter() - .map(|bind| { - let visibility = match wgt::ShaderStages::from_bits(bind.visibility) { - Some(visibility) => visibility, - None => { - valid = false; - wgt::ShaderStages::empty() - }, - }; - let ty = if let Some(buffer) = &bind.buffer { - wgt::BindingType::Buffer { - ty: match buffer.type_ { - GPUBufferBindingType::Uniform => wgt::BufferBindingType::Uniform, - GPUBufferBindingType::Storage => { - wgt::BufferBindingType::Storage { read_only: false } - }, - GPUBufferBindingType::Read_only_storage => { - wgt::BufferBindingType::Storage { read_only: true } - }, - }, - has_dynamic_offset: buffer.hasDynamicOffset, - min_binding_size: NonZeroU64::new(buffer.minBindingSize), - } - } else if let Some(sampler) = &bind.sampler { - wgt::BindingType::Sampler(match sampler.type_ { - GPUSamplerBindingType::Filtering => wgt::SamplerBindingType::Filtering, - GPUSamplerBindingType::Non_filtering => { - wgt::SamplerBindingType::NonFiltering - }, - GPUSamplerBindingType::Comparison => wgt::SamplerBindingType::Comparison, - }) - } else if let Some(storage) = &bind.storageTexture { - wgt::BindingType::StorageTexture { - access: match storage.access { - GPUStorageTextureAccess::Write_only => { - wgt::StorageTextureAccess::WriteOnly - }, - }, - format: self.validate_texture_format_required_features(&storage.format)?, - view_dimension: convert_view_dimension(storage.viewDimension), - } - } else if let Some(texture) = &bind.texture { - wgt::BindingType::Texture { - sample_type: match texture.sampleType { - GPUTextureSampleType::Float => { - wgt::TextureSampleType::Float { filterable: true } - }, - GPUTextureSampleType::Unfilterable_float => { - wgt::TextureSampleType::Float { filterable: false } - }, - GPUTextureSampleType::Depth => wgt::TextureSampleType::Depth, - GPUTextureSampleType::Sint => wgt::TextureSampleType::Sint, - GPUTextureSampleType::Uint => wgt::TextureSampleType::Uint, - }, - view_dimension: convert_view_dimension(texture.viewDimension), - multisampled: texture.multisampled, - } - } else { - valid = false; - todo!("Handle error"); - }; + .map(|bgle| convert_bind_group_layout_entry(bgle, &self)) + .collect::, _>>>()?; - Ok(wgt::BindGroupLayoutEntry { - binding: bind.binding, - visibility, - ty, - count: None, - }) - }) - .collect::>>()?; - - let desc = if valid { - Some(wgpu_bind::BindGroupLayoutDescriptor { + let desc = match entries { + Ok(entries) => Some(wgpu_bind::BindGroupLayoutDescriptor { label: convert_label(&descriptor.parent), entries: Cow::Owned(entries), - }) - } else { - self.dispatch_error(webgpu::Error::Validation(String::from( - "Invalid GPUShaderStage", - ))); - None + }), + Err(error) => { + self.dispatch_error(error); + None + }, }; let bind_group_layout_id = self @@ -833,7 +761,9 @@ impl GPUDeviceMethods for GPUDevice { .send(WebGPURequest::CreateCommandEncoder { device_id: self.device.0, command_encoder_id, - label: convert_label(&descriptor.parent), + desc: wgt::CommandEncoderDescriptor { + label: convert_label(&descriptor.parent), + }, }) .expect("Failed to create WebGPU command encoder"); @@ -850,40 +780,31 @@ impl GPUDeviceMethods for GPUDevice { /// fn CreateTexture(&self, descriptor: &GPUTextureDescriptor) -> Fallible> { - // TODO(sagudev): This should be https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-gpuextent3d-shape - let size = convert_texture_size_to_dict(&descriptor.size); - // TODO(sagudev): We should pass invalid bits to wgpu - let desc = wgt::TextureUsages::from_bits(descriptor.usage) - .map(|usg| -> Fallible<_> { - Ok(wgpu_res::TextureDescriptor { - label: convert_label(&descriptor.parent), - 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: self.validate_texture_format_required_features(&descriptor.format)?, - usage: usg, - view_formats: descriptor - .viewFormats - .iter() - .map(|tf| self.validate_texture_format_required_features(tf)) - .collect::>()?, - }) - }) - .transpose()?; + let size = convert_texture_size(&descriptor.size)?; + let desc = wgpu_res::TextureDescriptor { + label: convert_label(&descriptor.parent), + 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: self.validate_texture_format_required_features(&descriptor.format)?, + usage: wgt::TextureUsages::from_bits_retain(descriptor.usage), + view_formats: descriptor + .viewFormats + .iter() + .map(|tf| self.validate_texture_format_required_features(tf)) + .collect::>()?, + }; let texture_id = self .global() .wgpu_id_hub() .create_texture_id(self.device.0.backend()); - if desc.is_none() { - return Err(Error::Type(String::from("Invalid GPUTextureUsage"))); - } self.channel .0 .send(WebGPURequest::CreateTexture { diff --git a/components/script/dom/gpuqueue.rs b/components/script/dom/gpuqueue.rs index e4a4102141d..8db840163bd 100644 --- a/components/script/dom/gpuqueue.rs +++ b/components/script/dom/gpuqueue.rs @@ -22,10 +22,7 @@ use crate::dom::bindings::str::USVString; use crate::dom::globalscope::GlobalScope; use crate::dom::gpubuffer::GPUBuffer; use crate::dom::gpucommandbuffer::GPUCommandBuffer; -use crate::dom::gpuconvert::{ - convert_ic_texture, convert_image_data_layout, convert_texture_size_to_dict, - convert_texture_size_to_wgt, -}; +use crate::dom::gpuconvert::{convert_ic_texture, convert_image_data_layout, convert_texture_size}; use crate::dom::gpudevice::GPUDevice; use crate::dom::promise::Promise; @@ -166,9 +163,9 @@ impl GPUQueueMethods for GPUQueue { return Err(Error::Operation); } - let texture_cv = convert_ic_texture(destination); + let texture_cv = convert_ic_texture(destination)?; let texture_layout = convert_image_data_layout(data_layout); - let write_size = convert_texture_size_to_wgt(&convert_texture_size_to_dict(&size)); + let write_size = convert_texture_size(&size)?; let final_data = IpcSharedMemory::from_bytes(&bytes); if let Err(e) = self.channel.0.send(WebGPURequest::WriteTexture { diff --git a/components/script/dom/gpurenderpassencoder.rs b/components/script/dom/gpurenderpassencoder.rs index 19a9850519e..2d4341fdc7b 100644 --- a/components/script/dom/gpurenderpassencoder.rs +++ b/components/script/dom/gpurenderpassencoder.rs @@ -6,6 +6,7 @@ use dom_struct::dom_struct; use webgpu::{wgt, RenderCommand, WebGPU, WebGPURenderPass, WebGPURequest}; use super::bindings::codegen::Bindings::WebGPUBinding::GPUIndexFormat; +use super::bindings::error::Fallible; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ GPUColor, GPURenderPassEncoderMethods, @@ -18,6 +19,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::gpubindgroup::GPUBindGroup; use crate::dom::gpubuffer::GPUBuffer; use crate::dom::gpucommandencoder::GPUCommandEncoder; +use crate::dom::gpuconvert::convert_color; use crate::dom::gpurenderbundle::GPURenderBundle; use crate::dom::gpurenderpipeline::GPURenderPipeline; @@ -129,28 +131,9 @@ impl GPURenderPassEncoderMethods for GPURenderPassEncoder { } /// - fn SetBlendConstant(&self, color: GPUColor) { - let color = 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], - } - }, - }; - self.send_render_command(RenderCommand::SetBlendConstant(color)) + fn SetBlendConstant(&self, color: GPUColor) -> Fallible<()> { + self.send_render_command(RenderCommand::SetBlendConstant(convert_color(&color)?)); + Ok(()) } /// diff --git a/components/script/dom/gputexture.rs b/components/script/dom/gputexture.rs index 9547f173d48..61ab4231951 100644 --- a/components/script/dom/gputexture.rs +++ b/components/script/dom/gputexture.rs @@ -12,7 +12,7 @@ use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView}; use super::bindings::error::Fallible; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ - GPUExtent3DDict, GPUTextureAspect, GPUTextureDimension, GPUTextureFormat, GPUTextureMethods, + GPUTextureAspect, GPUTextureDimension, GPUTextureFormat, GPUTextureMethods, GPUTextureViewDescriptor, }; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; @@ -33,8 +33,9 @@ pub struct GPUTexture { #[ignore_malloc_size_of = "channels are hard"] #[no_trace] channel: WebGPU, - #[ignore_malloc_size_of = "defined in webgpu"] - texture_size: GPUExtent3DDict, + #[ignore_malloc_size_of = "defined in wgpu"] + #[no_trace] + texture_size: wgt::Extent3d, mip_level_count: u32, sample_count: u32, dimension: GPUTextureDimension, @@ -49,7 +50,7 @@ impl GPUTexture { texture: WebGPUTexture, device: &GPUDevice, channel: WebGPU, - texture_size: GPUExtent3DDict, + texture_size: wgt::Extent3d, mip_level_count: u32, sample_count: u32, dimension: GPUTextureDimension, @@ -79,7 +80,7 @@ impl GPUTexture { texture: WebGPUTexture, device: &GPUDevice, channel: WebGPU, - texture_size: GPUExtent3DDict, + texture_size: wgt::Extent3d, mip_level_count: u32, sample_count: u32, dimension: GPUTextureDimension, @@ -230,7 +231,7 @@ impl GPUTextureMethods for GPUTexture { /// fn DepthOrArrayLayers(&self) -> u32 { - self.texture_size.depthOrArrayLayers + self.texture_size.depth_or_array_layers } /// diff --git a/components/script/dom/webidls/WebGPU.webidl b/components/script/dom/webidls/WebGPU.webidl index 65694fb3b29..2de46855b19 100644 --- a/components/script/dom/webidls/WebGPU.webidl +++ b/components/script/dom/webidls/WebGPU.webidl @@ -462,10 +462,12 @@ dictionary GPUBindGroupLayoutDescriptor : GPUObjectDescriptorBase { dictionary GPUBindGroupLayoutEntry { required GPUIndex32 binding; required GPUShaderStageFlags visibility; + GPUBufferBindingLayout buffer; GPUSamplerBindingLayout sampler; GPUTextureBindingLayout texture; GPUStorageTextureBindingLayout storageTexture; + GPUExternalTextureBindingLayout externalTexture; }; typedef [EnforceRange] unsigned long GPUShaderStageFlags; @@ -514,6 +516,8 @@ dictionary GPUTextureBindingLayout { enum GPUStorageTextureAccess { "write-only", + "read-only", + "read-write", }; dictionary GPUStorageTextureBindingLayout { @@ -522,6 +526,9 @@ dictionary GPUStorageTextureBindingLayout { GPUTextureViewDimension viewDimension = "2d"; }; +dictionary GPUExternalTextureBindingLayout { +}; + [Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"] interface GPUBindGroup { }; @@ -867,7 +874,7 @@ dictionary GPUCommandBufferDescriptor : GPUObjectDescriptorBase { interface GPUCommandEncoder { [NewObject] GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {}); - [NewObject] + [NewObject, Throws] GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor); undefined copyBufferToBuffer( @@ -877,16 +884,19 @@ interface GPUCommandEncoder { GPUSize64 destinationOffset, GPUSize64 size); + [Throws] undefined copyBufferToTexture( GPUImageCopyBuffer source, GPUImageCopyTexture destination, GPUExtent3D copySize); + [Throws] undefined copyTextureToBuffer( GPUImageCopyTexture source, GPUImageCopyBuffer destination, GPUExtent3D copySize); + [Throws] undefined copyTextureToTexture( GPUImageCopyTexture source, GPUImageCopyTexture destination, @@ -942,6 +952,7 @@ interface GPURenderPassEncoder { undefined setScissorRect(GPUIntegerCoordinate x, GPUIntegerCoordinate y, GPUIntegerCoordinate width, GPUIntegerCoordinate height); + [Throws] undefined setBlendConstant(GPUColor color); undefined setStencilReference(GPUStencilValue reference); diff --git a/components/webgpu/ipc_messages/recv.rs b/components/webgpu/ipc_messages/recv.rs index 6e89806792b..8bc8f261b15 100644 --- a/components/webgpu/ipc_messages/recv.rs +++ b/components/webgpu/ipc_messages/recv.rs @@ -5,8 +5,6 @@ //! IPC messages that are received in wgpu thread //! (usually from script thread more specifically from dom objects) -use std::borrow::Cow; - use arrayvec::ArrayVec; use base::id::PipelineId; use ipc_channel::ipc::{IpcSender, IpcSharedMemory}; @@ -27,6 +25,7 @@ use wgc::resource::{ BufferDescriptor, SamplerDescriptor, TextureDescriptor, TextureViewDescriptor, }; use wgpu_core::command::{RenderPassColorAttachment, RenderPassDepthStencilAttachment}; +use wgpu_core::Label; pub use {wgpu_core as wgc, wgpu_types as wgt}; use crate::identity::*; @@ -46,9 +45,7 @@ pub enum WebGPURequest { CommandEncoderFinish { command_encoder_id: id::CommandEncoderId, device_id: id::DeviceId, - is_error: bool, - // TODO(zakorgy): Serialize CommandBufferDescriptor in wgpu-core - // wgc::command::CommandBufferDescriptor, + desc: wgt::CommandBufferDescriptor>, }, CopyBufferToBuffer { command_encoder_id: id::CommandEncoderId, @@ -93,10 +90,8 @@ pub enum WebGPURequest { }, CreateCommandEncoder { device_id: id::DeviceId, - // TODO(zakorgy): Serialize CommandEncoderDescriptor in wgpu-core - // wgc::command::CommandEncoderDescriptor, command_encoder_id: id::CommandEncoderId, - label: Option>, + desc: wgt::CommandEncoderDescriptor>, }, CreateComputePipeline { device_id: id::DeviceId, @@ -144,7 +139,7 @@ pub enum WebGPURequest { CreateTexture { device_id: id::DeviceId, texture_id: id::TextureId, - descriptor: Option>, + descriptor: TextureDescriptor<'static>, }, CreateTextureView { texture_id: id::TextureId, @@ -203,7 +198,7 @@ pub enum WebGPURequest { BeginComputePass { command_encoder_id: id::CommandEncoderId, compute_pass_id: ComputePassId, - label: Option>, + label: Label<'static>, device_id: id::DeviceId, }, ComputePassSetPipeline { @@ -240,7 +235,7 @@ pub enum WebGPURequest { BeginRenderPass { command_encoder_id: id::CommandEncoderId, render_pass_id: RenderPassId, - label: Option>, + label: Label<'static>, color_attachments: Vec>, depth_stencil_attachment: Option, device_id: id::DeviceId, diff --git a/components/webgpu/wgpu_thread.rs b/components/webgpu/wgpu_thread.rs index cebe38f4930..8d252447be3 100644 --- a/components/webgpu/wgpu_thread.rs +++ b/components/webgpu/wgpu_thread.rs @@ -230,21 +230,15 @@ impl WGPU { WebGPURequest::CommandEncoderFinish { command_encoder_id, device_id, - is_error, + desc, } => { let global = &self.global; - let result = if is_error { - Err(Error::Validation(String::from("Invalid GPUCommandEncoder"))) - } else if let Some(err) = + let result = if let Some(err) = self.error_command_encoders.get(&command_encoder_id) { Err(Error::Validation(err.clone())) - } else if let Some(error) = global - .command_encoder_finish( - command_encoder_id, - &wgt::CommandBufferDescriptor::default(), - ) - .1 + } else if let Some(error) = + global.command_encoder_finish(command_encoder_id, &desc).1 { Err(Error::from_error(error)) } else { @@ -363,10 +357,9 @@ impl WGPU { WebGPURequest::CreateCommandEncoder { device_id, command_encoder_id, - label, + desc, } => { let global = &self.global; - let desc = wgt::CommandEncoderDescriptor { label }; let (_, error) = global.device_create_command_encoder( device_id, &desc, @@ -579,11 +572,9 @@ impl WGPU { descriptor, } => { let global = &self.global; - if let Some(desc) = descriptor { - let (_, error) = - global.device_create_texture(device_id, &desc, Some(texture_id)); - self.maybe_dispatch_wgpu_error(device_id, error); - } + let (_, error) = + global.device_create_texture(device_id, &descriptor, Some(texture_id)); + self.maybe_dispatch_wgpu_error(device_id, error); }, WebGPURequest::CreateTextureView { texture_id, diff --git a/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini b/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini index 0a50568c31b..0e8676e9bbc 100644 --- a/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini @@ -20514,8 +20514,6 @@ if os == "linux" and not debug: FAIL [:format="rg32float";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rg32float";access="write-only"] @@ -20524,8 +20522,6 @@ if os == "linux" and not debug: FAIL [:format="rg32sint";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rg32sint";access="write-only"] @@ -20534,8 +20530,6 @@ if os == "linux" and not debug: FAIL [:format="rg32uint";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rg32uint";access="write-only"] @@ -20586,8 +20580,6 @@ if os == "linux" and not debug: FAIL [:format="rgba16float";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba16float";access="write-only"] @@ -20596,8 +20588,6 @@ if os == "linux" and not debug: FAIL [:format="rgba16sint";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba16sint";access="write-only"] @@ -20606,8 +20596,6 @@ if os == "linux" and not debug: FAIL [:format="rgba16uint";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba16uint";access="write-only"] @@ -20616,8 +20604,6 @@ if os == "linux" and not debug: FAIL [:format="rgba32float";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba32float";access="write-only"] @@ -20626,8 +20612,6 @@ if os == "linux" and not debug: FAIL [:format="rgba32sint";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba32sint";access="write-only"] @@ -20636,8 +20620,6 @@ if os == "linux" and not debug: FAIL [:format="rgba32uint";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba32uint";access="write-only"] @@ -20646,8 +20628,6 @@ if os == "linux" and not debug: FAIL [:format="rgba8sint";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8sint";access="write-only"] @@ -20656,8 +20636,6 @@ if os == "linux" and not debug: FAIL [:format="rgba8snorm";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8snorm";access="write-only"] @@ -20666,8 +20644,6 @@ if os == "linux" and not debug: FAIL [:format="rgba8uint";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8uint";access="write-only"] @@ -20676,8 +20652,6 @@ if os == "linux" and not debug: FAIL [:format="rgba8unorm";access="read-write"] - expected: - if os == "linux" and not debug: FAIL [:format="rgba8unorm";access="write-only"] @@ -60688,20 +60662,12 @@ [:resourceType="nonFiltSamp";entry={"sampler":{"type":"non-filtering"}};awaitLost=true] [:resourceType="readonlyStorageTex";entry={"storageTexture":{"access":"read-only","format":"r32float"}};awaitLost=false] - expected: - if os == "linux" and not debug: FAIL [:resourceType="readonlyStorageTex";entry={"storageTexture":{"access":"read-only","format":"r32float"}};awaitLost=true] - expected: - if os == "linux" and not debug: FAIL [:resourceType="readwriteStorageTex";entry={"storageTexture":{"access":"read-write","format":"r32float"}};awaitLost=false] - expected: - if os == "linux" and not debug: FAIL [:resourceType="readwriteStorageTex";entry={"storageTexture":{"access":"read-write","format":"r32float"}};awaitLost=true] - expected: - if os == "linux" and not debug: FAIL [:resourceType="sampledTex";entry={"texture":{"multisampled":false,"sampleType":"unfilterable-float"}};awaitLost=false] @@ -60754,20 +60720,12 @@ [:entry={"sampler":{"type":"non-filtering"}};awaitLost=true] [:entry={"storageTexture":{"access":"read-only","format":"r32float"}};awaitLost=false] - expected: - if os == "linux" and not debug: FAIL [:entry={"storageTexture":{"access":"read-only","format":"r32float"}};awaitLost=true] - expected: - if os == "linux" and not debug: FAIL [:entry={"storageTexture":{"access":"read-write","format":"r32float"}};awaitLost=false] - expected: - if os == "linux" and not debug: FAIL [:entry={"storageTexture":{"access":"read-write","format":"r32float"}};awaitLost=true] - expected: - if os == "linux" and not debug: FAIL [:entry={"storageTexture":{"access":"write-only","format":"r32float"}};awaitLost=false] @@ -61056,20 +61014,12 @@ [:entry={"sampler":{"type":"non-filtering"}};awaitLost=true] [:entry={"storageTexture":{"access":"read-only","format":"r32float"}};awaitLost=false] - expected: - if os == "linux" and not debug: FAIL [:entry={"storageTexture":{"access":"read-only","format":"r32float"}};awaitLost=true] - expected: - if os == "linux" and not debug: FAIL [:entry={"storageTexture":{"access":"read-write","format":"r32float"}};awaitLost=false] - expected: - if os == "linux" and not debug: FAIL [:entry={"storageTexture":{"access":"read-write","format":"r32float"}};awaitLost=true] - expected: - if os == "linux" and not debug: FAIL [:entry={"storageTexture":{"access":"write-only","format":"r32float"}};awaitLost=false]