From 425577029d318b697f6c2ed467ba800226704daa Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Thu, 13 Apr 2023 15:56:16 -0400 Subject: [PATCH] Start on implementing texture mapping (partially complete section 28 of the tutorial) --- src/app/data.rs | 283 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 215 insertions(+), 68 deletions(-) diff --git a/src/app/data.rs b/src/app/data.rs index 4ad25ce..a9afaad 100644 --- a/src/app/data.rs +++ b/src/app/data.rs @@ -1,3 +1,4 @@ +#![allow(clippy::too_many_arguments)] use super::functions::*; use super::*; use crate::VALIDATION_ENABLED; @@ -6,6 +7,7 @@ use ::anyhow::{anyhow, Result}; use ::log::*; use ::std::collections::HashSet; use ::std::ffi::CStr; +use ::std::fs::File; use ::std::os::raw::c_void; use ::std::ptr::copy_nonoverlapping as memcpy; use ::vulkanalia::prelude::v1_0::*; @@ -61,6 +63,9 @@ pub(crate) struct AppData { framebuffers: Vec, // Command Pool command_pool: vk::CommandPool, + // Texture + texture_image: vk::Image, + texture_image_memory: vk::DeviceMemory, // Buffers vertex_buffer: vk::Buffer, vertex_buffer_memory: vk::DeviceMemory, @@ -68,6 +73,7 @@ pub(crate) struct AppData { index_buffer_memory: vk::DeviceMemory, uniform_buffers: Vec, pub(super) uniform_buffers_memory: Vec, + // Descriptors descriptor_pool: vk::DescriptorPool, descriptor_sets: Vec, // Command Buffers @@ -102,6 +108,7 @@ impl AppData { self.create_pipeline(&device)?; self.create_framebuffers(&device)?; self.create_command_pool(&instance, &device)?; + self.create_texture_image(&instance, &device)?; self.create_vertex_buffer(&instance, &device)?; self.create_index_buffer(&instance, &device)?; self.create_uniform_buffers(&instance, &device)?; @@ -474,21 +481,6 @@ impl AppData { // Pipeline //================================================ - unsafe fn create_descriptor_set_layout(&mut self, device: &Device) -> 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); - - self.descriptor_set_layout = device.create_descriptor_set_layout(&info, None)?; - - Ok(()) - } - unsafe fn create_render_pass(&mut self, _instance: &Instance, device: &Device) -> Result<()> { let color_attachment = vk::AttachmentDescription::builder() .format(self.swapchain_format) @@ -529,6 +521,21 @@ impl AppData { Ok(()) } + unsafe fn create_descriptor_set_layout(&mut self, device: &Device) -> 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); + + self.descriptor_set_layout = device.create_descriptor_set_layout(&info, None)?; + + Ok(()) + } + unsafe fn create_pipeline(&mut self, device: &Device) -> Result<()> { let vert = include_bytes!("../../shaders/vert.spv"); let frag = include_bytes!("../../shaders/frag.spv"); @@ -632,6 +639,10 @@ impl AppData { Ok(()) } + //================================================ + // Framebuffers + //================================================ + unsafe fn create_framebuffers(&mut self, device: &Device) -> Result<()> { self.framebuffers = self .swapchain_image_views @@ -669,74 +680,62 @@ impl AppData { } //================================================ - // Buffers + // Texture //================================================ - unsafe fn create_buffer( - &self, - instance: &Instance, - device: &Device, - 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); + fn create_texture_image(&mut self, instance: &Instance, device: &Device) -> Result<()> { + let image = File::open("resources/texture.png")?; - let buffer = device.create_buffer(&buffer_info, None)?; + let decoder = png::Decoder::new(image); + let mut reader = decoder.read_info()?; - let requirements = device.get_buffer_memory_requirements(buffer); + let mut pixels = vec![0; reader.info().raw_bytes()]; + reader.next_frame(&mut pixels)?; - let memory_info = vk::MemoryAllocateInfo::builder() - .allocation_size(requirements.size) - .memory_type_index(self.get_memory_type_index(instance, properties, requirements)?); + let size = reader.info().raw_bytes() as u64; + let (width, height) = reader.info().size(); - let buffer_memory = device.allocate_memory(&memory_info, None)?; + let (_, staging_buffer_memory) = unsafe { + self.create_buffer( + instance, + device, + size, + vk::BufferUsageFlags::TRANSFER_SRC, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )? + }; - device.bind_buffer_memory(buffer, buffer_memory, 0)?; + let memory = unsafe { + device.map_memory(staging_buffer_memory, 0, size, vk::MemoryMapFlags::empty())? + }; - Ok((buffer, buffer_memory)) - } + unsafe { + memcpy(pixels.as_ptr(), memory.cast(), pixels.len()); - unsafe fn copy_buffer( - &self, - device: &Device, - source: vk::Buffer, - destination: vk::Buffer, - size: vk::DeviceSize, - ) -> Result<()> { - // Create the command buffer - let info = vk::CommandBufferAllocateInfo::builder() - .level(vk::CommandBufferLevel::PRIMARY) - .command_pool(self.command_pool) - .command_buffer_count(1); + device.unmap_memory(staging_buffer_memory); - let command_buffer = device.allocate_command_buffers(&info)?[0]; + let (texture_image, texture_image_memory) = self.create_image( + instance, + device, + width, + height, + vk::Format::R8G8B8A8_SRGB, + vk::ImageTiling::OPTIMAL, + vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )?; - 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)?; - - // Execute command buffer - let command_buffers = &[command_buffer]; - let info = vk::SubmitInfo::builder().command_buffers(command_buffers); - - device.queue_submit(self.graphics_queue, &[info], vk::Fence::null())?; - device.queue_wait_idle(self.graphics_queue)?; - - device.free_command_buffers(self.command_pool, &[command_buffer]); + self.texture_image = texture_image; + self.texture_image_memory = texture_image_memory; + } Ok(()) } + //================================================ + // Buffers + //================================================ + unsafe fn create_vertex_buffer(&mut self, instance: &Instance, device: &Device) -> Result<()> { // Create staging buffer let size = (size_of::() * VERTICES.len()) as u64; @@ -833,6 +832,10 @@ impl AppData { Ok(()) } + //================================================ + // Descriptors + //================================================ + unsafe fn create_descriptor_pool(&mut self, device: &Device) -> Result<()> { let ubo_size = vk::DescriptorPoolSize::builder() .type_(vk::DescriptorType::UNIFORM_BUFFER) @@ -973,6 +976,116 @@ impl AppData { Ok(()) } + //================================================ + // Shared (Buffers) + //================================================ + + unsafe fn create_buffer( + &self, + instance: &Instance, + device: &Device, + 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(self.get_memory_type_index(instance, 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 copy_buffer( + &self, + device: &Device, + source: vk::Buffer, + destination: vk::Buffer, + size: vk::DeviceSize, + ) -> Result<()> { + let command_buffer = self.begin_single_time_commands(device)?; + + let regions = vk::BufferCopy::builder().size(size); + device.cmd_copy_buffer(command_buffer, source, destination, &[regions]); + + self.end_single_time_commands(device, command_buffer)?; + + Ok(()) + } + + //================================================ + // Shared (Images) + //================================================ + + unsafe fn create_image( + &self, + instance: &Instance, + device: &Device, + width: u32, + height: u32, + format: vk::Format, + tiling: vk::ImageTiling, + usage: vk::ImageUsageFlags, + properties: vk::MemoryPropertyFlags, + ) -> Result<(vk::Image, vk::DeviceMemory)> { + let info = vk::ImageCreateInfo::builder() + .image_type(vk::ImageType::_2D) + .extent(vk::Extent3D { + width, + height, + depth: 1, + }) + .mip_levels(1) + .array_layers(1) + .format(format) + .tiling(tiling) + .initial_layout(vk::ImageLayout::UNDEFINED) + .usage(usage) + .samples(vk::SampleCountFlags::_1) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + let image = device.create_image(&info, None)?; + + let requirements = device.get_image_memory_requirements(image); + + let info = vk::MemoryAllocateInfo::builder() + .allocation_size(requirements.size) + .memory_type_index(self.get_memory_type_index(instance, properties, requirements)?); + + let image_memory = device.allocate_memory(&info, None)?; + + device.bind_image_memory(image, image_memory, 0)?; + + Ok((image, image_memory)) + } + + unsafe fn transition_image_layout( + &self, + device: &Device, + image: vk::Image, + format: vk::Format, + old_layout: vk::ImageLayout, + new_layout: vk::ImageLayout, + ) -> Result<()> { + let command_buffer = self.begin_single_time_commands(device)?; + + self.end_single_time_commands(device, command_buffer)?; + + Ok(()) + } + //================================================ // Shared (Other) //================================================ @@ -993,4 +1106,38 @@ impl AppData { }) .ok_or_else(|| anyhow!("Failed to find suitable memory type.")) } + + unsafe fn begin_single_time_commands(&self, device: &Device) -> Result { + let info = vk::CommandBufferAllocateInfo::builder() + .level(vk::CommandBufferLevel::PRIMARY) + .command_pool(self.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)?; + + Ok(command_buffer) + } + + unsafe fn end_single_time_commands( + &self, + device: &Device, + command_buffer: vk::CommandBuffer, + ) -> Result<()> { + device.end_command_buffer(command_buffer)?; + + let command_buffers = &[command_buffer]; + let info = vk::SubmitInfo::builder().command_buffers(command_buffers); + + device.queue_submit(self.graphics_queue, &[info], vk::Fence::null())?; + device.queue_wait_idle(self.graphics_queue)?; + + device.free_command_buffers(self.command_pool, command_buffers); + + Ok(()) + } }