feat(renderer): implement vertex buffer allocation and memory mapping
This commit is contained in:
parent
8af89292b6
commit
e6f8414817
|
|
@ -2,10 +2,16 @@ use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum RendererError {
|
pub enum RendererError {
|
||||||
|
/// The Vulkan library could not be loaded from the system.
|
||||||
#[error("Failed to load Vulkan library")]
|
#[error("Failed to load Vulkan library")]
|
||||||
LoadFailed(#[from] ash::LoadingError),
|
LoadFailed(#[from] ash::LoadingError),
|
||||||
|
/// A raw Vulkan result indicated a failure.
|
||||||
#[error("Vulkan error")]
|
#[error("Vulkan error")]
|
||||||
VulkanError(#[from] ash::vk::Result),
|
VulkanError(#[from] ash::vk::Result),
|
||||||
|
/// No GPU was found that meets the engine's requirements.
|
||||||
#[error("No suitable GPU found")]
|
#[error("No suitable GPU found")]
|
||||||
NoSuitableGpu,
|
NoSuitableGpu,
|
||||||
|
/// An error occurred during GPU memory allocation.
|
||||||
|
#[error("GPU allocation error")]
|
||||||
|
AllocationError(#[from] gpu_allocator::AllocationError),
|
||||||
}
|
}
|
||||||
|
|
@ -89,6 +89,8 @@ impl Renderer {
|
||||||
let sync =
|
let sync =
|
||||||
sync::create_sync_primitives(&device, MAX_FRAMES_IN_FLIGHT, swapchain_images.len())?;
|
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 {
|
let allocator_create_info = gpu_allocator::vulkan::AllocatorCreateDesc {
|
||||||
instance: instance.clone(),
|
instance: instance.clone(),
|
||||||
device: device.clone(),
|
device: device.clone(),
|
||||||
|
|
@ -101,10 +103,53 @@ impl Renderer {
|
||||||
let allocator = gpu_allocator::vulkan::Allocator::new(&allocator_create_info)
|
let allocator = gpu_allocator::vulkan::Allocator::new(&allocator_create_info)
|
||||||
.expect("Failed to create Vulkan allocator");
|
.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 pipeline_layout = pipeline::create_pipeline_layout(&device);
|
||||||
let graphics_pipeline =
|
let graphics_pipeline =
|
||||||
pipeline::create_graphics_pipeline(&device, pipeline_layout, swapchain_format);
|
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 {
|
Ok(Self {
|
||||||
_entry: entry,
|
_entry: entry,
|
||||||
instance,
|
instance,
|
||||||
|
|
@ -127,6 +172,8 @@ impl Renderer {
|
||||||
allocator,
|
allocator,
|
||||||
pipeline_layout,
|
pipeline_layout,
|
||||||
graphics_pipeline,
|
graphics_pipeline,
|
||||||
|
vertex_buffer,
|
||||||
|
vertex_allocation,
|
||||||
sync,
|
sync,
|
||||||
current_frame: 0,
|
current_frame: 0,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::error::RendererError;
|
use crate::error::RendererError;
|
||||||
use crate::sync::SyncPrimitives;
|
use crate::sync::SyncPrimitives;
|
||||||
use ash::{Device, Instance, khr, vk};
|
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,
|
pub(crate) graphics_pipeline: vk::Pipeline,
|
||||||
/// Memory manager for GPU allocations.
|
/// Memory manager for GPU allocations.
|
||||||
pub(crate) allocator: Allocator,
|
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.
|
/// Synchronization primitives for frame-by-frame execution.
|
||||||
pub(crate) sync: SyncPrimitives,
|
pub(crate) sync: SyncPrimitives,
|
||||||
/// Index of the current frame being processed (0 to crate::MAX_FRAMES_IN_FLIGHT - 1).
|
/// 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
|
self.device
|
||||||
.destroy_pipeline_layout(self.pipeline_layout, None);
|
.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);
|
self.device.destroy_command_pool(self.command_pool, None);
|
||||||
|
|
||||||
// Use the safe cleanup function from sync module
|
// Use the safe cleanup function from sync module
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue