feat(renderer): implement vertex buffer allocation and memory mapping

This commit is contained in:
Serkyo 2026-05-11 00:04:42 +02:00
parent 8af89292b6
commit e6f8414817
3 changed files with 63 additions and 1 deletions

View file

@ -2,10 +2,16 @@ use thiserror::Error;
#[derive(Debug, Error)]
pub enum RendererError {
/// The Vulkan library could not be loaded from the system.
#[error("Failed to load Vulkan library")]
LoadFailed(#[from] ash::LoadingError),
/// A raw Vulkan result indicated a failure.
#[error("Vulkan error")]
VulkanError(#[from] ash::vk::Result),
/// No GPU was found that meets the engine's requirements.
#[error("No suitable GPU found")]
NoSuitableGpu,
/// An error occurred during GPU memory allocation.
#[error("GPU allocation error")]
AllocationError(#[from] gpu_allocator::AllocationError),
}

View file

@ -89,6 +89,8 @@ impl Renderer {
let sync =
sync::create_sync_primitives(&device, MAX_FRAMES_IN_FLIGHT, swapchain_images.len())?;
// 11. GPU Memory Allocator
// The allocator handles the complexity of sub-allocating memory blocks from the GPU.
let allocator_create_info = gpu_allocator::vulkan::AllocatorCreateDesc {
instance: instance.clone(),
device: device.clone(),
@ -101,10 +103,53 @@ impl Renderer {
let allocator = gpu_allocator::vulkan::Allocator::new(&allocator_create_info)
.expect("Failed to create Vulkan allocator");
// 12. Graphics Pipeline Configuration
// The pipeline defines the fixed-function and programmable state for rendering voxel geometry.
let pipeline_layout = pipeline::create_pipeline_layout(&device);
let graphics_pipeline =
pipeline::create_graphics_pipeline(&device, pipeline_layout, swapchain_format);
// 13. Vertex Buffer Initialization
// A simple triangle is defined in normalized device coordinates and moved to GPU memory.
let vertices = [
mesh::Vertex { position: [0.0, -0.5, 0.0], tex_coord: [0.5, 0.0] },
mesh::Vertex { position: [0.5, 0.5, 0.0], tex_coord: [1.0, 1.0] },
mesh::Vertex { position: [-0.5, 0.5, 0.0], tex_coord: [0.0, 1.0] },
];
// Create the buffer handle and query its memory requirements.
let buffer_info = vk::BufferCreateInfo::default()
.size(std::mem::size_of_val(&vertices) as u64)
.usage(vk::BufferUsageFlags::VERTEX_BUFFER);
let vertex_buffer = unsafe { device.create_buffer(&buffer_info, None)? };
let requirements = unsafe { device.get_buffer_memory_requirements(vertex_buffer) };
let mut allocator = allocator;
// Allocate memory that is visible to the CPU for data transfer.
let vertex_allocation = allocator.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
name: "Vertex Buffer",
requirements,
location: gpu_allocator::MemoryLocation::CpuToGpu,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})?;
// Bind the allocated memory to the buffer handle and copy the vertex data.
unsafe {
device.bind_buffer_memory(vertex_buffer, vertex_allocation.memory(), vertex_allocation.offset())?;
let ptr = vertex_allocation.mapped_ptr()
.expect("Failed to map vertex buffer memory")
.as_ptr();
std::ptr::copy_nonoverlapping(
vertices.as_ptr() as *const u8,
ptr as *mut u8,
std::mem::size_of_val(&vertices));
}
Ok(Self {
_entry: entry,
instance,
@ -127,6 +172,8 @@ impl Renderer {
allocator,
pipeline_layout,
graphics_pipeline,
vertex_buffer,
vertex_allocation,
sync,
current_frame: 0,
})

View file

@ -1,7 +1,7 @@
use crate::error::RendererError;
use crate::sync::SyncPrimitives;
use ash::{Device, Instance, khr, vk};
use gpu_allocator::vulkan::Allocator;
use gpu_allocator::vulkan::{Allocation, Allocator};
@ -49,6 +49,10 @@ pub struct Renderer {
pub(crate) graphics_pipeline: vk::Pipeline,
/// Memory manager for GPU allocations.
pub(crate) allocator: Allocator,
/// Buffer containing the vertex data for the initial triangle.
pub(crate) vertex_buffer: vk::Buffer,
/// Memory allocation for the vertex buffer.
pub(crate) vertex_allocation: Allocation,
/// Synchronization primitives for frame-by-frame execution.
pub(crate) sync: SyncPrimitives,
/// Index of the current frame being processed (0 to crate::MAX_FRAMES_IN_FLIGHT - 1).
@ -202,6 +206,11 @@ impl Drop for Renderer {
self.device
.destroy_pipeline_layout(self.pipeline_layout, None);
self.allocator.free(std::ptr::read(&self.vertex_allocation))
.expect(" Failed to free vertex buffer allocation");
self.device.destroy_buffer(self.vertex_buffer, None);
self.device.destroy_command_pool(self.command_pool, None);
// Use the safe cleanup function from sync module