use crate::allocator::GpuReadbackIdentifier;
use crate::texture_info::Texture2DBufferInfo;
use crate::{GpuReadbackError, RenderContext};
pub struct TextureReadback {
pub data: Vec<u8>,
pub extent: wgpu::Extent3d,
pub format: wgpu::TextureFormat,
}
struct ReadbackMetadata {
extent: wgpu::Extent3d,
format: wgpu::TextureFormat,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TextureReadbackId(GpuReadbackIdentifier);
pub fn schedule_read_texture(
ctx: &RenderContext,
texture: &wgpu::Texture,
) -> Result<TextureReadbackId, GpuReadbackError> {
static NEXT_GPU_READBACK_IDENTIFIER: std::sync::atomic::AtomicU64 =
std::sync::atomic::AtomicU64::new(0xa8291af2e7dd);
let extent = texture.size();
let format = texture.format();
let buffer_info = Texture2DBufferInfo::new(format, extent);
let id = NEXT_GPU_READBACK_IDENTIFIER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let mut readback_buffer = ctx.gpu_readback_belt.lock().allocate(
&ctx.device,
&ctx.gpu_resources.buffers,
buffer_info.buffer_size_padded,
id,
Box::new(ReadbackMetadata { extent, format }),
);
readback_buffer.read_texture2d(
ctx.active_frame.before_view_builder_encoder.lock().get(),
wgpu::TexelCopyTextureInfo {
texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
extent,
)?;
Ok(TextureReadbackId(id))
}
pub fn poll_read_texture(ctx: &RenderContext, id: TextureReadbackId) -> Option<TextureReadback> {
ctx.gpu_readback_belt.lock().readback_next_available(
id.0,
|data: &[u8], metadata: Box<ReadbackMetadata>| {
let buffer_info = Texture2DBufferInfo::new(metadata.format, metadata.extent);
let data = buffer_info.remove_padding(data).into_owned();
TextureReadback {
data,
extent: metadata.extent,
format: metadata.format,
}
},
)
}