Start on implementing texture mapping (partially complete section 28 of the tutorial)

This commit is contained in:
Timothy Warren 2023-04-13 15:56:16 -04:00
parent 2d5a0420cd
commit 425577029d
1 changed files with 215 additions and 68 deletions

View File

@ -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<vk::Framebuffer>,
// 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<vk::Buffer>,
pub(super) uniform_buffers_memory: Vec<vk::DeviceMemory>,
// Descriptors
descriptor_pool: vk::DescriptorPool,
descriptor_sets: Vec<vk::DescriptorSet>,
// 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::<Vertex>() * 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<vk::CommandBuffer> {
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(())
}
}