From db64249ce8108439ada78a2d23d67d2c573a1688 Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Sat, 15 Aug 2026 20:26:28 -0700 Subject: move uniform buffers into Frame it's better this way. same lifetime. Force-Push: yes Change-Id: Ida309f05132838febcc9eb606f5915e7592ac398 --- src/graphics/frame.rs | 219 +++++++++++++++++++++++++++----------------------- 1 file changed, 119 insertions(+), 100 deletions(-) (limited to 'src/graphics/frame.rs') 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 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> { - 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, 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, 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> { 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, 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> { - 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 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::>() 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::>() as vk::DeviceSize, + vk::BufferUsageFlags::UNIFORM_BUFFER, + vk::MemoryPropertyFlags::HOST_COHERENT + | vk::MemoryPropertyFlags::HOST_VISIBLE)?; + + Ok((buffer, memory)) +} + + -- cgit 1.4.1