#![deny(unsafe_code)] use crate::error::*; use crate::graphics::{ Permanent, ForReinit, WindowDressing, Texture }; use crate::shader_data::UniformBlock; use std::mem::size_of; use vulkanalia::Device; use vulkanalia::vk::{ self, HasBuilder, DeviceV1_0 }; // Frame is a state object that collects the Vulkan graphics objects which // are used as part of rendering and which need to exist in multiples, one for // each frame that can be rendered in parallel (see N_SIMULTANEOUS_FRAMES in // window_dressing.rs). As with WindowDressing, these need to be regenerated // or modified when the window changes. #[derive(Debug)] pub struct Frame { pub framebuffer: vk::Framebuffer, pub command_buffer: vk::CommandBuffer, pub descriptor_set: vk::DescriptorSet, } impl Frame { // The lifecycle stuff for Frame is a little different. The Vulkan API to // allocate and deallocate command buffers is designed on the assumption you // 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. 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, }); } Ok(frames) } // See new() in regard to the Vec. pub fn reinit(frames: &mut Vec, permanent: &Permanent, for_reinit: &ForReinit, window_dressing: &WindowDressing, texture: &Texture, render_pass: &vk::RenderPass) -> Result<()> { Frame::destroy_replaceable(frames, permanent); 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; frames.clear(); 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 descriptor_sets = init_descriptor_sets(count, device, descriptor_set_layout, &uniform_buffers, &descriptor_pool, &texture.image_view, sampler)?; 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, }); } Ok(()) } // This relies on its caller to have already waited for the device to be // idle. #[allow(unsafe_code)] pub fn destroy(frames: &mut Vec, permanent: &Permanent) { Frame::destroy_replaceable(frames, permanent); } #[allow(unsafe_code)] pub fn destroy_replaceable(frames: &mut Vec, permanent: &Permanent) { let device = &permanent.device; let mut command_buffers = Vec::new(); for frame in frames { unsafe { device.destroy_framebuffer(frame.framebuffer, None) }; command_buffers.push(frame.command_buffer); } // 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(permanent.primary_command_pool, &command_buffers) }; } } #[allow(unsafe_code)] fn init_framebuffer(device: &Device, extent: &vk::Extent2D, color_image_view: &vk::ImageView, depth_image_view: &vk::ImageView, color_resolve_image_view: &vk::ImageView, render_pass: &vk::RenderPass) -> Result { 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) }?; Ok(framebuffer) } #[allow(unsafe_code)] fn init_command_buffers(count: usize, 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(count as u32); let command_buffers = unsafe { device.allocate_command_buffers(&command_buffer_allocation_info) }?; Ok(command_buffers) } #[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) -> 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] = []; unsafe { device.update_descriptor_sets(&write_info_list, ©_info_list) }; } Ok(sets) }