diff options
| -rw-r--r-- | shaders/shader.vert | 10 | ||||
| -rw-r--r-- | src/graphics_window_dressing.rs | 115 | ||||
| -rw-r--r-- | src/linear_algebra.rs | 62 | ||||
| -rw-r--r-- | src/main.rs | 1 |
4 files changed, 179 insertions, 9 deletions
diff --git a/shaders/shader.vert b/shaders/shader.vert index 186ba52..d53ef0a 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -1,5 +1,9 @@ #version 460 +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; +layout(location = 0) out vec3 vertexColor; + vec2 triangle[3] = vec2[]( vec2(0.0, -0.5), vec2(0.5, 0.5), @@ -12,10 +16,8 @@ vec3 colors[3] = vec3[]( vec3(0.0, 0.0, 1.0) ); -layout(location = 0) out vec3 vertexColor; - void main() { - gl_Position = vec4(triangle[gl_VertexIndex], 0.0, 1.0); - vertexColor = colors[gl_VertexIndex]; + gl_Position = vec4(inPosition, 0.0, 1.0); + vertexColor = inColor; } 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() + }) +} diff --git a/src/linear_algebra.rs b/src/linear_algebra.rs new file mode 100644 index 0000000..950877b --- /dev/null +++ b/src/linear_algebra.rs @@ -0,0 +1,62 @@ +#![forbid(unsafe_code)] +use std::mem::size_of; +use vulkanalia::vk::{ self, HasBuilder }; + + +pub static VERTICES: [Vertex<f32>; 3] = [ + Vertex::new(Vec2( 0.0, -0.5), Vec3(1.0, 0.0, 0.0)), + Vertex::new(Vec2( 0.5, 0.5), Vec3(0.0, 1.0, 0.0)), + Vertex::new(Vec2(-0.5, 0.5), Vec3(0.0, 0.0, 1.0)), +]; + + +#[derive(Clone, Debug)] +pub struct Vec2<T>(T, T); +#[derive(Clone, Debug)] +pub struct Vec3<T>(T, T, T); +#[derive(Clone, Debug)] +#[allow(unused)] +pub struct Vec4<T>(T, T, T, T); + + +#[repr(C)] +#[derive(Clone, Debug)] +pub struct Vertex<T> { + pub position: Vec2<T>, + pub color: Vec3<T>, +} + +impl<T> Vertex<T> { + const fn new(position: Vec2<T>, color: Vec3<T>) -> Self { + Self { position, color } + } + + pub fn binding_description() -> vk::VertexInputBindingDescription { + vk::VertexInputBindingDescription::builder() + .binding(0) + .stride(size_of::<Vertex<f32>>() as u32) + .input_rate(vk::VertexInputRate::VERTEX) + .build() + } + + pub fn attribute_descriptions() + -> [vk::VertexInputAttributeDescription; 2] + { + let position = vk::VertexInputAttributeDescription::builder() + .binding(0) + .location(0) + .format(vk::Format::R32G32_SFLOAT) + .offset(0) + .build(); + + let color = vk::VertexInputAttributeDescription::builder() + .binding(0) + .location(1) + .format(vk::Format::R32G32B32_SFLOAT) + .offset(size_of::<Vec2<f32>>() as u32) + .build(); + + [position, color] + } +} + diff --git a/src/main.rs b/src/main.rs index ba4ffb7..e6e3c0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ use winit::window::WindowId; mod error; mod graphics_permanent; mod graphics_window_dressing; +mod linear_algebra; struct Surreality { |