webgpu: Sync various parts of spec (#33009)

* Sync `GPUObjectDescriptorBase` (label is not option anymore)

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

* Sync `GPUFeatureName`

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

* shader_f16 feature is not usable in wgpu so disable it

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

* sync `GPUTextureFormat`

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

* `validate_texture_format_required_features`

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

* Sync `GPUTexture` attributes

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

* Make `entryPoint` in `GPUProgrammableStage` optional

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

* Set good expectations

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

* Bad expectations because naga does not support cons declarations

Also fail on firefox, where skipped before due to missing device features

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

* Bad expectation, also fails on firefox

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

* Bad expectations, because naga does not support `let pos = positions[vertex_index];`

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

* Set expectation

external texture does not work in firefox too (again naga)

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

* set bad expectations, because naga does not support `enable`

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

* Set bad expectations for, `Texture with '' label has been destroyed`

also fails in firefox with same reason

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

* one bad expectation

also on firefox

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

* expect that also matches firefox

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

* more expect

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

* Use only 1 proc for _webgpu

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

* better doc comment

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-19 16:06:30 +02:00 committed by GitHub
parent f45c98496e
commit 94ff89a5e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 910 additions and 4947 deletions

View file

@ -18,12 +18,13 @@ use webgpu::wgc::pipeline::RenderPipelineDescriptor;
use webgpu::wgc::{
binding_model as wgpu_bind, command as wgpu_com, pipeline as wgpu_pipe, resource as wgpu_res,
};
use webgpu::wgt::TextureFormat;
use webgpu::{
self, wgt, PopError, WebGPU, WebGPUComputePipeline, WebGPURenderPipeline, WebGPURequest,
WebGPUResponse,
};
use super::bindings::codegen::Bindings::WebGPUBinding::GPUPipelineErrorReason;
use super::bindings::codegen::Bindings::WebGPUBinding::{GPUPipelineErrorReason, GPUTextureFormat};
use super::bindings::codegen::UnionTypes::GPUPipelineLayoutOrGPUAutoLayoutMode;
use super::bindings::error::Fallible;
use super::gpu::AsyncWGPUListener;
@ -190,6 +191,28 @@ impl GPUDevice {
let _ = self.eventtarget.DispatchEvent(ev.event());
}
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-validate-texture-format-required-features>
///
/// Validates that the device suppports required features,
/// and if so returns an ok containing wgpu's `TextureFormat`
pub fn validate_texture_format_required_features(
&self,
format: &GPUTextureFormat,
) -> Fallible<TextureFormat> {
let texture_format = convert_texture_format(*format);
if self
.features
.wgpu_features()
.contains(texture_format.required_features())
{
Ok(texture_format)
} else {
Err(Error::Type(format!(
"{texture_format:?} is not supported by this GPUDevice"
)))
}
}
fn get_pipeline_layout_data(
&self,
layout: &GPUPipelineLayoutOrGPUAutoLayoutMode,
@ -223,10 +246,10 @@ impl GPUDevice {
fn parse_render_pipeline(
&self,
descriptor: &GPURenderPipelineDescriptor,
) -> (
) -> Fallible<(
Option<(PipelineLayoutId, Vec<BindGroupLayoutId>)>,
RenderPipelineDescriptor<'static>,
) {
)> {
let (layout, implicit_ids, _) = self.get_pipeline_layout_data(&descriptor.parent.layout);
let desc = wgpu_pipe::RenderPipelineDescriptor {
@ -236,7 +259,12 @@ impl GPUDevice {
vertex: wgpu_pipe::VertexState {
stage: wgpu_pipe::ProgrammableStageDescriptor {
module: descriptor.vertex.parent.module.id().0,
entry_point: Some(Cow::Owned(descriptor.vertex.parent.entryPoint.to_string())),
entry_point: descriptor
.vertex
.parent
.entryPoint
.as_ref()
.map(|ep| Cow::Owned(ep.to_string())),
constants: Cow::Owned(HashMap::new()),
zero_initialize_workgroup_memory: true,
},
@ -269,59 +297,88 @@ impl GPUDevice {
fragment: descriptor
.fragment
.as_ref()
.map(|stage| wgpu_pipe::FragmentState {
stage: wgpu_pipe::ProgrammableStageDescriptor {
module: stage.parent.module.id().0,
entry_point: Some(Cow::Owned(stage.parent.entryPoint.to_string())),
constants: Cow::Owned(HashMap::new()),
zero_initialize_workgroup_memory: true,
},
targets: Cow::Owned(
stage
.targets
.iter()
.map(|state| {
Some(wgt::ColorTargetState {
format: convert_texture_format(state.format),
write_mask: wgt::ColorWrites::from_bits_retain(state.writeMask),
blend: state.blend.as_ref().map(|blend| wgt::BlendState {
color: convert_blend_component(&blend.color),
alpha: convert_blend_component(&blend.alpha),
}),
.map(|stage| -> Fallible<wgpu_pipe::FragmentState> {
Ok(wgpu_pipe::FragmentState {
stage: wgpu_pipe::ProgrammableStageDescriptor {
module: stage.parent.module.id().0,
entry_point: stage
.parent
.entryPoint
.as_ref()
.map(|ep| Cow::Owned(ep.to_string())),
constants: Cow::Owned(HashMap::new()),
zero_initialize_workgroup_memory: true,
},
targets: Cow::Owned(
stage
.targets
.iter()
.map(|state| {
self.validate_texture_format_required_features(&state.format)
.map(|format| {
Some(wgt::ColorTargetState {
format,
write_mask: wgt::ColorWrites::from_bits_retain(
state.writeMask,
),
blend: state.blend.as_ref().map(|blend| {
wgt::BlendState {
color: convert_blend_component(
&blend.color,
),
alpha: convert_blend_component(
&blend.alpha,
),
}
}),
})
})
})
})
.collect::<Vec<_>>(),
),
}),
.collect::<Result<Vec<_>, _>>()?,
),
})
})
.transpose()?,
primitive: convert_primitive_state(&descriptor.primitive),
depth_stencil: descriptor.depthStencil.as_ref().map(|dss_desc| {
wgt::DepthStencilState {
format: convert_texture_format(dss_desc.format),
depth_write_enabled: dss_desc.depthWriteEnabled,
depth_compare: convert_compare_function(dss_desc.depthCompare),
stencil: wgt::StencilState {
front: wgt::StencilFaceState {
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),
},
back: wgt::StencilFaceState {
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),
},
read_mask: dss_desc.stencilReadMask,
write_mask: dss_desc.stencilWriteMask,
},
bias: wgt::DepthBiasState {
constant: dss_desc.depthBias,
slope_scale: *dss_desc.depthBiasSlopeScale,
clamp: *dss_desc.depthBiasClamp,
},
}
}),
depth_stencil: descriptor
.depthStencil
.as_ref()
.map(|dss_desc| {
self.validate_texture_format_required_features(&dss_desc.format)
.map(|format| wgt::DepthStencilState {
format,
depth_write_enabled: dss_desc.depthWriteEnabled,
depth_compare: convert_compare_function(dss_desc.depthCompare),
stencil: wgt::StencilState {
front: wgt::StencilFaceState {
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),
},
back: wgt::StencilFaceState {
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),
},
read_mask: dss_desc.stencilReadMask,
write_mask: dss_desc.stencilWriteMask,
},
bias: wgt::DepthBiasState {
constant: dss_desc.depthBias,
slope_scale: *dss_desc.depthBiasSlopeScale,
clamp: *dss_desc.depthBiasClamp,
},
})
})
.transpose()?,
multisample: wgt::MultisampleState {
count: descriptor.multisample.count,
mask: descriptor.multisample.mask as u64,
@ -329,7 +386,7 @@ impl GPUDevice {
},
multiview: None,
};
(implicit_ids, desc)
Ok((implicit_ids, desc))
}
/// <https://gpuweb.github.io/gpuweb/#lose-the-device>
@ -420,7 +477,7 @@ impl GPUDeviceMethods for GPUDevice {
state,
descriptor.size,
map_info,
descriptor.parent.label.clone().unwrap_or_default(),
descriptor.parent.label.clone(),
))
}
@ -429,7 +486,8 @@ impl GPUDeviceMethods for GPUDevice {
fn CreateBindGroupLayout(
&self,
descriptor: &GPUBindGroupLayoutDescriptor,
) -> DomRoot<GPUBindGroupLayout> {
) -> Fallible<DomRoot<GPUBindGroupLayout>> {
// TODO(sagudev): pass invalid bits to wgpu
let mut valid = true;
let entries = descriptor
.entries
@ -471,7 +529,7 @@ impl GPUDeviceMethods for GPUDevice {
wgt::StorageTextureAccess::WriteOnly
},
},
format: convert_texture_format(storage.format),
format: self.validate_texture_format_required_features(&storage.format)?,
view_dimension: convert_view_dimension(storage.viewDimension),
}
} else if let Some(texture) = &bind.texture {
@ -495,14 +553,14 @@ impl GPUDeviceMethods for GPUDevice {
todo!("Handle error");
};
wgt::BindGroupLayoutEntry {
Ok(wgt::BindGroupLayoutEntry {
binding: bind.binding,
visibility,
ty,
count: None,
}
})
})
.collect::<Vec<_>>();
.collect::<Fallible<Vec<_>>>()?;
let desc = if valid {
Some(wgpu_bind::BindGroupLayoutDescriptor {
@ -531,12 +589,12 @@ impl GPUDeviceMethods for GPUDevice {
let bgl = webgpu::WebGPUBindGroupLayout(bind_group_layout_id);
GPUBindGroupLayout::new(
Ok(GPUBindGroupLayout::new(
&self.global(),
self.channel.clone(),
bgl,
descriptor.parent.label.clone().unwrap_or_default(),
)
descriptor.parent.label.clone(),
))
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createpipelinelayout>
@ -579,7 +637,7 @@ impl GPUDeviceMethods for GPUDevice {
&self.global(),
self.channel.clone(),
pipeline_layout,
descriptor.parent.label.clone().unwrap_or_default(),
descriptor.parent.label.clone(),
bgls,
)
}
@ -636,7 +694,7 @@ impl GPUDeviceMethods for GPUDevice {
bind_group,
self.device,
&descriptor.layout,
descriptor.parent.label.clone().unwrap_or_default(),
descriptor.parent.label.clone(),
)
}
@ -655,7 +713,7 @@ impl GPUDeviceMethods for GPUDevice {
&self.global(),
self.channel.clone(),
webgpu::WebGPUShaderModule(program_id),
descriptor.parent.label.clone().unwrap_or_default(),
descriptor.parent.label.clone(),
promise.clone(),
);
let sender = response_async(&promise, &*shader_module);
@ -689,7 +747,11 @@ impl GPUDeviceMethods for GPUDevice {
layout,
stage: wgpu_pipe::ProgrammableStageDescriptor {
module: descriptor.compute.module.id().0,
entry_point: Some(Cow::Owned(descriptor.compute.entryPoint.to_string())),
entry_point: descriptor
.compute
.entryPoint
.as_ref()
.map(|ep| Cow::Owned(ep.to_string())),
constants: Cow::Owned(HashMap::new()),
zero_initialize_workgroup_memory: true,
},
@ -711,7 +773,7 @@ impl GPUDeviceMethods for GPUDevice {
GPUComputePipeline::new(
&self.global(),
compute_pipeline,
descriptor.parent.parent.label.clone().unwrap_or_default(),
descriptor.parent.parent.label.clone(),
self,
)
}
@ -736,7 +798,11 @@ impl GPUDeviceMethods for GPUDevice {
layout,
stage: wgpu_pipe::ProgrammableStageDescriptor {
module: descriptor.compute.module.id().0,
entry_point: Some(Cow::Owned(descriptor.compute.entryPoint.to_string())),
entry_point: descriptor
.compute
.entryPoint
.as_ref()
.map(|ep| Cow::Owned(ep.to_string())),
constants: Cow::Owned(HashMap::new()),
zero_initialize_workgroup_memory: true,
},
@ -781,33 +847,37 @@ impl GPUDeviceMethods for GPUDevice {
self.channel.clone(),
self,
encoder,
descriptor.parent.label.clone().unwrap_or_default(),
descriptor.parent.label.clone(),
)
}
/// <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);
let desc = wgt::TextureUsages::from_bits(descriptor.usage).map(|usg| {
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: convert_texture_format(descriptor.format),
usage: usg,
view_formats: descriptor
.viewFormats
.iter()
.map(|tf| convert_texture_format(*tf))
.collect(),
}
});
// 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 texture_id = self
.global()
@ -839,7 +909,7 @@ impl GPUDeviceMethods for GPUDevice {
descriptor.dimension,
descriptor.format,
descriptor.usage,
descriptor.parent.label.clone().unwrap_or_default(),
descriptor.parent.label.clone(),
))
}
@ -884,7 +954,7 @@ impl GPUDeviceMethods for GPUDevice {
self.device,
compare_enable,
sampler,
descriptor.parent.label.clone().unwrap_or_default(),
descriptor.parent.label.clone(),
)
}
@ -892,8 +962,8 @@ impl GPUDeviceMethods for GPUDevice {
fn CreateRenderPipeline(
&self,
descriptor: &GPURenderPipelineDescriptor,
) -> DomRoot<GPURenderPipeline> {
let (implicit_ids, desc) = self.parse_render_pipeline(&descriptor);
) -> Fallible<DomRoot<GPURenderPipeline>> {
let (implicit_ids, desc) = self.parse_render_pipeline(&descriptor)?;
let render_pipeline_id = self
.global()
@ -913,12 +983,12 @@ impl GPUDeviceMethods for GPUDevice {
let render_pipeline = webgpu::WebGPURenderPipeline(render_pipeline_id);
GPURenderPipeline::new(
Ok(GPURenderPipeline::new(
&self.global(),
render_pipeline,
descriptor.parent.parent.label.clone().unwrap_or_default(),
descriptor.parent.parent.label.clone(),
self,
)
))
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderpipelineasync>
@ -926,10 +996,10 @@ impl GPUDeviceMethods for GPUDevice {
&self,
descriptor: &GPURenderPipelineDescriptor,
comp: InRealm,
) -> Rc<Promise> {
let promise = Promise::new_in_current_realm(comp);
let (implicit_ids, desc) = self.parse_render_pipeline(&descriptor);
) -> Fallible<Rc<Promise>> {
let (implicit_ids, desc) = self.parse_render_pipeline(&descriptor)?;
let promise = Promise::new_in_current_realm(comp);
let sender = response_async(&promise, self);
let render_pipeline_id = self
@ -948,14 +1018,14 @@ impl GPUDeviceMethods for GPUDevice {
})
.expect("Failed to create WebGPU render pipeline");
promise
Ok(promise)
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderbundleencoder>
fn CreateRenderBundleEncoder(
&self,
descriptor: &GPURenderBundleEncoderDescriptor,
) -> DomRoot<GPURenderBundleEncoder> {
) -> Fallible<DomRoot<GPURenderBundleEncoder>> {
let desc = wgpu_com::RenderBundleEncoderDescriptor {
label: convert_label(&descriptor.parent.parent),
color_formats: Cow::Owned(
@ -963,16 +1033,24 @@ impl GPUDeviceMethods for GPUDevice {
.parent
.colorFormats
.iter()
.map(|f| Some(convert_texture_format(*f)))
.collect::<Vec<_>>(),
.map(|format| {
self.validate_texture_format_required_features(format)
.map(|f| Some(f))
})
.collect::<Fallible<Vec<_>>>()?,
),
depth_stencil: descriptor.parent.depthStencilFormat.map(|dsf| {
wgt::RenderBundleDepthStencil {
format: convert_texture_format(dsf),
depth_read_only: descriptor.depthReadOnly,
stencil_read_only: descriptor.stencilReadOnly,
}
}),
depth_stencil: descriptor
.parent
.depthStencilFormat
.map(|dsf| {
self.validate_texture_format_required_features(&dsf)
.map(|format| wgt::RenderBundleDepthStencil {
format,
depth_read_only: descriptor.depthReadOnly,
stencil_read_only: descriptor.stencilReadOnly,
})
})
.transpose()?,
sample_count: descriptor.parent.sampleCount,
multiview: None,
};
@ -981,13 +1059,13 @@ impl GPUDeviceMethods for GPUDevice {
let render_bundle_encoder =
wgpu_com::RenderBundleEncoder::new(&desc, self.device.0, None).unwrap();
GPURenderBundleEncoder::new(
Ok(GPURenderBundleEncoder::new(
&self.global(),
render_bundle_encoder,
self,
self.channel.clone(),
descriptor.parent.parent.label.clone().unwrap_or_default(),
)
descriptor.parent.parent.label.clone(),
))
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-pusherrorscope>