diff options
Diffstat (limited to 'src/graphics_window_dressing.rs')
| -rw-r--r-- | src/graphics_window_dressing.rs | 115 |
1 files changed, 110 insertions, 5 deletions
diff --git a/src/graphics_window_dressing.rs b/src/graphics_window_dressing.rs index 63fc693..7fa25cf 100644 --- a/src/graphics_window_dressing.rs +++ b/src/graphics_window_dressing.rs @@ -3,10 +3,12 @@ use crate::error::*; use crate::graphics_permanent::{ PermanentGraphicsState, GraphicsStateForReinit, QueueFamilyIndices }; +use crate::linear_algebra::{ Vertex, VERTICES }; use std::collections::BTreeSet; +use std::ptr; use vulkanalia::{ Device, Instance }; -use vulkanalia::vk::{ self, Handle, HasBuilder, DeviceV1_0, +use vulkanalia::vk::{ self, Handle, HasBuilder, InstanceV1_0, DeviceV1_0, KhrSwapchainExtensionDeviceCommands }; use winit::window::Window; @@ -32,6 +34,9 @@ pub struct WindowDressing { framebuffers: Vec<vk::Framebuffer>, + vertex_buffer: vk::Buffer, + vertex_buffer_memory: vk::DeviceMemory, + command_pool: vk::CommandPool, pub command_buffers: Vec<vk::CommandBuffer>, @@ -96,10 +101,14 @@ impl WindowDressing { let framebuffers = init_framebuffers( device, &swapchain.extent, &swapchain.image_views, &render_pass)?; + let (vertex_buffer, vertex_buffer_memory) + = init_vertex_buffer(instance, physical_device, device)?; + let command_pool = init_command_pool(device, indices)?; let command_buffers = init_commands(device, &swapchain.extent, &framebuffers, &render_pass, - &pipeline, &command_pool)?; + &pipeline, &vertex_buffer, + &command_pool)?; let concurrency = init_concurrency(device, &swapchain.images)?; @@ -109,6 +118,8 @@ impl WindowDressing { pipeline, pipeline_layout, framebuffers, + vertex_buffer, + vertex_buffer_memory, command_pool, command_buffers, concurrency, @@ -146,7 +157,7 @@ impl WindowDressing { // Notice that we reused the command pool. let command_buffers = init_commands( device, &swapchain.extent, &framebuffers, &render_pass, - &pipeline, &self.command_pool)?; + &pipeline, &self.vertex_buffer, &self.command_pool)?; self.concurrency.image_fences.resize(swapchain.images.len(), vk::Fence::null()); @@ -168,6 +179,9 @@ impl WindowDressing { pub fn destroy(mut self, device: &Device) { self.destroy_replaceable(device); + unsafe { device.destroy_buffer(self.vertex_buffer, None) }; + unsafe { device.free_memory(self.vertex_buffer_memory, None) }; + for semaphore in self.concurrency.image_available_semaphores { unsafe { device.destroy_semaphore(semaphore, None) }; } @@ -386,8 +400,12 @@ fn init_pipeline(device: &Device, extent: &vk::Extent2D, .module(fragment_module) .name(b"main\0"); + let binding_descriptions = [Vertex::<f32>::binding_description()]; + let attribute_descriptions = Vertex::<f32>::attribute_descriptions(); let vertex_input_state_info - = vk::PipelineVertexInputStateCreateInfo::builder(); + = vk::PipelineVertexInputStateCreateInfo::builder() + .vertex_binding_descriptions(&binding_descriptions) + .vertex_attribute_descriptions(&attribute_descriptions); let input_assembly_state_info = vk::PipelineInputAssemblyStateCreateInfo::builder() @@ -509,6 +527,53 @@ fn init_framebuffers(device: &Device, extent: &vk::Extent2D, #[allow(unsafe_code)] +fn init_vertex_buffer(instance: &Instance, + physical_device: &vk::PhysicalDevice, device: &Device) + -> Result<(vk::Buffer, vk::DeviceMemory)> +{ + let buffer_info + = vk::BufferCreateInfo::builder() + .size((size_of::<Vertex<f32>>() * VERTICES.len()) as u64) + .usage(vk::BufferUsageFlags::VERTEX_BUFFER) + .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 flags = vk::MemoryPropertyFlags::HOST_COHERENT + | vk::MemoryPropertyFlags::HOST_VISIBLE; + let type_index = pick_memory_type(instance, physical_device, + &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) }?; + + let host_memory = unsafe { + device.map_memory(device_memory, 0, buffer_info.size, + vk::MemoryMapFlags::empty()) + }?; + + unsafe { + ptr::copy_nonoverlapping(VERTICES.as_ptr(), host_memory.cast(), + VERTICES.len()) + }; + + unsafe { device.unmap_memory(device_memory) }; + + Ok((buffer, device_memory)) +} + + +#[allow(unsafe_code)] fn init_command_pool(device: &Device, indices: &QueueFamilyIndices) -> Result<vk::CommandPool> { @@ -528,6 +593,7 @@ fn init_commands(device: &Device, framebuffers: &Vec<vk::Framebuffer>, render_pass: &vk::RenderPass, pipeline: &vk::Pipeline, + vertex_buffer: &vk::Buffer, command_pool: &vk::CommandPool) -> Result<Vec<vk::CommandBuffer>> { @@ -583,7 +649,14 @@ fn init_commands(device: &Device, *pipeline) }; - unsafe { device.cmd_draw(command_buffer, 3, 1, 0, 0) }; + unsafe { + device.cmd_bind_vertex_buffers(command_buffer, 0, + &[*vertex_buffer], &[0]) + }; + + unsafe { + device.cmd_draw(command_buffer, VERTICES.len() as u32, 1, 0, 0) + }; unsafe { device.cmd_end_render_pass(command_buffer) }; @@ -679,3 +752,35 @@ 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<u32> +{ + 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() + }) +} |