raindrop/crates/vk-rs/src/renderer.rs
2024-12-28 19:08:21 -05:00

1428 lines
54 KiB
Rust

use ash::{
extensions::khr::{Surface, Swapchain},
vk::{self, Buffer},
Device,
};
use cgmath::num_traits::Float;
use egui_ash::EguiCommand;
use glam::{Mat4, Vec3};
use gpu_allocator::vulkan::{Allocation, Allocator};
use shaders_shared::UniformBufferObject;
use std::{
ffi::CString,
mem::ManuallyDrop,
sync::{Arc, Mutex},
};
macro_rules! include_spirv {
($file:literal) => {{
let bytes = include_bytes!($file);
bytes
.chunks_exact(4)
.map(|x| x.try_into().unwrap())
.map(match bytes[0] {
0x03 => u32::from_le_bytes,
0x07 => u32::from_be_bytes,
_ => panic!("Unknown endianness"),
})
.collect::<Vec<u32>>()
}};
}
#[repr(C)]
#[derive(Debug, Clone)]
struct Vertex {
position: Vec3,
normal: Vec3,
}
impl Vertex {
fn get_binding_descriptions() -> [vk::VertexInputBindingDescription; 1] {
[vk::VertexInputBindingDescription::builder()
.binding(0)
.stride(std::mem::size_of::<Self>() as u32)
.input_rate(vk::VertexInputRate::VERTEX)
.build()]
}
fn get_attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] {
[
vk::VertexInputAttributeDescription::builder()
.binding(0)
.location(0)
.format(vk::Format::R32G32B32_SFLOAT)
.offset(0)
.build(),
vk::VertexInputAttributeDescription::builder()
.binding(0)
.location(1)
.format(vk::Format::R32G32B32_SFLOAT)
.offset(4 * 3)
.build(),
]
}
}
pub struct RendererInner {
width: u32,
height: u32,
physical_device: vk::PhysicalDevice,
device: Device,
surface_loader: Surface,
swapchain_loader: Swapchain,
allocator: ManuallyDrop<Arc<Mutex<Allocator>>>,
surface: vk::SurfaceKHR,
queue: vk::Queue,
swapchain: vk::SwapchainKHR,
surface_format: vk::SurfaceFormatKHR,
surface_extent: vk::Extent2D,
swapchain_images: Vec<vk::Image>,
uniform_buffers: Vec<Buffer>,
uniform_buffer_allocations: Vec<Allocation>,
descriptor_pool: vk::DescriptorPool,
descriptor_set_layouts: Vec<vk::DescriptorSetLayout>,
descriptor_sets: Vec<vk::DescriptorSet>,
render_pass: vk::RenderPass,
framebuffers: Vec<vk::Framebuffer>,
depth_images_and_allocations: Vec<(vk::Image, Allocation)>,
color_image_views: Vec<vk::ImageView>,
depth_image_views: Vec<vk::ImageView>,
pipeline: vk::Pipeline,
pipeline_layout: vk::PipelineLayout,
vertex_buffer: Buffer,
vertex_buffer_allocation: Option<Allocation>,
vertex_count: u32,
command_buffers: Vec<vk::CommandBuffer>,
in_flight_fences: Vec<vk::Fence>,
image_available_semaphores: Vec<vk::Semaphore>,
render_finished_semaphores: Vec<vk::Semaphore>,
current_frame: usize,
dirty_swapchain: bool,
frame_counter: u32,
camera_position: Vec3,
camera_yaw: f32,
camera_pitch: f32,
accumulation_reset_needed: bool,
}
struct CreateFramebuffersResult(
Vec<vk::Framebuffer>,
Vec<(vk::Image, Allocation)>,
Vec<vk::ImageView>,
Vec<vk::ImageView>,
);
impl RendererInner {
fn create_swapchain(
physical_device: vk::PhysicalDevice,
surface_loader: &ash::extensions::khr::Surface,
swapchain_loader: &ash::extensions::khr::Swapchain,
surface: vk::SurfaceKHR,
queue_family_index: u32,
width: u32,
height: u32,
) -> (
vk::SwapchainKHR,
vk::SurfaceFormatKHR,
vk::Extent2D,
Vec<vk::Image>,
) {
let surface_formats = unsafe {
surface_loader
.get_physical_device_surface_formats(physical_device, surface)
.expect("Failed to get physical device surface formats")
};
let surface_format = *surface_formats
.iter()
.find(|format| {
format.format == vk::Format::B8G8R8A8_UNORM
|| format.format == vk::Format::R8G8B8A8_UNORM
})
.unwrap_or(&surface_formats[0]);
let surface_capabilities = unsafe {
surface_loader
.get_physical_device_surface_capabilities(physical_device, surface)
.expect("Failed to get physical device surface capabilities")
};
let surface_extent = if surface_capabilities.current_extent.width != u32::MAX {
surface_capabilities.current_extent
} else {
vk::Extent2D {
width: width
.max(surface_capabilities.min_image_extent.width)
.min(surface_capabilities.max_image_extent.width),
height: height
.max(surface_capabilities.min_image_extent.height)
.min(surface_capabilities.max_image_extent.height),
}
};
let image_count = surface_capabilities.min_image_count + 1;
let image_count = if surface_capabilities.max_image_count != 0 {
image_count.min(surface_capabilities.max_image_count)
} else {
image_count
};
let image_sharing_mode = vk::SharingMode::EXCLUSIVE;
let queue_family_indices = [queue_family_index];
let swapchain_create_info = vk::SwapchainCreateInfoKHR::builder()
.surface(surface)
.min_image_count(image_count)
.image_format(surface_format.format)
.image_color_space(surface_format.color_space)
.image_extent(surface_extent)
.image_array_layers(1)
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
.image_sharing_mode(image_sharing_mode)
.queue_family_indices(&queue_family_indices)
.pre_transform(surface_capabilities.current_transform)
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
.present_mode(vk::PresentModeKHR::FIFO)
.clipped(true);
let swapchain = unsafe {
swapchain_loader
.create_swapchain(&swapchain_create_info, None)
.expect("Failed to create swapchain")
};
let swapchain_images = unsafe {
swapchain_loader
.get_swapchain_images(swapchain)
.expect("Failed to get swapchain images")
};
(swapchain, surface_format, surface_extent, swapchain_images)
}
fn create_uniform_buffers(
device: &Device,
allocator: Arc<Mutex<Allocator>>,
swapchain_count: usize,
) -> (Vec<Buffer>, Vec<Allocation>) {
let buffer_size = std::mem::size_of::<UniformBufferObject>() as u64;
let buffer_usage = vk::BufferUsageFlags::UNIFORM_BUFFER;
let buffer_create_info = vk::BufferCreateInfo::builder()
.size(buffer_size)
.usage(buffer_usage)
.sharing_mode(vk::SharingMode::EXCLUSIVE);
let buffers = (0..swapchain_count)
.map(|_| unsafe {
device
.create_buffer(&buffer_create_info, None)
.expect("Failed to create buffer")
})
.collect::<Vec<_>>();
let buffer_memory_requirements =
unsafe { device.get_buffer_memory_requirements(buffers[0]) };
let buffer_alloc_info = gpu_allocator::vulkan::AllocationCreateDesc {
name: "Uniform Buffer",
requirements: buffer_memory_requirements,
location: gpu_allocator::MemoryLocation::CpuToGpu,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
};
let buffer_allocations = buffers
.iter()
.map(|_| {
allocator
.lock()
.unwrap()
.allocate(&buffer_alloc_info)
.expect("Failed to allocate memory")
})
.collect::<Vec<_>>();
for (&buffer, buffer_memory) in buffers.iter().zip(buffer_allocations.iter()) {
unsafe {
device
.bind_buffer_memory(buffer, buffer_memory.memory(), buffer_memory.offset())
.expect("Failed to bind buffer memory")
}
}
(buffers, buffer_allocations)
}
fn create_descriptor_pool(device: &Device, swapchain_count: usize) -> vk::DescriptorPool {
let pool_size = vk::DescriptorPoolSize::builder()
.ty(vk::DescriptorType::UNIFORM_BUFFER)
.descriptor_count(swapchain_count as u32);
let descriptor_pool_create_info = vk::DescriptorPoolCreateInfo::builder()
.pool_sizes(std::slice::from_ref(&pool_size))
.max_sets(swapchain_count as u32);
unsafe {
device
.create_descriptor_pool(&descriptor_pool_create_info, None)
.expect("Failed to create descriptor pool")
}
}
fn create_descriptor_set_layouts(
device: &Device,
swapchain_count: usize,
) -> Vec<vk::DescriptorSetLayout> {
let ubo_layout_binding = vk::DescriptorSetLayoutBinding::builder()
.binding(0)
.descriptor_type(vk::DescriptorType::UNIFORM_BUFFER)
.descriptor_count(1)
.stage_flags(vk::ShaderStageFlags::VERTEX);
let ubo_layout_create_info = vk::DescriptorSetLayoutCreateInfo::builder()
.bindings(std::slice::from_ref(&ubo_layout_binding));
(0..swapchain_count)
.map(|_| unsafe {
device
.create_descriptor_set_layout(&ubo_layout_create_info, None)
.expect("Failed to create descriptor set layout")
})
.collect()
}
fn create_descriptor_sets(
device: &Device,
descriptor_pool: vk::DescriptorPool,
descriptor_set_layouts: &[vk::DescriptorSetLayout],
uniform_buffers: &[Buffer],
) -> Vec<vk::DescriptorSet> {
let descriptor_set_allocate_info = vk::DescriptorSetAllocateInfo::builder()
.descriptor_pool(descriptor_pool)
.set_layouts(descriptor_set_layouts);
let descriptor_sets = unsafe {
device
.allocate_descriptor_sets(&descriptor_set_allocate_info)
.expect("Failed to allocate descriptor sets")
};
for index in 0..descriptor_sets.len() {
let buffer_info = vk::DescriptorBufferInfo::builder()
.buffer(uniform_buffers[index])
.offset(0)
.range(vk::WHOLE_SIZE);
let descriptor_write = vk::WriteDescriptorSet::builder()
.dst_set(descriptor_sets[index])
.dst_binding(0)
.descriptor_type(vk::DescriptorType::UNIFORM_BUFFER)
.buffer_info(std::slice::from_ref(&buffer_info));
unsafe {
device.update_descriptor_sets(std::slice::from_ref(&descriptor_write), &[]);
}
}
descriptor_sets
}
fn create_render_pass(device: &Device, surface_format: vk::SurfaceFormatKHR) -> vk::RenderPass {
let attachments = [
vk::AttachmentDescription::builder()
.format(surface_format.format)
.samples(vk::SampleCountFlags::TYPE_1)
.load_op(vk::AttachmentLoadOp::CLEAR)
.store_op(vk::AttachmentStoreOp::STORE)
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
.initial_layout(vk::ImageLayout::UNDEFINED)
.final_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.build(),
vk::AttachmentDescription::builder()
.format(vk::Format::D32_SFLOAT)
.samples(vk::SampleCountFlags::TYPE_1)
.load_op(vk::AttachmentLoadOp::CLEAR)
.store_op(vk::AttachmentStoreOp::DONT_CARE)
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
.initial_layout(vk::ImageLayout::UNDEFINED)
.final_layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
.build(),
];
let color_reference = [vk::AttachmentReference::builder()
.attachment(0)
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.build()];
let depth_reference = vk::AttachmentReference::builder()
.attachment(1)
.layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
let subpasses = [vk::SubpassDescription::builder()
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
.color_attachments(&color_reference)
.depth_stencil_attachment(&depth_reference)
.build()];
let render_pass_create_info = vk::RenderPassCreateInfo::builder()
.attachments(&attachments)
.subpasses(&subpasses);
unsafe {
device
.create_render_pass(&render_pass_create_info, None)
.expect("Failed to create render pass")
}
}
fn create_framebuffers(
device: &Device,
allocator: Arc<Mutex<Allocator>>,
render_pass: vk::RenderPass,
format: vk::SurfaceFormatKHR,
extent: vk::Extent2D,
swapchain_images: &[vk::Image],
) -> CreateFramebuffersResult {
let mut framebuffers = vec![];
let mut depth_images_and_allocations = vec![];
let mut color_image_views = vec![];
let mut depth_image_views = vec![];
for &image in swapchain_images.iter() {
let mut attachments = vec![];
let color_attachment = unsafe {
device
.create_image_view(
&vk::ImageViewCreateInfo::builder()
.image(image)
.view_type(vk::ImageViewType::TYPE_2D)
.format(format.format)
.subresource_range(
vk::ImageSubresourceRange::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.base_mip_level(0)
.level_count(1)
.base_array_layer(0)
.layer_count(1)
.build(),
),
None,
)
.expect("Failed to create image view")
};
attachments.push(color_attachment);
color_image_views.push(color_attachment);
let depth_image_create_info = vk::ImageCreateInfo::builder()
.format(vk::Format::D32_SFLOAT)
.samples(vk::SampleCountFlags::TYPE_1)
.mip_levels(1)
.array_layers(1)
.usage(vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT)
.initial_layout(vk::ImageLayout::UNDEFINED)
.image_type(vk::ImageType::TYPE_2D)
.extent(vk::Extent3D {
width: extent.width,
height: extent.height,
depth: 1,
});
let depth_image = unsafe {
device
.create_image(&depth_image_create_info, None)
.expect("Failed to create image")
};
let depth_allocation = allocator
.lock()
.unwrap()
.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
name: "Depth Image",
requirements: unsafe { device.get_image_memory_requirements(depth_image) },
location: gpu_allocator::MemoryLocation::GpuOnly,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("Failed to allocate memory");
unsafe {
device
.bind_image_memory(
depth_image,
depth_allocation.memory(),
depth_allocation.offset(),
)
.expect("Failed to bind image memory")
};
let depth_attachment = unsafe {
device
.create_image_view(
&vk::ImageViewCreateInfo::builder()
.image(depth_image)
.view_type(vk::ImageViewType::TYPE_2D)
.format(vk::Format::D32_SFLOAT)
.subresource_range(
vk::ImageSubresourceRange::builder()
.aspect_mask(vk::ImageAspectFlags::DEPTH)
.base_mip_level(0)
.level_count(1)
.base_array_layer(0)
.layer_count(1)
.build(),
),
None,
)
.expect("Failed to create depth image view")
};
attachments.push(depth_attachment);
depth_image_views.push(depth_attachment);
framebuffers.push(unsafe {
device
.create_framebuffer(
&vk::FramebufferCreateInfo::builder()
.render_pass(render_pass)
.attachments(attachments.as_slice())
.width(extent.width)
.height(extent.height)
.layers(1),
None,
)
.expect("Failed to create framebuffer")
});
depth_images_and_allocations.push((depth_image, depth_allocation));
}
CreateFramebuffersResult(
framebuffers,
depth_images_and_allocations,
color_image_views,
depth_image_views,
)
}
fn create_graphics_pipeline(
device: &Device,
descriptor_set_layouts: &[vk::DescriptorSetLayout],
render_pass: vk::RenderPass,
) -> (vk::Pipeline, vk::PipelineLayout) {
let vertex_shader_module = {
let spirv = include_spirv!("../shaders/main_vs.spv");
let shader_module_create_info = vk::ShaderModuleCreateInfo::builder().code(&spirv);
unsafe {
device
.create_shader_module(&shader_module_create_info, None)
.expect("Failed to create shader module")
}
};
let fragment_shader_module = {
let spirv = include_spirv!("../shaders/main_fs.spv");
let shader_module_create_info = vk::ShaderModuleCreateInfo::builder().code(&spirv);
unsafe {
device
.create_shader_module(&shader_module_create_info, None)
.expect("Failed to create shader module")
}
};
let main_function_name_fs = CString::new("main_fs").unwrap();
let main_function_name_vs = CString::new("main_vs").unwrap();
let pipeline_shader_stages = [
vk::PipelineShaderStageCreateInfo::builder()
.stage(vk::ShaderStageFlags::VERTEX)
.module(vertex_shader_module)
.name(&main_function_name_vs)
.build(),
vk::PipelineShaderStageCreateInfo::builder()
.stage(vk::ShaderStageFlags::FRAGMENT)
.module(fragment_shader_module)
.name(&main_function_name_fs)
.build(),
];
let pipeline_layout = unsafe {
device
.create_pipeline_layout(
&vk::PipelineLayoutCreateInfo::builder().set_layouts(descriptor_set_layouts),
None,
)
.expect("Failed to create pipeline layout")
};
let vertex_input_binding = Vertex::get_binding_descriptions();
let vertex_input_attribute = Vertex::get_attribute_descriptions();
let input_assembly_info = vk::PipelineInputAssemblyStateCreateInfo::builder()
.topology(vk::PrimitiveTopology::TRIANGLE_LIST);
let viewport_info = vk::PipelineViewportStateCreateInfo::builder()
.viewport_count(1)
.scissor_count(1);
let rasterization_info = vk::PipelineRasterizationStateCreateInfo::builder()
.depth_clamp_enable(false)
.rasterizer_discard_enable(false)
.polygon_mode(vk::PolygonMode::FILL)
.cull_mode(vk::CullModeFlags::NONE)
.front_face(vk::FrontFace::COUNTER_CLOCKWISE)
.depth_bias_enable(false)
.line_width(1.0);
let stencil_op = vk::StencilOpState::builder()
.fail_op(vk::StencilOp::KEEP)
.pass_op(vk::StencilOp::KEEP)
.compare_op(vk::CompareOp::ALWAYS);
let depth_stencil_info = vk::PipelineDepthStencilStateCreateInfo::builder()
.depth_test_enable(true)
.depth_write_enable(true)
.depth_compare_op(vk::CompareOp::LESS_OR_EQUAL)
.depth_bounds_test_enable(false)
.stencil_test_enable(false)
.front(*stencil_op)
.back(*stencil_op);
let color_blend_attachment = vk::PipelineColorBlendAttachmentState::builder()
.color_write_mask(
vk::ColorComponentFlags::R
| vk::ColorComponentFlags::G
| vk::ColorComponentFlags::B
| vk::ColorComponentFlags::A,
);
let color_blend_info = vk::PipelineColorBlendStateCreateInfo::builder()
.attachments(std::slice::from_ref(&color_blend_attachment));
let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR];
let dynamic_state_info =
vk::PipelineDynamicStateCreateInfo::builder().dynamic_states(&dynamic_states);
let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::builder()
.vertex_attribute_descriptions(&vertex_input_attribute)
.vertex_binding_descriptions(&vertex_input_binding);
let multisample_info = vk::PipelineMultisampleStateCreateInfo::builder()
.rasterization_samples(vk::SampleCountFlags::TYPE_1);
let pipeline_create_info = vk::GraphicsPipelineCreateInfo::builder()
.stages(&pipeline_shader_stages)
.vertex_input_state(&vertex_input_state)
.input_assembly_state(&input_assembly_info)
.viewport_state(&viewport_info)
.rasterization_state(&rasterization_info)
.multisample_state(&multisample_info)
.depth_stencil_state(&depth_stencil_info)
.color_blend_state(&color_blend_info)
.dynamic_state(&dynamic_state_info)
.layout(pipeline_layout)
.render_pass(render_pass)
.subpass(0);
let graphics_pipeline = unsafe {
device
.create_graphics_pipelines(
vk::PipelineCache::null(),
std::slice::from_ref(&pipeline_create_info),
None,
)
.unwrap()[0]
};
unsafe {
device.destroy_shader_module(vertex_shader_module, None);
device.destroy_shader_module(fragment_shader_module, None);
}
(graphics_pipeline, pipeline_layout)
}
fn load_model_and_create_vertex_buffer(
device: &Device,
allocator: Arc<Mutex<Allocator>>,
command_pool: vk::CommandPool,
queue: vk::Queue,
) -> (Buffer, Allocation, u32) {
let mut allocator = allocator.lock().unwrap();
let vertices = {
let model_obj = tobj::load_obj(
"./crates/vk-rs/assets/suzanne.obj",
&tobj::LoadOptions {
single_index: true,
triangulate: true,
ignore_points: true,
ignore_lines: true,
},
)
.expect("Failed to load model");
let mut vertices = vec![];
let (models, _) = model_obj;
for m in models.iter() {
let mesh = &m.mesh;
for &i in mesh.indices.iter() {
let i = i as usize;
let vertex = Vertex {
position: Vec3::new(
mesh.positions[3 * i],
mesh.positions[3 * i + 1],
mesh.positions[3 * i + 2],
),
normal: Vec3::new(
mesh.normals[3 * i],
mesh.normals[3 * i + 1],
mesh.normals[3 * i + 2],
),
};
vertices.push(vertex);
}
}
vertices
};
let vertex_buffer_size = vertices.len() as u64 * std::mem::size_of::<Vertex>() as u64;
let temporary_buffer = unsafe {
device
.create_buffer(
&vk::BufferCreateInfo::builder()
.size(vertex_buffer_size)
.usage(vk::BufferUsageFlags::TRANSFER_SRC),
None,
)
.expect("Failed to create buffer")
};
let temporary_buffer_memory_requirements =
unsafe { device.get_buffer_memory_requirements(temporary_buffer) };
let temporary_buffer_allocation = allocator
.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
name: "Temporary Vertex Buffer",
requirements: temporary_buffer_memory_requirements,
location: gpu_allocator::MemoryLocation::CpuToGpu,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("Failed to allocate memory");
unsafe {
device
.bind_buffer_memory(
temporary_buffer,
temporary_buffer_allocation.memory(),
temporary_buffer_allocation.offset(),
)
.expect("Failed to bind buffer memory")
}
unsafe {
let ptr = temporary_buffer_allocation.mapped_ptr().unwrap().as_ptr() as *mut Vertex;
ptr.copy_from_nonoverlapping(vertices.as_ptr(), vertices.len());
}
let vertex_buffer = unsafe {
device
.create_buffer(
&vk::BufferCreateInfo::builder()
.size(vertex_buffer_size)
.usage(
vk::BufferUsageFlags::TRANSFER_DST
| vk::BufferUsageFlags::VERTEX_BUFFER,
),
None,
)
.expect("Failed to create buffer")
};
let vertex_buffer_memory_requirements =
unsafe { device.get_buffer_memory_requirements(vertex_buffer) };
let vertex_buffer_allocation = allocator
.allocate(&gpu_allocator::vulkan::AllocationCreateDesc {
name: "Vertex Buffer",
requirements: vertex_buffer_memory_requirements,
location: gpu_allocator::MemoryLocation::GpuOnly,
linear: true,
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
})
.expect("Failed to allocate memory");
unsafe {
device
.bind_buffer_memory(
vertex_buffer,
vertex_buffer_allocation.memory(),
vertex_buffer_allocation.offset(),
)
.expect("Failed to bind buffer memory")
}
let cmd = unsafe {
device
.allocate_command_buffers(
&vk::CommandBufferAllocateInfo::builder()
.command_pool(command_pool)
.level(vk::CommandBufferLevel::PRIMARY)
.command_buffer_count(1),
)
.expect("Failed to allocate command buffer")[0]
};
unsafe {
device
.begin_command_buffer(
cmd,
&vk::CommandBufferBeginInfo::builder()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),
)
.expect("Failed to begin command buffer");
device.cmd_copy_buffer(
cmd,
temporary_buffer,
vertex_buffer,
&[vk::BufferCopy::builder()
.src_offset(0)
.dst_offset(0)
.size(vertex_buffer_size)
.build()],
);
device
.end_command_buffer(cmd)
.expect("Failed to end command buffer");
device
.queue_submit(
queue,
&[vk::SubmitInfo::builder().command_buffers(&[cmd]).build()],
vk::Fence::null(),
)
.expect("Failed to submit queue");
device.queue_wait_idle(queue).expect("Failed to wait queue");
device.free_command_buffers(command_pool, &[cmd]);
}
allocator
.free(temporary_buffer_allocation)
.expect("Failed to free memory");
unsafe {
device.destroy_buffer(temporary_buffer, None);
}
(
vertex_buffer,
vertex_buffer_allocation,
vertices.len() as u32,
)
}
fn create_command_buffers(
device: &Device,
command_pool: vk::CommandPool,
swapchain_count: usize,
) -> Vec<vk::CommandBuffer> {
unsafe {
device
.allocate_command_buffers(
&vk::CommandBufferAllocateInfo::builder()
.command_pool(command_pool)
.level(vk::CommandBufferLevel::PRIMARY)
.command_buffer_count(swapchain_count as u32),
)
.expect("Failed to allocate command buffers")
}
}
fn create_sync_objects(
device: &Device,
swapchain_count: usize,
) -> (Vec<vk::Fence>, Vec<vk::Semaphore>, Vec<vk::Semaphore>) {
let fence_create_info =
vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED);
let mut in_flight_fences = vec![];
for _ in 0..swapchain_count {
let fence = unsafe {
device
.create_fence(&fence_create_info, None)
.expect("Failed to create fence")
};
in_flight_fences.push(fence);
}
let mut image_available_semaphores = vec![];
for _ in 0..swapchain_count {
let semaphore_create_info = vk::SemaphoreCreateInfo::builder();
let semaphore = unsafe {
device
.create_semaphore(&semaphore_create_info, None)
.expect("Failed to create semaphore")
};
image_available_semaphores.push(semaphore);
}
let mut render_finished_semaphores = vec![];
for _ in 0..swapchain_count {
let semaphore_create_info = vk::SemaphoreCreateInfo::builder();
let semaphore = unsafe {
device
.create_semaphore(&semaphore_create_info, None)
.expect("Failed to create semaphore")
};
render_finished_semaphores.push(semaphore);
}
(
in_flight_fences,
image_available_semaphores,
render_finished_semaphores,
)
}
fn recreate_swapchain(&mut self, width: u32, height: u32, egui_cmd: &mut EguiCommand) {
unsafe {
self.device
.device_wait_idle()
.expect("Failed to wait device idle")
};
unsafe {
let mut allocator = self.allocator.lock().unwrap();
for &fence in self.in_flight_fences.iter() {
self.device.destroy_fence(fence, None);
}
for &semaphore in self.image_available_semaphores.iter() {
self.device.destroy_semaphore(semaphore, None);
}
for &semaphore in self.render_finished_semaphores.iter() {
self.device.destroy_semaphore(semaphore, None);
}
for &framebuffer in self.framebuffers.iter() {
self.device.destroy_framebuffer(framebuffer, None);
}
for &image_view in self.color_image_views.iter() {
self.device.destroy_image_view(image_view, None);
}
for &image_view in self.depth_image_views.iter() {
self.device.destroy_image_view(image_view, None);
}
for (image, allocation) in self.depth_images_and_allocations.drain(..) {
self.device.destroy_image(image, None);
allocator.free(allocation).expect("Failed to free memory");
}
self.device.destroy_render_pass(self.render_pass, None);
self.swapchain_loader
.destroy_swapchain(self.swapchain, None);
}
self.width = width;
self.height = height;
let (swapchain, swapchain_images, surface_format, surface_extent) = {
let surface_capabilities = unsafe {
self.surface_loader
.get_physical_device_surface_capabilities(self.physical_device, self.surface)
.expect("Failed to get physical device surface capabilities")
};
let surface_formats = unsafe {
self.surface_loader
.get_physical_device_surface_formats(self.physical_device, self.surface)
.expect("Failed to get physical device surface formats")
};
let surface_format = *surface_formats
.iter()
.find(|surface_format| {
surface_format.format == vk::Format::B8G8R8A8_UNORM
|| surface_format.format == vk::Format::R8G8B8A8_UNORM
})
.unwrap_or(&surface_formats[0]);
let surface_present_mode = vk::PresentModeKHR::FIFO;
let surface_extent = if surface_capabilities.current_extent.width != u32::MAX {
surface_capabilities.current_extent
} else {
vk::Extent2D {
width: self.width.clamp(
surface_capabilities.min_image_extent.width,
surface_capabilities.max_image_extent.width,
),
height: self.height.clamp(
surface_capabilities.min_image_extent.height,
surface_capabilities.max_image_extent.height,
),
}
};
let image_count = surface_capabilities.min_image_count + 1;
let image_count = if surface_capabilities.max_image_count != 0 {
image_count.min(surface_capabilities.max_image_count)
} else {
image_count
};
let swapchain_create_info = vk::SwapchainCreateInfoKHR::builder()
.surface(self.surface)
.min_image_count(image_count)
.image_color_space(surface_format.color_space)
.image_format(surface_format.format)
.image_extent(surface_extent)
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
.image_sharing_mode(vk::SharingMode::EXCLUSIVE)
.pre_transform(surface_capabilities.current_transform)
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
.present_mode(surface_present_mode)
.image_array_layers(1)
.clipped(true);
let swapchain = unsafe {
self.swapchain_loader
.create_swapchain(&swapchain_create_info, None)
.expect("Failed to create swapchain")
};
let swapchain_images = unsafe {
self.swapchain_loader
.get_swapchain_images(swapchain)
.expect("Failed to get swapchain images")
};
(swapchain, swapchain_images, surface_format, surface_extent)
};
self.swapchain = swapchain;
self.swapchain_images = swapchain_images;
self.surface_format = surface_format;
self.surface_extent = surface_extent;
egui_cmd.update_swapchain(egui_ash::SwapchainUpdateInfo {
swapchain_images: self.swapchain_images.clone(),
surface_format: self.surface_format.format,
width: self.width,
height: self.height,
});
self.render_pass = Self::create_render_pass(&self.device, self.surface_format);
let CreateFramebuffersResult(
framebuffers,
depth_images_and_allocations,
color_image_views,
depth_image_views,
) = Self::create_framebuffers(
&self.device,
Arc::clone(&self.allocator),
self.render_pass,
self.surface_format,
self.surface_extent,
&self.swapchain_images,
);
self.framebuffers = framebuffers;
self.depth_images_and_allocations = depth_images_and_allocations;
self.color_image_views = color_image_views;
self.depth_image_views = depth_image_views;
let (in_flight_fences, image_available_semaphores, render_finished_semaphores) =
Self::create_sync_objects(&self.device, self.swapchain_images.len());
self.in_flight_fences = in_flight_fences;
self.image_available_semaphores = image_available_semaphores;
self.render_finished_semaphores = render_finished_semaphores;
self.current_frame = 0;
self.dirty_swapchain = false;
}
fn new(
physical_device: vk::PhysicalDevice,
device: Device,
surface_loader: Surface,
swapchain_loader: Swapchain,
allocator: Arc<Mutex<Allocator>>,
surface: vk::SurfaceKHR,
queue_family_index: u32,
queue: vk::Queue,
command_pool: vk::CommandPool,
width: u32,
height: u32,
) -> Self {
let (swapchain, surface_format, surface_extent, swapchain_images) = Self::create_swapchain(
physical_device,
&surface_loader,
&swapchain_loader,
surface,
queue_family_index,
width,
height,
);
let (uniform_buffers, uniform_buffer_allocations) =
Self::create_uniform_buffers(&device, allocator.clone(), swapchain_images.len());
let descriptor_pool = Self::create_descriptor_pool(&device, swapchain_images.len());
let descriptor_set_layouts =
Self::create_descriptor_set_layouts(&device, swapchain_images.len());
let descriptor_sets = Self::create_descriptor_sets(
&device,
descriptor_pool,
&descriptor_set_layouts,
&uniform_buffers,
);
let render_pass = Self::create_render_pass(&device, surface_format);
let CreateFramebuffersResult(
framebuffers,
depth_images_and_allocations,
color_image_views,
depth_image_views,
) = Self::create_framebuffers(
&device,
allocator.clone(),
render_pass,
surface_format,
surface_extent,
&swapchain_images,
);
let (pipeline, pipeline_layout) =
Self::create_graphics_pipeline(&device, &descriptor_set_layouts, render_pass);
let (vertex_buffer, vertex_buffer_allocation, vertex_count) =
Self::load_model_and_create_vertex_buffer(
&device,
allocator.clone(),
command_pool,
queue,
);
let command_buffers =
Self::create_command_buffers(&device, command_pool, swapchain_images.len());
let (in_flight_fences, image_available_semaphores, render_finished_semaphores) =
Self::create_sync_objects(&device, swapchain_images.len());
Self {
width,
height,
physical_device,
device,
surface_loader,
swapchain_loader,
allocator: ManuallyDrop::new(allocator),
surface,
queue,
swapchain,
surface_format,
surface_extent,
swapchain_images,
uniform_buffers,
uniform_buffer_allocations,
descriptor_pool,
descriptor_set_layouts,
descriptor_sets,
render_pass,
framebuffers,
depth_images_and_allocations,
color_image_views,
depth_image_views,
pipeline,
pipeline_layout,
vertex_buffer,
vertex_buffer_allocation: Some(vertex_buffer_allocation),
vertex_count,
command_buffers,
in_flight_fences,
image_available_semaphores,
render_finished_semaphores,
current_frame: 0,
dirty_swapchain: true,
frame_counter: 0,
camera_position: Vec3::new(0.0, 0.0, -5.0),
camera_yaw: 0.,
camera_pitch: 0.,
accumulation_reset_needed: true,
}
}
pub fn update_camera(&mut self, new_position: Vec3, yaw: f32, pitch: f32) {
if (new_position - self.camera_position).length() > 0.0001
|| (yaw - self.camera_yaw).abs() > 0.001
|| (pitch - self.camera_pitch).abs() > 0.001
{
self.camera_position = new_position;
self.camera_yaw = yaw;
self.camera_pitch = pitch;
self.accumulation_reset_needed = true;
}
}
pub fn render(&mut self, width: u32, height: u32, mut egui_cmd: EguiCommand, rotate_y: f32) {
if width == 0 || height == 0 {
return;
}
if self.dirty_swapchain || self.accumulation_reset_needed {
self.frame_counter = 0;
self.accumulation_reset_needed = false;
}
if self.dirty_swapchain
|| width != self.width
|| height != self.height
|| egui_cmd.swapchain_recreate_required()
{
self.recreate_swapchain(width, height, &mut egui_cmd);
}
let result = unsafe {
self.swapchain_loader.acquire_next_image(
self.swapchain,
u64::MAX,
self.image_available_semaphores[self.current_frame],
vk::Fence::null(),
)
};
let index = match result {
Ok((index, _)) => index as usize,
Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => {
self.dirty_swapchain = true;
return;
}
Err(_) => return,
};
unsafe {
self.device.wait_for_fences(
std::slice::from_ref(&self.in_flight_fences[self.current_frame]),
true,
u64::MAX,
)
}
.expect("Failed to wait for fences");
unsafe {
self.device.reset_fences(std::slice::from_ref(
&self.in_flight_fences[self.current_frame],
))
}
.expect("Failed to reset fences");
let view = {
let (sin_pitch, cos_pitch) = self.camera_pitch.sin_cos();
let (sin_yaw, cos_yaw) = self.camera_yaw.sin_cos();
let look_dir =
Vec3::new(cos_pitch * sin_yaw, sin_pitch, cos_pitch * cos_yaw).normalize();
Mat4::look_at_rh(
self.camera_position,
self.camera_position + look_dir,
Vec3::new(0.0, -1.0, 0.0),
)
};
let ubo = UniformBufferObject {
model: Mat4::from_rotation_y(rotate_y.to_radians()),
view,
proj: Mat4::perspective_rh(
45.0_f32.to_radians(),
width as f32 / height as f32,
0.1,
10.0,
),
};
unsafe {
let ptr = self.uniform_buffer_allocations[self.current_frame]
.mapped_ptr()
.unwrap()
.as_ptr() as *mut UniformBufferObject;
ptr.copy_from_nonoverlapping([ubo].as_ptr(), 1);
}
let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
unsafe {
self.device
.begin_command_buffer(
self.command_buffers[self.current_frame],
&command_buffer_begin_info,
)
.expect("Failed to begin command buffer");
self.device.cmd_begin_render_pass(
self.command_buffers[self.current_frame],
&vk::RenderPassBeginInfo::builder()
.render_pass(self.render_pass)
.framebuffer(self.framebuffers[index])
.render_area(
vk::Rect2D::builder()
.offset(vk::Offset2D::builder().x(0).y(0).build())
.extent(self.surface_extent)
.build(),
)
.clear_values(&[
vk::ClearValue {
color: vk::ClearColorValue {
float32: [0.4, 0.3, 0.2, 1.0],
},
},
vk::ClearValue {
depth_stencil: vk::ClearDepthStencilValue {
depth: 1.0,
stencil: 0,
},
},
]),
vk::SubpassContents::INLINE,
);
self.device.cmd_bind_pipeline(
self.command_buffers[self.current_frame],
vk::PipelineBindPoint::GRAPHICS,
self.pipeline,
);
self.device.cmd_set_viewport(
self.command_buffers[self.current_frame],
0,
std::slice::from_ref(
&vk::Viewport::builder()
.width(width as f32)
.height(height as f32)
.min_depth(0.0)
.max_depth(1.0),
),
);
self.device.cmd_set_scissor(
self.command_buffers[self.current_frame],
0,
std::slice::from_ref(
&vk::Rect2D::builder()
.offset(vk::Offset2D::builder().build())
.extent(self.surface_extent),
),
);
self.device.cmd_bind_descriptor_sets(
self.command_buffers[self.current_frame],
vk::PipelineBindPoint::GRAPHICS,
self.pipeline_layout,
0,
&[self.descriptor_sets[self.current_frame]],
&[],
);
self.device.cmd_bind_vertex_buffers(
self.command_buffers[self.current_frame],
0,
&[self.vertex_buffer],
&[0],
);
self.device.cmd_draw(
self.command_buffers[self.current_frame],
self.vertex_count,
1,
0,
0,
);
self.device
.cmd_end_render_pass(self.command_buffers[self.current_frame]);
egui_cmd.record(self.command_buffers[self.current_frame], index);
self.device
.end_command_buffer(self.command_buffers[self.current_frame])
.expect("Failed to end command buffer");
}
let buffers_to_submit = [self.command_buffers[self.current_frame]];
let submit_info = vk::SubmitInfo::builder()
.command_buffers(&buffers_to_submit)
.wait_semaphores(std::slice::from_ref(
&self.image_available_semaphores[self.current_frame],
))
.wait_dst_stage_mask(&[vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT])
.signal_semaphores(std::slice::from_ref(
&self.render_finished_semaphores[self.current_frame],
));
unsafe {
self.device
.queue_submit(
self.queue,
std::slice::from_ref(&submit_info),
self.in_flight_fences[self.current_frame],
)
.expect("Failed to submit queue");
};
let image_indices = [index as u32];
let present_info = vk::PresentInfoKHR::builder()
.wait_semaphores(std::slice::from_ref(
&self.render_finished_semaphores[self.current_frame],
))
.swapchains(std::slice::from_ref(&self.swapchain))
.image_indices(&image_indices);
let result = unsafe {
self.swapchain_loader
.queue_present(self.queue, &present_info)
};
let is_dirty_swapchain = match result {
Ok(true) | Err(vk::Result::ERROR_OUT_OF_DATE_KHR | vk::Result::SUBOPTIMAL_KHR) => true,
Err(error) => panic!("Failed to present queue. Cause: {}", error),
_ => false,
};
self.dirty_swapchain = is_dirty_swapchain;
self.current_frame = (self.current_frame + 1) % self.in_flight_fences.len();
self.frame_counter += 1;
static mut LAST_ROTATE_Y: f32 = 0.0;
unsafe {
if (LAST_ROTATE_Y - rotate_y).abs() > 0.001 {
self.accumulation_reset_needed = true;
LAST_ROTATE_Y = rotate_y;
}
}
}
fn destroy(&mut self) {
unsafe {
self.device
.device_wait_idle()
.expect("Failed to wait device idle");
let mut allocator = self.allocator.lock().unwrap();
for fence in self.in_flight_fences.drain(..) {
self.device.destroy_fence(fence, None);
}
for semaphore in self.image_available_semaphores.drain(..) {
self.device.destroy_semaphore(semaphore, None);
}
for semaphore in self.render_finished_semaphores.drain(..) {
self.device.destroy_semaphore(semaphore, None);
}
self.device.destroy_buffer(self.vertex_buffer, None);
if let Some(vertex_buffer_allocation) = self.vertex_buffer_allocation.take() {
allocator
.free(vertex_buffer_allocation)
.expect("Failed to free memory");
}
self.device.destroy_pipeline(self.pipeline, None);
self.device
.destroy_pipeline_layout(self.pipeline_layout, None);
for &framebuffer in self.framebuffers.iter() {
self.device.destroy_framebuffer(framebuffer, None);
}
for &color_image_view in self.color_image_views.iter() {
self.device.destroy_image_view(color_image_view, None);
}
for &depth_image_view in self.depth_image_views.iter() {
self.device.destroy_image_view(depth_image_view, None);
}
for (depth_image, allocation) in self.depth_images_and_allocations.drain(..) {
self.device.destroy_image(depth_image, None);
allocator.free(allocation).expect("Failed to free memory");
}
self.device.destroy_render_pass(self.render_pass, None);
for &descriptor_set_layout in self.descriptor_set_layouts.iter() {
self.device
.destroy_descriptor_set_layout(descriptor_set_layout, None);
}
self.device
.destroy_descriptor_pool(self.descriptor_pool, None);
for &uniform_buffer in self.uniform_buffers.iter() {
self.device.destroy_buffer(uniform_buffer, None);
}
for allocation in self.uniform_buffer_allocations.drain(..) {
allocator.free(allocation).expect("Failed to free memory");
}
self.swapchain_loader
.destroy_swapchain(self.swapchain, None);
}
unsafe {
ManuallyDrop::drop(&mut self.allocator);
}
}
}
#[derive(Clone)]
pub struct Renderer {
pub inner: Arc<Mutex<RendererInner>>,
}
impl Renderer {
pub fn new(
physical_device: vk::PhysicalDevice,
device: Device,
surface_loader: Surface,
swapchain_loader: Swapchain,
allocator: Arc<Mutex<Allocator>>,
surface: vk::SurfaceKHR,
queue_family_index: u32,
queue: vk::Queue,
command_pool: vk::CommandPool,
width: u32,
height: u32,
) -> Self {
Self {
inner: Arc::new(Mutex::new(RendererInner::new(
physical_device,
device,
surface_loader,
swapchain_loader,
allocator,
surface,
queue_family_index,
queue,
command_pool,
width,
height,
))),
}
}
pub fn destroy(&mut self) {
self.inner.lock().unwrap().destroy();
}
}