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 / gpu / mod.rs

//! Thin, safe-by-construction layer over the raw `volcanic` Vulkan bindings.
//!
//! Targets Vulkan 1.3 with `maintenance5`, dynamic rendering and buffer device addresses. Shaders
//! reach their textures through `VK_EXT_descriptor_heap` where available, or one descriptor set.

mod descriptors;
mod device;
mod heap;
mod instance;
mod pacing;
mod pipeline;
mod resources;
mod swapchain;
mod validation;

use volcanic::VkResult;

pub use descriptors::{Binding, Descriptors};
pub use device::Device;
pub use instance::{Instance, Surface};
pub use pipeline::{Blend, ComputePipeline, GraphicsPipeline, PipelineDesc};
pub use resources::{Buffer, Image, subresource_range};
pub use swapchain::{PresentMode, Presentation, Swapchain};
pub use validation::Validation;
pub use volcanic as vk;
pub use volcanic_mem::MemoryLocation;

/// Bytes of push data a pipeline may read: Vulkan 1.4's minimum `maxPushConstantsSize`.
pub const MAX_PUSH_SIZE: u32 = 256;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("failed to load the Vulkan library: {0}")]
    Load(#[from] volcanic::loader::LoadError),
    #[error("Vulkan call failed with {0:?}")]
    Vulkan(VkResult),
    #[error(
        "no GPU supports Vulkan 1.3 with maintenance5, indirect draw counts, fragment stores, {}-byte push constants and presentation",
        MAX_PUSH_SIZE
    )]
    NoSuitableDevice,
    #[error("unsupported window system")]
    UnsupportedWindowSystem,
    #[error("the surface offers no B8G8R8A8 or R8G8B8A8 UNORM format with sRGB color space")]
    UnsupportedSurfaceFormat,
    #[error(transparent)]
    Memory(#[from] volcanic_mem::Error),
    #[error("SPIR-V byte length {0} is not a multiple of 4")]
    InvalidSpirv(usize),
    #[error("the swapchain offers no time domain that frame pacing can use")]
    NoPresentTimeDomain,
}

pub type Result<T> = std::result::Result<T, Error>;

pub fn check(result: VkResult) -> Result<()> {
    (result == VkResult::Success)
        .then_some(())
        .ok_or(Error::Vulkan(result))
}

/// All-zero Vulkan struct. Valid for every `volcanic` record: they only hold
/// integers, transparent enums, bitflags, raw pointers and optional callbacks.
pub(crate) fn zeroed<T: Copy>() -> T {
    unsafe { std::mem::zeroed() }
}

/// Runs a Vulkan create call and returns the handle it wrote.
pub(crate) fn create<T: Copy>(call: impl FnOnce(&mut T) -> VkResult) -> Result<T> {
    let mut handle = zeroed();
    check(call(&mut handle))?;
    Ok(handle)
}

/// Collects a variable-length Vulkan array using the two-call idiom.
pub(crate) fn enumerate<T: Copy>(
    mut call: impl FnMut(*mut u32, *mut T) -> VkResult,
) -> Result<Vec<T>> {
    let mut count = 0;
    check(call(&mut count, std::ptr::null_mut()))?;
    let mut items = vec![zeroed::<T>(); count as usize];
    check(call(&mut count, items.as_mut_ptr()))?;
    items.truncate(count as usize);
    Ok(items)
}