diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-08-15 20:26:28 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-08-16 02:08:18 -0700 |
| commit | db64249ce8108439ada78a2d23d67d2c573a1688 (patch) | |
| tree | 3029aeaab6f3e30ff199ae367f75a5851e8f0222 /src | |
| parent | 2fae64a18c3253a892c9b3e529fb7b09e0bac753 (diff) | |
move uniform buffers into Frame
it's better this way. same lifetime. Force-Push: yes Change-Id: Ida309f05132838febcc9eb606f5915e7592ac398
Diffstat (limited to 'src')
| -rw-r--r-- | src/graphics/frame.rs | 219 | ||||
| -rw-r--r-- | src/graphics/window_dressing.rs | 50 | ||||
| -rw-r--r-- | src/main.rs | 2 |
3 files changed, 121 insertions, 150 deletions
diff --git a/src/graphics/frame.rs b/src/graphics/frame.rs index 749b5ac..d8d4bcd 100644 --- a/src/graphics/frame.rs +++ b/src/graphics/frame.rs @@ -1,11 +1,12 @@ #![deny(unsafe_code)] use crate::error::*; use crate::graphics::{ Permanent, ForReinit, WindowDressing, Texture }; +use crate::graphics::util::allocate_buffer; use crate::shader_data::UniformBlock; use std::mem::size_of; -use vulkanalia::Device; +use vulkanalia::{ Device, Instance }; use vulkanalia::vk::{ self, HasBuilder, DeviceV1_0 }; @@ -18,6 +19,14 @@ use vulkanalia::vk::{ self, HasBuilder, DeviceV1_0 }; pub struct Frame { pub framebuffer: vk::Framebuffer, pub command_buffer: vk::CommandBuffer, + + // Uniform buffers are unlike the other things in Frame in that they are + // not used at render-time. It's still cleanest to have them here, since + // they exist per-frame. Otherwise we get action-at-a-distance passing + // around indices, which is harder to trace through. + pub uniform_buffer: vk::Buffer, + pub uniform_buffer_memory: vk::DeviceMemory, + pub descriptor_set: vk::DescriptorSet, } @@ -28,50 +37,22 @@ impl Frame { // want to handle a few of them simultaneously. That is in fact what we want, // so the interfaces to new() and reinit() work on Vec<Frame> instead of on // an indidivual Frame. + #[allow(unsafe_code)] pub fn new(permanent: &Permanent, for_reinit: &ForReinit, window_dressing: &WindowDressing, texture: &Texture, render_pass: &vk::RenderPass) -> Result<Vec<Self>> { - let device = &permanent.device; - let primary_command_pool = &permanent.primary_command_pool; - let descriptor_set_layout = &for_reinit.descriptor_set_layout; - let swapchain = &window_dressing.swapchain; - let color_image_view = &window_dressing.color_image_view; - let depth_image_view = &window_dressing.depth_image_view; - let uniform_buffers = &window_dressing.uniform_buffers; - let descriptor_pool = &window_dressing.descriptor_pool; - let sampler = &window_dressing.sampler; - - let count = swapchain.image_views.len(); - - let command_buffers = init_command_buffers(count, device, - primary_command_pool)?; - - let descriptor_sets - = init_descriptor_sets(count, device, descriptor_set_layout, - &uniform_buffers, &descriptor_pool, - &texture.image_view, &sampler)?; - let mut frames = Vec::new(); - for (index, color_resolve_image_view) - in swapchain.image_views.iter().enumerate() - { - let framebuffer = init_framebuffer( - device, &swapchain.extent, &color_image_view, &depth_image_view, - color_resolve_image_view, &render_pass)?; - frames.push(Frame { - command_buffer: command_buffers[index], - descriptor_set: descriptor_sets[index], - framebuffer, - }); - } + Frame::reinit(&mut frames, permanent, for_reinit, window_dressing, + texture, render_pass)?; Ok(frames) } // See new() in regard to the Vec. + #[allow(unsafe_code)] pub fn reinit(frames: &mut Vec<Self>, permanent: &Permanent, for_reinit: &ForReinit, window_dressing: &WindowDressing, texture: &Texture, render_pass: &vk::RenderPass) @@ -79,13 +60,13 @@ impl Frame { { Frame::destroy_replaceable(frames, permanent); + let instance = &permanent.instance; let device = &permanent.device; let primary_command_pool = &permanent.primary_command_pool; let descriptor_set_layout = &for_reinit.descriptor_set_layout; let swapchain = &window_dressing.swapchain; let color_image_view = &window_dressing.color_image_view; let depth_image_view = &window_dressing.depth_image_view; - let uniform_buffers = &window_dressing.uniform_buffers; let descriptor_pool = &window_dressing.descriptor_pool; let sampler = &window_dressing.sampler; @@ -94,25 +75,31 @@ impl Frame { let count = swapchain.image_views.len(); // Notice that we reused the command pool. - let command_buffers = init_command_buffers(count, device, - primary_command_pool)?; + let command_buffers = allocate_command_buffers(count, device, + primary_command_pool)?; - let descriptor_sets - = init_descriptor_sets(count, device, descriptor_set_layout, - &uniform_buffers, &descriptor_pool, - &texture.image_view, sampler)?; + let descriptor_sets = allocate_descriptor_sets( + count, device, descriptor_set_layout, descriptor_pool)?; for (index, color_resolve_image_view) in swapchain.image_views.iter().enumerate() { + let command_buffer = command_buffers[index]; + let mut descriptor_set = descriptor_sets[index]; + let framebuffer = init_framebuffer( device, &swapchain.extent, &color_image_view, &depth_image_view, color_resolve_image_view, &render_pass)?; + let (uniform_buffer, uniform_buffer_memory) + = init_uniform_buffer(instance, device)?; + + configure_descriptor_set(&mut descriptor_set, device, &uniform_buffer, + &texture.image_view, sampler)?; + frames.push(Frame { - command_buffer: command_buffers[index], - descriptor_set: descriptor_sets[index], - framebuffer, + framebuffer, command_buffer, uniform_buffer, uniform_buffer_memory, + descriptor_set, }); } @@ -128,6 +115,10 @@ impl Frame { #[allow(unsafe_code)] pub fn destroy_replaceable(frames: &mut Vec<Self>, permanent: &Permanent) { + if frames.is_empty() { + return; + } + let device = &permanent.device; let mut command_buffers = Vec::new(); @@ -135,6 +126,9 @@ impl Frame { unsafe { device.destroy_framebuffer(frame.framebuffer, None) }; command_buffers.push(frame.command_buffer); + + unsafe { device.destroy_buffer(frame.uniform_buffer, None) }; + unsafe { device.free_memory(frame.uniform_buffer_memory, None) }; } // Notice that we free the buffers in the pool, but do not destroy the @@ -178,8 +172,8 @@ fn init_framebuffer(device: &Device, extent: &vk::Extent2D, #[allow(unsafe_code)] -fn init_command_buffers(count: usize, device: &Device, - command_pool: &vk::CommandPool) +fn allocate_command_buffers(count: usize, device: &Device, + command_pool: &vk::CommandPool) -> Result<Vec<vk::CommandBuffer>> { let command_buffer_allocation_info @@ -196,64 +190,89 @@ fn init_command_buffers(count: usize, device: &Device, #[allow(unsafe_code)] -fn init_descriptor_sets(count: usize, device: &Device, - layout: &vk::DescriptorSetLayout, - buffers: &Vec<vk::Buffer>, pool: &vk::DescriptorPool, - texture_image_view: &vk::ImageView, - sampler: &vk::Sampler) +fn allocate_descriptor_sets(count: usize, device: &Device, + descriptor_set_layout: &vk::DescriptorSetLayout, + descriptor_pool: &vk::DescriptorPool) -> Result<Vec<vk::DescriptorSet>> { - 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::<UniformBlock<f32>>() 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 sampler_image_info = vk::DescriptorImageInfo::builder() - .sampler(*sampler); - let sampler_image_info_list = [sampler_image_info]; - let sampler_write_info = vk::WriteDescriptorSet::builder() - .dst_set(sets[index]) - .dst_binding(1) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::SAMPLER) - .image_info(&sampler_image_info_list); - - let texture_image_info = vk::DescriptorImageInfo::builder() - .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) - .image_view(*texture_image_view); - let texture_image_info_list = [texture_image_info]; - let texture_write_info = vk::WriteDescriptorSet::builder() - .dst_set(sets[index]) - .dst_binding(2) - .dst_array_element(0) - .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) - .image_info(&texture_image_info_list); - - let write_info_list = [ - uniform_block_write_info, sampler_write_info, texture_write_info - ]; - let copy_info_list: [vk::CopyDescriptorSet; 0] = []; + let layouts = vec![*descriptor_set_layout; count]; + let descriptor_set_info = vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(*descriptor_pool) + .set_layouts(&layouts[..]); + let descriptor_sets = unsafe { + device.allocate_descriptor_sets(&descriptor_set_info) + }?; - unsafe { - device.update_descriptor_sets(&write_info_list, ©_info_list) - }; - } + Ok(descriptor_sets) +} - Ok(sets) + +#[allow(unsafe_code)] +fn configure_descriptor_set(descriptor_set: &mut vk::DescriptorSet, + device: &Device, + uniform_buffer: &vk::Buffer, + texture_image_view: &vk::ImageView, + sampler: &vk::Sampler) + -> Result<()> +{ + let buffer_info = vk::DescriptorBufferInfo::builder() + .buffer(*uniform_buffer) + .offset(0) + .range(size_of::<UniformBlock<f32>>() as vk::DeviceSize); + + let buffer_info_list = [buffer_info]; + let uniform_block_write_info = vk::WriteDescriptorSet::builder() + .dst_set(*descriptor_set) + .dst_binding(0) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .buffer_info(&buffer_info_list); + + let sampler_image_info = vk::DescriptorImageInfo::builder() + .sampler(*sampler); + let sampler_image_info_list = [sampler_image_info]; + let sampler_write_info = vk::WriteDescriptorSet::builder() + .dst_set(*descriptor_set) + .dst_binding(1) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::SAMPLER) + .image_info(&sampler_image_info_list); + + let texture_image_info = vk::DescriptorImageInfo::builder() + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .image_view(*texture_image_view); + let texture_image_info_list = [texture_image_info]; + let texture_write_info = vk::WriteDescriptorSet::builder() + .dst_set(*descriptor_set) + .dst_binding(2) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) + .image_info(&texture_image_info_list); + + let write_info_list = [ + uniform_block_write_info, sampler_write_info, texture_write_info + ]; + let copy_info_list: [vk::CopyDescriptorSet; 0] = []; + + unsafe { + device.update_descriptor_sets(&write_info_list, ©_info_list) + }; + + Ok(()) } + +fn init_uniform_buffer(instance: &Instance, device: &Device) + -> Result<(vk::Buffer, vk::DeviceMemory)> +{ + let (buffer, memory) = allocate_buffer( + instance, device, + size_of::<UniformBlock<f32>>() as vk::DeviceSize, + vk::BufferUsageFlags::UNIFORM_BUFFER, + vk::MemoryPropertyFlags::HOST_COHERENT + | vk::MemoryPropertyFlags::HOST_VISIBLE)?; + + Ok((buffer, memory)) +} + + diff --git a/src/graphics/window_dressing.rs b/src/graphics/window_dressing.rs index 07dfaf0..d6afa20 100644 --- a/src/graphics/window_dressing.rs +++ b/src/graphics/window_dressing.rs @@ -2,13 +2,9 @@ use crate::error::*; use crate::graphics::{ Permanent, ForReinit }; use crate::graphics::permanent::{ QueueFamilyIndices, EnableAnisotropy }; -use crate::graphics::util::{ - allocate_buffer, allocate_image, init_image_view -}; -use crate::shader_data::UniformBlock; +use crate::graphics::util::{ allocate_image, init_image_view }; use std::collections::BTreeSet; -use std::mem::size_of; use vulkanalia::{ Device, Instance }; use vulkanalia::vk::{ self, Handle, HasBuilder, InstanceV1_0, DeviceV1_0, @@ -42,9 +38,6 @@ pub struct WindowDressing { pub sampler: vk::Sampler, - pub uniform_buffers: Vec<vk::Buffer>, - pub uniform_buffer_memory: Vec<vk::DeviceMemory>, - pub descriptor_pool: vk::DescriptorPool, pub concurrency: Concurrency, @@ -110,9 +103,6 @@ impl WindowDressing { let sampler = init_sampler(&device, &enable_anisotropy, mip_count)?; - let (uniform_buffers, uniform_buffer_memory) - = init_uniform_buffers(instance, device, swapchain.images.len())?; - let descriptor_pool = init_descriptor_pool(device, swapchain.images.len())?; @@ -128,8 +118,6 @@ impl WindowDressing { depth_image_view, depth_format, sampler, - uniform_buffers, - uniform_buffer_memory, descriptor_pool, concurrency, }) @@ -161,9 +149,6 @@ impl WindowDressing { let (depth_image, depth_image_memory, depth_image_view, depth_format) = init_depth(instance, device, &swapchain.extent, sample_count)?; - let (uniform_buffers, uniform_buffer_memory) - = init_uniform_buffers(instance, device, swapchain.images.len())?; - // Notice that we did NOT reuse the descriptor pool. let descriptor_pool = init_descriptor_pool(device, swapchain.images.len())?; @@ -179,8 +164,6 @@ impl WindowDressing { self.depth_image_memory = depth_image_memory; self.depth_image_view = depth_image_view; self.depth_format = depth_format; - self.uniform_buffers = uniform_buffers; - self.uniform_buffer_memory = uniform_buffer_memory; self.descriptor_pool = descriptor_pool; Ok(()) @@ -215,16 +198,6 @@ impl WindowDressing { // which will be different next time. So, we destroy it all the way. unsafe { device.destroy_descriptor_pool(self.descriptor_pool, None) }; - // Notice that, unlike the vertex and index buffers, we destroy and - // re-create these on every reinitialization. That's because the number of - // them depends on how many images the swapchain has. - for buffer in &self.uniform_buffers { - unsafe { device.destroy_buffer(*buffer, None) }; - } - for memory in &self.uniform_buffer_memory { - unsafe { device.free_memory(*memory, None) }; - } - unsafe { device.destroy_image(self.color_image, None) }; unsafe { device.free_memory(self.color_image_memory, None) }; unsafe { device.destroy_image_view(self.color_image_view, None) }; @@ -365,27 +338,6 @@ fn init_depth(instance: &Instance, device: &Device, extent: &vk::Extent2D, } -fn init_uniform_buffers(instance: &Instance, device: &Device, count: usize) - -> Result<(Vec<vk::Buffer>, Vec<vk::DeviceMemory>)> -{ - let mut buffers = Vec::new(); - let mut all_memory = Vec::new(); - - for _ in 0 .. count { - let (buffer, memory) = allocate_buffer( - instance, device, - size_of::<UniformBlock<f32>>() as vk::DeviceSize, - vk::BufferUsageFlags::UNIFORM_BUFFER, - vk::MemoryPropertyFlags::HOST_COHERENT - | vk::MemoryPropertyFlags::HOST_VISIBLE)?; - buffers.push(buffer); - all_memory.push(memory); - } - - Ok((buffers, all_memory)) -} - - #[allow(unsafe_code)] fn init_sampler(device: &Device, enable_anisotropy: &EnableAnisotropy, mip_count: u32) diff --git a/src/main.rs b/src/main.rs index b5af438..d461a63 100644 --- a/src/main.rs +++ b/src/main.rs @@ -167,7 +167,7 @@ impl Surreality { &window_dressing.swapchain.extent)?; render_uniforms(device, - &window_dressing.uniform_buffer_memory[image_index], + &render.per_frame[image_index].uniform_buffer_memory, &window_dressing.swapchain.extent)?; let first_semaphores = [*image_available_semaphore]; |