From 698c9493c89fb0c41eb7a10186c6befc7ad01d79 Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Thu, 6 Aug 2026 17:10:19 -0700 Subject: further splitting of graphics submodules now this is starting to feel like halfway decent organization Force-Push: yes Change-Id: I45cc4afb45e1528705680eb4192c1e9ba72f53fb --- src/graphics/mod.rs | 2 + src/graphics/render_state.rs | 574 ++++++++++++++++++++++++++++++ src/graphics/scene.rs | 2 +- src/graphics/util.rs | 173 +++++++++ src/graphics/window_dressing.rs | 761 ++-------------------------------------- 5 files changed, 770 insertions(+), 742 deletions(-) create mode 100644 src/graphics/render_state.rs create mode 100644 src/graphics/util.rs (limited to 'src/graphics') diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index f164588..7eca16a 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -1,5 +1,7 @@ #![deny(unsafe_code)] pub mod permanent; +pub mod render_state; pub mod scene; +pub mod util; pub mod window_dressing; diff --git a/src/graphics/render_state.rs b/src/graphics/render_state.rs new file mode 100644 index 0000000..d8a607c --- /dev/null +++ b/src/graphics/render_state.rs @@ -0,0 +1,574 @@ +#![deny(unsafe_code)] +use crate::error::*; +use crate::graphics::permanent::{ + PermanentGraphicsState, GraphicsStateForReinit +}; +use crate::graphics::util::{ + allocate_buffer, copy_buffer, stage_in_buffer +}; +use crate::model_loader::load_model; +use crate::graphics::window_dressing::WindowDressing; +use crate::shader_data::{ Vertex, UniformBlock, VertexPushBlock }; + +use std::mem::size_of; + +use vulkanalia::{ Device, Instance }; +use vulkanalia::vk::{ self, Handle, HasBuilder, DeviceV1_0 }; + + +// The RenderState collects the Vulkan graphics objects which need to be +// regenerated or modified when the window changes, as with WindowDressing, +// and which are also used as part of rendering. +#[derive(Debug)] +pub struct RenderState { + pub render_pass: vk::RenderPass, + + pub pipeline: vk::Pipeline, + pub pipeline_layout: vk::PipelineLayout, + + pub vertex_buffer: vk::Buffer, + vertex_buffer_memory: vk::DeviceMemory, + + pub index_buffer: vk::Buffer, + index_buffer_memory: vk::DeviceMemory, + pub index_count: usize, + + pub framebuffers: Vec, + pub command_buffers: Vec, + pub descriptor_sets: Vec, +} + + +impl RenderState { + pub fn new(permanent: &PermanentGraphicsState, + for_reinit: &GraphicsStateForReinit, + window_dressing: &WindowDressing) + -> Result + { + let device = &permanent.device; + let instance = &permanent.instance; + let graphics_queue = &permanent.graphics_queue; + let physical_device = &for_reinit.physical_device; + let sample_count = for_reinit.sample_count; + let descriptor_set_layout = &for_reinit.descriptor_set_layout; + let primary_command_pool = &window_dressing.primary_command_pool; + let transient_command_pool = &window_dressing.transient_command_pool; + let swapchain = &window_dressing.swapchain; + let depth_format = &window_dressing.depth_format; + let color_image_view = &window_dressing.color_image_view; + let depth_image_view = &window_dressing.depth_image_view; + let texture_image_view = &window_dressing.texture_image_view; + let uniform_buffers = &window_dressing.uniform_buffers; + let descriptor_pool = &window_dressing.descriptor_pool; + let sampler = &window_dressing.sampler; + + let render_pass = init_render_pass(device, sample_count, + &swapchain.format, &depth_format)?; + + let (pipeline_layout, pipeline) + = init_pipeline(device, descriptor_set_layout, &swapchain.extent, + sample_count, &render_pass)?; + + let framebuffers = init_framebuffers( + device, &swapchain.extent, &swapchain.image_views, + &color_image_view, &depth_image_view, &render_pass)?; + + let (vertices, indices) = load_model()?; + let index_count = indices.len(); + + let command_buffers = init_command_buffers(device, &framebuffers, + primary_command_pool)?; + + let (vertex_buffer, vertex_buffer_memory) + = init_vertex_buffer(vertices, instance, physical_device, device, + graphics_queue, &transient_command_pool)?; + let (index_buffer, index_buffer_memory) + = init_index_buffer(indices, instance, physical_device, device, + graphics_queue, &transient_command_pool)?; + + let descriptor_sets + = init_descriptor_sets(device, descriptor_set_layout, + &uniform_buffers, &descriptor_pool, + swapchain.images.len(), + &texture_image_view, &sampler)?; + + Ok(RenderState { + render_pass, + pipeline, + pipeline_layout, + vertex_buffer, + vertex_buffer_memory, + index_buffer, + index_buffer_memory, + index_count, + framebuffers, + command_buffers, + descriptor_sets, + }) + } + + // This relies on its caller to have already waited for the device to be + // idle. + pub fn reinit(&mut self, permanent: &PermanentGraphicsState, + for_reinit: &GraphicsStateForReinit, + window_dressing: &WindowDressing) + -> Result<()> + { + let device = &permanent.device; + let sample_count = for_reinit.sample_count; + let descriptor_set_layout = &for_reinit.descriptor_set_layout; + let primary_command_pool = &window_dressing.primary_command_pool; + let swapchain = &window_dressing.swapchain; + let depth_format = &window_dressing.depth_format; + let color_image_view = &window_dressing.color_image_view; + let depth_image_view = &window_dressing.depth_image_view; + let texture_image_view = &window_dressing.texture_image_view; + let uniform_buffers = &window_dressing.uniform_buffers; + let descriptor_pool = &window_dressing.descriptor_pool; + let sampler = &window_dressing.sampler; + + self.destroy_replaceable(device, primary_command_pool); + + let render_pass = init_render_pass(device, sample_count, + &swapchain.format, &depth_format)?; + + let (pipeline_layout, pipeline) + = init_pipeline(device, descriptor_set_layout, &swapchain.extent, + sample_count, &render_pass)?; + + let framebuffers = init_framebuffers( + device, &swapchain.extent, &swapchain.image_views, + &color_image_view, &depth_image_view, &render_pass)?; + + // Notice that we reused the command pool. + let command_buffers = init_command_buffers(device, &framebuffers, + primary_command_pool)?; + + let descriptor_sets + = init_descriptor_sets(device, descriptor_set_layout, + &uniform_buffers, &descriptor_pool, + swapchain.images.len(), + texture_image_view, sampler)?; + + self.render_pass = render_pass; + self.pipeline = pipeline; + self.pipeline_layout = pipeline_layout; + self.framebuffers = framebuffers; + self.command_buffers = command_buffers; + self.descriptor_sets = descriptor_sets; + + Ok(()) + } + + // This relies on its caller to have already waited for the device to be + // idle. + #[allow(unsafe_code)] + pub fn destroy(mut self, device: &Device, + window_dressing: &WindowDressing) + { + self.destroy_replaceable(device, &window_dressing.primary_command_pool); + + unsafe { device.destroy_buffer(self.vertex_buffer, None) }; + unsafe { device.free_memory(self.vertex_buffer_memory, None) }; + + unsafe { device.destroy_buffer(self.index_buffer, None) }; + unsafe { device.free_memory(self.index_buffer_memory, None) }; + } + + #[allow(unsafe_code)] + fn destroy_replaceable(&mut self, device: &Device, + primary_command_pool: &vk::CommandPool) + { + for framebuffer in &self.framebuffers { + unsafe { device.destroy_framebuffer(*framebuffer, None) }; + } + + // Notice that we free the buffers in the pool, but do not destroy the + // pool itself. Notice also that we only do this for the primary command + // pool, because that's the only one where we've kept track of the + // buffers. We promise ourselves to free buffers in the transient pool + // immediately after using them. + unsafe { + device.free_command_buffers(*primary_command_pool, + &self.command_buffers) + }; + + unsafe { device.destroy_pipeline(self.pipeline, None) }; + unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) }; + unsafe { device.destroy_render_pass(self.render_pass, None) }; + } +} + + +#[allow(unsafe_code)] +fn init_render_pass(device: &Device, sample_count: vk::SampleCountFlags, + color_format: &vk::Format, depth_format: &vk::Format) + -> Result +{ + let color_attachment = vk::AttachmentDescription::builder() + .format(*color_format) + .samples(sample_count) + .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); + + let color_attachment_reference = vk::AttachmentReference::builder() + .attachment(0) + .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); + + let depth_attachment = vk::AttachmentDescription::builder() + .format(*depth_format) + .samples(sample_count) + .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); + + let depth_attachment_reference = vk::AttachmentReference::builder() + .attachment(1) + .layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + + let color_resolve_attachment = vk::AttachmentDescription::builder() + .format(*color_format) + .samples(vk::SampleCountFlags::_1) + .load_op(vk::AttachmentLoadOp::DONT_CARE) + .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::PRESENT_SRC_KHR); + + let color_resolve_attachment_reference = vk::AttachmentReference::builder() + .attachment(2) + .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); + + let color_attachments = [color_attachment_reference]; + let resolve_attachments = [color_resolve_attachment_reference]; + let subpass = vk::SubpassDescription::builder() + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) + .color_attachments(&color_attachments) + .depth_stencil_attachment(&depth_attachment_reference) + .resolve_attachments(&resolve_attachments); + + let dependency = vk::SubpassDependency::builder() + .src_subpass(vk::SUBPASS_EXTERNAL) + .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT + | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS) + .src_access_mask(vk::AccessFlags::empty()) + .dst_subpass(0) + .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT + | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS) + .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE + | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE); + + let render_attachments = [color_attachment, + depth_attachment, + color_resolve_attachment]; + let subpasses = [subpass]; + let dependencies = [dependency]; + let render_pass_info = vk::RenderPassCreateInfo::builder() + .attachments(&render_attachments) + .subpasses(&subpasses) + .dependencies(&dependencies); + + let render_pass = unsafe { + device.create_render_pass(&render_pass_info, None) + }?; + + Ok(render_pass) +} + + +#[allow(unsafe_code)] +fn init_pipeline(device: &Device, + descriptor_set_layout: &vk::DescriptorSetLayout, + extent: &vk::Extent2D, sample_count: vk::SampleCountFlags, + render_pass: &vk::RenderPass) + -> Result<(vk::PipelineLayout, vk::Pipeline)> +{ + let vertex_binary = include_bytes!( + concat!(env!("OUT_DIR"), "/shader.vert.spv")); + let fragment_binary = include_bytes!( + concat!(env!("OUT_DIR"), "/shader.frag.spv")); + + let vertex_module = PermanentGraphicsState::load_spirv_shader_module( + device, vertex_binary)?; + let fragment_module = PermanentGraphicsState::load_spirv_shader_module( + device, fragment_binary)?; + + let vertex_stage_info = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::VERTEX) + .module(vertex_module) + .name(b"main\0"); + + let fragment_stage_info = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::FRAGMENT) + .module(fragment_module) + .name(b"main\0"); + + let binding_descriptions = [Vertex::::binding_description()]; + let attribute_descriptions = Vertex::::attribute_descriptions(); + let vertex_input_state_info + = vk::PipelineVertexInputStateCreateInfo::builder() + .vertex_binding_descriptions(&binding_descriptions) + .vertex_attribute_descriptions(&attribute_descriptions); + + let input_assembly_state_info + = vk::PipelineInputAssemblyStateCreateInfo::builder() + .topology(vk::PrimitiveTopology::TRIANGLE_LIST) + .primitive_restart_enable(false); + + let viewport = vk::Viewport::builder() + .x(0.0) + .y(0.0) + .width(extent.width as f32) + .height(extent.height as f32) + .min_depth(0.0) + .max_depth(1.0); + let viewports = [viewport]; + + let scissor = vk::Rect2D::builder() + .offset(vk::Offset2D { x: 0, y: 0 }) + .extent(*extent); + let scissor_list = [scissor]; + + let viewport_state_info = vk::PipelineViewportStateCreateInfo::builder() + .viewports(&viewports) + .scissors(&scissor_list); + + let rasterizer_state_info = vk::PipelineRasterizationStateCreateInfo::builder() + .depth_clamp_enable(false) + .rasterizer_discard_enable(false) + .polygon_mode(vk::PolygonMode::FILL) + .line_width(1.0) + .cull_mode(vk::CullModeFlags::BACK) + .front_face(vk::FrontFace::CLOCKWISE) + .depth_bias_enable(false); + + let multisample_state_info + = vk::PipelineMultisampleStateCreateInfo::builder() + .sample_shading_enable(false) + .rasterization_samples(sample_count); + + let depth_state_info = vk::PipelineDepthStencilStateCreateInfo::builder() + .depth_test_enable(true) + .depth_write_enable(true) + .depth_compare_op(vk::CompareOp::LESS) + .depth_bounds_test_enable(false) + .min_depth_bounds(0.0) + .max_depth_bounds(1.0) + .stencil_test_enable(false); + + let blend_attachment_info = vk::PipelineColorBlendAttachmentState::builder() + .color_write_mask(vk::ColorComponentFlags::all()) + .blend_enable(false) + .src_color_blend_factor(vk::BlendFactor::ONE) + .dst_color_blend_factor(vk::BlendFactor::ZERO) + .color_blend_op(vk::BlendOp::ADD) + .src_alpha_blend_factor(vk::BlendFactor::ONE) + .dst_alpha_blend_factor(vk::BlendFactor::ZERO) + .alpha_blend_op(vk::BlendOp::ADD); + let blend_attachments = [blend_attachment_info]; + + let blend_info = vk::PipelineColorBlendStateCreateInfo::builder() + .logic_op_enable(false) + .logic_op(vk::LogicOp::COPY) + .attachments(&blend_attachments) + .blend_constants([0.0, 0.0, 0.0, 0.0]); + + let vertex_push_constant_range = vk::PushConstantRange::builder() + .stage_flags(vk::ShaderStageFlags::VERTEX) + .offset(0) + .size(size_of::>() as u32); + + let layouts = [*descriptor_set_layout]; + let push_constant_ranges = [vertex_push_constant_range]; + let pipeline_layout_info = vk::PipelineLayoutCreateInfo::builder() + .set_layouts(&layouts) + .push_constant_ranges(&push_constant_ranges); + + let pipeline_layout = unsafe { + device.create_pipeline_layout(&pipeline_layout_info, None) + }?; + + let stages = [vertex_stage_info, fragment_stage_info]; + let pipeline_info = vk::GraphicsPipelineCreateInfo::builder() + .stages(&stages) + .vertex_input_state(&vertex_input_state_info) + .input_assembly_state(&input_assembly_state_info) + .viewport_state(&viewport_state_info) + .rasterization_state(&rasterizer_state_info) + .multisample_state(&multisample_state_info) + .depth_stencil_state(&depth_state_info) + .color_blend_state(&blend_info) + .layout(pipeline_layout) + .render_pass(*render_pass) + .subpass(0); + + let pipeline = unsafe { + device.create_graphics_pipelines(vk::PipelineCache::null(), + &[pipeline_info], None) + }?.0[0]; + + unsafe { + device.destroy_shader_module(vertex_module, None); + device.destroy_shader_module(fragment_module, None); + }; + + Ok((pipeline_layout, pipeline)) +} + + +#[allow(unsafe_code)] +fn init_framebuffers(device: &Device, extent: &vk::Extent2D, + swapchain_image_views: &Vec, + color_image_view: &vk::ImageView, + depth_image_view: &vk::ImageView, + render_pass: &vk::RenderPass) + -> Result> +{ + let mut framebuffers = Vec::new(); + + for color_resolve_image_view in swapchain_image_views { + let attachments = [*color_image_view, + *depth_image_view, + *color_resolve_image_view]; + + let framebuffer_info = vk::FramebufferCreateInfo::builder() + .render_pass(*render_pass) + .attachments(&attachments) + .width(extent.width) + .height(extent.height) + .layers(1); + + let framebuffer = unsafe { + device.create_framebuffer(&framebuffer_info, None) + }?; + + framebuffers.push(framebuffer); + } + + Ok(framebuffers) +} + + +#[allow(unsafe_code)] +fn init_command_buffers(device: &Device, + framebuffers: &Vec, + command_pool: &vk::CommandPool) + -> Result> +{ + let command_buffer_allocation_info + = vk::CommandBufferAllocateInfo::builder() + .command_pool(*command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(framebuffers.len() as u32); + let command_buffers = unsafe { + device.allocate_command_buffers(&command_buffer_allocation_info) + }?; + + Ok(command_buffers) +} + + +fn init_vertex_buffer(vertices: Vec>, instance: &Instance, + physical_device: &vk::PhysicalDevice, device: &Device, + queue: &vk::Queue, command_pool: &vk::CommandPool) + -> Result<(vk::Buffer, vk::DeviceMemory)> +{ + init_buffer(instance, physical_device, device, queue, command_pool, + vk::BufferUsageFlags::VERTEX_BUFFER, &vertices) +} + + +fn init_index_buffer(indices: Vec, instance: &Instance, + physical_device: &vk::PhysicalDevice, device: &Device, + queue: &vk::Queue, command_pool: &vk::CommandPool) + -> Result<(vk::Buffer, vk::DeviceMemory)> +{ + init_buffer(instance, physical_device, device, queue, command_pool, + vk::BufferUsageFlags::INDEX_BUFFER, &indices) +} + + +#[allow(unsafe_code)] +fn init_buffer(instance: &Instance, + physical_device: &vk::PhysicalDevice, device: &Device, + queue: &vk::Queue, command_pool: &vk::CommandPool, + usage: vk::BufferUsageFlags, contents: &[T]) + -> Result<(vk::Buffer, vk::DeviceMemory)> +{ + let (staging_buffer, staging_memory, size) + = stage_in_buffer(instance, physical_device, device, contents)?; + + let final_usage = vk::BufferUsageFlags::TRANSFER_DST | usage; + let final_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL; + let (final_buffer, device_memory) + = allocate_buffer(instance, physical_device, device, + size as vk::DeviceSize, final_usage, + final_memory_flags)?; + + copy_buffer(device, queue, command_pool, &staging_buffer, &final_buffer, + size as vk::DeviceSize)?; + + unsafe { device.destroy_buffer(staging_buffer, None) }; + unsafe { device.free_memory(staging_memory, None) }; + + Ok((final_buffer, device_memory)) +} + + +#[allow(unsafe_code)] +fn init_descriptor_sets(device: &Device, layout: &vk::DescriptorSetLayout, + buffers: &Vec, pool: &vk::DescriptorPool, + count: usize, texture_image_view: &vk::ImageView, + sampler: &vk::Sampler) + -> Result> +{ + let layouts = vec![*layout; count]; + let set_info = vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(*pool) + .set_layouts(&layouts); + let sets = unsafe { device.allocate_descriptor_sets(&set_info) }?; + + for index in 0 .. count { + let buffer_info = vk::DescriptorBufferInfo::builder() + .buffer(buffers[index]) + .offset(0) + .range(size_of::>() as vk::DeviceSize); + + let buffer_info_list = [buffer_info]; + let uniform_block_write_info = vk::WriteDescriptorSet::builder() + .dst_set(sets[index]) + .dst_binding(0) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .buffer_info(&buffer_info_list); + + let image_info = vk::DescriptorImageInfo::builder() + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .image_view(*texture_image_view) + .sampler(*sampler); + let image_info_list = [image_info]; + let sampler_write_info = vk::WriteDescriptorSet::builder() + .dst_set(sets[index]) + .dst_binding(1) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .image_info(&image_info_list); + + let write_info_list = [uniform_block_write_info, sampler_write_info]; + let copy_info_list: [vk::CopyDescriptorSet; 0] = []; + + unsafe { + device.update_descriptor_sets(&write_info_list, ©_info_list) + }; + } + + Ok(sets) +} diff --git a/src/graphics/scene.rs b/src/graphics/scene.rs index e59ae89..b5cf7bd 100644 --- a/src/graphics/scene.rs +++ b/src/graphics/scene.rs @@ -1,6 +1,6 @@ #![deny(unsafe_code)] use crate::error::*; -use crate::graphics::window_dressing::RenderState; +use crate::graphics::render_state::RenderState; use crate::linear_algebra::{ Vec3, Vec4, Transformation }; use crate::shader_data::VertexPushBlock; diff --git a/src/graphics/util.rs b/src/graphics/util.rs new file mode 100644 index 0000000..2debc4e --- /dev/null +++ b/src/graphics/util.rs @@ -0,0 +1,173 @@ +#![allow(unsafe_code)] +use crate::error::*; + +use std::mem::size_of; +use std::ptr::copy_nonoverlapping; + +use vulkanalia::{ Device, Instance }; +use vulkanalia::vk::{ self, Handle, HasBuilder, InstanceV1_0, DeviceV1_0 }; + + +pub fn stage_in_buffer(instance: &Instance, + physical_device: &vk::PhysicalDevice, + device: &Device, contents: &[T]) + -> Result<(vk::Buffer, vk::DeviceMemory, usize)> +{ + let size = size_of::() * contents.len(); + + let staging_usage = vk::BufferUsageFlags::TRANSFER_SRC; + let staging_memory_flags = vk::MemoryPropertyFlags::HOST_COHERENT + | vk::MemoryPropertyFlags::HOST_VISIBLE; + let (staging_buffer, staging_memory) + = allocate_buffer(instance, physical_device, device, + size as vk::DeviceSize, staging_usage, + staging_memory_flags)?; + + let host_memory = unsafe { + device.map_memory(staging_memory, 0, size as vk::DeviceSize, + vk::MemoryMapFlags::empty()) + }?; + + unsafe { + copy_nonoverlapping(contents.as_ptr(), host_memory.cast(), contents.len()) + }; + + unsafe { device.unmap_memory(staging_memory) }; + + Ok((staging_buffer, staging_memory, size)) +} + + +#[allow(unsafe_code)] +pub fn allocate_buffer(instance: &Instance, + physical_device: &vk::PhysicalDevice, device: &Device, + size: vk::DeviceSize, usage: vk::BufferUsageFlags, + memory_flags: vk::MemoryPropertyFlags) + -> Result<(vk::Buffer, vk::DeviceMemory)> +{ + let buffer_info = vk::BufferCreateInfo::builder() + .size(size) + .usage(usage) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + let buffer = unsafe { device.create_buffer(&buffer_info, None) }?; + + // The requirements are mostly what you'd think: size and alignment. The + // bits field is something special; see pick_memory_type() for the + // explanation. Despite the simplicity of this data, Vulkan wants to be the + // one to tell us about it, and we let it. + let requirements = unsafe { device.get_buffer_memory_requirements(buffer) }; + + let type_index = pick_memory_type(instance, physical_device, + &memory_flags, &requirements)?; + + let memory_info = vk::MemoryAllocateInfo::builder() + .allocation_size(requirements.size) + .memory_type_index(type_index); + + let device_memory = unsafe { device.allocate_memory(&memory_info, None) }?; + + unsafe { device.bind_buffer_memory(buffer, device_memory, 0) }?; + + Ok((buffer, device_memory)) +} + + +#[allow(unsafe_code)] +pub fn copy_buffer(device: &Device, queue: &vk::Queue, + command_pool: &vk::CommandPool, source: &vk::Buffer, + destination: &vk::Buffer, size: vk::DeviceSize) + -> Result<()> +{ + let command_buffer = begin_transient_commands(device, command_pool)?; + + let copy_info = vk::BufferCopy::builder().size(size); + unsafe { + device.cmd_copy_buffer(command_buffer, *source, *destination, + &[copy_info]) + }; + + end_transient_commands(command_buffer, device, queue, command_pool)?; + + Ok(()) +} + + +#[allow(unsafe_code)] +pub fn pick_memory_type(instance: &Instance, + physical_device: &vk::PhysicalDevice, + properties: &vk::MemoryPropertyFlags, + requirements: &vk::MemoryRequirements) + -> Result +{ + let memory_map = unsafe { + instance.get_physical_device_memory_properties(*physical_device) + }; + + // So. The memory_type_bits field is a map of which indices are suitable, + // based on the buffer our caller passed to + // get_buffer_memory_requirements(). Yes, that means there's a hard cap on + // how many memory types there can be, based on the size of the bitfield. + for index in 0 .. memory_map.memory_type_count { + if requirements.memory_type_bits & (1 << index) == 0 { + continue; + } + + let memory_type = memory_map.memory_types[index as usize]; + + if memory_type.property_flags.contains(*properties) { + return Ok(index); + } + } + + Err(Error { + message: "The system has no suitable memory for a buffer.".to_string() + }) +} + + +#[allow(unsafe_code)] +pub fn begin_transient_commands(device: &Device, + command_pool: &vk::CommandPool) + -> Result +{ + let command_buffer_allocation_info + = vk::CommandBufferAllocateInfo::builder() + .command_pool(*command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(1); + let command_buffer = unsafe { + device.allocate_command_buffers(&command_buffer_allocation_info) + }?[0]; + + let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder() + .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); + + unsafe { + device.begin_command_buffer(command_buffer, &command_buffer_begin_info) + }?; + + Ok(command_buffer) +} + + +#[allow(unsafe_code)] +pub fn end_transient_commands(command_buffer: vk::CommandBuffer, + device: &Device, queue: &vk::Queue, + command_pool: &vk::CommandPool) + -> Result<()> +{ + unsafe { device.end_command_buffer(command_buffer) }?; + + let command_buffers = [command_buffer]; + let submit_info = vk::SubmitInfo::builder() + .command_buffers(&command_buffers); + unsafe { device.queue_submit(*queue, &[submit_info], vk::Fence::null()) }?; + + unsafe { device.queue_wait_idle(*queue) }?; + + unsafe { device.free_command_buffers(*command_pool, &command_buffers) }; + + Ok(()) +} + diff --git a/src/graphics/window_dressing.rs b/src/graphics/window_dressing.rs index dc7f47f..065bd53 100644 --- a/src/graphics/window_dressing.rs +++ b/src/graphics/window_dressing.rs @@ -4,13 +4,16 @@ use crate::graphics::permanent::{ PermanentGraphicsState, GraphicsStateForReinit, QueueFamilyIndices, EnableAnisotropy }; -use crate::model_loader::load_model; -use crate::shader_data::{ Vertex, UniformBlock, VertexPushBlock }; +use crate::graphics::util::{ + allocate_buffer, stage_in_buffer, + pick_memory_type, + begin_transient_commands, end_transient_commands +}; +use crate::shader_data::UniformBlock; use std::collections::BTreeSet; use std::io::Cursor; use std::mem::size_of; -use std::ptr::copy_nonoverlapping; use png::Decoder; use vulkanalia::{ Device, Instance }; @@ -36,51 +39,29 @@ pub struct WindowDressing { color_image: vk::Image, color_image_memory: vk::DeviceMemory, - color_image_view: vk::ImageView, + pub color_image_view: vk::ImageView, depth_image: vk::Image, depth_image_memory: vk::DeviceMemory, - depth_image_view: vk::ImageView, - depth_format: vk::Format, + pub depth_image_view: vk::ImageView, + pub depth_format: vk::Format, - primary_command_pool: vk::CommandPool, - transient_command_pool: vk::CommandPool, + pub primary_command_pool: vk::CommandPool, + pub transient_command_pool: vk::CommandPool, texture_image: vk::Image, texture_image_memory: vk::DeviceMemory, - texture_image_view: vk::ImageView, - mip_count: u32, - sampler: vk::Sampler, + pub texture_image_view: vk::ImageView, + pub sampler: vk::Sampler, - uniform_buffers: Vec, + pub uniform_buffers: Vec, pub uniform_buffer_memory: Vec, - descriptor_pool: vk::DescriptorPool, + pub descriptor_pool: vk::DescriptorPool, pub concurrency: Concurrency, } -// The RenderState collects the Vulkan graphics objects which need to be -// regenerated or modified when the window changes, as with WindowDressing, -// and which are also used as part of rendering. -#[derive(Debug)] -pub struct RenderState { - pub render_pass: vk::RenderPass, - - pub pipeline: vk::Pipeline, - pub pipeline_layout: vk::PipelineLayout, - - pub vertex_buffer: vk::Buffer, - vertex_buffer_memory: vk::DeviceMemory, - - pub index_buffer: vk::Buffer, - index_buffer_memory: vk::DeviceMemory, - pub index_count: usize, - - pub framebuffers: Vec, - pub command_buffers: Vec, - pub descriptor_sets: Vec, -} // A swapchain is the generalized facility that is used to implement // double buffering, triple buffering, rendering passes that feed into each @@ -89,9 +70,9 @@ pub struct RenderState { #[derive(Debug)] pub struct Swapchain { pub swapchain: vk::SwapchainKHR, - images: Vec, - image_views: Vec, - format: vk::Format, + pub images: Vec, + pub image_views: Vec, + pub format: vk::Format, pub extent: vk::Extent2D, } @@ -173,7 +154,6 @@ impl WindowDressing { texture_image, texture_image_memory, texture_image_view, - mip_count, sampler, uniform_buffers, uniform_buffer_memory, @@ -197,7 +177,6 @@ impl WindowDressing { let physical_device = &for_reinit.physical_device; let sample_count = for_reinit.sample_count; let indices = &for_reinit.indices; - let descriptor_set_layout = &for_reinit.descriptor_set_layout; unsafe { device.device_wait_idle() }.unwrap(); @@ -303,167 +282,6 @@ impl WindowDressing { } -impl RenderState { - pub fn new(permanent: &PermanentGraphicsState, - for_reinit: &GraphicsStateForReinit, - window_dressing: &WindowDressing) - -> Result - { - let device = &permanent.device; - let instance = &permanent.instance; - let graphics_queue = &permanent.graphics_queue; - let physical_device = &for_reinit.physical_device; - let sample_count = for_reinit.sample_count; - let descriptor_set_layout = &for_reinit.descriptor_set_layout; - let primary_command_pool = &window_dressing.primary_command_pool; - let transient_command_pool = &window_dressing.transient_command_pool; - let swapchain = &window_dressing.swapchain; - let depth_format = &window_dressing.depth_format; - let color_image_view = &window_dressing.color_image_view; - let depth_image_view = &window_dressing.depth_image_view; - let texture_image_view = &window_dressing.texture_image_view; - let uniform_buffers = &window_dressing.uniform_buffers; - let descriptor_pool = &window_dressing.descriptor_pool; - let sampler = &window_dressing.sampler; - - let render_pass = init_render_pass(device, sample_count, - &swapchain.format, &depth_format)?; - - let (pipeline_layout, pipeline) - = init_pipeline(device, descriptor_set_layout, &swapchain.extent, - sample_count, &render_pass)?; - - let framebuffers = init_framebuffers( - device, &swapchain.extent, &swapchain.image_views, - &color_image_view, &depth_image_view, &render_pass)?; - - let (vertices, indices) = load_model()?; - let index_count = indices.len(); - - let command_buffers = init_command_buffers(device, &framebuffers, - primary_command_pool)?; - - let (vertex_buffer, vertex_buffer_memory) - = init_vertex_buffer(vertices, instance, physical_device, device, - graphics_queue, &transient_command_pool)?; - let (index_buffer, index_buffer_memory) - = init_index_buffer(indices, instance, physical_device, device, - graphics_queue, &transient_command_pool)?; - - let descriptor_sets - = init_descriptor_sets(device, descriptor_set_layout, - &uniform_buffers, &descriptor_pool, - swapchain.images.len(), - &texture_image_view, &sampler)?; - - Ok(RenderState { - render_pass, - pipeline, - pipeline_layout, - vertex_buffer, - vertex_buffer_memory, - index_buffer, - index_buffer_memory, - index_count, - framebuffers, - command_buffers, - descriptor_sets, - }) - } - - // This relies on its caller to have already waited for the device to be - // idle. - pub fn reinit(&mut self, permanent: &PermanentGraphicsState, - for_reinit: &GraphicsStateForReinit, - window_dressing: &WindowDressing) - -> Result<()> - { - let device = &permanent.device; - let sample_count = for_reinit.sample_count; - let descriptor_set_layout = &for_reinit.descriptor_set_layout; - let primary_command_pool = &window_dressing.primary_command_pool; - let swapchain = &window_dressing.swapchain; - let depth_format = &window_dressing.depth_format; - let color_image_view = &window_dressing.color_image_view; - let depth_image_view = &window_dressing.depth_image_view; - let texture_image_view = &window_dressing.texture_image_view; - let uniform_buffers = &window_dressing.uniform_buffers; - let descriptor_pool = &window_dressing.descriptor_pool; - let sampler = &window_dressing.sampler; - - self.destroy_replaceable(device, primary_command_pool); - - let render_pass = init_render_pass(device, sample_count, - &swapchain.format, &depth_format)?; - - let (pipeline_layout, pipeline) - = init_pipeline(device, descriptor_set_layout, &swapchain.extent, - sample_count, &render_pass)?; - - let framebuffers = init_framebuffers( - device, &swapchain.extent, &swapchain.image_views, - &color_image_view, &depth_image_view, &render_pass)?; - - // Notice that we reused the command pool. - let command_buffers = init_command_buffers(device, &framebuffers, - primary_command_pool)?; - - let descriptor_sets - = init_descriptor_sets(device, descriptor_set_layout, - &uniform_buffers, &descriptor_pool, - swapchain.images.len(), - texture_image_view, sampler)?; - - self.render_pass = render_pass; - self.pipeline = pipeline; - self.pipeline_layout = pipeline_layout; - self.framebuffers = framebuffers; - self.command_buffers = command_buffers; - self.descriptor_sets = descriptor_sets; - - Ok(()) - } - - // This relies on its caller to have already waited for the device to be - // idle. - #[allow(unsafe_code)] - pub fn destroy(mut self, device: &Device, - window_dressing: &WindowDressing) - { - self.destroy_replaceable(device, &window_dressing.primary_command_pool); - - unsafe { device.destroy_buffer(self.vertex_buffer, None) }; - unsafe { device.free_memory(self.vertex_buffer_memory, None) }; - - unsafe { device.destroy_buffer(self.index_buffer, None) }; - unsafe { device.free_memory(self.index_buffer_memory, None) }; - } - - #[allow(unsafe_code)] - fn destroy_replaceable(&mut self, device: &Device, - primary_command_pool: &vk::CommandPool) - { - for framebuffer in &self.framebuffers { - unsafe { device.destroy_framebuffer(*framebuffer, None) }; - } - - // Notice that we free the buffers in the pool, but do not destroy the - // pool itself. Notice also that we only do this for the primary command - // pool, because that's the only one where we've kept track of the - // buffers. We promise ourselves to free buffers in the transient pool - // immediately after using them. - unsafe { - device.free_command_buffers(*primary_command_pool, - &self.command_buffers) - }; - - unsafe { device.destroy_pipeline(self.pipeline, None) }; - unsafe { device.destroy_pipeline_layout(self.pipeline_layout, None) }; - unsafe { device.destroy_render_pass(self.render_pass, None) }; - } -} - - #[allow(unsafe_code)] fn init_swapchain(window: &Window, instance: &Instance, surface: &vk::SurfaceKHR, @@ -587,283 +405,6 @@ fn init_depth(instance: &Instance, physical_device: &vk::PhysicalDevice, } -#[allow(unsafe_code)] -fn init_render_pass(device: &Device, sample_count: vk::SampleCountFlags, - color_format: &vk::Format, depth_format: &vk::Format) - -> Result -{ - let color_attachment = vk::AttachmentDescription::builder() - .format(*color_format) - .samples(sample_count) - .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); - - let color_attachment_reference = vk::AttachmentReference::builder() - .attachment(0) - .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); - - let depth_attachment = vk::AttachmentDescription::builder() - .format(*depth_format) - .samples(sample_count) - .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); - - let depth_attachment_reference = vk::AttachmentReference::builder() - .attachment(1) - .layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - - let color_resolve_attachment = vk::AttachmentDescription::builder() - .format(*color_format) - .samples(vk::SampleCountFlags::_1) - .load_op(vk::AttachmentLoadOp::DONT_CARE) - .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::PRESENT_SRC_KHR); - - let color_resolve_attachment_reference = vk::AttachmentReference::builder() - .attachment(2) - .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); - - let color_attachments = [color_attachment_reference]; - let resolve_attachments = [color_resolve_attachment_reference]; - let subpass = vk::SubpassDescription::builder() - .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) - .color_attachments(&color_attachments) - .depth_stencil_attachment(&depth_attachment_reference) - .resolve_attachments(&resolve_attachments); - - let dependency = vk::SubpassDependency::builder() - .src_subpass(vk::SUBPASS_EXTERNAL) - .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT - | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS) - .src_access_mask(vk::AccessFlags::empty()) - .dst_subpass(0) - .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT - | vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS) - .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE - | vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE); - - let render_attachments = [color_attachment, - depth_attachment, - color_resolve_attachment]; - let subpasses = [subpass]; - let dependencies = [dependency]; - let render_pass_info = vk::RenderPassCreateInfo::builder() - .attachments(&render_attachments) - .subpasses(&subpasses) - .dependencies(&dependencies); - - let render_pass = unsafe { - device.create_render_pass(&render_pass_info, None) - }?; - - Ok(render_pass) -} - - -#[allow(unsafe_code)] -fn init_pipeline(device: &Device, - descriptor_set_layout: &vk::DescriptorSetLayout, - extent: &vk::Extent2D, sample_count: vk::SampleCountFlags, - render_pass: &vk::RenderPass) - -> Result<(vk::PipelineLayout, vk::Pipeline)> -{ - let vertex_binary = include_bytes!( - concat!(env!("OUT_DIR"), "/shader.vert.spv")); - let fragment_binary = include_bytes!( - concat!(env!("OUT_DIR"), "/shader.frag.spv")); - - let vertex_module = PermanentGraphicsState::load_spirv_shader_module( - device, vertex_binary)?; - let fragment_module = PermanentGraphicsState::load_spirv_shader_module( - device, fragment_binary)?; - - let vertex_stage_info = vk::PipelineShaderStageCreateInfo::builder() - .stage(vk::ShaderStageFlags::VERTEX) - .module(vertex_module) - .name(b"main\0"); - - let fragment_stage_info = vk::PipelineShaderStageCreateInfo::builder() - .stage(vk::ShaderStageFlags::FRAGMENT) - .module(fragment_module) - .name(b"main\0"); - - let binding_descriptions = [Vertex::::binding_description()]; - let attribute_descriptions = Vertex::::attribute_descriptions(); - let vertex_input_state_info - = vk::PipelineVertexInputStateCreateInfo::builder() - .vertex_binding_descriptions(&binding_descriptions) - .vertex_attribute_descriptions(&attribute_descriptions); - - let input_assembly_state_info - = vk::PipelineInputAssemblyStateCreateInfo::builder() - .topology(vk::PrimitiveTopology::TRIANGLE_LIST) - .primitive_restart_enable(false); - - let viewport = vk::Viewport::builder() - .x(0.0) - .y(0.0) - .width(extent.width as f32) - .height(extent.height as f32) - .min_depth(0.0) - .max_depth(1.0); - let viewports = [viewport]; - - let scissor = vk::Rect2D::builder() - .offset(vk::Offset2D { x: 0, y: 0 }) - .extent(*extent); - let scissor_list = [scissor]; - - let viewport_state_info = vk::PipelineViewportStateCreateInfo::builder() - .viewports(&viewports) - .scissors(&scissor_list); - - let rasterizer_state_info = vk::PipelineRasterizationStateCreateInfo::builder() - .depth_clamp_enable(false) - .rasterizer_discard_enable(false) - .polygon_mode(vk::PolygonMode::FILL) - .line_width(1.0) - .cull_mode(vk::CullModeFlags::BACK) - .front_face(vk::FrontFace::CLOCKWISE) - .depth_bias_enable(false); - - let multisample_state_info - = vk::PipelineMultisampleStateCreateInfo::builder() - .sample_shading_enable(false) - .rasterization_samples(sample_count); - - let depth_state_info = vk::PipelineDepthStencilStateCreateInfo::builder() - .depth_test_enable(true) - .depth_write_enable(true) - .depth_compare_op(vk::CompareOp::LESS) - .depth_bounds_test_enable(false) - .min_depth_bounds(0.0) - .max_depth_bounds(1.0) - .stencil_test_enable(false); - - let blend_attachment_info = vk::PipelineColorBlendAttachmentState::builder() - .color_write_mask(vk::ColorComponentFlags::all()) - .blend_enable(false) - .src_color_blend_factor(vk::BlendFactor::ONE) - .dst_color_blend_factor(vk::BlendFactor::ZERO) - .color_blend_op(vk::BlendOp::ADD) - .src_alpha_blend_factor(vk::BlendFactor::ONE) - .dst_alpha_blend_factor(vk::BlendFactor::ZERO) - .alpha_blend_op(vk::BlendOp::ADD); - let blend_attachments = [blend_attachment_info]; - - let blend_info = vk::PipelineColorBlendStateCreateInfo::builder() - .logic_op_enable(false) - .logic_op(vk::LogicOp::COPY) - .attachments(&blend_attachments) - .blend_constants([0.0, 0.0, 0.0, 0.0]); - - let vertex_push_constant_range = vk::PushConstantRange::builder() - .stage_flags(vk::ShaderStageFlags::VERTEX) - .offset(0) - .size(size_of::>() as u32); - - let layouts = [*descriptor_set_layout]; - let push_constant_ranges = [vertex_push_constant_range]; - let pipeline_layout_info = vk::PipelineLayoutCreateInfo::builder() - .set_layouts(&layouts) - .push_constant_ranges(&push_constant_ranges); - - let pipeline_layout = unsafe { - device.create_pipeline_layout(&pipeline_layout_info, None) - }?; - - let stages = [vertex_stage_info, fragment_stage_info]; - let pipeline_info = vk::GraphicsPipelineCreateInfo::builder() - .stages(&stages) - .vertex_input_state(&vertex_input_state_info) - .input_assembly_state(&input_assembly_state_info) - .viewport_state(&viewport_state_info) - .rasterization_state(&rasterizer_state_info) - .multisample_state(&multisample_state_info) - .depth_stencil_state(&depth_state_info) - .color_blend_state(&blend_info) - .layout(pipeline_layout) - .render_pass(*render_pass) - .subpass(0); - - let pipeline = unsafe { - device.create_graphics_pipelines(vk::PipelineCache::null(), - &[pipeline_info], None) - }?.0[0]; - - unsafe { - device.destroy_shader_module(vertex_module, None); - device.destroy_shader_module(fragment_module, None); - }; - - Ok((pipeline_layout, pipeline)) -} - - -#[allow(unsafe_code)] -fn init_framebuffers(device: &Device, extent: &vk::Extent2D, - swapchain_image_views: &Vec, - color_image_view: &vk::ImageView, - depth_image_view: &vk::ImageView, - render_pass: &vk::RenderPass) - -> Result> -{ - let mut framebuffers = Vec::new(); - - for color_resolve_image_view in swapchain_image_views { - let attachments = [*color_image_view, - *depth_image_view, - *color_resolve_image_view]; - - let framebuffer_info = vk::FramebufferCreateInfo::builder() - .render_pass(*render_pass) - .attachments(&attachments) - .width(extent.width) - .height(extent.height) - .layers(1); - - let framebuffer = unsafe { - device.create_framebuffer(&framebuffer_info, None) - }?; - - framebuffers.push(framebuffer); - } - - Ok(framebuffers) -} - - -fn init_vertex_buffer(vertices: Vec>, instance: &Instance, - physical_device: &vk::PhysicalDevice, device: &Device, - queue: &vk::Queue, command_pool: &vk::CommandPool) - -> Result<(vk::Buffer, vk::DeviceMemory)> -{ - init_buffer(instance, physical_device, device, queue, command_pool, - vk::BufferUsageFlags::VERTEX_BUFFER, &vertices) -} - - -fn init_index_buffer(indices: Vec, instance: &Instance, - physical_device: &vk::PhysicalDevice, device: &Device, - queue: &vk::Queue, command_pool: &vk::CommandPool) - -> Result<(vk::Buffer, vk::DeviceMemory)> -{ - init_buffer(instance, physical_device, device, queue, command_pool, - vk::BufferUsageFlags::INDEX_BUFFER, &indices) -} - - #[allow(unsafe_code)] fn init_texture(instance: &Instance, physical_device: &vk::PhysicalDevice, device: &Device, @@ -909,7 +450,6 @@ fn init_texture(instance: &Instance, vk::MemoryPropertyFlags::DEVICE_LOCAL)?; change_image_layout(device, queue, command_pool, &image, mip_count, - vk::Format::R8G8B8A8_SRGB, vk::ImageLayout::UNDEFINED, vk::ImageLayout::TRANSFER_DST_OPTIMAL)?; @@ -955,33 +495,6 @@ fn init_uniform_buffers(instance: &Instance, } -#[allow(unsafe_code)] -fn init_buffer(instance: &Instance, - physical_device: &vk::PhysicalDevice, device: &Device, - queue: &vk::Queue, command_pool: &vk::CommandPool, - usage: vk::BufferUsageFlags, contents: &[T]) - -> Result<(vk::Buffer, vk::DeviceMemory)> -{ - let (staging_buffer, staging_memory, size) - = stage_in_buffer(instance, physical_device, device, contents)?; - - let final_usage = vk::BufferUsageFlags::TRANSFER_DST | usage; - let final_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL; - let (final_buffer, device_memory) - = allocate_buffer(instance, physical_device, device, - size as vk::DeviceSize, final_usage, - final_memory_flags)?; - - copy_buffer(device, queue, command_pool, &staging_buffer, &final_buffer, - size as vk::DeviceSize)?; - - unsafe { device.destroy_buffer(staging_buffer, None) }; - unsafe { device.free_memory(staging_memory, None) }; - - Ok((final_buffer, device_memory)) -} - - #[allow(unsafe_code)] fn init_sampler(device: &Device, enable_anisotropy: &EnableAnisotropy, mip_count: u32) @@ -1037,57 +550,6 @@ fn init_descriptor_pool(device: &Device, count: usize) } -#[allow(unsafe_code)] -fn init_descriptor_sets(device: &Device, layout: &vk::DescriptorSetLayout, - buffers: &Vec, pool: &vk::DescriptorPool, - count: usize, texture_image_view: &vk::ImageView, - sampler: &vk::Sampler) - -> Result> -{ - let layouts = vec![*layout; count]; - let set_info = vk::DescriptorSetAllocateInfo::builder() - .descriptor_pool(*pool) - .set_layouts(&layouts); - let sets = unsafe { device.allocate_descriptor_sets(&set_info) }?; - - for index in 0 .. count { - let buffer_info = vk::DescriptorBufferInfo::builder() - .buffer(buffers[index]) - .offset(0) - .range(size_of::>() as vk::DeviceSize); - - let buffer_info_list = [buffer_info]; - let uniform_block_write_info = vk::WriteDescriptorSet::builder() - .dst_set(sets[index]) - .dst_binding(0) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) - .buffer_info(&buffer_info_list); - - let image_info = vk::DescriptorImageInfo::builder() - .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) - .image_view(*texture_image_view) - .sampler(*sampler); - let image_info_list = [image_info]; - let sampler_write_info = vk::WriteDescriptorSet::builder() - .dst_set(sets[index]) - .dst_binding(1) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) - .image_info(&image_info_list); - - let write_info_list = [uniform_block_write_info, sampler_write_info]; - let copy_info_list: [vk::CopyDescriptorSet; 0] = []; - - unsafe { - device.update_descriptor_sets(&write_info_list, ©_info_list) - }; - } - - Ok(sets) -} - - #[allow(unsafe_code)] fn init_command_pools(device: &Device, indices: &QueueFamilyIndices) -> Result<(vk::CommandPool, vk::CommandPool)> @@ -1110,25 +572,6 @@ fn init_command_pools(device: &Device, indices: &QueueFamilyIndices) } -#[allow(unsafe_code)] -fn init_command_buffers(device: &Device, - framebuffers: &Vec, - command_pool: &vk::CommandPool) - -> Result> -{ - let command_buffer_allocation_info - = vk::CommandBufferAllocateInfo::builder() - .command_pool(*command_pool) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(framebuffers.len() as u32); - let command_buffers = unsafe { - device.allocate_command_buffers(&command_buffer_allocation_info) - }?; - - Ok(command_buffers) -} - - #[allow(unsafe_code)] fn init_concurrency(device: &Device, swapchain_images: &Vec) @@ -1277,125 +720,6 @@ fn pick_image_extent(window: &Window, } -#[allow(unsafe_code)] -fn pick_memory_type(instance: &Instance, - physical_device: &vk::PhysicalDevice, - properties: &vk::MemoryPropertyFlags, - requirements: &vk::MemoryRequirements) - -> Result -{ - let memory_map = unsafe { - instance.get_physical_device_memory_properties(*physical_device) - }; - - // So. The memory_type_bits field is a map of which indices are suitable, - // based on the buffer our caller passed to - // get_buffer_memory_requirements(). Yes, that means there's a hard cap on - // how many memory types there can be, based on the size of the bitfield. - for index in 0 .. memory_map.memory_type_count { - if requirements.memory_type_bits & (1 << index) == 0 { - continue; - } - - let memory_type = memory_map.memory_types[index as usize]; - - if memory_type.property_flags.contains(*properties) { - return Ok(index); - } - } - - Err(Error { - message: "The system has no suitable memory for a buffer.".to_string() - }) -} - - -#[allow(unsafe_code)] -fn stage_in_buffer(instance: &Instance, - physical_device: &vk::PhysicalDevice, device: &Device, - contents: &[T]) - -> Result<(vk::Buffer, vk::DeviceMemory, usize)> -{ - let size = size_of::() * contents.len(); - - let staging_usage = vk::BufferUsageFlags::TRANSFER_SRC; - let staging_memory_flags = vk::MemoryPropertyFlags::HOST_COHERENT - | vk::MemoryPropertyFlags::HOST_VISIBLE; - let (staging_buffer, staging_memory) - = allocate_buffer(instance, physical_device, device, - size as vk::DeviceSize, staging_usage, - staging_memory_flags)?; - - let host_memory = unsafe { - device.map_memory(staging_memory, 0, size as vk::DeviceSize, - vk::MemoryMapFlags::empty()) - }?; - - unsafe { - copy_nonoverlapping(contents.as_ptr(), host_memory.cast(), contents.len()) - }; - - unsafe { device.unmap_memory(staging_memory) }; - - Ok((staging_buffer, staging_memory, size)) -} - - -#[allow(unsafe_code)] -fn allocate_buffer(instance: &Instance, - physical_device: &vk::PhysicalDevice, device: &Device, - size: vk::DeviceSize, usage: vk::BufferUsageFlags, - memory_flags: vk::MemoryPropertyFlags) - -> Result<(vk::Buffer, vk::DeviceMemory)> -{ - let buffer_info = vk::BufferCreateInfo::builder() - .size(size) - .usage(usage) - .sharing_mode(vk::SharingMode::EXCLUSIVE); - - let buffer = unsafe { device.create_buffer(&buffer_info, None) }?; - - // The requirements are mostly what you'd think: size and alignment. The - // bits field is something special; see pick_memory_type() for the - // explanation. Despite the simplicity of this data, Vulkan wants to be the - // one to tell us about it, and we let it. - let requirements = unsafe { device.get_buffer_memory_requirements(buffer) }; - - let type_index = pick_memory_type(instance, physical_device, - &memory_flags, &requirements)?; - - let memory_info = vk::MemoryAllocateInfo::builder() - .allocation_size(requirements.size) - .memory_type_index(type_index); - - let device_memory = unsafe { device.allocate_memory(&memory_info, None) }?; - - unsafe { device.bind_buffer_memory(buffer, device_memory, 0) }?; - - Ok((buffer, device_memory)) -} - - -#[allow(unsafe_code)] -fn copy_buffer(device: &Device, queue: &vk::Queue, - command_pool: &vk::CommandPool, source: &vk::Buffer, - destination: &vk::Buffer, size: vk::DeviceSize) - -> Result<()> -{ - let command_buffer = begin_transient_commands(device, command_pool)?; - - let copy_info = vk::BufferCopy::builder().size(size); - unsafe { - device.cmd_copy_buffer(command_buffer, *source, *destination, - &[copy_info]) - }; - - end_transient_commands(command_buffer, device, queue, command_pool)?; - - Ok(()) -} - - #[allow(unsafe_code)] fn allocate_image(instance: &Instance, physical_device: &vk::PhysicalDevice, device: &Device, width: u32, height: u32, mip_count: u32, @@ -1473,8 +797,8 @@ fn copy_buffer_to_image(device: &Device, queue: &vk::Queue, #[allow(unsafe_code)] fn change_image_layout(device: &Device, queue: &vk::Queue, command_pool: &vk::CommandPool, image: &vk::Image, - mip_count: u32, format: vk::Format, - old: vk::ImageLayout, new: vk::ImageLayout) + mip_count: u32, old: vk::ImageLayout, + new: vk::ImageLayout) -> Result<()> { let command_buffer = begin_transient_commands(device, command_pool)?; @@ -1691,48 +1015,3 @@ fn fill_mip_levels(device: &Device, queue: &vk::Queue, Ok(()) } - -#[allow(unsafe_code)] -fn begin_transient_commands(device: &Device, command_pool: &vk::CommandPool) - -> Result -{ - let command_buffer_allocation_info - = vk::CommandBufferAllocateInfo::builder() - .command_pool(*command_pool) - .level(vk::CommandBufferLevel::PRIMARY) - .command_buffer_count(1); - let command_buffer = unsafe { - device.allocate_command_buffers(&command_buffer_allocation_info) - }?[0]; - - let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder() - .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); - - unsafe { - device.begin_command_buffer(command_buffer, &command_buffer_begin_info) - }?; - - Ok(command_buffer) -} - - -#[allow(unsafe_code)] -fn end_transient_commands(command_buffer: vk::CommandBuffer, - device: &Device, queue: &vk::Queue, - command_pool: &vk::CommandPool) - -> Result<()> -{ - unsafe { device.end_command_buffer(command_buffer) }?; - - let command_buffers = [command_buffer]; - let submit_info = vk::SubmitInfo::builder() - .command_buffers(&command_buffers); - unsafe { device.queue_submit(*queue, &[submit_info], vk::Fence::null()) }?; - - unsafe { device.queue_wait_idle(*queue) }?; - - unsafe { device.free_command_buffers(*command_pool, &command_buffers) }; - - Ok(()) -} - -- cgit 1.4.1