scena 1.7.2

A Rust-native scene-graph renderer with typed scene state, glTF assets, and explicit prepare/render lifecycles.
Documentation
#[cfg(not(target_arch = "wasm32"))]
use std::sync::mpsc;

use crate::diagnostics::RenderError;

use super::super::RasterTarget;
use super::GpuPreparedResources;

#[cfg(not(target_arch = "wasm32"))]
pub(super) fn encode_copy_target_to_readback(
    encoder: &mut wgpu::CommandEncoder,
    resources: &GpuPreparedResources,
    target: RasterTarget,
) {
    encoder.copy_texture_to_buffer(
        wgpu::TexelCopyTextureInfo {
            texture: &resources.texture,
            mip_level: 0,
            origin: wgpu::Origin3d::ZERO,
            aspect: wgpu::TextureAspect::All,
        },
        wgpu::TexelCopyBufferInfo {
            buffer: &resources.readback,
            layout: wgpu::TexelCopyBufferLayout {
                offset: 0,
                bytes_per_row: Some(resources.padded_bytes_per_row),
                rows_per_image: None,
            },
        },
        wgpu::Extent3d {
            width: target.width,
            height: target.height,
            depth_or_array_layers: 1,
        },
    );
}

#[cfg(not(target_arch = "wasm32"))]
pub(super) fn map_readback_to_frame(
    device: &wgpu::Device,
    resources: &GpuPreparedResources,
    target: RasterTarget,
    frame: &mut Vec<u8>,
) -> Result<(), RenderError> {
    let readback = resources.readback.slice(..);
    let (sender, receiver) = mpsc::channel();
    readback.map_async(wgpu::MapMode::Read, move |result| {
        let _ = sender.send(result);
    });
    device
        .poll(wgpu::PollType::wait_indefinitely())
        .map_err(|_| RenderError::GpuReadback {
            backend: target.backend,
        })?;
    receiver
        .recv()
        .map_err(|_| RenderError::GpuReadback {
            backend: target.backend,
        })?
        .map_err(|_| RenderError::GpuReadback {
            backend: target.backend,
        })?;

    let mapped = readback.get_mapped_range();
    if frame.len() != target.byte_len() {
        frame.resize(target.byte_len(), 0);
    }
    for row in 0..target.height as usize {
        let source_start = row * resources.padded_bytes_per_row as usize;
        let source_end = source_start + resources.unpadded_bytes_per_row as usize;
        let target_start = row * resources.unpadded_bytes_per_row as usize;
        let target_end = target_start + resources.unpadded_bytes_per_row as usize;
        frame[target_start..target_end].copy_from_slice(&mapped[source_start..source_end]);
    }
    drop(mapped);
    resources.readback.unmap();
    Ok(())
}