Theme

alex/beta-minecraft-rust

Minecraft Beta 1.7.3 Rewrite

BRANCH main
main
SNAPSHOT Draw terrain GPU-driven from packed per-section buffers with GPU occlusion culling, add a render distance slider (2-128) with a quad/disk shape, cut chunk bookkeeping at high render distances, and fix a light underflow at y=0
DOWNLOAD
Download file

root / crates / client / src / render / capture.rs

use std::sync::Arc;

use crate::assets::RgbaImage;
use crate::gpu::vk::*;
use crate::gpu::{Buffer, Device, MemoryLocation};

use super::{
    COLOR, COLOR_WRITE, COPY_READ, COPY_WRITE, NO_ACCESS, image_barrier, image_copy, memory_barrier,
};

pub(super) struct Capture {
    buffer: Buffer,
    extent: VkExtent2D,
    format: VkFormat,
}

impl Capture {
    pub fn new(
        device: &Arc<Device>,
        extent: VkExtent2D,
        format: VkFormat,
    ) -> crate::gpu::Result<Self> {
        let buffer = Buffer::new(
            device,
            u64::from(extent.width) * u64::from(extent.height) * 4,
            VkBufferUsageFlags2::TRANSFER_DST,
            MemoryLocation::GpuToCpu,
        )?;
        Ok(Self {
            buffer,
            extent,
            format,
        })
    }

    pub unsafe fn record(&self, device: &Device, cmd: VkCommandBuffer, image: VkImage) {
        unsafe {
            let source = VkImageLayout::TransferSrcOptimal;
            let layouts = (VkImageLayout::ColorAttachmentOptimal, source);
            image_barrier(device, cmd, image, COLOR, layouts, COLOR_WRITE, COPY_READ);
            let region = image_copy(0, [0, 0], self.extent.width, self.extent.height);
            let (commands, buffer) = (&device.commands, self.buffer.handle());
            commands.vkCmdCopyImageToBuffer(cmd, image, source, buffer, 1, &region);
            let host = (VkPipelineStageFlags2::HOST, VkAccessFlags2::HOST_READ);
            memory_barrier(device, cmd, COPY_WRITE, host);
            let layouts = (source, VkImageLayout::PresentSrcKhr);
            image_barrier(device, cmd, image, COLOR, layouts, COPY_READ, NO_ACCESS);
        }
    }

    // Read only after the submission's fence signals
    pub fn finish(mut self) -> crate::gpu::Result<RgbaImage> {
        self.buffer.invalidate()?;
        let mut pixels = self.buffer.mapped().to_vec();
        let bgra = self.format == VkFormat::B8G8R8A8Unorm;
        for pixel in pixels.as_chunks_mut::<4>().0 {
            if bgra {
                pixel.swap(0, 2);
            }
            pixel[3] = 255;
        }
        Ok(RgbaImage {
            width: self.extent.width,
            height: self.extent.height,
            pixels,
        })
    }
}