chore(workspace): configure linters and format codebase
This commit is contained in:
parent
f483d4b981
commit
fd5d5e4e4b
63
.github/workflows/ci.yml
vendored
Normal file
63
.github/workflows/ci.yml
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "dev" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "dev", "main" ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
rust-lint:
|
||||||
|
name: Rust Check & Lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
components: clippy, rustfmt
|
||||||
|
|
||||||
|
- name: Check Rust Formatting
|
||||||
|
run: cargo fmt --all -- --check
|
||||||
|
|
||||||
|
- name: Run Clippy
|
||||||
|
# -D warnings turns all clippy warnings into hard errors that fail the build
|
||||||
|
run: cargo clippy --all-targets --all-features -- -D warnings
|
||||||
|
|
||||||
|
lua-lint:
|
||||||
|
name: Lua Lint & Format
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install StyLua
|
||||||
|
uses: JohnnyMorganz/stylua-action@v4
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Check Lua Formatting
|
||||||
|
# We use a glob that won't fail if the directories don't exist yet
|
||||||
|
run: |
|
||||||
|
if [ -d "assets/scripts" ] || [ -d "mods" ]; then
|
||||||
|
stylua --check assets/scripts/ mods/ 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "No Lua scripts found to format yet."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install Selene
|
||||||
|
uses: NTBBloodbath/selene-action@v1.0.0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Run Selene
|
||||||
|
run: |
|
||||||
|
if [ -d "assets/scripts" ] || [ -d "mods" ]; then
|
||||||
|
selene assets/scripts/ mods/ 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "No Lua scripts found to lint yet."
|
||||||
|
fi
|
||||||
21
Cargo.toml
21
Cargo.toml
|
|
@ -1,3 +1,24 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["crates/*"]
|
members = ["crates/*"]
|
||||||
|
|
||||||
|
[workspace.lints.rust]
|
||||||
|
unsafe_code = "warn"
|
||||||
|
missing_docs = "warn"
|
||||||
|
|
||||||
|
[workspace.lints.clippy]
|
||||||
|
unwrap_used = "warn"
|
||||||
|
expect_used = "warn"
|
||||||
|
print_stdout = "warn"
|
||||||
|
print_stderr = "warn"
|
||||||
|
|
||||||
|
pedantic = { level = "warn", priority = -1 }
|
||||||
|
clone_on_ref_ptr = "warn"
|
||||||
|
|
||||||
|
todo = "warn"
|
||||||
|
unimplemented = "warn"
|
||||||
|
|
||||||
|
# Pedantic exceptions (too noisy)
|
||||||
|
module_name_repetitions = "allow"
|
||||||
|
must_use_candidate = "allow"
|
||||||
|
missing_errors_doc = "allow"
|
||||||
|
|
@ -3,6 +3,9 @@ name = "client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
tracing = "0.1.44"
|
tracing = "0.1.44"
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,21 @@ struct App {
|
||||||
|
|
||||||
impl ApplicationHandler for App {
|
impl ApplicationHandler for App {
|
||||||
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
let attributes = Window::default_attributes()
|
let attributes = Window::default_attributes().with_title("Project Catalyst");
|
||||||
.with_title("Project Catalyst");
|
|
||||||
|
|
||||||
self.window = Some(event_loop.create_window(attributes).unwrap());
|
self.window = Some(event_loop.create_window(attributes).unwrap());
|
||||||
|
|
||||||
let display_handle = event_loop.display_handle()
|
let display_handle = event_loop
|
||||||
|
.display_handle()
|
||||||
.expect("Failed to get display handle")
|
.expect("Failed to get display handle")
|
||||||
.as_raw();
|
.as_raw();
|
||||||
|
|
||||||
// Get the window handle for surface creation
|
// Get the window handle for surface creation
|
||||||
let window_handle = self.window.as_ref().unwrap().window_handle()
|
let window_handle = self
|
||||||
|
.window
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.window_handle()
|
||||||
.expect("Failed to get window handle")
|
.expect("Failed to get window handle")
|
||||||
.as_raw();
|
.as_raw();
|
||||||
|
|
||||||
|
|
@ -48,7 +52,7 @@ impl ApplicationHandler for App {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => {
|
WindowEvent::CloseRequested => {
|
||||||
event_loop.exit();
|
event_loop.exit();
|
||||||
},
|
}
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
if let Some(renderer) = self.renderer.as_mut() {
|
if let Some(renderer) = self.renderer.as_mut() {
|
||||||
renderer.draw_frame().expect("Failed to draw frame");
|
renderer.draw_frame().expect("Failed to draw frame");
|
||||||
|
|
@ -74,6 +78,8 @@ fn main() -> Result<()> {
|
||||||
event_loop.set_control_flow(ControlFlow::Poll);
|
event_loop.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
event_loop.run_app(&mut app).context("Failed to run event loop")?;
|
event_loop
|
||||||
|
.run_app(&mut app)
|
||||||
|
.context("Failed to run event loop")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,9 @@ name = "renderer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ash = "0.38.0"
|
ash = "0.38.0"
|
||||||
ash-window = "0.13.0"
|
ash-window = "0.13.0"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use ash::{Device, Instance, khr, vk};
|
|
||||||
use crate::error::RendererError;
|
use crate::error::RendererError;
|
||||||
|
use ash::{Device, Instance, khr, vk};
|
||||||
|
|
||||||
/// Picks a physical device (GPU) that supports the required features and extensions.
|
/// Picks a physical device (GPU) that supports the required features and extensions.
|
||||||
pub fn pick_physical_device(
|
pub fn pick_physical_device(
|
||||||
|
|
@ -12,7 +12,8 @@ pub fn pick_physical_device(
|
||||||
for device in devices {
|
for device in devices {
|
||||||
if is_device_suitable(instance, device, surface_loader, surface) {
|
if is_device_suitable(instance, device, surface_loader, surface) {
|
||||||
let props = unsafe { instance.get_physical_device_properties(device) };
|
let props = unsafe { instance.get_physical_device_properties(device) };
|
||||||
let name = unsafe { std::ffi::CStr::from_ptr(props.device_name.as_ptr()).to_string_lossy() };
|
let name =
|
||||||
|
unsafe { std::ffi::CStr::from_ptr(props.device_name.as_ptr()).to_string_lossy() };
|
||||||
tracing::info!("Selected GPU: \"{name}\"");
|
tracing::info!("Selected GPU: \"{name}\"");
|
||||||
return Ok(device);
|
return Ok(device);
|
||||||
}
|
}
|
||||||
|
|
@ -35,10 +36,10 @@ pub fn create_logical_device(
|
||||||
let device_extensions = [khr::swapchain::NAME.as_ptr()];
|
let device_extensions = [khr::swapchain::NAME.as_ptr()];
|
||||||
|
|
||||||
// Enable Vulkan 1.3 features
|
// Enable Vulkan 1.3 features
|
||||||
let mut synchronization2_features = vk::PhysicalDeviceSynchronization2Features::default()
|
let mut synchronization2_features =
|
||||||
.synchronization2(true);
|
vk::PhysicalDeviceSynchronization2Features::default().synchronization2(true);
|
||||||
let mut dynamic_rendering_features = vk::PhysicalDeviceDynamicRenderingFeatures::default()
|
let mut dynamic_rendering_features =
|
||||||
.dynamic_rendering(true);
|
vk::PhysicalDeviceDynamicRenderingFeatures::default().dynamic_rendering(true);
|
||||||
|
|
||||||
let create_info = vk::DeviceCreateInfo::default()
|
let create_info = vk::DeviceCreateInfo::default()
|
||||||
.queue_create_infos(std::slice::from_ref(&queue_info))
|
.queue_create_infos(std::slice::from_ref(&queue_info))
|
||||||
|
|
@ -82,16 +83,24 @@ fn is_device_suitable(
|
||||||
surface_loader: &khr::surface::Instance,
|
surface_loader: &khr::surface::Instance,
|
||||||
surface: vk::SurfaceKHR,
|
surface: vk::SurfaceKHR,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let extensions = unsafe { instance.enumerate_device_extension_properties(device).unwrap_or_default() };
|
let extensions = unsafe {
|
||||||
let has_swapchain = extensions.iter().any(|ext| {
|
instance
|
||||||
unsafe { std::ffi::CStr::from_ptr(ext.extension_name.as_ptr()) == khr::swapchain::NAME }
|
.enumerate_device_extension_properties(device)
|
||||||
|
.unwrap_or_default()
|
||||||
|
};
|
||||||
|
let has_swapchain = extensions.iter().any(|ext| unsafe {
|
||||||
|
std::ffi::CStr::from_ptr(ext.extension_name.as_ptr()) == khr::swapchain::NAME
|
||||||
});
|
});
|
||||||
|
|
||||||
let formats = unsafe {
|
let formats = unsafe {
|
||||||
surface_loader.get_physical_device_surface_formats(device, surface).unwrap_or_default()
|
surface_loader
|
||||||
|
.get_physical_device_surface_formats(device, surface)
|
||||||
|
.unwrap_or_default()
|
||||||
};
|
};
|
||||||
let present_modes = unsafe {
|
let present_modes = unsafe {
|
||||||
surface_loader.get_physical_device_surface_present_modes(device, surface).unwrap_or_default()
|
surface_loader
|
||||||
|
.get_physical_device_surface_present_modes(device, surface)
|
||||||
|
.unwrap_or_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
has_swapchain && !formats.is_empty() && !present_modes.is_empty()
|
has_swapchain && !formats.is_empty() && !present_modes.is_empty()
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,20 @@
|
||||||
use std::ffi::{CStr, c_char};
|
|
||||||
use ash::{Entry, Instance, ext, vk};
|
|
||||||
use tracing::{debug, error, info, warn};
|
|
||||||
use crate::error::RendererError;
|
use crate::error::RendererError;
|
||||||
|
use ash::{Entry, Instance, ext, vk};
|
||||||
|
use std::ffi::{CStr, c_char};
|
||||||
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
/// Creates a Vulkan instance and optionally a debug messenger.
|
/// Creates a Vulkan instance and optionally a debug messenger.
|
||||||
pub fn create_instance(
|
pub fn create_instance(
|
||||||
entry: &Entry,
|
entry: &Entry,
|
||||||
required_extensions: &[*const c_char],
|
required_extensions: &[*const c_char],
|
||||||
) -> Result<(Instance, Option<ext::debug_utils::Instance>, vk::DebugUtilsMessengerEXT), RendererError> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
Instance,
|
||||||
|
Option<ext::debug_utils::Instance>,
|
||||||
|
vk::DebugUtilsMessengerEXT,
|
||||||
|
),
|
||||||
|
RendererError,
|
||||||
|
> {
|
||||||
let mut extensions = required_extensions.to_vec();
|
let mut extensions = required_extensions.to_vec();
|
||||||
let mut layers = Vec::new();
|
let mut layers = Vec::new();
|
||||||
|
|
||||||
|
|
@ -17,8 +24,7 @@ pub fn create_instance(
|
||||||
layers.push(c"VK_LAYER_KHRONOS_validation".as_ptr());
|
layers.push(c"VK_LAYER_KHRONOS_validation".as_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
let app_info = vk::ApplicationInfo::default()
|
let app_info = vk::ApplicationInfo::default().api_version(vk::API_VERSION_1_3);
|
||||||
.api_version(vk::API_VERSION_1_3);
|
|
||||||
|
|
||||||
let create_info = vk::InstanceCreateInfo::default()
|
let create_info = vk::InstanceCreateInfo::default()
|
||||||
.application_info(&app_info)
|
.application_info(&app_info)
|
||||||
|
|
@ -31,13 +37,13 @@ pub fn create_instance(
|
||||||
let (debug_utils, debug_messenger) = {
|
let (debug_utils, debug_messenger) = {
|
||||||
let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::default()
|
let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::default()
|
||||||
.message_severity(
|
.message_severity(
|
||||||
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING |
|
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
|
||||||
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR
|
| vk::DebugUtilsMessageSeverityFlagsEXT::ERROR,
|
||||||
)
|
)
|
||||||
.message_type(
|
.message_type(
|
||||||
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL |
|
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
|
||||||
vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION |
|
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
|
||||||
vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE
|
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
|
||||||
)
|
)
|
||||||
.pfn_user_callback(Some(vulkan_debug_callback));
|
.pfn_user_callback(Some(vulkan_debug_callback));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,9 +112,18 @@ impl Renderer {
|
||||||
// 13. Vertex Buffer Initialization
|
// 13. Vertex Buffer Initialization
|
||||||
// A simple triangle is defined in normalized device coordinates and moved to GPU memory.
|
// A simple triangle is defined in normalized device coordinates and moved to GPU memory.
|
||||||
let vertices = [
|
let vertices = [
|
||||||
mesh::Vertex { position: [0.0, -0.5, 0.0], tex_coord: [0.5, 0.0] },
|
mesh::Vertex {
|
||||||
mesh::Vertex { position: [0.5, 0.5, 0.0], tex_coord: [1.0, 1.0] },
|
position: [0.0, -0.5, 0.0],
|
||||||
mesh::Vertex { position: [-0.5, 0.5, 0.0], tex_coord: [0.0, 1.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.
|
// Create the buffer handle and query its memory requirements.
|
||||||
|
|
@ -128,26 +137,33 @@ impl Renderer {
|
||||||
let mut allocator = allocator;
|
let mut allocator = allocator;
|
||||||
|
|
||||||
// Allocate memory that is visible to the CPU for data transfer.
|
// Allocate memory that is visible to the CPU for data transfer.
|
||||||
let vertex_allocation = allocator.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
|
let vertex_allocation =
|
||||||
name: "Vertex Buffer",
|
allocator.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
|
||||||
requirements,
|
name: "Vertex Buffer",
|
||||||
location: gpu_allocator::MemoryLocation::CpuToGpu,
|
requirements,
|
||||||
linear: true,
|
location: gpu_allocator::MemoryLocation::CpuToGpu,
|
||||||
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
|
linear: true,
|
||||||
})?;
|
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
|
||||||
|
})?;
|
||||||
|
|
||||||
// Bind the allocated memory to the buffer handle and copy the vertex data.
|
// Bind the allocated memory to the buffer handle and copy the vertex data.
|
||||||
unsafe {
|
unsafe {
|
||||||
device.bind_buffer_memory(vertex_buffer, vertex_allocation.memory(), vertex_allocation.offset())?;
|
device.bind_buffer_memory(
|
||||||
|
vertex_buffer,
|
||||||
|
vertex_allocation.memory(),
|
||||||
|
vertex_allocation.offset(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let ptr = vertex_allocation.mapped_ptr()
|
let ptr = vertex_allocation
|
||||||
|
.mapped_ptr()
|
||||||
.expect("Failed to map vertex buffer memory")
|
.expect("Failed to map vertex buffer memory")
|
||||||
.as_ptr();
|
.as_ptr();
|
||||||
|
|
||||||
std::ptr::copy_nonoverlapping(
|
std::ptr::copy_nonoverlapping(
|
||||||
vertices.as_ptr() as *const u8,
|
vertices.as_ptr() as *const u8,
|
||||||
ptr as *mut u8,
|
ptr as *mut u8,
|
||||||
std::mem::size_of_val(&vertices));
|
std::mem::size_of_val(&vertices),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use ash::{vk, Device};
|
|
||||||
use std::io::Cursor;
|
|
||||||
use crate::mesh::Vertex;
|
use crate::mesh::Vertex;
|
||||||
|
use ash::{Device, vk};
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
/// Helper to load SPIR-V bytes and create a Vulkan Shader Module.
|
/// Helper to load SPIR-V bytes and create a Vulkan Shader Module.
|
||||||
///
|
///
|
||||||
|
|
@ -15,7 +15,8 @@ pub fn create_shader_module(device: &Device, bytes: &[u8]) -> vk::ShaderModule {
|
||||||
let create_info = vk::ShaderModuleCreateInfo::default().code(&code);
|
let create_info = vk::ShaderModuleCreateInfo::default().code(&code);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
device.create_shader_module(&create_info, None)
|
device
|
||||||
|
.create_shader_module(&create_info, None)
|
||||||
.expect("Failed to create Vulkan shader module")
|
.expect("Failed to create Vulkan shader module")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +37,8 @@ pub fn create_pipeline_layout(device: &Device) -> vk::PipelineLayout {
|
||||||
.push_constant_ranges(std::slice::from_ref(&push_constant_range));
|
.push_constant_ranges(std::slice::from_ref(&push_constant_range));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
device.create_pipeline_layout(&layout_create_info, None)
|
device
|
||||||
|
.create_pipeline_layout(&layout_create_info, None)
|
||||||
.expect("Failed to create pipeline layout")
|
.expect("Failed to create pipeline layout")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +50,7 @@ pub fn create_pipeline_layout(device: &Device) -> vk::PipelineLayout {
|
||||||
pub fn create_graphics_pipeline(
|
pub fn create_graphics_pipeline(
|
||||||
device: &Device,
|
device: &Device,
|
||||||
layout: vk::PipelineLayout,
|
layout: vk::PipelineLayout,
|
||||||
color_format: vk::Format
|
color_format: vk::Format,
|
||||||
) -> vk::Pipeline {
|
) -> vk::Pipeline {
|
||||||
// 1. Load and compile shader modules
|
// 1. Load and compile shader modules
|
||||||
// Using include_bytes! embeds the shaders directly into the engine binary.
|
// Using include_bytes! embeds the shaders directly into the engine binary.
|
||||||
|
|
@ -116,13 +118,13 @@ pub fn create_graphics_pipeline(
|
||||||
// 8. Define Dynamic States
|
// 8. Define Dynamic States
|
||||||
// This allows the window to be resized without recreating the entire pipeline.
|
// This allows the window to be resized without recreating the entire pipeline.
|
||||||
let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR];
|
let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR];
|
||||||
let dynamic_state_info = vk::PipelineDynamicStateCreateInfo::default()
|
let dynamic_state_info =
|
||||||
.dynamic_states(&dynamic_states);
|
vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states);
|
||||||
|
|
||||||
// 9. Configure Dynamic Rendering (Vulkan 1.3)
|
// 9. Configure Dynamic Rendering (Vulkan 1.3)
|
||||||
let color_formats = [color_format];
|
let color_formats = [color_format];
|
||||||
let mut rendering_info = vk::PipelineRenderingCreateInfo::default()
|
let mut rendering_info =
|
||||||
.color_attachment_formats(&color_formats);
|
vk::PipelineRenderingCreateInfo::default().color_attachment_formats(&color_formats);
|
||||||
|
|
||||||
// 10. Finalize Pipeline Creation
|
// 10. Finalize Pipeline Creation
|
||||||
let pipeline_info = vk::GraphicsPipelineCreateInfo::default()
|
let pipeline_info = vk::GraphicsPipelineCreateInfo::default()
|
||||||
|
|
@ -138,7 +140,8 @@ pub fn create_graphics_pipeline(
|
||||||
.layout(layout);
|
.layout(layout);
|
||||||
|
|
||||||
let pipeline = unsafe {
|
let pipeline = unsafe {
|
||||||
device.create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None)
|
device
|
||||||
|
.create_graphics_pipelines(vk::PipelineCache::null(), &[pipeline_info], None)
|
||||||
.expect("Failed to create graphics pipeline")[0]
|
.expect("Failed to create graphics pipeline")[0]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ use crate::sync::SyncPrimitives;
|
||||||
use ash::{Device, Instance, khr, vk};
|
use ash::{Device, Instance, khr, vk};
|
||||||
use gpu_allocator::vulkan::{Allocation, Allocator};
|
use gpu_allocator::vulkan::{Allocation, Allocator};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// The core renderer structure holding the Vulkan resources.
|
/// The core renderer structure holding the Vulkan resources.
|
||||||
pub struct Renderer {
|
pub struct Renderer {
|
||||||
/// Entry point to the Vulkan library.
|
/// Entry point to the Vulkan library.
|
||||||
|
|
@ -206,7 +204,8 @@ 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))
|
self.allocator
|
||||||
|
.free(std::ptr::read(&self.vertex_allocation))
|
||||||
.expect(" Failed to free vertex buffer allocation");
|
.expect(" Failed to free vertex buffer allocation");
|
||||||
|
|
||||||
self.device.destroy_buffer(self.vertex_buffer, None);
|
self.device.destroy_buffer(self.vertex_buffer, None);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
use crate::error::RendererError;
|
||||||
use ash::{Entry, Instance, khr, vk};
|
use ash::{Entry, Instance, khr, vk};
|
||||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||||
use crate::error::RendererError;
|
|
||||||
|
|
||||||
/// Creates a Vulkan surface for the given window.
|
/// Creates a Vulkan surface for the given window.
|
||||||
pub fn create_surface(
|
pub fn create_surface(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use ash::{Device, Instance, khr, vk};
|
|
||||||
use crate::error::RendererError;
|
use crate::error::RendererError;
|
||||||
|
use ash::{Device, Instance, khr, vk};
|
||||||
|
|
||||||
/// Creates a swapchain and retrieves its images.
|
/// Creates a swapchain and retrieves its images.
|
||||||
pub fn create_swapchain(
|
pub fn create_swapchain(
|
||||||
|
|
@ -10,19 +10,31 @@ pub fn create_swapchain(
|
||||||
surface: vk::SurfaceKHR,
|
surface: vk::SurfaceKHR,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
) -> Result<(khr::swapchain::Device, vk::SwapchainKHR, Vec<vk::Image>, vk::Format, vk::Extent2D), RendererError> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
khr::swapchain::Device,
|
||||||
|
vk::SwapchainKHR,
|
||||||
|
Vec<vk::Image>,
|
||||||
|
vk::Format,
|
||||||
|
vk::Extent2D,
|
||||||
|
),
|
||||||
|
RendererError,
|
||||||
|
> {
|
||||||
let surface_capabilities = unsafe {
|
let surface_capabilities = unsafe {
|
||||||
surface_loader.get_physical_device_surface_capabilities(physical_device, surface)?
|
surface_loader.get_physical_device_surface_capabilities(physical_device, surface)?
|
||||||
};
|
};
|
||||||
let surface_formats = unsafe {
|
let surface_formats =
|
||||||
surface_loader.get_physical_device_surface_formats(physical_device, surface)?
|
unsafe { surface_loader.get_physical_device_surface_formats(physical_device, surface)? };
|
||||||
};
|
|
||||||
let _surface_present_modes = unsafe {
|
let _surface_present_modes = unsafe {
|
||||||
surface_loader.get_physical_device_surface_present_modes(physical_device, surface)?
|
surface_loader.get_physical_device_surface_present_modes(physical_device, surface)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let format = surface_formats.iter()
|
let format = surface_formats
|
||||||
.find(|f| f.format == vk::Format::B8G8R8A8_SRGB && f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR)
|
.iter()
|
||||||
|
.find(|f| {
|
||||||
|
f.format == vk::Format::B8G8R8A8_SRGB
|
||||||
|
&& f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
|
||||||
|
})
|
||||||
.unwrap_or(&surface_formats[0]);
|
.unwrap_or(&surface_formats[0]);
|
||||||
|
|
||||||
let present_mode = vk::PresentModeKHR::FIFO;
|
let present_mode = vk::PresentModeKHR::FIFO;
|
||||||
|
|
@ -31,12 +43,20 @@ pub fn create_swapchain(
|
||||||
surface_capabilities.current_extent
|
surface_capabilities.current_extent
|
||||||
} else {
|
} else {
|
||||||
vk::Extent2D {
|
vk::Extent2D {
|
||||||
width: width.clamp(surface_capabilities.min_image_extent.width, surface_capabilities.max_image_extent.width),
|
width: width.clamp(
|
||||||
height: height.clamp(surface_capabilities.min_image_extent.height, surface_capabilities.max_image_extent.height),
|
surface_capabilities.min_image_extent.width,
|
||||||
|
surface_capabilities.max_image_extent.width,
|
||||||
|
),
|
||||||
|
height: height.clamp(
|
||||||
|
surface_capabilities.min_image_extent.height,
|
||||||
|
surface_capabilities.max_image_extent.height,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let image_count = if surface_capabilities.max_image_count > 0 && surface_capabilities.min_image_count + 1 > surface_capabilities.max_image_count {
|
let image_count = if surface_capabilities.max_image_count > 0
|
||||||
|
&& surface_capabilities.min_image_count + 1 > surface_capabilities.max_image_count
|
||||||
|
{
|
||||||
surface_capabilities.max_image_count
|
surface_capabilities.max_image_count
|
||||||
} else {
|
} else {
|
||||||
surface_capabilities.min_image_count + 1
|
surface_capabilities.min_image_count + 1
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use ash::{Device, vk};
|
|
||||||
use crate::error::RendererError;
|
use crate::error::RendererError;
|
||||||
|
use ash::{Device, vk};
|
||||||
|
|
||||||
/// Groups all synchronization primitives for the renderer.
|
/// Groups all synchronization primitives for the renderer.
|
||||||
pub struct SyncPrimitives {
|
pub struct SyncPrimitives {
|
||||||
|
|
@ -18,8 +18,7 @@ pub fn create_sync_primitives(
|
||||||
image_count: usize,
|
image_count: usize,
|
||||||
) -> Result<SyncPrimitives, RendererError> {
|
) -> Result<SyncPrimitives, RendererError> {
|
||||||
let semaphore_info = vk::SemaphoreCreateInfo::default();
|
let semaphore_info = vk::SemaphoreCreateInfo::default();
|
||||||
let fence_info = vk::FenceCreateInfo::default()
|
let fence_info = vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED);
|
||||||
.flags(vk::FenceCreateFlags::SIGNALED);
|
|
||||||
|
|
||||||
let mut image_available = Vec::with_capacity(max_frames_in_flight);
|
let mut image_available = Vec::with_capacity(max_frames_in_flight);
|
||||||
let mut render_finished = Vec::with_capacity(image_count);
|
let mut render_finished = Vec::with_capacity(image_count);
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,7 @@ name = "scripting"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,7 @@ name = "server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,7 @@ name = "shared"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
||||||
3
rustfmt.toml
Normal file
3
rustfmt.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
edition = "2024"
|
||||||
|
# By default, rustfmt enforces standard Rust formatting rules.
|
||||||
|
# You can override specific rules here if you disagree with the standard.
|
||||||
4
selene.toml
Normal file
4
selene.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
std = "lua54"
|
||||||
|
|
||||||
|
[rules]
|
||||||
|
unknown_variable = "error"
|
||||||
5
stylua.toml
Normal file
5
stylua.toml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
column_width = 120
|
||||||
|
line_endings = "Unix"
|
||||||
|
indent_type = "Spaces"
|
||||||
|
indent_width = 4
|
||||||
|
quote_style = "AutoPreferDouble"
|
||||||
Loading…
Reference in a new issue