mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-02-19 18:33:30 +00:00
Add tests for scissors (#3877)
This commit is contained in:
parent
d089b9488b
commit
11b8dbbea3
@ -20,11 +20,12 @@ webgl = ["wgpu/webgl"]
|
||||
|
||||
[dependencies]
|
||||
bitflags.workspace = true
|
||||
bytemuck.workspace = true
|
||||
cfg-if.workspace = true
|
||||
env_logger.workspace = true
|
||||
log.workspace = true
|
||||
pollster.workspace = true
|
||||
png.workspace = true
|
||||
pollster.workspace = true
|
||||
wgpu.workspace = true
|
||||
wgt.workspace = true
|
||||
|
||||
@ -38,13 +39,12 @@ wasm-bindgen.workspace = true
|
||||
web-sys = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bytemuck.workspace = true
|
||||
naga = { workspace = true, features = ["wgsl-in"] }
|
||||
wasm-bindgen-test.workspace = true
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||
js-sys.workspace = true
|
||||
image.workspace = true
|
||||
wasm-bindgen.workspace = true
|
||||
js-sys.workspace = true
|
||||
wasm-bindgen-futures.workspace = true
|
||||
wasm-bindgen.workspace = true
|
||||
web-sys = { workspace = true, features = ["CanvasRenderingContext2d", "Blob"] }
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::{borrow::Cow, ffi::OsStr, io, path::Path};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use wgpu::util::{align_to, DeviceExt};
|
||||
use wgpu::*;
|
||||
|
||||
fn read_png(path: impl AsRef<Path>, width: u32, height: u32) -> Option<Vec<u8>> {
|
||||
@ -149,7 +150,7 @@ impl ComparisonType {
|
||||
|
||||
pub fn compare_image_output(
|
||||
path: impl AsRef<Path> + AsRef<OsStr>,
|
||||
backend: wgpu::Backend,
|
||||
backend: Backend,
|
||||
width: u32,
|
||||
height: u32,
|
||||
test_with_alpha: &[u8],
|
||||
@ -367,6 +368,10 @@ fn copy_texture_to_buffer_with_aspect(
|
||||
) {
|
||||
let (block_width, block_height) = texture.format().block_dimensions();
|
||||
let block_size = texture.format().block_size(Some(aspect)).unwrap();
|
||||
let bytes_per_row = align_to(
|
||||
(texture.width() / block_width) * block_size,
|
||||
COPY_BYTES_PER_ROW_ALIGNMENT,
|
||||
);
|
||||
let mip_level = 0;
|
||||
encoder.copy_texture_to_buffer(
|
||||
ImageCopyTexture {
|
||||
@ -382,7 +387,7 @@ fn copy_texture_to_buffer_with_aspect(
|
||||
},
|
||||
layout: ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some((texture.width() / block_width) * block_size),
|
||||
bytes_per_row: Some(bytes_per_row),
|
||||
rows_per_image: Some(texture.height() / block_height),
|
||||
},
|
||||
},
|
||||
@ -449,6 +454,14 @@ fn copy_texture_to_buffer(
|
||||
}
|
||||
|
||||
pub struct ReadbackBuffers {
|
||||
/// texture format
|
||||
texture_format: TextureFormat,
|
||||
/// texture width
|
||||
texture_width: u32,
|
||||
/// texture height
|
||||
texture_height: u32,
|
||||
/// texture depth or array layer count
|
||||
texture_depth_or_array_layers: u32,
|
||||
/// buffer for color or depth aspects
|
||||
buffer: Buffer,
|
||||
/// buffer for stencil aspect
|
||||
@ -458,20 +471,37 @@ pub struct ReadbackBuffers {
|
||||
impl ReadbackBuffers {
|
||||
pub fn new(device: &Device, texture: &Texture) -> Self {
|
||||
let (block_width, block_height) = texture.format().block_dimensions();
|
||||
let base_size = (texture.width() / block_width)
|
||||
* (texture.height() / block_height)
|
||||
* texture.depth_or_array_layers();
|
||||
const SKIP_ALIGNMENT_FORMATS: [TextureFormat; 2] = [
|
||||
TextureFormat::Depth24Plus,
|
||||
TextureFormat::Depth24PlusStencil8,
|
||||
];
|
||||
let should_align_buffer_size = !SKIP_ALIGNMENT_FORMATS.contains(&texture.format());
|
||||
if texture.format().is_combined_depth_stencil_format() {
|
||||
let buffer_size = base_size
|
||||
let mut buffer_depth_bytes_per_row = (texture.width() / block_width)
|
||||
* texture
|
||||
.format()
|
||||
.block_size(Some(TextureAspect::DepthOnly))
|
||||
.unwrap_or(4);
|
||||
let buffer_stencil_size = base_size
|
||||
* texture
|
||||
.format()
|
||||
.block_size(Some(TextureAspect::StencilOnly))
|
||||
.unwrap();
|
||||
if should_align_buffer_size {
|
||||
buffer_depth_bytes_per_row =
|
||||
align_to(buffer_depth_bytes_per_row, COPY_BYTES_PER_ROW_ALIGNMENT);
|
||||
}
|
||||
let buffer_size = buffer_depth_bytes_per_row
|
||||
* (texture.height() / block_height)
|
||||
* texture.depth_or_array_layers();
|
||||
|
||||
let buffer_stencil_bytes_per_row = align_to(
|
||||
(texture.width() / block_width)
|
||||
* texture
|
||||
.format()
|
||||
.block_size(Some(TextureAspect::StencilOnly))
|
||||
.unwrap_or(4),
|
||||
COPY_BYTES_PER_ROW_ALIGNMENT,
|
||||
);
|
||||
let buffer_stencil_size = buffer_stencil_bytes_per_row
|
||||
* (texture.height() / block_height)
|
||||
* texture.depth_or_array_layers();
|
||||
|
||||
let buffer = device.create_buffer_init(&util::BufferInitDescriptor {
|
||||
label: Some("Texture Readback"),
|
||||
usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
|
||||
@ -483,17 +513,31 @@ impl ReadbackBuffers {
|
||||
contents: &vec![255; buffer_stencil_size as usize],
|
||||
});
|
||||
ReadbackBuffers {
|
||||
texture_format: texture.format(),
|
||||
texture_width: texture.width(),
|
||||
texture_height: texture.height(),
|
||||
texture_depth_or_array_layers: texture.depth_or_array_layers(),
|
||||
buffer,
|
||||
buffer_stencil: Some(buffer_stencil),
|
||||
}
|
||||
} else {
|
||||
let buffer_size = base_size * texture.format().block_size(None).unwrap_or(4);
|
||||
let mut bytes_per_row =
|
||||
(texture.width() / block_width) * texture.format().block_size(None).unwrap_or(4);
|
||||
if should_align_buffer_size {
|
||||
bytes_per_row = align_to(bytes_per_row, COPY_BYTES_PER_ROW_ALIGNMENT);
|
||||
}
|
||||
let buffer_size =
|
||||
bytes_per_row * (texture.height() / block_height) * texture.depth_or_array_layers();
|
||||
let buffer = device.create_buffer_init(&util::BufferInitDescriptor {
|
||||
label: Some("Texture Readback"),
|
||||
usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
|
||||
contents: &vec![255; buffer_size as usize],
|
||||
});
|
||||
ReadbackBuffers {
|
||||
texture_format: texture.format(),
|
||||
texture_width: texture.width(),
|
||||
texture_height: texture.height(),
|
||||
texture_depth_or_array_layers: texture.depth_or_array_layers(),
|
||||
buffer,
|
||||
buffer_stencil: None,
|
||||
}
|
||||
@ -505,24 +549,67 @@ impl ReadbackBuffers {
|
||||
copy_texture_to_buffer(device, encoder, texture, &self.buffer, &self.buffer_stencil);
|
||||
}
|
||||
|
||||
fn retrieve_buffer(
|
||||
&self,
|
||||
device: &Device,
|
||||
buffer: &Buffer,
|
||||
aspect: Option<TextureAspect>,
|
||||
) -> Vec<u8> {
|
||||
let buffer_slice = buffer.slice(..);
|
||||
buffer_slice.map_async(MapMode::Read, |_| ());
|
||||
device.poll(Maintain::Wait);
|
||||
let (block_width, block_height) = self.texture_format.block_dimensions();
|
||||
let expected_bytes_per_row = (self.texture_width / block_width)
|
||||
* self.texture_format.block_size(aspect).unwrap_or(4);
|
||||
let expected_buffer_size = expected_bytes_per_row
|
||||
* (self.texture_height / block_height)
|
||||
* self.texture_depth_or_array_layers;
|
||||
let data: BufferView = buffer_slice.get_mapped_range();
|
||||
if expected_buffer_size as usize == data.len() {
|
||||
data.to_vec()
|
||||
} else {
|
||||
bytemuck::cast_slice(&data)
|
||||
.chunks_exact(
|
||||
align_to(expected_bytes_per_row, COPY_BYTES_PER_ROW_ALIGNMENT) as usize,
|
||||
)
|
||||
.flat_map(|x| x.iter().take(expected_bytes_per_row as usize))
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn buffer_aspect(&self) -> Option<TextureAspect> {
|
||||
if self.texture_format.is_combined_depth_stencil_format() {
|
||||
Some(TextureAspect::DepthOnly)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn are_zero(&self, device: &Device) -> bool {
|
||||
fn is_zero(device: &Device, buffer: &Buffer) -> bool {
|
||||
let is_zero = {
|
||||
let buffer_slice = buffer.slice(..);
|
||||
buffer_slice.map_async(MapMode::Read, |_| ());
|
||||
device.poll(Maintain::Wait);
|
||||
let buffer_view = buffer_slice.get_mapped_range();
|
||||
buffer_view.iter().all(|b| *b == 0)
|
||||
};
|
||||
let is_zero = |device: &Device, buffer: &Buffer, aspect: Option<TextureAspect>| -> bool {
|
||||
let is_zero = self
|
||||
.retrieve_buffer(device, buffer, aspect)
|
||||
.iter()
|
||||
.all(|b| *b == 0);
|
||||
buffer.unmap();
|
||||
is_zero
|
||||
}
|
||||
};
|
||||
|
||||
is_zero(device, &self.buffer)
|
||||
&& self
|
||||
.buffer_stencil
|
||||
.as_ref()
|
||||
.map(|buffer_stencil| is_zero(device, buffer_stencil))
|
||||
.unwrap_or(true)
|
||||
let buffer_zero = is_zero(device, &self.buffer, self.buffer_aspect());
|
||||
let mut stencil_buffer_zero = true;
|
||||
if let Some(buffer) = &self.buffer_stencil {
|
||||
stencil_buffer_zero = is_zero(device, buffer, Some(TextureAspect::StencilOnly));
|
||||
};
|
||||
buffer_zero && stencil_buffer_zero
|
||||
}
|
||||
|
||||
pub fn check_buffer_contents(&self, device: &Device, expected_data: &[u8]) -> bool {
|
||||
let result = self
|
||||
.retrieve_buffer(device, &self.buffer, self.buffer_aspect())
|
||||
.iter()
|
||||
.eq(expected_data.iter());
|
||||
self.buffer.unmap();
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use wasm_bindgen_test::wasm_bindgen_test_configure;
|
||||
mod regression {
|
||||
mod issue_3457;
|
||||
}
|
||||
|
||||
mod buffer;
|
||||
mod buffer_copy;
|
||||
mod buffer_usages;
|
||||
@ -16,6 +17,7 @@ mod poll;
|
||||
mod queue_transfer;
|
||||
mod resource_descriptor_accessor;
|
||||
mod resource_error;
|
||||
mod scissor_tests;
|
||||
mod shader;
|
||||
mod shader_primitive_index;
|
||||
mod shader_view_format;
|
||||
|
163
tests/tests/scissor_tests/mod.rs
Normal file
163
tests/tests/scissor_tests/mod.rs
Normal file
@ -0,0 +1,163 @@
|
||||
use wgpu_test::{image, initialize_test, TestParameters, TestingContext};
|
||||
|
||||
struct Rect {
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
const TEXTURE_HEIGHT: u32 = 2;
|
||||
const TEXTURE_WIDTH: u32 = 2;
|
||||
const BUFFER_SIZE: usize = (TEXTURE_WIDTH * TEXTURE_HEIGHT * 4) as usize;
|
||||
|
||||
fn scissor_test_impl(ctx: &TestingContext, scissor_rect: Rect, expected_data: [u8; BUFFER_SIZE]) {
|
||||
let texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("Offscreen texture"),
|
||||
size: wgpu::Extent3d {
|
||||
width: TEXTURE_WIDTH,
|
||||
height: TEXTURE_HEIGHT,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
view_formats: &[],
|
||||
});
|
||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let shader = ctx
|
||||
.device
|
||||
.create_shader_module(wgpu::include_wgsl!("solid_white.wgsl"));
|
||||
|
||||
let pipeline = ctx
|
||||
.device
|
||||
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Pipeline"),
|
||||
layout: None,
|
||||
vertex: wgpu::VertexState {
|
||||
entry_point: "vs_main",
|
||||
module: &shader,
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
entry_point: "fs_main",
|
||||
module: &shader,
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
});
|
||||
|
||||
let readback_buffer = image::ReadbackBuffers::new(&ctx.device, &texture);
|
||||
{
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||
{
|
||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Renderpass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &texture_view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||
r: 0.0,
|
||||
g: 0.0,
|
||||
b: 0.0,
|
||||
a: 0.0,
|
||||
}),
|
||||
store: true,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
render_pass.set_pipeline(&pipeline);
|
||||
render_pass.set_scissor_rect(
|
||||
scissor_rect.x,
|
||||
scissor_rect.y,
|
||||
scissor_rect.width,
|
||||
scissor_rect.height,
|
||||
);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
}
|
||||
readback_buffer.copy_from(&ctx.device, &mut encoder, &texture);
|
||||
ctx.queue.submit(Some(encoder.finish()));
|
||||
}
|
||||
assert!(readback_buffer.check_buffer_contents(&ctx.device, &expected_data));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scissor_test_full_rect() {
|
||||
initialize_test(TestParameters::default(), |ctx| {
|
||||
scissor_test_impl(
|
||||
&ctx,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: TEXTURE_WIDTH,
|
||||
height: TEXTURE_HEIGHT,
|
||||
},
|
||||
[255; BUFFER_SIZE],
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scissor_test_empty_rect() {
|
||||
initialize_test(TestParameters::default(), |ctx| {
|
||||
scissor_test_impl(
|
||||
&ctx,
|
||||
Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
[0; BUFFER_SIZE],
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scissor_test_empty_rect_with_offset() {
|
||||
initialize_test(TestParameters::default(), |ctx| {
|
||||
scissor_test_impl(
|
||||
&ctx,
|
||||
Rect {
|
||||
x: TEXTURE_WIDTH / 2,
|
||||
y: TEXTURE_HEIGHT / 2,
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
[0; BUFFER_SIZE],
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scissor_test_custom_rect() {
|
||||
let mut expected_result = [0; BUFFER_SIZE];
|
||||
expected_result[((3 * BUFFER_SIZE) / 4)..][..BUFFER_SIZE / 4]
|
||||
.copy_from_slice(&[255; BUFFER_SIZE / 4]);
|
||||
initialize_test(TestParameters::default(), |ctx| {
|
||||
scissor_test_impl(
|
||||
&ctx,
|
||||
Rect {
|
||||
x: TEXTURE_WIDTH / 2,
|
||||
y: TEXTURE_HEIGHT / 2,
|
||||
width: TEXTURE_WIDTH / 2,
|
||||
height: TEXTURE_HEIGHT / 2,
|
||||
},
|
||||
expected_result,
|
||||
);
|
||||
})
|
||||
}
|
33
tests/tests/scissor_tests/solid_white.wgsl
Normal file
33
tests/tests/scissor_tests/solid_white.wgsl
Normal file
@ -0,0 +1,33 @@
|
||||
// meant to be called with 3 vertex indices: 0, 1, 2
|
||||
// draws one large triangle over the clip space like this:
|
||||
// (the asterisks represent the clip space bounds)
|
||||
//-1,1 1,1
|
||||
// ---------------------------------
|
||||
// | * .
|
||||
// | * .
|
||||
// | * .
|
||||
// | * .
|
||||
// | * .
|
||||
// | * .
|
||||
// |***************
|
||||
// | . 1,-1
|
||||
// | .
|
||||
// | .
|
||||
// | .
|
||||
// | .
|
||||
// |.
|
||||
@vertex
|
||||
fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4<f32> {
|
||||
let x = i32(vertex_index) / 2;
|
||||
let y = i32(vertex_index) & 1;
|
||||
return vec4<f32>(
|
||||
f32(x) * 4.0 - 1.0,
|
||||
1.0 - f32(y) * 4.0,
|
||||
0.0, 1.0
|
||||
);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main() -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(1.0);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
use wasm_bindgen_test::*;
|
||||
use wgpu::util::{align_to, DeviceExt};
|
||||
use wgpu_test::{initialize_test, TestParameters, TestingContext};
|
||||
|
||||
use wgpu::util::DeviceExt;
|
||||
use wgpu_test::{image, initialize_test, TestParameters, TestingContext};
|
||||
|
||||
//
|
||||
// These tests render two triangles to a 2x2 render target. The first triangle
|
||||
@ -89,7 +90,7 @@ fn draw_indexed() {
|
||||
fn pulling_common(
|
||||
ctx: TestingContext,
|
||||
expected: &[u8],
|
||||
function: impl FnOnce(&mut wgpu::RenderPass<'_>),
|
||||
draw_command: impl FnOnce(&mut wgpu::RenderPass<'_>),
|
||||
) {
|
||||
let shader = ctx
|
||||
.device
|
||||
@ -168,83 +169,31 @@ fn pulling_common(
|
||||
});
|
||||
let color_view = color_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let readback_buffer = image::ReadbackBuffers::new(&ctx.device, &color_texture);
|
||||
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
|
||||
store: true,
|
||||
},
|
||||
resolve_target: None,
|
||||
view: &color_view,
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
label: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32);
|
||||
rpass.set_vertex_buffer(0, vertex_buffer.slice(..));
|
||||
function(&mut rpass);
|
||||
|
||||
drop(rpass);
|
||||
|
||||
ctx.queue.submit(Some(encoder.finish()));
|
||||
|
||||
let data = capture_rgba_u8_texture(ctx, color_texture, texture_size);
|
||||
|
||||
assert_eq!(data, expected);
|
||||
}
|
||||
|
||||
fn capture_rgba_u8_texture(
|
||||
ctx: TestingContext,
|
||||
color_texture: wgpu::Texture,
|
||||
texture_size: wgpu::Extent3d,
|
||||
) -> Vec<u8> {
|
||||
let bytes_per_row = align_to(4 * texture_size.width, wgpu::COPY_BYTES_PER_ROW_ALIGNMENT);
|
||||
let buffer_size = bytes_per_row * texture_size.height;
|
||||
let output_buffer = ctx
|
||||
.device
|
||||
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
|
||||
store: true,
|
||||
},
|
||||
resolve_target: None,
|
||||
view: &color_view,
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
label: None,
|
||||
contents: &vec![0u8; buffer_size as usize],
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
});
|
||||
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||
|
||||
encoder.copy_texture_to_buffer(
|
||||
wgpu::ImageCopyTexture {
|
||||
texture: &color_texture,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d::ZERO,
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
wgpu::ImageCopyBuffer {
|
||||
buffer: &output_buffer,
|
||||
layout: wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(bytes_per_row),
|
||||
rows_per_image: None,
|
||||
},
|
||||
},
|
||||
texture_size,
|
||||
);
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32);
|
||||
rpass.set_vertex_buffer(0, vertex_buffer.slice(..));
|
||||
draw_command(&mut rpass);
|
||||
}
|
||||
readback_buffer.copy_from(&ctx.device, &mut encoder, &color_texture);
|
||||
ctx.queue.submit(Some(encoder.finish()));
|
||||
let slice = output_buffer.slice(..);
|
||||
slice.map_async(wgpu::MapMode::Read, |_| ());
|
||||
ctx.device.poll(wgpu::Maintain::Wait);
|
||||
let data: Vec<u8> = bytemuck::cast_slice(&slice.get_mapped_range()).to_vec();
|
||||
// Chunk rows from output buffer, take actual pixel
|
||||
// bytes from each row and flatten into a vector.
|
||||
data.chunks_exact(bytes_per_row as usize)
|
||||
.flat_map(|x| x.iter().take(4 * texture_size.width as usize))
|
||||
.copied()
|
||||
.collect()
|
||||
assert!(readback_buffer.check_buffer_contents(&ctx.device, expected));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user