diff --git a/Cargo.lock b/Cargo.lock index 0d1b366..959c213 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -505,6 +505,19 @@ dependencies = [ "wasi", ] +[[package]] +name = "gpu-allocator" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +dependencies = [ + "ash", + "log", + "presser", + "thiserror", + "windows", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -792,6 +805,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -1159,17 +1178,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "vk-mem" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb12b79bcec57a3334d0284f1364c1846f378bb47df9779c6dbfcfc245c9404" -dependencies = [ - "ash", - "bitflags 2.6.0", - "cc", -] - [[package]] name = "vk-shader-macros" version = "0.2.10" @@ -1190,9 +1198,9 @@ dependencies = [ "ash-window", "dotenvy", "env_logger", + "gpu-allocator", "log", "thiserror", - "vk-mem", "vk-shader-macros", "winit", ] @@ -1417,6 +1425,70 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index 89c3699..96d6179 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,8 @@ ash = "0.38.0" ash-window = "0.13.0" dotenvy = "0.15.7" env_logger = "0.11.3" +gpu-allocator = "0.27.0" log = "0.4.22" thiserror = "1.0.62" -vk-mem = "0.4.0" vk-shader-macros = "0.2.10" winit = { version = "0.29", features = ["rwh_06"] } diff --git a/shaders/shader.frag b/shaders/shader.frag index 5e48a77..44ecd7f 100644 --- a/shaders/shader.frag +++ b/shaders/shader.frag @@ -2,8 +2,8 @@ layout(location = 0) out vec4 theColour; -layout(location = 1) in vec4 colourdata_from_the_vertexshader; +layout(location = 0) in vec4 data_from_the_vertexshader; void main() { - theColour = colourdata_from_the_vertexshader; + theColour = data_from_the_vertexshader; } diff --git a/shaders/shader.vert b/shaders/shader.vert index 27bff2e..93ea71f 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -1,9 +1,13 @@ #version 450 -layout(location = 1) out vec4 colourdata_from_the_vertexshader; +layout(location = 0) in vec4 position; +layout(location = 1) in float size; +layout(location = 2) in vec4 colour; + +layout(location = 0) out vec4 colourdata_for_the_fragmentshader; void main() { - gl_PointSize = 10.0; - gl_Position = vec4(0.0, 0.0, 0.0, 1.0); - colourdata_from_the_vertexshader = vec4(0.0, 0.6, 1.0, 1.0); + gl_PointSize = size; + gl_Position = position; + colourdata_for_the_fragmentshader = vec4(0.4, 1.0, 0.5, 1.0); } diff --git a/src/instance/buffer.rs b/src/instance/buffer.rs new file mode 100644 index 0000000..d8abe7f --- /dev/null +++ b/src/instance/buffer.rs @@ -0,0 +1,89 @@ +use ash::vk; +use gpu_allocator::vulkan::Allocation as GpuAllocation; +use gpu_allocator::vulkan::AllocationCreateDesc; +use gpu_allocator::vulkan::AllocationScheme; +use gpu_allocator::vulkan::Allocator as GpuAllocator; +use gpu_allocator::vulkan::AllocatorCreateDesc; +use gpu_allocator::MemoryLocation; + +use super::EngineError; + +pub struct BufferAllocator { + pub allocator: GpuAllocator, +} + +pub struct Buffer { + pub allocation: Option, + pub buffer: vk::Buffer, +} + +impl BufferAllocator { + pub fn init( + ash_instance: &ash::Instance, + physical_device: vk::PhysicalDevice, + device: &ash::Device, + ) -> Result { + let allocator = GpuAllocator::new(&AllocatorCreateDesc { + instance: ash_instance.clone(), + device: device.clone(), + physical_device, + debug_settings: Default::default(), + buffer_device_address: true, // Ideally, check the BufferDeviceAddressFeatures struct. + allocation_sizes: Default::default(), + })?; + Ok(Self { allocator }) + } + + pub fn create_buffer( + &mut self, + device: &ash::Device, + size: u64, + ) -> Result { + let vk_info = vk::BufferCreateInfo::default() + .size(size) + .usage(vk::BufferUsageFlags::STORAGE_BUFFER); + + let buffer = unsafe { device.create_buffer(&vk_info, None) }.unwrap(); + let requirements = unsafe { device.get_buffer_memory_requirements(buffer) }; + let allocation = self.allocator.allocate(&AllocationCreateDesc { + name: "Example allocation", + requirements, + location: MemoryLocation::CpuToGpu, + linear: true, // Buffers are always linear + allocation_scheme: AllocationScheme::GpuAllocatorManaged, + })?; + + // Bind memory to the buffer + unsafe { + device + .bind_buffer_memory(buffer, allocation.memory(), allocation.offset()) + .unwrap() + }; + + Ok(Buffer { + allocation: Some(allocation), + buffer, + }) + } + + pub fn free_buffer_allocation(&mut self, device: &ash::Device, buffer: &mut Buffer) { + let allocation = buffer.allocation.take(); + self.allocator.free(allocation.unwrap()).unwrap(); + unsafe { device.destroy_buffer(buffer.buffer, None) }; + } +} + +impl Buffer { + pub fn mapped_slice_mut(&mut self) -> Option<&mut [u8]> { + if let Some(v) = &mut self.allocation { + v.mapped_slice_mut() + } else { + None + } + } + + pub unsafe fn fill(&mut self, data: &[u8]) { + let inner_buffer = self.mapped_slice_mut().unwrap(); + inner_buffer.copy_from_slice(data); + } +} diff --git a/src/instance/error.rs b/src/instance/error.rs new file mode 100644 index 0000000..6d52945 --- /dev/null +++ b/src/instance/error.rs @@ -0,0 +1,17 @@ +use ash::vk; + +#[derive(Debug, thiserror::Error)] +pub enum EngineError { + #[error(transparent)] + VkError(#[from] vk::Result), + #[error(transparent)] + AshLoadingError(#[from] ash::LoadingError), + #[error(transparent)] + WinitOsError(#[from] winit::error::OsError), + #[error(transparent)] + WinitEventLoopError(#[from] winit::error::EventLoopError), + #[error(transparent)] + RWHError(#[from] winit::raw_window_handle::HandleError), + #[error(transparent)] + AllocationError(#[from] gpu_allocator::AllocationError), +} diff --git a/src/instance/mod.rs b/src/instance/mod.rs index 69305e9..27ad04f 100644 --- a/src/instance/mod.rs +++ b/src/instance/mod.rs @@ -1,8 +1,11 @@ use std::ffi::{c_char, CString}; use ash::vk; +use buffer::{Buffer, BufferAllocator}; +pub mod buffer; pub mod debug; +pub mod error; pub mod pipeline; pub mod pools; pub mod queue; @@ -10,6 +13,8 @@ pub mod surface; pub mod swapchain; pub mod window; +pub use error::EngineError; + pub use debug::DebugInstance; pub use pipeline::Pipeline; use pools::Pools; @@ -23,20 +28,6 @@ use crate::frame_counter::FrameCounter; const ENGINE_NAME: &core::ffi::CStr = c"UnknownGameEngine"; const APP_NAME: &core::ffi::CStr = c"Vulkan Tutorial"; -#[derive(Debug, thiserror::Error)] -pub enum EngineError { - #[error(transparent)] - VkError(#[from] vk::Result), - #[error(transparent)] - AshLoadingError(#[from] ash::LoadingError), - #[error(transparent)] - WinitOsError(#[from] winit::error::OsError), - #[error(transparent)] - WinitEventLoopError(#[from] winit::error::EventLoopError), - #[error(transparent)] - RWHError(#[from] winit::raw_window_handle::HandleError), -} - pub struct EngineInstance { pub entry: ash::Entry, pub ash_instance: ash::Instance, @@ -53,6 +44,9 @@ pub struct EngineInstance { pub pipeline: Pipeline, pub pools: Pools, pub commandbuffers: Vec, + pub allocator: std::mem::ManuallyDrop, + pub buffer1: Buffer, + pub buffer2: Buffer, pub framecount: FrameCounter, } @@ -118,8 +112,62 @@ impl EngineInstance { let renderpass = Self::init_renderpass(&device, surface_format.format)?; swapchain.create_framebuffers(&device, renderpass)?; + log::debug!("Create allocator"); + let mut allocator = BufferAllocator::init(&ash_instance, physical_device, &device)?; + let mut buffer1 = allocator.create_buffer(&device, 16)?; + + unsafe { + let data: [u8; 16] = std::mem::transmute([-0.5f32, 0.0f32, 0.0f32, 1.0f32]); + buffer1.fill(&data); + } + + let mut buffer2 = allocator.create_buffer(&device, 20)?; + unsafe { + let data: [u8; 20] = std::mem::transmute([5.0f32, 1.0f32, 1.0f32, 0.0f32, 1.0f32]); + buffer2.fill(&data); + } + + let vertex_attrib_descs = [ + vk::VertexInputAttributeDescription { + binding: 0, + location: 0, + offset: 0, + format: vk::Format::R32G32B32A32_SFLOAT, + }, + vk::VertexInputAttributeDescription { + binding: 1, + location: 1, + offset: 0, + format: vk::Format::R32_SFLOAT, + }, + vk::VertexInputAttributeDescription { + binding: 1, + location: 2, + offset: 4, + format: vk::Format::R32G32B32A32_SFLOAT, + }, + ]; + let vertex_binding_descs = [ + vk::VertexInputBindingDescription { + binding: 0, + stride: 16, + input_rate: vk::VertexInputRate::VERTEX, + }, + vk::VertexInputBindingDescription { + binding: 1, + stride: 20, + input_rate: vk::VertexInputRate::VERTEX, + }, + ]; + log::debug!("Init pipeline"); - let pipeline = Pipeline::init(&device, &swapchain, &renderpass)?; + let pipeline = Pipeline::init( + &device, + &swapchain, + &renderpass, + &vertex_attrib_descs, + &vertex_binding_descs, + )?; log::debug!("Init pools"); let pools = Pools::init(&device, &queue_families)?; @@ -127,7 +175,16 @@ impl EngineInstance { log::debug!("Create command buffers"); let commandbuffers = pools.create_commandbuffers(&device, swapchain.framebuffers.len())?; for (i, &commandbuffer) in commandbuffers.iter().enumerate() { - Self::fill_commandbuffer(&device, commandbuffer, renderpass, &swapchain, i, &pipeline)?; + Self::fill_commandbuffer( + &device, + commandbuffer, + renderpass, + &swapchain, + i, + &pipeline, + buffer1.buffer, + buffer2.buffer, + )?; } Ok(Self { @@ -146,6 +203,9 @@ impl EngineInstance { pipeline, pools, commandbuffers, + allocator: std::mem::ManuallyDrop::new(allocator), + buffer1, + buffer2, framecount: FrameCounter::new(), }) } @@ -156,8 +216,14 @@ impl EngineInstance { .device_wait_idle() .expect("something wrong while waiting"); self.pools.cleanup(&self.device); - // self.queues.cleanup(); self.pipeline.cleanup(&self.device); + + self.allocator + .free_buffer_allocation(&self.device, &mut self.buffer1); + self.allocator + .free_buffer_allocation(&self.device, &mut self.buffer2); + std::mem::ManuallyDrop::drop(&mut self.allocator); + self.device.destroy_render_pass(self.renderpass, None); self.swapchain.cleanup(&self.device); std::mem::ManuallyDrop::drop(&mut self.surface); @@ -325,6 +391,9 @@ impl EngineInstance { swapchain: &Swapchain, framebuffer_index: usize, pipeline: &Pipeline, + // buffers: &[vk::Buffer], + buffer1: vk::Buffer, + buffer2: vk::Buffer, ) -> Result<(), vk::Result> { let commandbuffer_begininfo = vk::CommandBufferBeginInfo::default(); unsafe { @@ -356,6 +425,8 @@ impl EngineInstance { vk::PipelineBindPoint::GRAPHICS, pipeline.pipeline, ); + device.cmd_bind_vertex_buffers(commandbuffer, 0, &[buffer1], &[0]); + device.cmd_bind_vertex_buffers(commandbuffer, 1, &[buffer2], &[0]); device.cmd_draw(commandbuffer, 1, 1, 0, 0); device.cmd_end_render_pass(commandbuffer); device.end_command_buffer(commandbuffer)?; diff --git a/src/instance/pipeline.rs b/src/instance/pipeline.rs index 2a763d8..b0a9aab 100644 --- a/src/instance/pipeline.rs +++ b/src/instance/pipeline.rs @@ -21,6 +21,8 @@ impl Pipeline { logical_device: &ash::Device, swapchain: &Swapchain, renderpass: &vk::RenderPass, + vertex_attrib_descs: &[vk::VertexInputAttributeDescription], + vertex_binding_descs: &[vk::VertexInputBindingDescription], ) -> Result { let vertexshader_createinfo = vk::ShaderModuleCreateInfo::default() .code(vk_shader_macros::include_glsl!("./shaders/shader.vert", kind: vert)); @@ -42,18 +44,6 @@ impl Pipeline { .name(&mainfunctionname); let shader_stages = vec![vertexshader_stage, fragmentshader_stage]; - let vertex_attrib_descs = [vk::VertexInputAttributeDescription { - binding: 0, - location: 0, - offset: 0, - format: vk::Format::R32G32B32A32_SFLOAT, - }]; - let vertex_binding_descs = [vk::VertexInputBindingDescription { - binding: 0, - stride: 16, - input_rate: vk::VertexInputRate::VERTEX, - }]; - let vertex_input_info = vk::PipelineVertexInputStateCreateInfo::default() .vertex_attribute_descriptions(&vertex_attrib_descs) .vertex_binding_descriptions(&vertex_binding_descs); diff --git a/src/main.rs b/src/main.rs index c4e8e8a..d2fb0ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,10 +54,7 @@ fn main() -> Result<(), Box> { let semaphores_available = [e.swapchain.image_available[e.swapchain.current_image]]; let waiting_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; - let semaphores_finished = [ - e.swapchain.rendering_finished[e.swapchain.current_image], - // e.swapchain.next_frame[next_image], - ]; + let semaphores_finished = [e.swapchain.rendering_finished[e.swapchain.current_image]]; let commandbuffers = [e.commandbuffers[image_index as usize]]; let submit_info = [vk::SubmitInfo::default() .wait_semaphores(&semaphores_available)