diff --git a/shaders/shader.vert b/shaders/shader.vert index cb40e1e..b56a6bc 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -1,11 +1,18 @@ #version 450 +layout(binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + + layout(location = 0) in vec2 inPosition; layout(location = 1) in vec3 inColor; layout(location = 0) out vec3 fragColor; void main() { - gl_Position = vec4(inPosition, 0.0, 1.0); + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); fragColor = inColor; } \ No newline at end of file diff --git a/shaders/vert.spv b/shaders/vert.spv index 1e4ce0c..2b7afb0 100644 Binary files a/shaders/vert.spv and b/shaders/vert.spv differ diff --git a/src/app_data.rs b/src/app_data.rs index 4dfc417..21b9205 100644 --- a/src/app_data.rs +++ b/src/app_data.rs @@ -15,6 +15,7 @@ pub struct AppData { pub swapchain_image_views: Vec, + pub descriptor_set_layout: vk::DescriptorSetLayout, pub pipeline_layout: vk::PipelineLayout, pub render_pass: vk::RenderPass, pub pipeline: vk::Pipeline, @@ -30,4 +31,14 @@ pub struct AppData { pub vertex_buffer: vk::Buffer, pub vertex_buffer_memory: vk::DeviceMemory, + + pub index_buffer: vk::Buffer, + pub index_buffer_memory: vk::DeviceMemory, + + + pub uniform_buffers: Vec, + pub uniform_buffers_memory: Vec, + + pub descriptor_pool: vk::DescriptorPool, + pub descriptor_sets: Vec, } \ No newline at end of file diff --git a/src/buffer.rs b/src/buffer.rs new file mode 100644 index 0000000..985307c --- /dev/null +++ b/src/buffer.rs @@ -0,0 +1,291 @@ +use anyhow::{anyhow, Result}; + +use vulkanalia::prelude::v1_0::*; + +use std::mem::size_of; +use std::ptr::copy_nonoverlapping as memcpy; + +use cgmath::{vec2, vec3}; + +pub type Mat4 = cgmath::Matrix4; + +use crate::app_data; +use crate::vertex; + +static VERTICES: [vertex::Vertex; 4] = [ + vertex::Vertex::new(vec2(-0.5, -0.5), vec3(1.0, 0.0, 0.0)), + vertex::Vertex::new(vec2(0.5, -0.5), vec3(0.0, 1.0, 0.0)), + vertex::Vertex::new(vec2(0.5, 0.5), vec3(0.0, 0.0, 1.0)), + vertex::Vertex::new(vec2(-0.5, 0.5), vec3(1.0, 1.0, 1.0)), +]; + +pub const INDICES: &[u16] = &[0, 1, 2, 2, 3, 0]; + +pub unsafe fn create_buffer( + instance: &Instance, + device: &Device, + data: &app_data::AppData, + size: vk::DeviceSize, + usage: vk::BufferUsageFlags, + properties: vk::MemoryPropertyFlags, +) -> Result<(vk::Buffer, vk::DeviceMemory)> { + let buffer_info = vk::BufferCreateInfo::builder() + .size(size) + .usage(usage) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + let buffer = device.create_buffer(&buffer_info, None)?; + + let requirements = device.get_buffer_memory_requirements(buffer); + + let memory_info = vk::MemoryAllocateInfo::builder() + .allocation_size(requirements.size) + .memory_type_index(get_memory_type_index( + instance, + data, + properties, + requirements, + )?); + + let buffer_memory = device.allocate_memory(&memory_info, None)?; + + device.bind_buffer_memory(buffer, buffer_memory, 0)?; + + Ok((buffer, buffer_memory)) +} + +pub unsafe fn create_vertex_buffer( + instance: &Instance, + device: &Device, + data: &mut app_data::AppData, +) -> Result<()> { + let size = (size_of::() * VERTICES.len()) as u64; + + let (staging_buffer, staging_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_SRC, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + let memory = device.map_memory( + staging_buffer_memory, + 0, + size, + vk::MemoryMapFlags::empty(), + )?; + + memcpy(VERTICES.as_ptr(), memory.cast(), VERTICES.len()); + + device.unmap_memory(staging_buffer_memory); + + let (vertex_buffer, vertex_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )?; + + data.vertex_buffer = vertex_buffer; + data.vertex_buffer_memory = vertex_buffer_memory; + + copy_buffer(device, data, staging_buffer, vertex_buffer, size)?; + + device.destroy_buffer(staging_buffer, None); + device.free_memory(staging_buffer_memory, None); + + Ok(()) +} + +pub unsafe fn get_memory_type_index( + instance: &Instance, + data: &app_data::AppData, + properties: vk::MemoryPropertyFlags, + requirements: vk::MemoryRequirements, +) -> Result { + let memory = instance.get_physical_device_memory_properties(data.physical_device); + + (0..memory.memory_type_count) + .find(|i| { + let suitable = (requirements.memory_type_bits & (1 << i)) != 0; + let memory_type = memory.memory_types[*i as usize]; + suitable && memory_type.property_flags.contains(properties) + }) + .ok_or_else(|| anyhow!("Failed to find suitable memory type.")) +} + +pub unsafe fn copy_buffer( + device: &Device, + data: &app_data::AppData, + source: vk::Buffer, + destination: vk::Buffer, + size: vk::DeviceSize, +) -> Result<()> { + let info = vk::CommandBufferAllocateInfo::builder() + .level(vk::CommandBufferLevel::PRIMARY) + .command_pool(data.command_pool) + .command_buffer_count(1); + + let command_buffer = device.allocate_command_buffers(&info)?[0]; + + let info = vk::CommandBufferBeginInfo::builder() + .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); + + device.begin_command_buffer(command_buffer, &info)?; + let regions = vk::BufferCopy::builder().size(size); + device.cmd_copy_buffer(command_buffer, source, destination, &[regions]); + + device.end_command_buffer(command_buffer)?; + + let command_buffers = &[command_buffer]; + let info = vk::SubmitInfo::builder() + .command_buffers(command_buffers); + + device.queue_submit(data.graphics_queue, &[info], vk::Fence::null())?; + device.queue_wait_idle(data.graphics_queue)?; + + device.free_command_buffers(data.command_pool, &[command_buffer]); + + Ok(()) +} + +pub unsafe fn create_index_buffer( + instance: &Instance, + device: &Device, + data: &mut app_data::AppData, +) -> Result<()> { + let size = (size_of::() * INDICES.len()) as u64; + + let (staging_buffer, staging_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_SRC, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + let memory = device.map_memory( + staging_buffer_memory, + 0, + size, + vk::MemoryMapFlags::empty(), + )?; + + memcpy(INDICES.as_ptr(), memory.cast(), INDICES.len()); + + device.unmap_memory(staging_buffer_memory); + + let (index_buffer, index_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )?; + + data.index_buffer = index_buffer; + data.index_buffer_memory = index_buffer_memory; + + copy_buffer(device, data, staging_buffer, index_buffer, size)?; + + device.destroy_buffer(staging_buffer, None); + device.free_memory(staging_buffer_memory, None); + + Ok(()) +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct UniformBufferObject { + pub model: Mat4, + pub view: Mat4, + pub proj: Mat4, +} + +pub unsafe fn create_descriptor_set_layout( + device: &Device, + data: &mut app_data::AppData, +) -> Result<()> { + let ubo_binding = vk::DescriptorSetLayoutBinding::builder() + .binding(0) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::VERTEX); + + let bindings = &[ubo_binding]; + let info = vk::DescriptorSetLayoutCreateInfo::builder() + .bindings(bindings); + + data.descriptor_set_layout = device.create_descriptor_set_layout(&info, None)?; + + Ok(()) +} + +pub unsafe fn create_uniform_buffers( + instance: &Instance, + device: &Device, + data: &mut app_data::AppData, +) -> Result<()> { + data.uniform_buffers.clear(); + data.uniform_buffers_memory.clear(); + + for _ in 0..data.swapchain_images.len() { + let (uniform_buffer, uniform_buffer_memory) = create_buffer( + instance, + device, + data, + size_of::() as u64, + vk::BufferUsageFlags::UNIFORM_BUFFER, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + data.uniform_buffers.push(uniform_buffer); + data.uniform_buffers_memory.push(uniform_buffer_memory); + } + + Ok(()) +} + +pub unsafe fn create_descriptor_pool(device: &Device, data: &mut app_data::AppData) -> Result<()> { + let ubo_size = vk::DescriptorPoolSize::builder() + .type_(vk::DescriptorType::UNIFORM_BUFFER) + .descriptor_count(data.swapchain_images.len() as u32); + let pool_sizes = &[ubo_size]; + let info = vk::DescriptorPoolCreateInfo::builder() + .pool_sizes(pool_sizes) + .max_sets(data.swapchain_images.len() as u32); + + data.descriptor_pool = device.create_descriptor_pool(&info, None)?; + Ok(()) +} + +pub unsafe fn create_descriptor_sets(device: &Device, data: &mut app_data::AppData) -> Result<()> { + let layouts = vec![data.descriptor_set_layout; data.swapchain_images.len()]; + let info = vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(data.descriptor_pool) + .set_layouts(&layouts); + data.descriptor_sets = device.allocate_descriptor_sets(&info)?; + + for i in 0..data.swapchain_images.len() { + let info = vk::DescriptorBufferInfo::builder() + .buffer(data.uniform_buffers[i]) + .offset(0) + .range(size_of::() as u64); + let buffer_info = &[info]; + let ubo_write = vk::WriteDescriptorSet::builder() + .dst_set(data.descriptor_sets[i]) + .dst_binding(0) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .buffer_info(buffer_info); + device.update_descriptor_sets(&[ubo_write], &[] as &[vk::CopyDescriptorSet]); + } + + Ok(()) +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 29b94f7..d1e389e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,14 +29,16 @@ use vulkanalia::vk::KhrSwapchainExtension; use cgmath::{vec2, vec3}; use std::mem::size_of; - use std::ptr::copy_nonoverlapping as memcpy; +use std::time::Instant; + pub mod app_data; pub mod errors; pub mod swapchain; pub mod queue_family_indices; pub mod vertex; +pub mod buffer; const PORTABILITY_MACOS_VERSION: Version = Version::new(1, 3, 216); const VALIDATION_ENABLED: bool = @@ -48,12 +50,6 @@ const DEVICE_EXTENSIONS: &[vk::ExtensionName] = &[vk::KHR_SWAPCHAIN_EXTENSION.na const MAX_FRAMES_IN_FLIGHT: usize = 2; -static VERTICES: [vertex::Vertex; 3] = [ - vertex::Vertex::new(vec2(0.0, -0.5), vec3(1.0, 0.0, 0.0)), - vertex::Vertex::new(vec2(0.5, 0.5), vec3(0.0, 1.0, 0.0)), - vertex::Vertex::new(vec2(-0.5, 0.5), vec3(0.0, 0.0, 1.0)), -]; - fn main() -> Result<()> { pretty_env_logger::init(); @@ -108,6 +104,7 @@ struct App { frame: usize, resized: bool, minimized: bool, + start: Instant, } impl App { @@ -124,19 +121,25 @@ impl App { swapchain::create_swapchain_image_views(&device, &mut data)?; create_render_pass(&instance, &device, &mut data)?; + buffer::create_descriptor_set_layout(&device, &mut data)?; create_pipeline(&device, &mut data)?; create_framebuffers(&device, &mut data)?; create_command_pool(&instance, &device, &mut data)?; - create_vertex_buffer(&instance, &device, &mut data)?; + buffer::create_vertex_buffer(&instance, &device, &mut data)?; + buffer::create_index_buffer(&instance, &device, &mut data)?; + + buffer::create_uniform_buffers(&instance, &device, &mut data)?; + buffer::create_descriptor_pool(&device, &mut data)?; + buffer::create_descriptor_sets(&device, &mut data)?; create_command_buffers(&device, &mut data)?; create_sync_objects(&device, &mut data)?; - Ok(Self { entry, instance, data, device, frame: 0 , resized: false, minimized: false}) + Ok(Self { entry, instance, data, device, frame: 0 , resized: false, minimized: false, start: Instant::now()}) } /// Renders a frame for our Vulkan app. @@ -165,6 +168,8 @@ impl App { self.data.images_in_flight[image_index] = in_flight_fence; + self.update_uniform_buffer(image_index)?; + let wait_semaphores = &[self.data.image_available_semaphores[self.frame]]; let wait_stages = &[vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; let command_buffers = &[self.data.command_buffers[image_index]]; @@ -205,6 +210,11 @@ impl App { unsafe fn destroy(&mut self) { self.destroy_swapchain(); + self.device.destroy_descriptor_set_layout(self.data.descriptor_set_layout, None); + + self.device.destroy_buffer(self.data.index_buffer, None); + self.device.free_memory(self.data.index_buffer_memory, None); + self.device.destroy_buffer(self.data.vertex_buffer, None); self.device.free_memory(self.data.vertex_buffer_memory, None); @@ -236,6 +246,9 @@ impl App { create_render_pass(&self.instance, &self.device, &mut self.data)?; create_pipeline(&self.device, &mut self.data)?; create_framebuffers(&self.device, &mut self.data)?; + buffer::create_uniform_buffers(&self.instance, &self.device, &mut self.data)?; + buffer::create_descriptor_pool(&self.device, &mut self.data)?; + buffer::create_descriptor_sets(&self.device, &mut self.data)?; create_command_buffers(&self.device, &mut self.data)?; self.data .images_in_flight @@ -244,6 +257,13 @@ impl App { } unsafe fn destroy_swapchain(&mut self) { + self.device.destroy_descriptor_pool(self.data.descriptor_pool, None); + self.data.uniform_buffers + .iter() + .for_each(|b| self.device.destroy_buffer(*b, None)); + self.data.uniform_buffers_memory + .iter() + .for_each(|m| self.device.free_memory(*m, None)); self.data.framebuffers .iter() .for_each(|f| self.device.destroy_framebuffer(*f, None)); @@ -257,6 +277,45 @@ impl App { self.device.destroy_swapchain_khr(self.data.swapchain, None); } + + unsafe fn update_uniform_buffer(&self, image_index: usize) -> Result<()> { + let time = self.start.elapsed().as_secs_f32(); + + let model = buffer::Mat4::from_axis_angle( + vec3(0.0, 0.0, 1.0), + cgmath::Deg(90.0) * time + ); + + let view = buffer::Mat4::look_at_rh( + cgmath::point3(2.0, 2.0, 2.0), + cgmath::point3(0.0, 0.0, 0.0), + vec3(0.0, 0.0, 1.0), + ); + + let mut proj = cgmath::perspective( + cgmath::Deg(45.0), + self.data.swapchain_extent.width as f32 / self.data.swapchain_extent.height as f32, + 0.1, + 10.0, + ); + + proj[1][1] *= -1.0; + + let ubo = buffer::UniformBufferObject { model, view, proj }; + + let memory = self.device.map_memory( + self.data.uniform_buffers_memory[image_index], + 0, + size_of::() as u64, + vk::MemoryMapFlags::empty(), + )?; + + memcpy(&ubo, memory.cast(), 1); + + self.device.unmap_memory(self.data.uniform_buffers_memory[image_index]); + + Ok(()) + } } //================================================ @@ -528,7 +587,7 @@ unsafe fn create_pipeline(device: &Device, data: &mut app_data::AppData) -> Resu .polygon_mode(vk::PolygonMode::FILL) .line_width(1.0) .cull_mode(vk::CullModeFlags::BACK) - .front_face(vk::FrontFace::CLOCKWISE) + .front_face(vk::FrontFace::COUNTER_CLOCKWISE) .depth_bias_enable(false); let multisample_state = vk::PipelineMultisampleStateCreateInfo::builder() @@ -552,7 +611,9 @@ unsafe fn create_pipeline(device: &Device, data: &mut app_data::AppData) -> Resu .attachments(attachments) .blend_constants([0.0, 0.0, 0.0, 0.0]); - let layout_info = vk::PipelineLayoutCreateInfo::builder(); + let set_layouts = &[data.descriptor_set_layout]; + let layout_info = vk::PipelineLayoutCreateInfo::builder() + .set_layouts(set_layouts); data.pipeline_layout = device.create_pipeline_layout(&layout_info, None)?; @@ -712,7 +773,18 @@ unsafe fn create_command_buffers(device: &Device, data: &mut app_data::AppData) *command_buffer, vk::PipelineBindPoint::GRAPHICS, data.pipeline); device.cmd_bind_vertex_buffers(*command_buffer, 0, &[data.vertex_buffer], &[0]); - device.cmd_draw(*command_buffer, VERTICES.len() as u32, 1, 0, 0); + device.cmd_bind_index_buffer(*command_buffer, data.index_buffer, 0, vk::IndexType::UINT16); + + device.cmd_bind_descriptor_sets( + *command_buffer, + vk::PipelineBindPoint::GRAPHICS, + data.pipeline_layout, + 0, + &[data.descriptor_sets[i]], + &[], + ); + + device.cmd_draw_indexed(*command_buffer, buffer::INDICES.len() as u32, 1, 0, 0, 0); device.cmd_end_render_pass(*command_buffer); @@ -742,87 +814,4 @@ unsafe fn create_sync_objects(device: &Device, data: &mut app_data::AppData) -> .collect(); Ok(()) -} - -unsafe fn create_buffer( - instance: &Instance, - device: &Device, - data: &app_data::AppData, - size: vk::DeviceSize, - usage: vk::BufferUsageFlags, - properties: vk::MemoryPropertyFlags, -) -> Result<(vk::Buffer, vk::DeviceMemory)> { - let buffer_info = vk::BufferCreateInfo::builder() - .size(size) - .usage(usage) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - - let buffer = device.create_buffer(&buffer_info, None)?; - - let requirements = device.get_buffer_memory_requirements(buffer); - - let memory_info = vk::MemoryAllocateInfo::builder() - .allocation_size(requirements.size) - .memory_type_index(get_memory_type_index( - instance, - data, - properties, - requirements, - )?); - - let buffer_memory = device.allocate_memory(&memory_info, None)?; - - device.bind_buffer_memory(buffer, buffer_memory, 0)?; - - Ok((buffer, buffer_memory)) -} - -unsafe fn create_vertex_buffer( - instance: &Instance, - device: &Device, - data: &mut app_data::AppData, -) -> Result<()> { - let size = (size_of::() * VERTICES.len()) as u64; - - let (vertex_buffer, vertex_buffer_memory) = create_buffer( - instance, - device, - data, - size, - vk::BufferUsageFlags::VERTEX_BUFFER, - vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, - )?; - - data.vertex_buffer = vertex_buffer; - data.vertex_buffer_memory = vertex_buffer_memory; - - let memory = device.map_memory( - vertex_buffer_memory, - 0, - size, - vk::MemoryMapFlags::empty(), - )?; - - memcpy(VERTICES.as_ptr(), memory.cast(), VERTICES.len()); - - device.unmap_memory(vertex_buffer_memory); - - Ok(()) -} - -unsafe fn get_memory_type_index( - instance: &Instance, - data: &app_data::AppData, - properties: vk::MemoryPropertyFlags, - requirements: vk::MemoryRequirements, -) -> Result { - let memory = instance.get_physical_device_memory_properties(data.physical_device); - - (0..memory.memory_type_count) - .find(|i| { - let suitable = (requirements.memory_type_bits & (1 << i)) != 0; - let memory_type = memory.memory_types[*i as usize]; - suitable && memory_type.property_flags.contains(properties) - }) - .ok_or_else(|| anyhow!("Failed to find suitable memory type.")) } \ No newline at end of file