mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-06-01 09:09:48 +09:00
test: Additional "life cycle" tests
This commit is contained in:
committed by
Teodor Tanasoaia
parent
fc1aa76bad
commit
8f4def424a
@@ -1,5 +1,7 @@
|
||||
use wgpu::util::DeviceExt;
|
||||
use wgpu_test::{fail, gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters};
|
||||
use wgpu_test::{
|
||||
fail, gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters, TestingContext,
|
||||
};
|
||||
|
||||
pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
|
||||
vec.extend([
|
||||
@@ -7,6 +9,8 @@ pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
|
||||
TEXTURE_DESTROY,
|
||||
BUFFER_DESTROY_BEFORE_SUBMIT,
|
||||
TEXTURE_DESTROY_BEFORE_SUBMIT,
|
||||
EXTERNAL_TEXTURE_DESTROY_BEFORE_SUBMIT,
|
||||
REPLACED_BIND_GROUP,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -126,12 +130,195 @@ static TEXTURE_DESTROY: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
texture.destroy();
|
||||
});
|
||||
|
||||
// Test that destroying a buffer between command buffer recording and
|
||||
// submission fails gracefully.
|
||||
#[gpu_test]
|
||||
static BUFFER_DESTROY_BEFORE_SUBMIT: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(TestParameters::default().enable_noop())
|
||||
.run_sync(|ctx| {
|
||||
#[derive(Copy, Clone)]
|
||||
enum UsageKind {
|
||||
Direct,
|
||||
RenderPass,
|
||||
ComputePass,
|
||||
RenderBundle,
|
||||
}
|
||||
|
||||
const BUFFER_RENDER_SHADER: &str = "\
|
||||
@group(0) @binding(0) var<uniform> buf: vec4<f32>;
|
||||
@vertex fn vs() -> @builtin(position) vec4<f32> { return buf; }
|
||||
@fragment fn fs() -> @location(0) vec4<f32> { return vec4<f32>(0); }";
|
||||
|
||||
const BUFFER_COMPUTE_SHADER: &str = "\
|
||||
@group(0) @binding(0) var<uniform> buf: vec4<f32>;
|
||||
@compute @workgroup_size(1) fn main() { _ = buf; }";
|
||||
|
||||
const TEXTURE_RENDER_SHADER: &str = "\
|
||||
@group(0) @binding(0) var tex: texture_2d<f32>;
|
||||
@vertex fn vs() -> @builtin(position) vec4<f32> { return vec4<f32>(0); }
|
||||
@fragment fn fs() -> @location(0) vec4<f32> { return textureLoad(tex, vec2(0), 0); }";
|
||||
|
||||
const TEXTURE_COMPUTE_SHADER: &str = "\
|
||||
@group(0) @binding(0) var tex: texture_2d<f32>;
|
||||
@compute @workgroup_size(1) fn main() { _ = textureLoad(tex, vec2(0), 0); }";
|
||||
|
||||
const EXTERNAL_TEXTURE_RENDER_SHADER: &str = "\
|
||||
@group(0) @binding(0) var tex: texture_external;
|
||||
@vertex fn vs() -> @builtin(position) vec4<f32> { return vec4<f32>(0); }
|
||||
@fragment fn fs() -> @location(0) vec4<f32> { return textureLoad(tex, vec2(0)); }";
|
||||
|
||||
const EXTERNAL_TEXTURE_COMPUTE_SHADER: &str = "\
|
||||
@group(0) @binding(0) var tex: texture_external;
|
||||
@compute @workgroup_size(1) fn main() { _ = textureLoad(tex, vec2(0)); }";
|
||||
|
||||
fn create_render_target(device: &wgpu::Device) -> (wgpu::Texture, wgpu::TextureView) {
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
view_formats: &[],
|
||||
});
|
||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
(texture, view)
|
||||
}
|
||||
|
||||
fn create_render_pipeline(device: &wgpu::Device, shader_src: &str) -> wgpu::RenderPipeline {
|
||||
let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Wgsl(shader_src.into()),
|
||||
});
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
layout: None,
|
||||
vertex: wgpu::VertexState {
|
||||
module: &module,
|
||||
entry_point: None,
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &module,
|
||||
entry_point: None,
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn create_compute_pipeline(device: &wgpu::Device, shader_src: &str) -> wgpu::ComputePipeline {
|
||||
let module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Wgsl(shader_src.into()),
|
||||
});
|
||||
device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
|
||||
label: None,
|
||||
layout: None,
|
||||
module: &module,
|
||||
entry_point: None,
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
cache: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Records a bind group usage into an encoder and returns the encoder.
|
||||
fn record_encoder_with_resource(
|
||||
ctx: &TestingContext,
|
||||
usage: UsageKind,
|
||||
resource: wgpu::BindingResource<'_>,
|
||||
render_shader: &str,
|
||||
compute_shader: &str,
|
||||
) -> wgpu::CommandEncoder {
|
||||
let (_render_target, rt_view) = create_render_target(&ctx.device);
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||
|
||||
match usage {
|
||||
UsageKind::Direct => unreachable!(),
|
||||
UsageKind::RenderPass | UsageKind::RenderBundle => {
|
||||
let pipeline = create_render_pipeline(&ctx.device, render_shader);
|
||||
let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &pipeline.get_bind_group_layout(0),
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource,
|
||||
}],
|
||||
});
|
||||
|
||||
let color_attachment = [Some(wgpu::RenderPassColorAttachment {
|
||||
view: &rt_view,
|
||||
depth_slice: None,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})];
|
||||
|
||||
if matches!(usage, UsageKind::RenderPass) {
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &color_attachment,
|
||||
..Default::default()
|
||||
});
|
||||
pass.set_pipeline(&pipeline);
|
||||
pass.set_bind_group(0, &bind_group, &[]);
|
||||
pass.draw(0..0, 0..0);
|
||||
} else {
|
||||
let mut rbe =
|
||||
ctx.device
|
||||
.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
|
||||
label: None,
|
||||
color_formats: &[Some(wgpu::TextureFormat::Rgba8Unorm)],
|
||||
depth_stencil: None,
|
||||
sample_count: 1,
|
||||
multiview: None,
|
||||
});
|
||||
rbe.set_pipeline(&pipeline);
|
||||
rbe.set_bind_group(0, &bind_group, &[]);
|
||||
rbe.draw(0..0, 0..0);
|
||||
let bundle = rbe.finish(&wgpu::RenderBundleDescriptor::default());
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &color_attachment,
|
||||
..Default::default()
|
||||
});
|
||||
pass.execute_bundles([&bundle]);
|
||||
}
|
||||
}
|
||||
UsageKind::ComputePass => {
|
||||
let pipeline = create_compute_pipeline(&ctx.device, compute_shader);
|
||||
let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &pipeline.get_bind_group_layout(0),
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource,
|
||||
}],
|
||||
});
|
||||
|
||||
let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default());
|
||||
pass.set_pipeline(&pipeline);
|
||||
pass.set_bind_group(0, &bind_group, &[]);
|
||||
pass.dispatch_workgroups(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
encoder
|
||||
}
|
||||
|
||||
fn test_buffer_destroy_before_submit(ctx: &TestingContext, usage: UsageKind) {
|
||||
if matches!(usage, UsageKind::Direct) {
|
||||
let buffer_source = ctx
|
||||
.device
|
||||
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
@@ -154,21 +341,55 @@ static BUFFER_DESTROY_BEFORE_SUBMIT: GpuTestConfiguration = GpuTestConfiguration
|
||||
buffer_source.destroy();
|
||||
buffer_dest.destroy();
|
||||
|
||||
let cmd_buffer = encoder.finish();
|
||||
|
||||
fail(
|
||||
&ctx.device,
|
||||
|| ctx.queue.submit([cmd_buffer]),
|
||||
|| ctx.queue.submit([encoder.finish()]),
|
||||
Some("Buffer with '' label has been destroyed"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 16,
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
// Test that destroying a texture between command buffer recording and
|
||||
// submission fails gracefully.
|
||||
let encoder = record_encoder_with_resource(
|
||||
ctx,
|
||||
usage,
|
||||
buffer.as_entire_binding(),
|
||||
BUFFER_RENDER_SHADER,
|
||||
BUFFER_COMPUTE_SHADER,
|
||||
);
|
||||
|
||||
buffer.destroy();
|
||||
|
||||
fail(
|
||||
&ctx.device,
|
||||
|| ctx.queue.submit([encoder.finish()]),
|
||||
Some("Buffer with '' label has been destroyed"),
|
||||
);
|
||||
}
|
||||
|
||||
// Test that destroying a buffer between command encoding and submission fails gracefully.
|
||||
#[gpu_test]
|
||||
static TEXTURE_DESTROY_BEFORE_SUBMIT: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(TestParameters::default().enable_noop())
|
||||
static BUFFER_DESTROY_BEFORE_SUBMIT: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(
|
||||
TestParameters::default()
|
||||
.test_features_limits()
|
||||
.enable_noop(),
|
||||
)
|
||||
.run_sync(|ctx| {
|
||||
test_buffer_destroy_before_submit(&ctx, UsageKind::Direct);
|
||||
test_buffer_destroy_before_submit(&ctx, UsageKind::RenderPass);
|
||||
test_buffer_destroy_before_submit(&ctx, UsageKind::ComputePass);
|
||||
test_buffer_destroy_before_submit(&ctx, UsageKind::RenderBundle);
|
||||
});
|
||||
|
||||
fn test_texture_destroy_before_submit(ctx: &TestingContext, usage: UsageKind) {
|
||||
if matches!(usage, UsageKind::Direct) {
|
||||
let descriptor = wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
@@ -177,12 +398,10 @@ static TEXTURE_DESTROY_BEFORE_SUBMIT: GpuTestConfiguration = GpuTestConfiguratio
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1, // multisampling is not supported for clear
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Snorm,
|
||||
usage: wgpu::TextureUsages::COPY_DST
|
||||
| wgpu::TextureUsages::COPY_SRC
|
||||
| wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
};
|
||||
|
||||
@@ -215,11 +434,262 @@ static TEXTURE_DESTROY_BEFORE_SUBMIT: GpuTestConfiguration = GpuTestConfiguratio
|
||||
texture_1.destroy();
|
||||
texture_2.destroy();
|
||||
|
||||
let cmd_buffer = encoder.finish();
|
||||
|
||||
fail(
|
||||
&ctx.device,
|
||||
|| ctx.queue.submit([cmd_buffer]),
|
||||
|| ctx.queue.submit([encoder.finish()]),
|
||||
Some("Texture with '' label has been destroyed"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
});
|
||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let encoder = record_encoder_with_resource(
|
||||
ctx,
|
||||
usage,
|
||||
wgpu::BindingResource::TextureView(&view),
|
||||
TEXTURE_RENDER_SHADER,
|
||||
TEXTURE_COMPUTE_SHADER,
|
||||
);
|
||||
|
||||
texture.destroy();
|
||||
|
||||
fail(
|
||||
&ctx.device,
|
||||
|| ctx.queue.submit([encoder.finish()]),
|
||||
Some("Texture with '' label has been destroyed"),
|
||||
);
|
||||
}
|
||||
|
||||
// Test that destroying a texture between command encoding and submission fails gracefully.
|
||||
#[gpu_test]
|
||||
static TEXTURE_DESTROY_BEFORE_SUBMIT: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(
|
||||
TestParameters::default()
|
||||
.test_features_limits()
|
||||
.enable_noop()
|
||||
.features(wgpu::Features::CLEAR_TEXTURE),
|
||||
)
|
||||
.run_sync(|ctx| {
|
||||
test_texture_destroy_before_submit(&ctx, UsageKind::Direct);
|
||||
test_texture_destroy_before_submit(&ctx, UsageKind::RenderPass);
|
||||
test_texture_destroy_before_submit(&ctx, UsageKind::ComputePass);
|
||||
test_texture_destroy_before_submit(&ctx, UsageKind::RenderBundle);
|
||||
});
|
||||
|
||||
fn test_external_texture_destroy_before_submit(ctx: &TestingContext, usage: UsageKind) {
|
||||
let plane_texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
});
|
||||
|
||||
let external_texture = ctx.device.create_external_texture(
|
||||
&wgpu::ExternalTextureDescriptor {
|
||||
label: None,
|
||||
width: 1,
|
||||
height: 1,
|
||||
format: wgpu::ExternalTextureFormat::Rgba,
|
||||
yuv_conversion_matrix: [0.0; 16],
|
||||
gamut_conversion_matrix: [0.0; 9],
|
||||
src_transfer_function: Default::default(),
|
||||
dst_transfer_function: Default::default(),
|
||||
sample_transform: [0.0; 6],
|
||||
load_transform: [0.0; 6],
|
||||
},
|
||||
&[&plane_texture.create_view(&wgpu::TextureViewDescriptor::default())],
|
||||
);
|
||||
|
||||
let encoder = record_encoder_with_resource(
|
||||
ctx,
|
||||
usage,
|
||||
wgpu::BindingResource::ExternalTexture(&external_texture),
|
||||
EXTERNAL_TEXTURE_RENDER_SHADER,
|
||||
EXTERNAL_TEXTURE_COMPUTE_SHADER,
|
||||
);
|
||||
|
||||
plane_texture.destroy();
|
||||
external_texture.destroy();
|
||||
|
||||
// External textures use a buffer and several textures internally. We consider which one
|
||||
// triggers the error to be an implementation detail and match either.
|
||||
fail(
|
||||
&ctx.device,
|
||||
|| ctx.queue.submit([encoder.finish()]),
|
||||
Some("with '' label has been destroyed"),
|
||||
);
|
||||
}
|
||||
|
||||
// Test that destroying an external texture between command encoding and submission fails
|
||||
// gracefully.
|
||||
#[gpu_test]
|
||||
static EXTERNAL_TEXTURE_DESTROY_BEFORE_SUBMIT: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(
|
||||
TestParameters::default()
|
||||
.test_features_limits()
|
||||
.enable_noop()
|
||||
.features(wgpu::Features::EXTERNAL_TEXTURE | wgpu::Features::CLEAR_TEXTURE),
|
||||
)
|
||||
.run_sync(|ctx| {
|
||||
// UsageKind::Direct does not apply because external textures only support TEXTURE_BINDING.
|
||||
test_external_texture_destroy_before_submit(&ctx, UsageKind::RenderPass);
|
||||
test_external_texture_destroy_before_submit(&ctx, UsageKind::ComputePass);
|
||||
test_external_texture_destroy_before_submit(&ctx, UsageKind::RenderBundle);
|
||||
});
|
||||
|
||||
fn test_replaced_bind_group(ctx: &TestingContext, usage: UsageKind) {
|
||||
let buffer_a = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 16,
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let buffer_b = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: 16,
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let (_render_target, rt_view) = create_render_target(&ctx.device);
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||
|
||||
match usage {
|
||||
UsageKind::RenderPass | UsageKind::RenderBundle => {
|
||||
let pipeline = create_render_pipeline(&ctx.device, BUFFER_RENDER_SHADER);
|
||||
let layout = pipeline.get_bind_group_layout(0);
|
||||
let bind_group_a = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer_a.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
let bind_group_b = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer_b.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
|
||||
let color_attachment = [Some(wgpu::RenderPassColorAttachment {
|
||||
view: &rt_view,
|
||||
depth_slice: None,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})];
|
||||
|
||||
if matches!(usage, UsageKind::RenderPass) {
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &color_attachment,
|
||||
..Default::default()
|
||||
});
|
||||
pass.set_pipeline(&pipeline);
|
||||
pass.set_bind_group(0, &bind_group_a, &[]);
|
||||
pass.set_bind_group(0, &bind_group_b, &[]);
|
||||
pass.draw(0..0, 0..0);
|
||||
} else {
|
||||
let mut rbe =
|
||||
ctx.device
|
||||
.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
|
||||
label: None,
|
||||
color_formats: &[Some(wgpu::TextureFormat::Rgba8Unorm)],
|
||||
depth_stencil: None,
|
||||
sample_count: 1,
|
||||
multiview: None,
|
||||
});
|
||||
rbe.set_pipeline(&pipeline);
|
||||
rbe.set_bind_group(0, &bind_group_a, &[]);
|
||||
rbe.set_bind_group(0, &bind_group_b, &[]);
|
||||
rbe.draw(0..0, 0..0);
|
||||
let bundle = rbe.finish(&wgpu::RenderBundleDescriptor::default());
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &color_attachment,
|
||||
..Default::default()
|
||||
});
|
||||
pass.execute_bundles([&bundle]);
|
||||
}
|
||||
}
|
||||
UsageKind::ComputePass => {
|
||||
let pipeline = create_compute_pipeline(&ctx.device, BUFFER_COMPUTE_SHADER);
|
||||
let layout = pipeline.get_bind_group_layout(0);
|
||||
let bind_group_a = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer_a.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
let bind_group_b = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
label: None,
|
||||
layout: &layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer_b.as_entire_binding(),
|
||||
}],
|
||||
});
|
||||
|
||||
let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor::default());
|
||||
pass.set_pipeline(&pipeline);
|
||||
pass.set_bind_group(0, &bind_group_a, &[]);
|
||||
pass.set_bind_group(0, &bind_group_b, &[]);
|
||||
pass.dispatch_workgroups(0, 0, 0);
|
||||
}
|
||||
UsageKind::Direct => unreachable!(),
|
||||
}
|
||||
|
||||
buffer_a.destroy();
|
||||
|
||||
fail(
|
||||
&ctx.device,
|
||||
|| ctx.queue.submit([encoder.finish()]),
|
||||
Some("Buffer with '' label has been destroyed"),
|
||||
);
|
||||
}
|
||||
|
||||
/// Test that bind groups that are replaced before use in a draw/dispatch are still
|
||||
/// considered in submit-time liveness checks.
|
||||
#[gpu_test]
|
||||
static REPLACED_BIND_GROUP: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(
|
||||
TestParameters::default()
|
||||
.test_features_limits()
|
||||
.enable_noop(),
|
||||
)
|
||||
.run_sync(|ctx| {
|
||||
test_replaced_bind_group(&ctx, UsageKind::RenderPass);
|
||||
test_replaced_bind_group(&ctx, UsageKind::ComputePass);
|
||||
test_replaced_bind_group(&ctx, UsageKind::RenderBundle);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user