alex/beta-minecraft-rust
Minecraft Beta 1.7.3 Rewrite
BRANCH 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
root crates client src gpu resources.rs
use std::mem::ManuallyDrop;
use std::ptr::null;
use std::sync::Arc;
use volcanic::*;
use volcanic_mem::{BufferDesc, MemoryLocation};
use super::{Device, Result, create, zeroed};
/// A buffer sub-allocated from the device's allocator, persistently mapped when host-visible.
pub struct Buffer {
inner: ManuallyDrop<volcanic_mem::Buffer>,
device: Arc<Device>,
}
impl Buffer {
/// Buffers the GPU reads through their address directly should include `SHADER_DEVICE_ADDRESS`
/// in `usage`, so `CpuToGpu` places them in device-local host-visible memory when available.
pub fn new(
device: &Arc<Device>,
size: u64,
usage: VkBufferUsageFlags2,
location: MemoryLocation,
) -> Result<Self> {
let desc = BufferDesc {
size,
usage,
location,
};
Ok(Self {
inner: ManuallyDrop::new(device.allocator.create_buffer(&desc)?),
device: device.clone(),
})
}
pub fn handle(&self) -> VkBuffer {
self.inner.handle()
}
pub fn size(&self) -> u64 {
self.inner.size()
}
pub fn address(&self) -> VkDeviceAddress {
self.inner.address()
}
/// Host view of a host-visible buffer. Panics for GPU-only buffers.
pub fn mapped(&mut self) -> &mut [u8] {
self.inner
.mapped_slice_mut()
.expect("buffer is not host-visible")
}
/// Makes host writes to `offset..offset + size` visible to the device. A no-op on coherent memory.
pub fn flush(&self, offset: usize, size: usize) -> Result<()> {
if size == 0 {
return Ok(());
}
let allocation = self.inner.allocation();
Ok(self
.device
.allocator
.flush(allocation, offset as u64, size as u64)?)
}
/// Makes finished device writes visible to the host. A no-op on coherent memory.
pub fn invalidate(&self) -> Result<()> {
let allocation = self.inner.allocation();
Ok(self
.device
.allocator
.invalidate(allocation, 0, VK_WHOLE_SIZE)?)
}
pub fn write(&mut self, offset: usize, data: &[u8]) -> Result<()> {
self.mapped()[offset..offset + data.len()].copy_from_slice(data);
self.flush(offset, data.len())
}
}
impl Drop for Buffer {
fn drop(&mut self) {
let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
self.device.allocator.destroy_buffer(inner);
}
}
/// A 2D device-local image with a default view.
pub struct Image {
inner: ManuallyDrop<volcanic_mem::Image>,
view: VkImageView,
format: VkFormat,
aspect: VkImageAspectFlags,
device: Arc<Device>,
}
impl Image {
pub fn new(
device: &Arc<Device>,
extent: VkExtent2D,
format: VkFormat,
usage: VkImageUsageFlags,
aspect: VkImageAspectFlags,
) -> Result<Self> {
let info = VkImageCreateInfo {
sType: VkStructureType::ImageCreateInfo,
imageType: VkImageType::_2D,
format,
extent: VkExtent3D {
width: extent.width,
height: extent.height,
depth: 1,
},
mipLevels: 1,
arrayLayers: 1,
samples: VkSampleCountFlags::_1,
tiling: VkImageTiling::Optimal,
usage,
sharingMode: VkSharingMode::Exclusive,
initialLayout: VkImageLayout::Undefined,
..zeroed()
};
let inner = device
.allocator
.create_image(&info, MemoryLocation::GpuOnly)?;
let mut image = Self {
inner: ManuallyDrop::new(inner),
view: VK_NULL_HANDLE,
format,
aspect,
device: device.clone(),
};
let view_info = image.view_create_info();
image.view = create(|view| unsafe {
device
.commands
.vkCreateImageView(device.handle, &view_info, null(), view)
})?;
Ok(image)
}
pub fn handle(&self) -> VkImage {
self.inner.handle()
}
pub fn view(&self) -> VkImageView {
self.view
}
/// The view description, which descriptor heaps use to build image descriptors.
pub fn view_create_info(&self) -> VkImageViewCreateInfo {
view_create_info(self.handle(), self.format, self.aspect)
}
}
/// A 2D view of an image's first mip level and layer.
pub(crate) fn view_create_info(
image: VkImage,
format: VkFormat,
aspect: VkImageAspectFlags,
) -> VkImageViewCreateInfo {
VkImageViewCreateInfo {
sType: VkStructureType::ImageViewCreateInfo,
image,
viewType: VkImageViewType::_2D,
format,
subresourceRange: subresource_range(aspect),
..zeroed()
}
}
pub fn subresource_range(aspect: VkImageAspectFlags) -> VkImageSubresourceRange {
VkImageSubresourceRange {
aspectMask: aspect,
levelCount: 1,
layerCount: 1,
..zeroed()
}
}
impl Drop for Image {
fn drop(&mut self) {
let commands = &self.device.commands;
unsafe { commands.vkDestroyImageView(self.device.handle, self.view, null()) };
let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
self.device.allocator.destroy_image(inner);
}
}