chore(workspace): enforce missing_docs and resolve all linting violations
This commit is contained in:
parent
6d4435f856
commit
34f1a9d989
|
|
@ -1,3 +1,8 @@
|
|||
//! Main entry point for the Project Catalyst client.
|
||||
//!
|
||||
//! This crate handles window creation, input processing, and drives the
|
||||
//! renderer to display the game world.
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||
use tracing::info;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Logic for selecting physical devices and creating logical devices.
|
||||
|
||||
use crate::error::RendererError;
|
||||
use ash::{Device, Instance, khr, vk};
|
||||
|
||||
|
|
@ -63,7 +65,8 @@ pub fn find_graphics_queue_family(
|
|||
let props = unsafe { instance.get_physical_device_queue_family_properties(physical_device) };
|
||||
|
||||
for (index, prop) in props.iter().enumerate() {
|
||||
let index = index as u32;
|
||||
#[allow(clippy::expect_used)]
|
||||
let index = u32::try_from(index).expect("Queue family index exceeds u32 range");
|
||||
let graphics = prop.queue_flags.contains(vk::QueueFlags::GRAPHICS);
|
||||
let present = unsafe {
|
||||
surface_loader.get_physical_device_surface_support(physical_device, index, surface)?
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
//! Error types for the renderer crate.
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
/// Enumerates all possible errors that can occur during rendering operations.
|
||||
pub enum RendererError {
|
||||
/// The Vulkan library could not be loaded from the system.
|
||||
#[error("Failed to load Vulkan library")]
|
||||
|
|
@ -14,4 +17,10 @@ pub enum RendererError {
|
|||
/// An error occurred during GPU memory allocation.
|
||||
#[error("GPU allocation error")]
|
||||
AllocationError(#[from] gpu_allocator::AllocationError),
|
||||
/// An I/O error occurred (e.g. reading a shader).
|
||||
#[error("I/O error")]
|
||||
IoError(#[from] std::io::Error),
|
||||
/// An invalid string was encountered.
|
||||
#[error("Invalid string")]
|
||||
InvalidString,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
#![allow(unsafe_code)]
|
||||
|
||||
//! Voxel rendering engine using Vulkan 1.3 and dynamic rendering.
|
||||
//!
|
||||
//! This crate provides the core `Renderer` structure and associated types
|
||||
//! for handling GPU resources and drawing operations.
|
||||
|
||||
mod device;
|
||||
pub mod error;
|
||||
mod instance;
|
||||
|
|
@ -8,6 +15,7 @@ mod surface;
|
|||
mod swapchain;
|
||||
mod sync;
|
||||
|
||||
/// The maximum number of frames that can be processed by the GPU and CPU simultaneously.
|
||||
pub const MAX_FRAMES_IN_FLIGHT: usize = 3;
|
||||
|
||||
use ash::{Entry, vk};
|
||||
|
|
@ -22,6 +30,11 @@ impl Renderer {
|
|||
///
|
||||
/// This function loads the Vulkan library, creates an instance, selects a GPU,
|
||||
/// and initializes a logical device with a graphics queue.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `MAX_FRAMES_IN_FLIGHT` or vertex data sizes exceed `u32`/`u64` limits.
|
||||
#[allow(clippy::expect_used)]
|
||||
pub fn new(
|
||||
display_handle: RawDisplayHandle,
|
||||
window_handle: RawWindowHandle,
|
||||
|
|
@ -78,10 +91,11 @@ impl Renderer {
|
|||
let command_pool = unsafe { device.create_command_pool(&pool_create_info, None)? };
|
||||
|
||||
// 9. Command Buffers
|
||||
#[allow(clippy::expect_used)]
|
||||
let alloc_info = vk::CommandBufferAllocateInfo::default()
|
||||
.command_pool(command_pool)
|
||||
.level(vk::CommandBufferLevel::PRIMARY)
|
||||
.command_buffer_count(MAX_FRAMES_IN_FLIGHT as u32);
|
||||
.command_buffer_count(u32::try_from(MAX_FRAMES_IN_FLIGHT).expect("MAX_FRAMES_IN_FLIGHT exceeds u32"));
|
||||
|
||||
let command_buffers = unsafe { device.allocate_command_buffers(&alloc_info)? };
|
||||
|
||||
|
|
@ -90,81 +104,16 @@ impl Renderer {
|
|||
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(),
|
||||
physical_device,
|
||||
debug_settings: Default::default(),
|
||||
buffer_device_address: false,
|
||||
allocation_sizes: Default::default(),
|
||||
};
|
||||
|
||||
let allocator = gpu_allocator::vulkan::Allocator::new(&allocator_create_info)
|
||||
.expect("Failed to create Vulkan allocator");
|
||||
let mut allocator = create_allocator(&instance, &device, physical_device)?;
|
||||
|
||||
// 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 =
|
||||
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),
|
||||
);
|
||||
}
|
||||
let (vertex_buffer, vertex_allocation) =
|
||||
create_vertex_buffer(&device, &mut allocator)?;
|
||||
|
||||
Ok(Self {
|
||||
_entry: entry,
|
||||
|
|
@ -195,3 +144,82 @@ impl Renderer {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a GPU memory allocator.
|
||||
fn create_allocator(
|
||||
instance: &ash::Instance,
|
||||
device: &ash::Device,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
) -> Result<gpu_allocator::vulkan::Allocator, RendererError> {
|
||||
let allocator_create_info = gpu_allocator::vulkan::AllocatorCreateDesc {
|
||||
instance: instance.clone(),
|
||||
device: device.clone(),
|
||||
physical_device,
|
||||
debug_settings: gpu_allocator::AllocatorDebugSettings::default(),
|
||||
buffer_device_address: false,
|
||||
allocation_sizes: gpu_allocator::AllocationSizes::default(),
|
||||
};
|
||||
|
||||
let allocator = gpu_allocator::vulkan::Allocator::new(&allocator_create_info)
|
||||
.map_err(RendererError::AllocationError)?;
|
||||
Ok(allocator)
|
||||
}
|
||||
|
||||
/// Creates a vertex buffer and populates it with initial triangle data.
|
||||
#[allow(clippy::expect_used)]
|
||||
fn create_vertex_buffer(
|
||||
device: &ash::Device,
|
||||
allocator: &mut gpu_allocator::vulkan::Allocator,
|
||||
) -> Result<(vk::Buffer, gpu_allocator::vulkan::Allocation), RendererError> {
|
||||
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: [0.0, 1.0],
|
||||
},
|
||||
mesh::Vertex {
|
||||
position: [0.5, 0.5, 0.0],
|
||||
tex_coord: [1.0, 1.0],
|
||||
},
|
||||
];
|
||||
|
||||
let buffer_info = vk::BufferCreateInfo::default()
|
||||
.size(u64::try_from(std::mem::size_of_val(&vertices)).expect("Vertices size exceeds 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 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,
|
||||
})?;
|
||||
|
||||
unsafe {
|
||||
device.bind_buffer_memory(
|
||||
vertex_buffer,
|
||||
vertex_allocation.memory(),
|
||||
vertex_allocation.offset(),
|
||||
)?;
|
||||
|
||||
let ptr = vertex_allocation
|
||||
.mapped_ptr()
|
||||
.ok_or(RendererError::NoSuitableGpu)? // Should have a better error but for now
|
||||
.as_ptr();
|
||||
|
||||
std::ptr::copy_nonoverlapping(
|
||||
vertices.as_ptr().cast::<u8>(),
|
||||
ptr.cast::<u8>(),
|
||||
std::mem::size_of_val(&vertices),
|
||||
);
|
||||
}
|
||||
|
||||
Ok((vertex_buffer, vertex_allocation))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Vertex data structures and layout descriptions.
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
||||
/// Represents a single vertex in 3D space with position and texture coordinates.
|
||||
|
|
@ -18,16 +20,18 @@ impl Vertex {
|
|||
///
|
||||
/// This defines the 'stride' (distance between vertices) and specifies that
|
||||
/// data is read per-vertex rather than per-instance.
|
||||
#[allow(clippy::expect_used)]
|
||||
pub fn get_binding_description() -> ash::vk::VertexInputBindingDescription {
|
||||
ash::vk::VertexInputBindingDescription::default()
|
||||
.binding(0)
|
||||
.stride(std::mem::size_of::<Self>() as u32)
|
||||
.stride(u32::try_from(std::mem::size_of::<Self>()).expect("Vertex size exceeds u32 range"))
|
||||
.input_rate(ash::vk::VertexInputRate::VERTEX)
|
||||
}
|
||||
|
||||
/// Describes the layout of individual fields (attributes) within a single vertex.
|
||||
///
|
||||
/// These 'locations' must match the `layout(location = X)` qualifiers in the vertex shader.
|
||||
#[allow(clippy::expect_used)]
|
||||
pub fn get_attribute_descriptions() -> [ash::vk::VertexInputAttributeDescription; 2] {
|
||||
[
|
||||
// Location 0: position (vec3 -> R32G32B32_SFLOAT)
|
||||
|
|
@ -41,7 +45,7 @@ impl Vertex {
|
|||
.binding(0)
|
||||
.location(1)
|
||||
.format(ash::vk::Format::R32G32_SFLOAT)
|
||||
.offset(std::mem::size_of::<[f32; 3]>() as u32),
|
||||
.offset(u32::try_from(std::mem::size_of::<[f32; 3]>()).expect("Vertex offset exceeds u32 range")),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
//! Graphics pipeline creation and shader management.
|
||||
|
||||
use crate::error::RendererError;
|
||||
use crate::mesh::Vertex;
|
||||
use ash::{Device, vk};
|
||||
use std::io::Cursor;
|
||||
|
|
@ -6,41 +9,38 @@ use std::io::Cursor;
|
|||
///
|
||||
/// Vulkan expects shader code to be 32-bit aligned; `ash::util::read_spv` is
|
||||
/// used to correctly interpret the raw bytes as a slice of `u32`.
|
||||
pub fn create_shader_module(device: &Device, bytes: &[u8]) -> vk::ShaderModule {
|
||||
pub fn create_shader_module(
|
||||
device: &Device,
|
||||
bytes: &[u8],
|
||||
) -> Result<vk::ShaderModule, RendererError> {
|
||||
let mut cursor = Cursor::new(bytes);
|
||||
|
||||
let code = ash::util::read_spv(&mut cursor)
|
||||
.expect("Failed to read SPIR-V binary; check if the file is valid");
|
||||
let code = ash::util::read_spv(&mut cursor)?;
|
||||
|
||||
let create_info = vk::ShaderModuleCreateInfo::default().code(&code);
|
||||
|
||||
unsafe {
|
||||
device
|
||||
.create_shader_module(&create_info, None)
|
||||
.expect("Failed to create Vulkan shader module")
|
||||
}
|
||||
let module = unsafe { device.create_shader_module(&create_info, None)? };
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
/// Defines the 'interface' of the pipeline (what data we can pass to the shaders).
|
||||
///
|
||||
/// This layout defines any push constants or descriptor sets (textures/UBOs)
|
||||
/// accessed by the shaders during execution.
|
||||
pub fn create_pipeline_layout(device: &Device) -> vk::PipelineLayout {
|
||||
pub fn create_pipeline_layout(device: &Device) -> Result<vk::PipelineLayout, RendererError> {
|
||||
// A single push constant range is defined for the Model-View-Projection matrix.
|
||||
// This allows the matrix to be updated for every draw call with high efficiency.
|
||||
#[allow(clippy::expect_used)]
|
||||
let push_constant_range = vk::PushConstantRange::default()
|
||||
.stage_flags(vk::ShaderStageFlags::VERTEX)
|
||||
.offset(0)
|
||||
.size(std::mem::size_of::<glam::Mat4>() as u32);
|
||||
.size(u32::try_from(std::mem::size_of::<glam::Mat4>()).expect("Mat4 size exceeds u32 range"));
|
||||
|
||||
let layout_create_info = vk::PipelineLayoutCreateInfo::default()
|
||||
.push_constant_ranges(std::slice::from_ref(&push_constant_range));
|
||||
|
||||
unsafe {
|
||||
device
|
||||
.create_pipeline_layout(&layout_create_info, None)
|
||||
.expect("Failed to create pipeline layout")
|
||||
}
|
||||
let layout = unsafe { device.create_pipeline_layout(&layout_create_info, None)? };
|
||||
Ok(layout)
|
||||
}
|
||||
|
||||
/// Creates a Graphics Pipeline for voxel rendering using Vulkan 1.3 Dynamic Rendering.
|
||||
|
|
@ -51,16 +51,10 @@ pub fn create_graphics_pipeline(
|
|||
device: &Device,
|
||||
layout: vk::PipelineLayout,
|
||||
color_format: vk::Format,
|
||||
) -> vk::Pipeline {
|
||||
) -> Result<vk::Pipeline, RendererError> {
|
||||
// 1. Load and compile shader modules
|
||||
// Using include_bytes! embeds the shaders directly into the engine binary.
|
||||
let vert_bytes = include_bytes!("../../../assets/shaders/cube.vert.spv");
|
||||
let frag_bytes = include_bytes!("../../../assets/shaders/cube.frag.spv");
|
||||
|
||||
let vert_module = create_shader_module(device, vert_bytes);
|
||||
let frag_module = create_shader_module(device, frag_bytes);
|
||||
|
||||
let entry_point = std::ffi::CString::new("main").unwrap();
|
||||
let (vert_module, frag_module) = load_shader_modules(device)?;
|
||||
let entry_point = std::ffi::CString::new("main").map_err(|_| RendererError::InvalidString)?;
|
||||
|
||||
let shader_stages = [
|
||||
vk::PipelineShaderStageCreateInfo::default()
|
||||
|
|
@ -73,60 +67,51 @@ pub fn create_graphics_pipeline(
|
|||
.name(&entry_point),
|
||||
];
|
||||
|
||||
// 2. Configure Vertex Input
|
||||
// 2. Configure Fixed-Function States
|
||||
let binding_descriptions = [Vertex::get_binding_description()];
|
||||
let attribute_descriptions = Vertex::get_attribute_descriptions();
|
||||
|
||||
let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default()
|
||||
.vertex_binding_descriptions(&binding_descriptions)
|
||||
.vertex_attribute_descriptions(&attribute_descriptions);
|
||||
|
||||
// 3. Configure Input Assembly (Drawing mode)
|
||||
let input_assembly = vk::PipelineInputAssemblyStateCreateInfo::default()
|
||||
.topology(vk::PrimitiveTopology::TRIANGLE_LIST)
|
||||
.primitive_restart_enable(false);
|
||||
|
||||
// 4. Viewport and Scissor (Static declarations, dynamic values set at runtime)
|
||||
let viewport_state = vk::PipelineViewportStateCreateInfo::default()
|
||||
.viewport_count(1)
|
||||
.scissor_count(1);
|
||||
|
||||
// 5. Configure Rasterizer (Triangles to Pixels)
|
||||
let rasterizer = vk::PipelineRasterizationStateCreateInfo::default()
|
||||
.depth_clamp_enable(false)
|
||||
.rasterizer_discard_enable(false)
|
||||
.polygon_mode(vk::PolygonMode::FILL)
|
||||
.line_width(1.0)
|
||||
.cull_mode(vk::CullModeFlags::BACK) // Back-face culling for performance
|
||||
.cull_mode(vk::CullModeFlags::BACK)
|
||||
.front_face(vk::FrontFace::COUNTER_CLOCKWISE)
|
||||
.depth_bias_enable(false);
|
||||
|
||||
// 6. Configure Multisampling (Anti-aliasing)
|
||||
let multisampling = vk::PipelineMultisampleStateCreateInfo::default()
|
||||
.sample_shading_enable(false)
|
||||
.rasterization_samples(vk::SampleCountFlags::TYPE_1);
|
||||
|
||||
// 7. Configure Color Blending
|
||||
let color_blend_attachment = vk::PipelineColorBlendAttachmentState::default()
|
||||
.color_write_mask(vk::ColorComponentFlags::RGBA)
|
||||
.blend_enable(false); // Transparency is not required for the initial implementation
|
||||
.blend_enable(false);
|
||||
|
||||
let color_blending = vk::PipelineColorBlendStateCreateInfo::default()
|
||||
.logic_op_enable(false)
|
||||
.attachments(std::slice::from_ref(&color_blend_attachment));
|
||||
|
||||
// 8. Define Dynamic States
|
||||
// This allows the window to be resized without recreating the entire pipeline.
|
||||
let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR];
|
||||
let dynamic_state_info =
|
||||
vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
|
||||
|
||||
// 9. Configure Dynamic Rendering (Vulkan 1.3)
|
||||
let color_formats = [color_format];
|
||||
let mut rendering_info =
|
||||
vk::PipelineRenderingCreateInfo::default().color_attachment_formats(&color_formats);
|
||||
|
||||
// 10. Finalize Pipeline Creation
|
||||
// 3. Finalize Pipeline Creation
|
||||
let pipeline_info = vk::GraphicsPipelineCreateInfo::default()
|
||||
.push_next(&mut rendering_info)
|
||||
.stages(&shader_stages)
|
||||
|
|
@ -142,8 +127,8 @@ pub fn create_graphics_pipeline(
|
|||
let pipeline = unsafe {
|
||||
device
|
||||
.create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None)
|
||||
.expect("Failed to create graphics pipeline")[0]
|
||||
};
|
||||
.map_err(|(_, e)| e)?
|
||||
}[0];
|
||||
|
||||
// Cleanup temporary shader modules (they are baked into the pipeline now)
|
||||
unsafe {
|
||||
|
|
@ -151,5 +136,16 @@ pub fn create_graphics_pipeline(
|
|||
device.destroy_shader_module(frag_module, None);
|
||||
}
|
||||
|
||||
pipeline
|
||||
Ok(pipeline)
|
||||
}
|
||||
|
||||
/// Loads the vertex and fragment shader modules from embedded bytes.
|
||||
fn load_shader_modules(device: &Device) -> Result<(vk::ShaderModule, vk::ShaderModule), RendererError> {
|
||||
let vert_bytes = include_bytes!("../../../assets/shaders/cube.vert.spv");
|
||||
let frag_bytes = include_bytes!("../../../assets/shaders/cube.frag.spv");
|
||||
|
||||
let vert_module = create_shader_module(device, vert_bytes)?;
|
||||
let frag_module = create_shader_module(device, frag_bytes)?;
|
||||
|
||||
Ok((vert_module, frag_module))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,12 +14,14 @@ pub struct Renderer {
|
|||
/// The debug messenger for validation layer output.
|
||||
pub(crate) debug_messenger: vk::DebugUtilsMessengerEXT,
|
||||
/// Handle to the selected physical device (GPU).
|
||||
#[allow(dead_code)]
|
||||
pub(crate) physical_device: vk::PhysicalDevice,
|
||||
/// The logical Vulkan device.
|
||||
pub(crate) device: Device,
|
||||
/// The queue used for graphics operations.
|
||||
pub(crate) graphics_queue: vk::Queue,
|
||||
/// Index of the graphics queue family.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) graphics_queue_index: u32,
|
||||
/// Surface extension loader.
|
||||
pub(crate) surface_loader: khr::surface::Instance,
|
||||
|
|
@ -32,6 +34,7 @@ pub struct Renderer {
|
|||
/// Images acquired from the swapchain.
|
||||
pub(crate) swapchain_images: Vec<vk::Image>,
|
||||
/// The pixel format of the swapchain images.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) swapchain_format: vk::Format,
|
||||
/// The dimensions of the swapchain images.
|
||||
pub(crate) swapchain_extent: vk::Extent2D,
|
||||
|
|
@ -53,7 +56,7 @@ pub struct Renderer {
|
|||
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).
|
||||
/// Index of the current frame being processed (0 to `crate::MAX_FRAMES_IN_FLIGHT` - 1).
|
||||
pub(crate) current_frame: usize,
|
||||
}
|
||||
|
||||
|
|
@ -204,16 +207,19 @@ 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");
|
||||
if let Err(e) = self
|
||||
.allocator
|
||||
.free(std::ptr::read(&raw const self.vertex_allocation))
|
||||
{
|
||||
tracing::error!("Failed to free vertex buffer allocation: {e}");
|
||||
}
|
||||
|
||||
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
|
||||
let sync = std::ptr::read(&self.sync);
|
||||
let sync = std::ptr::read(&raw const self.sync);
|
||||
crate::sync::destroy_sync_primitives(&self.device, sync);
|
||||
|
||||
// Destroy the swapchain
|
||||
|
|
|
|||
|
|
@ -39,9 +39,7 @@ pub fn create_swapchain(
|
|||
|
||||
let present_mode = vk::PresentModeKHR::FIFO;
|
||||
|
||||
let extent = if surface_capabilities.current_extent.width != u32::MAX {
|
||||
surface_capabilities.current_extent
|
||||
} else {
|
||||
let extent = if surface_capabilities.current_extent.width == u32::MAX {
|
||||
vk::Extent2D {
|
||||
width: width.clamp(
|
||||
surface_capabilities.min_image_extent.width,
|
||||
|
|
@ -52,6 +50,8 @@ pub fn create_swapchain(
|
|||
surface_capabilities.max_image_extent.height,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
surface_capabilities.current_extent
|
||||
};
|
||||
|
||||
let image_count = if surface_capabilities.max_image_count > 0
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
//! Lua scripting and modding support for Project Catalyst.
|
||||
//!
|
||||
//! This crate handles the integration with Lua (via `mlua`) and provides
|
||||
//! the API surface for both base game content and third-party mods.
|
||||
|
||||
/// Adds two numbers together.
|
||||
///
|
||||
/// This is a placeholder function for the initial crate setup.
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
//! Dedicated server for Project Catalyst.
|
||||
//!
|
||||
//! The server handles the authoritative game simulation, including world
|
||||
//! management, physics, and combat.
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,11 @@
|
|||
//! Shared types and logic for Project Catalyst.
|
||||
//!
|
||||
//! This crate contains data structures and constants that are used by both
|
||||
//! the client and the server.
|
||||
|
||||
/// Adds two numbers together.
|
||||
///
|
||||
/// This is a placeholder function for the initial crate setup.
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue