#![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<()>
{
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(())
}
}
#[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)
}