mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Co-authored-by: Andreas Reich <r_andreas2@web.de> Co-authored-by: Magnus <85136135+SupaMaggie70Incorporated@users.noreply.github.com>
189 lines
6.5 KiB
Rust
189 lines
6.5 KiB
Rust
use wgpu::util::DeviceExt;
|
|
use wgpu_test::{
|
|
gpu_test, image::ReadbackBuffers, GpuTestConfiguration, GpuTestInitializer, TestParameters,
|
|
TestingContext,
|
|
};
|
|
|
|
pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
|
|
vec.push(MULTI_STAGE_DATA_BINDING);
|
|
}
|
|
|
|
/// We thought we had an OpenGL bug that, when running without explicit in-shader locations,
|
|
/// we will not properly bind uniform buffers to both the vertex and fragment
|
|
/// shaders. This turned out to not reproduce at all with this test case.
|
|
///
|
|
/// However, it also caught issues with the push constant implementation,
|
|
/// making sure that it works correctly with different definitions for the push constant
|
|
/// block in vertex and fragment shaders.
|
|
///
|
|
/// This test needs to be able to run on GLES 3.0
|
|
///
|
|
/// What this test does is render a 2x2 texture. Each pixel corresponds to a different
|
|
/// data source.
|
|
///
|
|
/// top left: Vertex Shader / Uniform Buffer
|
|
/// top right: Vertex Shader / Push Constant
|
|
/// bottom left: Fragment Shader / Uniform Buffer
|
|
/// bottom right: Fragment Shader / Push Constant
|
|
///
|
|
/// We then validate the data is correct from every position.
|
|
#[gpu_test]
|
|
static MULTI_STAGE_DATA_BINDING: GpuTestConfiguration = GpuTestConfiguration::new()
|
|
.parameters(
|
|
TestParameters::default()
|
|
.features(wgpu::Features::PUSH_CONSTANTS)
|
|
.limits(wgpu::Limits {
|
|
max_push_constant_size: 16,
|
|
..Default::default()
|
|
}),
|
|
)
|
|
.run_async(multi_stage_data_binding_test);
|
|
|
|
async fn multi_stage_data_binding_test(ctx: TestingContext) {
|
|
// We use different shader modules to allow us to use different
|
|
// types for the uniform and push constant blocks between stages.
|
|
let vs_sm = ctx
|
|
.device
|
|
.create_shader_module(wgpu::include_wgsl!("issue_3349.vs.wgsl"));
|
|
|
|
let fs_sm = ctx
|
|
.device
|
|
.create_shader_module(wgpu::include_wgsl!("issue_3349.fs.wgsl"));
|
|
|
|
// We start with u8s then convert to float, to make sure we don't have
|
|
// cross-vendor rounding issues unorm.
|
|
let input_as_unorm: [u8; 4] = [25_u8, 50, 75, 100];
|
|
let input = input_as_unorm.map(|v| v as f32 / 255.0);
|
|
|
|
let buffer = ctx
|
|
.device
|
|
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
label: Some("buffer"),
|
|
contents: bytemuck::cast_slice(&input),
|
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
|
});
|
|
|
|
let bgl = ctx
|
|
.device
|
|
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
label: Some("bgl"),
|
|
entries: &[wgpu::BindGroupLayoutEntry {
|
|
binding: 0,
|
|
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
|
ty: wgpu::BindingType::Buffer {
|
|
ty: wgpu::BufferBindingType::Uniform,
|
|
has_dynamic_offset: false,
|
|
min_binding_size: None,
|
|
},
|
|
count: None,
|
|
}],
|
|
});
|
|
|
|
let bg = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
label: Some("bg"),
|
|
layout: &bgl,
|
|
entries: &[wgpu::BindGroupEntry {
|
|
binding: 0,
|
|
resource: buffer.as_entire_binding(),
|
|
}],
|
|
});
|
|
|
|
let pll = ctx
|
|
.device
|
|
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
label: Some("pll"),
|
|
bind_group_layouts: &[&bgl],
|
|
push_constant_ranges: &[wgpu::PushConstantRange {
|
|
stages: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
|
range: 0..16,
|
|
}],
|
|
});
|
|
|
|
let pipeline = ctx
|
|
.device
|
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
label: Some("pipeline"),
|
|
layout: Some(&pll),
|
|
vertex: wgpu::VertexState {
|
|
module: &vs_sm,
|
|
entry_point: Some("vs_main"),
|
|
compilation_options: Default::default(),
|
|
buffers: &[],
|
|
},
|
|
fragment: Some(wgpu::FragmentState {
|
|
module: &fs_sm,
|
|
entry_point: Some("fs_main"),
|
|
compilation_options: Default::default(),
|
|
targets: &[Some(wgpu::ColorTargetState {
|
|
format: wgpu::TextureFormat::Rgba8Unorm,
|
|
blend: None,
|
|
write_mask: wgpu::ColorWrites::ALL,
|
|
})],
|
|
}),
|
|
primitive: wgpu::PrimitiveState::default(),
|
|
depth_stencil: None,
|
|
multisample: wgpu::MultisampleState::default(),
|
|
multiview_mask: None,
|
|
cache: None,
|
|
});
|
|
|
|
let texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
|
label: Some("texture"),
|
|
size: wgpu::Extent3d {
|
|
width: 2,
|
|
height: 2,
|
|
depth_or_array_layers: 1,
|
|
},
|
|
mip_level_count: 1,
|
|
sample_count: 1,
|
|
dimension: wgpu::TextureDimension::D2,
|
|
// Important: NOT srgb.
|
|
format: wgpu::TextureFormat::Rgba8Unorm,
|
|
usage: wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
view_formats: &[],
|
|
});
|
|
|
|
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
|
|
let mut encoder = ctx
|
|
.device
|
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
label: Some("encoder"),
|
|
});
|
|
|
|
{
|
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
label: Some("rpass"),
|
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
|
view: &view,
|
|
depth_slice: None,
|
|
resolve_target: None,
|
|
ops: wgpu::Operations {
|
|
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
|
store: wgpu::StoreOp::Store,
|
|
},
|
|
})],
|
|
depth_stencil_attachment: None,
|
|
timestamp_writes: None,
|
|
occlusion_query_set: None,
|
|
multiview_mask: None,
|
|
});
|
|
|
|
rpass.set_pipeline(&pipeline);
|
|
rpass.set_bind_group(0, &bg, &[]);
|
|
rpass.set_push_constants(
|
|
wgpu::ShaderStages::VERTEX_FRAGMENT,
|
|
0,
|
|
bytemuck::cast_slice(&input),
|
|
);
|
|
rpass.draw(0..3, 0..1);
|
|
}
|
|
|
|
let buffers = ReadbackBuffers::new(&ctx.device, &texture);
|
|
buffers.copy_from(&ctx.device, &mut encoder, &texture);
|
|
ctx.queue.submit([encoder.finish()]);
|
|
|
|
let result = input_as_unorm.repeat(4);
|
|
buffers.assert_buffer_contents(&ctx, &result).await;
|
|
}
|