use std::sync::mpsc;
use crate::Renderer;
pub async fn create_test_renderer(
label: &'static str,
) -> Option<(Renderer, wgpu::Device, wgpu::Queue)> {
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle());
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::LowPower,
compatible_surface: None,
force_fallback_adapter: false,
..Default::default()
})
.await
.ok()?;
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor {
label: Some(label),
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
..Default::default()
})
.await
.ok()?;
let renderer = Renderer::new(
device.clone(),
queue.clone(),
wgpu::TextureFormat::Rgba8UnormSrgb,
);
Some((renderer, device, queue))
}
pub fn read_texture_rgba(
device: &wgpu::Device,
queue: &wgpu::Queue,
texture: &wgpu::Texture,
width: u32,
height: u32,
) -> Vec<u8> {
let bytes_per_pixel = 4u32;
let unpadded_bytes_per_row = width * bytes_per_pixel;
let padded_bytes_per_row = unpadded_bytes_per_row.div_ceil(256) * 256;
let buffer_size = padded_bytes_per_row as u64 * height as u64;
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("teksilo_render_test_readback"),
size: buffer_size,
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
mapped_at_creation: false,
});
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("teksilo_render_test_copy"),
});
encoder.copy_texture_to_buffer(
wgpu::TexelCopyTextureInfo {
texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
wgpu::TexelCopyBufferInfo {
buffer: &buffer,
layout: wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(padded_bytes_per_row),
rows_per_image: Some(height),
},
},
wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
);
queue.submit(std::iter::once(encoder.finish()));
let slice = buffer.slice(..);
let (tx, rx) = mpsc::channel();
slice.map_async(wgpu::MapMode::Read, move |result| {
let _ = tx.send(result);
});
let _ = device.poll(wgpu::PollType::Wait {
submission_index: None,
timeout: None,
});
rx.recv()
.expect("map_async callback dropped")
.expect("map_async failed");
let mapped = slice
.get_mapped_range()
.expect("mapped range unavailable after a successful map_async");
let mut pixels = vec![0u8; (width * height * bytes_per_pixel) as usize];
for row in 0..height as usize {
let src_offset = row * padded_bytes_per_row as usize;
let dst_offset = row * unpadded_bytes_per_row as usize;
pixels[dst_offset..dst_offset + unpadded_bytes_per_row as usize]
.copy_from_slice(&mapped[src_offset..src_offset + unpadded_bytes_per_row as usize]);
}
drop(mapped);
buffer.unmap();
pixels
}