Skip to content

Commit 73021e2

Browse files
sagudevGae24
authored andcommitted
webgpu: Use wgpu's instead of string errors and update limits handling (servo#32925)
* Use wgpu specific errors Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixup expect Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * WIP Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Fix records erasing enforcerange Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * page can already be destroyed Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Support more limits Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Set good results Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Set OK (not PASS) expect CRASH Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixup expectation Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * bad expectations gfx-rs/wgpu#6075 Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * set bad expectation render bundleencoder needs to be rewritten Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
1 parent 1d55b93 commit 73021e2

File tree

8 files changed

+496
-871
lines changed

8 files changed

+496
-871
lines changed

components/script/dom/bindings/codegen/CodegenRust.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ def wrapObjectTemplate(templateBody, nullValue, isDefinitelyObject, type,
718718
isMember="Sequence",
719719
isAutoRooted=isAutoRooted)
720720
declType = wrapInNativeContainerType(type, innerInfo.declType)
721-
config = getConversionConfigForType(type, isEnforceRange, isClamp, treatNullAs)
721+
config = getConversionConfigForType(type, innerContainerType(type).hasEnforceRange(), isClamp, treatNullAs)
722722

723723
if type.nullable():
724724
declType = CGWrapper(declType, pre="Option<", post=" >")

components/script/dom/gpuadapter.rs

Lines changed: 34 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
44

5-
use std::convert::TryFrom;
65
use std::rc::Rc;
76

87
use dom_struct::dom_struct;
98
use js::jsapi::{Heap, JSObject};
9+
use webgpu::wgc::instance::RequestDeviceError;
1010
use webgpu::wgt::MemoryHints;
1111
use webgpu::{wgt, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse};
1212

13+
use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason;
1314
use super::gpusupportedfeatures::GPUSupportedFeatures;
15+
use super::gpusupportedlimits::set_limit;
1416
use super::types::{GPUAdapterInfo, GPUSupportedLimits};
1517
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
1618
GPUAdapterMethods, GPUDeviceDescriptor,
@@ -129,84 +131,10 @@ impl GPUAdapterMethods for GPUAdapter {
129131
};
130132
if let Some(limits) = &descriptor.requiredLimits {
131133
for (limit, value) in (*limits).iter() {
132-
let v = u32::try_from(*value).unwrap_or(u32::MAX);
133-
match limit.as_ref() {
134-
"maxTextureDimension1D" => desc.required_limits.max_texture_dimension_1d = v,
135-
"maxTextureDimension2D" => desc.required_limits.max_texture_dimension_2d = v,
136-
"maxTextureDimension3D" => desc.required_limits.max_texture_dimension_3d = v,
137-
"maxTextureArrayLayers" => desc.required_limits.max_texture_array_layers = v,
138-
"maxBindGroups" => desc.required_limits.max_bind_groups = v,
139-
"maxBindingsPerBindGroup" => {
140-
desc.required_limits.max_bindings_per_bind_group = v
141-
},
142-
"maxDynamicUniformBuffersPerPipelineLayout" => {
143-
desc.required_limits
144-
.max_dynamic_uniform_buffers_per_pipeline_layout = v
145-
},
146-
"maxDynamicStorageBuffersPerPipelineLayout" => {
147-
desc.required_limits
148-
.max_dynamic_storage_buffers_per_pipeline_layout = v
149-
},
150-
"maxSampledTexturesPerShaderStage" => {
151-
desc.required_limits.max_sampled_textures_per_shader_stage = v
152-
},
153-
"maxSamplersPerShaderStage" => {
154-
desc.required_limits.max_samplers_per_shader_stage = v
155-
},
156-
"maxStorageBuffersPerShaderStage" => {
157-
desc.required_limits.max_storage_buffers_per_shader_stage = v
158-
},
159-
"maxStorageTexturesPerShaderStage" => {
160-
desc.required_limits.max_storage_textures_per_shader_stage = v
161-
},
162-
"maxUniformBuffersPerShaderStage" => {
163-
desc.required_limits.max_uniform_buffers_per_shader_stage = v
164-
},
165-
"maxUniformBufferBindingSize" => {
166-
desc.required_limits.max_uniform_buffer_binding_size = v
167-
},
168-
"maxStorageBufferBindingSize" => {
169-
desc.required_limits.max_storage_buffer_binding_size = v
170-
},
171-
"minUniformBufferOffsetAlignment" => {
172-
desc.required_limits.min_uniform_buffer_offset_alignment = v
173-
},
174-
"minStorageBufferOffsetAlignment" => {
175-
desc.required_limits.min_storage_buffer_offset_alignment = v
176-
},
177-
"maxVertexBuffers" => desc.required_limits.max_vertex_buffers = v,
178-
"maxBufferSize" => desc.required_limits.max_buffer_size = *value,
179-
"maxVertexAttributes" => desc.required_limits.max_vertex_attributes = v,
180-
"maxVertexBufferArrayStride" => {
181-
desc.required_limits.max_vertex_buffer_array_stride = v
182-
},
183-
"maxInterStageShaderComponents" => {
184-
desc.required_limits.max_inter_stage_shader_components = v
185-
},
186-
"maxComputeWorkgroupStorageSize" => {
187-
desc.required_limits.max_compute_workgroup_storage_size = v
188-
},
189-
"maxComputeInvocationsPerWorkgroup" => {
190-
desc.required_limits.max_compute_invocations_per_workgroup = v
191-
},
192-
"maxComputeWorkgroupSizeX" => {
193-
desc.required_limits.max_compute_workgroup_size_x = v
194-
},
195-
"maxComputeWorkgroupSizeY" => {
196-
desc.required_limits.max_compute_workgroup_size_y = v
197-
},
198-
"maxComputeWorkgroupSizeZ" => {
199-
desc.required_limits.max_compute_workgroup_size_z = v
200-
},
201-
"maxComputeWorkgroupsPerDimension" => {
202-
desc.required_limits.max_compute_workgroups_per_dimension = v
203-
},
204-
_ => {
205-
error!("Unknown required limit: {limit} with value {value}");
206-
// we should reject but spec is still evolving
207-
// promise.reject_error(Error::Operation);
208-
// return promise;
209-
},
134+
if !set_limit(&mut desc.required_limits, limit.as_ref(), *value) {
135+
warn!("Unknown GPUDevice limit: {limit}");
136+
promise.reject_error(Error::Operation);
137+
return promise;
210138
}
211139
}
212140
}
@@ -267,25 +195,45 @@ impl GPUAdapterMethods for GPUAdapter {
267195
impl AsyncWGPUListener for GPUAdapter {
268196
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
269197
match response {
270-
WebGPUResponse::Device(Ok(device)) => {
271-
let descriptor = device.descriptor;
198+
WebGPUResponse::Device((device_id, queue_id, Ok(descriptor))) => {
272199
let device = GPUDevice::new(
273200
&self.global(),
274201
self.channel.clone(),
275202
self,
276203
Heap::default(),
277204
descriptor.required_features,
278205
descriptor.required_limits,
279-
device.device_id,
280-
device.queue_id,
206+
device_id,
207+
queue_id,
281208
descriptor.label.unwrap_or_default(),
282209
);
283210
self.global().add_gpu_device(&device);
284211
promise.resolve_native(&device);
285212
},
286-
WebGPUResponse::Device(Err(e)) => {
287-
warn!("Could not get GPUDevice({:?})", e);
288-
promise.reject_error(Error::Operation);
213+
WebGPUResponse::Device((_, _, Err(RequestDeviceError::UnsupportedFeature(f)))) => {
214+
promise.reject_error(Error::Type(
215+
RequestDeviceError::UnsupportedFeature(f).to_string(),
216+
))
217+
},
218+
WebGPUResponse::Device((
219+
_,
220+
_,
221+
Err(RequestDeviceError::LimitsExceeded(_) | RequestDeviceError::InvalidAdapter),
222+
)) => promise.reject_error(Error::Operation),
223+
WebGPUResponse::Device((device_id, queue_id, Err(e))) => {
224+
let device = GPUDevice::new(
225+
&self.global(),
226+
self.channel.clone(),
227+
self,
228+
Heap::default(),
229+
wgt::Features::default(),
230+
wgt::Limits::default(),
231+
device_id,
232+
queue_id,
233+
String::new(),
234+
);
235+
device.lose(GPUDeviceLostReason::Unknown, e.to_string());
236+
promise.resolve_native(&device);
289237
},
290238
WebGPUResponse::None => unreachable!("Failed to get a response for RequestDevice"),
291239
_ => unreachable!("GPUAdapter received wrong WebGPUResponse"),

components/script/dom/gpusupportedlimits.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
44

55
use dom_struct::dom_struct;
6+
use num_traits::bounds::UpperBounded;
67
use webgpu::wgt::Limits;
78
use GPUSupportedLimits_Binding::GPUSupportedLimitsMethods;
89

@@ -173,4 +174,144 @@ impl GPUSupportedLimitsMethods for GPUSupportedLimits {
173174
fn MaxComputeWorkgroupsPerDimension(&self) -> u32 {
174175
self.limits.max_compute_workgroups_per_dimension
175176
}
177+
178+
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxbindgroupsplusvertexbuffers>
179+
fn MaxBindGroupsPlusVertexBuffers(&self) -> u32 {
180+
// Not on wgpu yet, so we craft it manually
181+
self.limits.max_bind_groups + self.limits.max_vertex_buffers
182+
}
183+
184+
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxinterstageshadervariables>
185+
fn MaxInterStageShaderVariables(&self) -> u32 {
186+
// Not in wgpu yet, so we use default value from spec
187+
16
188+
}
189+
190+
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcolorattachments>
191+
fn MaxColorAttachments(&self) -> u32 {
192+
self.limits.max_color_attachments
193+
}
194+
195+
/// <https://gpuweb.github.io/gpuweb/#dom-gpusupportedlimits-maxcolorattachmentbytespersample>
196+
fn MaxColorAttachmentBytesPerSample(&self) -> u32 {
197+
self.limits.max_color_attachment_bytes_per_sample
198+
}
199+
}
200+
201+
/// Returns false if unknown limit or other value error
202+
pub fn set_limit(limits: &mut Limits, limit: &str, value: u64) -> bool {
203+
/// per spec defaults are lower bounds for values
204+
///
205+
/// https://www.w3.org/TR/webgpu/#limit-class-maximum
206+
fn set_maximum<T>(limit: &mut T, value: u64) -> bool
207+
where
208+
T: Ord + Copy + TryFrom<u64> + UpperBounded,
209+
{
210+
if let Ok(value) = T::try_from(value) {
211+
*limit = value.max(*limit);
212+
true
213+
} else {
214+
false
215+
}
216+
}
217+
218+
/// per spec defaults are higher bounds for values
219+
///
220+
/// <https://www.w3.org/TR/webgpu/#limit-class-alignment>
221+
fn set_alignment<T>(limit: &mut T, value: u64) -> bool
222+
where
223+
T: Ord + Copy + TryFrom<u64> + UpperBounded,
224+
{
225+
if !value.is_power_of_two() {
226+
return false;
227+
}
228+
if let Ok(value) = T::try_from(value) {
229+
*limit = value.min(*limit);
230+
true
231+
} else {
232+
false
233+
}
234+
}
235+
236+
match limit {
237+
"maxTextureDimension1D" => set_maximum(&mut limits.max_texture_dimension_1d, value),
238+
"maxTextureDimension2D" => set_maximum(&mut limits.max_texture_dimension_2d, value),
239+
"maxTextureDimension3D" => set_maximum(&mut limits.max_texture_dimension_3d, value),
240+
"maxTextureArrayLayers" => set_maximum(&mut limits.max_texture_array_layers, value),
241+
"maxBindGroups" => set_maximum(&mut limits.max_bind_groups, value),
242+
"maxBindGroupsPlusVertexBuffers" => {
243+
// not in wgpu but we're allowed to give back better limits than requested.
244+
// we use dummy value to still produce value verification
245+
let mut v: u32 = 0;
246+
set_maximum(&mut v, value)
247+
},
248+
"maxBindingsPerBindGroup" => set_maximum(&mut limits.max_bindings_per_bind_group, value),
249+
"maxDynamicUniformBuffersPerPipelineLayout" => set_maximum(
250+
&mut limits.max_dynamic_uniform_buffers_per_pipeline_layout,
251+
value,
252+
),
253+
"maxDynamicStorageBuffersPerPipelineLayout" => set_maximum(
254+
&mut limits.max_dynamic_storage_buffers_per_pipeline_layout,
255+
value,
256+
),
257+
"maxSampledTexturesPerShaderStage" => {
258+
set_maximum(&mut limits.max_sampled_textures_per_shader_stage, value)
259+
},
260+
"maxSamplersPerShaderStage" => {
261+
set_maximum(&mut limits.max_samplers_per_shader_stage, value)
262+
},
263+
"maxStorageBuffersPerShaderStage" => {
264+
set_maximum(&mut limits.max_storage_buffers_per_shader_stage, value)
265+
},
266+
"maxStorageTexturesPerShaderStage" => {
267+
set_maximum(&mut limits.max_storage_textures_per_shader_stage, value)
268+
},
269+
"maxUniformBuffersPerShaderStage" => {
270+
set_maximum(&mut limits.max_uniform_buffers_per_shader_stage, value)
271+
},
272+
"maxUniformBufferBindingSize" => {
273+
set_maximum(&mut limits.max_uniform_buffer_binding_size, value)
274+
},
275+
"maxStorageBufferBindingSize" => {
276+
set_maximum(&mut limits.max_storage_buffer_binding_size, value)
277+
},
278+
"minUniformBufferOffsetAlignment" => {
279+
set_alignment(&mut limits.min_uniform_buffer_offset_alignment, value)
280+
},
281+
"minStorageBufferOffsetAlignment" => {
282+
set_alignment(&mut limits.min_storage_buffer_offset_alignment, value)
283+
},
284+
"maxVertexBuffers" => set_maximum(&mut limits.max_vertex_buffers, value),
285+
"maxBufferSize" => set_maximum(&mut limits.max_buffer_size, value),
286+
"maxVertexAttributes" => set_maximum(&mut limits.max_vertex_attributes, value),
287+
"maxVertexBufferArrayStride" => {
288+
set_maximum(&mut limits.max_vertex_buffer_array_stride, value)
289+
},
290+
"maxInterStageShaderComponents" => {
291+
set_maximum(&mut limits.max_inter_stage_shader_components, value)
292+
},
293+
"maxInterStageShaderVariables" => {
294+
// not in wgpu but we're allowed to give back better limits than requested.
295+
// we use dummy value to still produce value verification
296+
let mut v: u32 = 0;
297+
set_maximum(&mut v, value)
298+
},
299+
"maxColorAttachments" => set_maximum(&mut limits.max_color_attachments, value),
300+
"maxColorAttachmentBytesPerSample" => {
301+
set_maximum(&mut limits.max_color_attachment_bytes_per_sample, value)
302+
},
303+
"maxComputeWorkgroupStorageSize" => {
304+
set_maximum(&mut limits.max_compute_workgroup_storage_size, value)
305+
},
306+
"maxComputeInvocationsPerWorkgroup" => {
307+
set_maximum(&mut limits.max_compute_invocations_per_workgroup, value)
308+
},
309+
"maxComputeWorkgroupSizeX" => set_maximum(&mut limits.max_compute_workgroup_size_x, value),
310+
"maxComputeWorkgroupSizeY" => set_maximum(&mut limits.max_compute_workgroup_size_y, value),
311+
"maxComputeWorkgroupSizeZ" => set_maximum(&mut limits.max_compute_workgroup_size_z, value),
312+
"maxComputeWorkgroupsPerDimension" => {
313+
set_maximum(&mut limits.max_compute_workgroups_per_dimension, value)
314+
},
315+
_ => false,
316+
}
176317
}

components/script/dom/webidls/WebGPU.webidl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ interface GPUSupportedLimits {
2121
readonly attribute unsigned long maxTextureDimension3D;
2222
readonly attribute unsigned long maxTextureArrayLayers;
2323
readonly attribute unsigned long maxBindGroups;
24-
//readonly attribute unsigned long maxBindGroupsPlusVertexBuffers;
24+
readonly attribute unsigned long maxBindGroupsPlusVertexBuffers;
2525
readonly attribute unsigned long maxBindingsPerBindGroup;
2626
readonly attribute unsigned long maxDynamicUniformBuffersPerPipelineLayout;
2727
readonly attribute unsigned long maxDynamicStorageBuffersPerPipelineLayout;
@@ -39,9 +39,9 @@ interface GPUSupportedLimits {
3939
readonly attribute unsigned long maxVertexAttributes;
4040
readonly attribute unsigned long maxVertexBufferArrayStride;
4141
readonly attribute unsigned long maxInterStageShaderComponents;
42-
//readonly attribute unsigned long maxInterStageShaderVariables;
43-
//readonly attribute unsigned long maxColorAttachments;
44-
//readonly attribute unsigned long maxColorAttachmentBytesPerSample;
42+
readonly attribute unsigned long maxInterStageShaderVariables;
43+
readonly attribute unsigned long maxColorAttachments;
44+
readonly attribute unsigned long maxColorAttachmentBytesPerSample;
4545
readonly attribute unsigned long maxComputeWorkgroupStorageSize;
4646
readonly attribute unsigned long maxComputeInvocationsPerWorkgroup;
4747
readonly attribute unsigned long maxComputeWorkgroupSizeX;

components/script/script_thread.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,8 +2427,9 @@ impl ScriptThread {
24272427
pipeline_id,
24282428
} => {
24292429
self.gpu_id_hub.free_device_id(device_id);
2430-
let global = self.documents.borrow().find_global(pipeline_id).unwrap();
2431-
global.remove_gpu_device(WebGPUDevice(device_id));
2430+
if let Some(global) = self.documents.borrow().find_global(pipeline_id) {
2431+
global.remove_gpu_device(WebGPUDevice(device_id));
2432+
} // page can already be destroyed
24322433
},
24332434
WebGPUMsg::FreeBuffer(id) => self.gpu_id_hub.free_buffer_id(id),
24342435
WebGPUMsg::FreePipelineLayout(id) => self.gpu_id_hub.free_pipeline_layout_id(id),

components/webgpu/ipc_messages/to_dom.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use ipc_channel::ipc::IpcSharedMemory;
88
use serde::{Deserialize, Serialize};
99
use wgc::pipeline::CreateShaderModuleError;
10+
use wgpu_core::instance::{RequestAdapterError, RequestDeviceError};
11+
use wgpu_core::resource::BufferAccessError;
1012
pub use {wgpu_core as wgc, wgpu_types as wgt};
1113

1214
use crate::identity::*;
@@ -63,22 +65,20 @@ pub struct Adapter {
6365
pub channel: WebGPU,
6466
}
6567

66-
#[derive(Debug, Deserialize, Serialize)]
67-
pub struct Device {
68-
pub device_id: WebGPUDevice,
69-
pub queue_id: WebGPUQueue,
70-
pub descriptor: wgt::DeviceDescriptor<Option<String>>,
71-
}
72-
7368
#[derive(Debug, Deserialize, Serialize)]
7469
#[allow(clippy::large_enum_variant)]
7570
pub enum WebGPUResponse {
7671
/// WebGPU is disabled
7772
None,
78-
// TODO: use wgpu errors
79-
Adapter(Result<Adapter, String>),
80-
Device(Result<Device, String>),
81-
BufferMapAsync(Result<IpcSharedMemory, String>),
73+
Adapter(Result<Adapter, RequestAdapterError>),
74+
Device(
75+
(
76+
WebGPUDevice,
77+
WebGPUQueue,
78+
Result<wgt::DeviceDescriptor<Option<String>>, RequestDeviceError>,
79+
),
80+
),
81+
BufferMapAsync(Result<IpcSharedMemory, BufferAccessError>),
8282
SubmittedWorkDone,
8383
PoppedErrorScope(Result<Option<Error>, PopError>),
8484
CompilationInfo(Option<ShaderCompilationInfo>),

0 commit comments

Comments
 (0)