Skip to content

Commit 334170b

Browse files
Block creating mesh shader pipelines when the feature is not available (#8298)
1 parent b3c6a0b commit 334170b

File tree

3 files changed

+96
-17
lines changed

3 files changed

+96
-17
lines changed

tests/tests/wgpu-gpu/mesh_shader/mod.rs

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ use std::{
33
process::Stdio,
44
};
55

6-
use wgpu::util::DeviceExt;
6+
use wgpu::{util::DeviceExt, Backends};
77
use wgpu_test::{
8-
gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters, TestingContext,
8+
fail, gpu_test, FailureCase, GpuTestConfiguration, GpuTestInitializer, TestParameters,
9+
TestingContext,
910
};
1011

12+
/// Backends that support mesh shaders
13+
const MESH_SHADER_BACKENDS: Backends = Backends::DX12.union(Backends::VULKAN);
14+
1115
pub fn all_tests(tests: &mut Vec<GpuTestInitializer>) {
1216
tests.extend([
1317
MESH_PIPELINE_BASIC_MESH,
@@ -19,6 +23,7 @@ pub fn all_tests(tests: &mut Vec<GpuTestInitializer>) {
1923
MESH_MULTI_DRAW_INDIRECT_COUNT,
2024
MESH_PIPELINE_BASIC_MESH_NO_DRAW,
2125
MESH_PIPELINE_BASIC_TASK_MESH_FRAG_NO_DRAW,
26+
MESH_DISABLED,
2227
]);
2328
}
2429

@@ -97,21 +102,44 @@ fn get_shaders(
97102
device: &wgpu::Device,
98103
backend: wgpu::Backend,
99104
test_name: &str,
100-
) -> (wgpu::ShaderModule, wgpu::ShaderModule, wgpu::ShaderModule) {
105+
info: &MeshPipelineTestInfo,
106+
) -> (
107+
Option<wgpu::ShaderModule>,
108+
wgpu::ShaderModule,
109+
Option<wgpu::ShaderModule>,
110+
) {
111+
// On backends that don't support mesh shaders, or for the MESH_DISABLED
112+
// test, compile a dummy shader so we can construct a structurally valid
113+
// pipeline description and test that `create_mesh_pipeline` fails.
114+
// (In the case that the platform does support mesh shaders, the dummy
115+
// shader is used to avoid requiring EXPERIMENTAL_PASSTHROUGH_SHADERS.)
116+
let dummy_shader = device.create_shader_module(wgpu::include_wgsl!("non_mesh.wgsl"));
101117
if backend == wgpu::Backend::Vulkan {
102118
(
103-
compile_glsl(device, "task"),
104-
compile_glsl(device, "mesh"),
105-
compile_glsl(device, "frag"),
119+
info.use_task.then(|| compile_glsl(device, "task")),
120+
if info.use_mesh {
121+
compile_glsl(device, "mesh")
122+
} else {
123+
dummy_shader
124+
},
125+
info.use_frag.then(|| compile_glsl(device, "frag")),
106126
)
107127
} else if backend == wgpu::Backend::Dx12 {
108128
(
109-
compile_hlsl(device, "Task", "as", test_name),
110-
compile_hlsl(device, "Mesh", "ms", test_name),
111-
compile_hlsl(device, "Frag", "ps", test_name),
129+
info.use_task
130+
.then(|| compile_hlsl(device, "Task", "as", test_name)),
131+
if info.use_mesh {
132+
compile_hlsl(device, "Mesh", "ms", test_name)
133+
} else {
134+
dummy_shader
135+
},
136+
info.use_frag
137+
.then(|| compile_hlsl(device, "Frag", "ps", test_name)),
112138
)
113139
} else {
114-
unreachable!()
140+
assert!(!MESH_SHADER_BACKENDS.contains(Backends::from(backend)));
141+
assert!(!info.use_task && !info.use_mesh && !info.use_frag);
142+
(None, dummy_shader, None)
115143
}
116144
}
117145

@@ -146,6 +174,7 @@ fn create_depth(
146174

147175
struct MeshPipelineTestInfo {
148176
use_task: bool,
177+
use_mesh: bool,
149178
use_frag: bool,
150179
draw: bool,
151180
}
@@ -158,16 +187,11 @@ fn hash_testing_context(ctx: &TestingContext) -> u64 {
158187

159188
fn mesh_pipeline_build(ctx: &TestingContext, info: MeshPipelineTestInfo) {
160189
let backend = ctx.adapter.get_info().backend;
161-
if backend != wgpu::Backend::Vulkan && backend != wgpu::Backend::Dx12 {
162-
return;
163-
}
164190
let device = &ctx.device;
165191
let (_depth_image, depth_view, depth_state) = create_depth(device);
166192

167193
let test_hash = hash_testing_context(ctx).to_string();
168-
let (task, mesh, frag) = get_shaders(device, backend, &test_hash);
169-
let task = if info.use_task { Some(task) } else { None };
170-
let frag = if info.use_frag { Some(frag) } else { None };
194+
let (task, mesh, frag) = get_shaders(device, backend, &test_hash, &info);
171195
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
172196
label: None,
173197
bind_group_layouts: &[],
@@ -246,7 +270,15 @@ fn mesh_draw(ctx: &TestingContext, draw_type: DrawType) {
246270
let device = &ctx.device;
247271
let (_depth_image, depth_view, depth_state) = create_depth(device);
248272
let test_hash = hash_testing_context(ctx).to_string();
249-
let (task, mesh, frag) = get_shaders(device, backend, &test_hash);
273+
let info = MeshPipelineTestInfo {
274+
use_task: true,
275+
use_mesh: true,
276+
use_frag: true,
277+
draw: true,
278+
};
279+
let (task, mesh, frag) = get_shaders(device, backend, &test_hash, &info);
280+
let task = task.unwrap();
281+
let frag = frag.unwrap();
250282
let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
251283
label: None,
252284
bind_group_layouts: &[],
@@ -343,6 +375,7 @@ fn mesh_draw(ctx: &TestingContext, draw_type: DrawType) {
343375
fn default_gpu_test_config(draw_type: DrawType) -> GpuTestConfiguration {
344376
GpuTestConfiguration::new().parameters(
345377
TestParameters::default()
378+
.skip(FailureCase::backend(!MESH_SHADER_BACKENDS))
346379
.test_features_limits()
347380
.features(
348381
wgpu::Features::EXPERIMENTAL_MESH_SHADER
@@ -365,6 +398,7 @@ pub static MESH_PIPELINE_BASIC_MESH: GpuTestConfiguration =
365398
&ctx,
366399
MeshPipelineTestInfo {
367400
use_task: false,
401+
use_mesh: true,
368402
use_frag: false,
369403
draw: true,
370404
},
@@ -377,6 +411,7 @@ pub static MESH_PIPELINE_BASIC_TASK_MESH: GpuTestConfiguration =
377411
&ctx,
378412
MeshPipelineTestInfo {
379413
use_task: true,
414+
use_mesh: true,
380415
use_frag: false,
381416
draw: true,
382417
},
@@ -389,6 +424,7 @@ pub static MESH_PIPELINE_BASIC_MESH_FRAG: GpuTestConfiguration =
389424
&ctx,
390425
MeshPipelineTestInfo {
391426
use_task: false,
427+
use_mesh: true,
392428
use_frag: true,
393429
draw: true,
394430
},
@@ -401,6 +437,7 @@ pub static MESH_PIPELINE_BASIC_TASK_MESH_FRAG: GpuTestConfiguration =
401437
&ctx,
402438
MeshPipelineTestInfo {
403439
use_task: true,
440+
use_mesh: true,
404441
use_frag: true,
405442
draw: true,
406443
},
@@ -413,6 +450,7 @@ pub static MESH_PIPELINE_BASIC_MESH_NO_DRAW: GpuTestConfiguration =
413450
&ctx,
414451
MeshPipelineTestInfo {
415452
use_task: false,
453+
use_mesh: true,
416454
use_frag: false,
417455
draw: false,
418456
},
@@ -425,6 +463,7 @@ pub static MESH_PIPELINE_BASIC_TASK_MESH_FRAG_NO_DRAW: GpuTestConfiguration =
425463
&ctx,
426464
MeshPipelineTestInfo {
427465
use_task: true,
466+
use_mesh: true,
428467
use_frag: true,
429468
draw: false,
430469
},
@@ -447,3 +486,30 @@ pub static MESH_MULTI_DRAW_INDIRECT_COUNT: GpuTestConfiguration =
447486
default_gpu_test_config(DrawType::MultiIndirectCount).run_sync(|ctx| {
448487
mesh_draw(&ctx, DrawType::MultiIndirectCount);
449488
});
489+
490+
/// When the mesh shading feature is disabled, calls to `create_mesh_pipeline`
491+
/// should be rejected. This should be the case on all backends, not just the
492+
/// ones where the feature could be turned on.
493+
#[gpu_test]
494+
pub static MESH_DISABLED: GpuTestConfiguration = GpuTestConfiguration::new().run_sync(|ctx| {
495+
fail(
496+
&ctx.device,
497+
|| {
498+
mesh_pipeline_build(
499+
&ctx,
500+
MeshPipelineTestInfo {
501+
use_task: false,
502+
use_mesh: false,
503+
use_frag: false,
504+
draw: true,
505+
},
506+
);
507+
},
508+
Some(concat![
509+
"Features Features { ",
510+
"features_wgpu: FeaturesWGPU(EXPERIMENTAL_MESH_SHADER), ",
511+
"features_webgpu: FeaturesWebGPU(0x0) ",
512+
"} are required but not enabled on the device",
513+
]),
514+
)
515+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
@vertex
2+
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
3+
let x = f32(i32(in_vertex_index) - 1);
4+
let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
5+
return vec4<f32>(x, y, 0.0, 1.0);
6+
}
7+
8+
@fragment
9+
fn fs_main() -> @location(0) vec4<f32> {
10+
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
11+
}

wgpu-core/src/device/resource.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4063,6 +4063,8 @@ impl Device {
40634063
};
40644064
}
40654065
pipeline::RenderPipelineVertexProcessor::Mesh(ref task, ref mesh) => {
4066+
self.require_features(wgt::Features::EXPERIMENTAL_MESH_SHADER)?;
4067+
40664068
task_stage = if let Some(task) = task {
40674069
let stage_desc = &task.stage;
40684070
let stage = wgt::ShaderStages::TASK;

0 commit comments

Comments
 (0)