webgpu: Clean up GPUCommandEncoders and add some validation (#33223)

* TextureUsages::from_bits_retain

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Fixup CreateBindGroupLayout

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* GPUExtent3D checking and converting

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Cleanup GPUCommandEncoders and some TODOs

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* validate gpuorigin3d

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* validate GPUColor

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* set good expect

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
Samson 2024-08-30 13:23:17 +02:00 committed by GitHub
parent 83a40c5180
commit 817a91f2ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 276 additions and 361 deletions

View file

@ -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<GPUBuffer> {}
impl Hash for DomRoot<GPUBuffer> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id().hash(state);
}
}
#[dom_struct]
pub struct GPUCommandBuffer {
@ -32,14 +21,12 @@ pub struct GPUCommandBuffer {
label: DomRefCell<USVString>,
#[no_trace]
command_buffer: WebGPUCommandBuffer,
buffers: DomRefCell<HashSet<Dom<GPUBuffer>>>,
}
impl GPUCommandBuffer {
fn new_inherited(
channel: WebGPU,
command_buffer: WebGPUCommandBuffer,
buffers: HashSet<DomRoot<GPUBuffer>>,
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<DomRoot<GPUBuffer>>,
label: USVString,
) -> DomRoot<Self> {
reflect_dom_object(
Box::new(GPUCommandBuffer::new_inherited(
channel,
command_buffer,
buffers,
label,
)),
global,

View file

@ -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<USVString>,
#[no_trace]
encoder: webgpu::WebGPUCommandEncoder,
buffers: DomRefCell<HashSet<DomRoot<GPUBuffer>>>,
device: Dom<GPUDevice>,
valid: Cell<bool>,
}
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<GPURenderPassEncoder> {
) -> Fallible<DomRoot<GPURenderPassEncoder>> {
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::<Vec<_>>();
.collect::<Fallible<Vec<_>>>()?;
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(),
)
))
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copybuffertobuffer>
@ -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(&copy_size)),
destination: convert_ic_texture(destination)?,
copy_size: convert_texture_size(&copy_size)?,
})
.expect("Failed to send CopyBufferToTexture");
Ok(())
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copybuffertotexture>
@ -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(&copy_size)),
copy_size: convert_texture_size(&copy_size)?,
})
.expect("Failed to send CopyTextureToBuffer");
Ok(())
}
/// <https://gpuweb.github.io/gpuweb/#GPUCommandEncoder-copyTextureToTexture>
@ -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(&copy_size)),
source: convert_ic_texture(source)?,
destination: convert_ic_texture(destination)?,
copy_size: convert_texture_size(&copy_size)?,
})
.expect("Failed to send CopyTextureToTexture");
Ok(())
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-finish>
@ -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(),
)
}

View file

@ -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<wgt::Extent3d> {
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<wgt::Origin3d> {
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<wgpu_com::ImageCopyTexture> {
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<Cow<'static, str>> {
@ -462,3 +480,102 @@ pub fn convert_label(parent: &GPUObjectDescriptorBase) -> Option<Cow<'static, st
Some(Cow::Owned(parent.label.to_string()))
}
}
pub fn convert_bind_group_layout_entry(
bgle: &GPUBindGroupLayoutEntry,
device: &GPUDevice,
) -> Fallible<Result<wgt::BindGroupLayoutEntry, webgpu::Error>> {
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<wgt::Color> {
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,
}),
}
}

View file

@ -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<DomRoot<GPUBindGroupLayout>> {
// 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::<Fallible<Result<Vec<_>, _>>>()?;
Ok(wgt::BindGroupLayoutEntry {
binding: bind.binding,
visibility,
ty,
count: None,
})
})
.collect::<Fallible<Vec<_>>>()?;
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 {
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createtexture>
fn CreateTexture(&self, descriptor: &GPUTextureDescriptor) -> Fallible<DomRoot<GPUTexture>> {
// 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::<Fallible<_>>()?,
})
})
.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::<Fallible<_>>()?,
};
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 {

View file

@ -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 {

View file

@ -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 {
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setblendcolor>
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(())
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-setstencilreference>

View file

@ -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 {
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-depthorarraylayers>
fn DepthOrArrayLayers(&self) -> u32 {
self.texture_size.depthOrArrayLayers
self.texture_size.depth_or_array_layers
}
/// <https://gpuweb.github.io/gpuweb/#dom-gputexture-miplevelcount>

View file

@ -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);