You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1287 lines
32 KiB

#![allow(dead_code)]
// TODO: remove allow
mod buffer;
mod model;
mod shader;
mod texture;
pub mod conf;
use self::conf::Conf;
use crate::{
c_str,
data::{self, uniforms::Uniforms, vertex::Vertex},
hal::win::Window,
types::{ffi::Nts, stkvec, Cast, Conv, StkVec},
};
use crate::{stkvec_e, stkvec_r, vec_r};
use ash::{
extensions::khr,
version::{DeviceV1_0, EntryV1_0, InstanceV1_0},
vk,
};
use std::{ffi::CStr, mem::size_of};
struct StaticData {
pipe_layout: vk::PipelineLayout,
desc_layout: vk::DescriptorSetLayout,
fen_frm: StkVec<[vk::Fence; 8]>,
sem_ren: StkVec<[vk::Semaphore; 8]>,
sem_img: StkVec<[vk::Semaphore; 8]>,
cmd_pool: vk::CommandPool,
shader_modules: Vec<Shader>,
queue_srf: vk::Queue,
queue_gfx: vk::Queue,
qf: QueueFamilies,
physical: vk::PhysicalDevice,
surface: vk::SurfaceKHR,
swp: khr::Swapchain,
dev: ash::Device,
srf: khr::Surface,
ins: ash::Instance,
ent: ash::Entry,
}
struct SwapchainData {
cmd_bufs: Vec<vk::CommandBuffer>,
desc_sets: Vec<vk::DescriptorSet>,
desc_pool: vk::DescriptorPool,
bon_bufs: StkVec<[Buf; 8]>,
ufm_bufs: StkVec<[Buf; 8]>,
framebuffers: StkVec<[vk::Framebuffer; 8]>,
sc_extent: vk::Extent2D,
sc_img_fn: StkVec<[Option<vk::Fence>; 8]>,
sc_img_vw: StkVec<[vk::ImageView; 8]>,
n_sc_imgs: usize,
sc_images: StkVec<[vk::Image; 8]>,
sc_img_in: ImageInfo,
pipeline: vk::Pipeline,
render_pass: vk::RenderPass,
depth_im: Texture,
swapchain: vk::SwapchainKHR,
}
struct RuntimeData {
models: Vec<Model>,
}
struct ImageInfo {
extent: StkVec<[vk::Extent3D; 8]>,
im_typ: vk::ImageType,
vw_typ: vk::ImageViewType,
aspect: vk::ImageAspectFlags,
format: vk::Format,
use_fl: vk::ImageUsageFlags,
}
struct QueueFamilies {
gfx: u32,
srf: u32,
}
struct Buf {
buff: vk::Buffer,
dmem: vk::DeviceMemory,
info: vk::DescriptorBufferInfo,
}
struct Shader {
module: vk::ShaderModule,
stages: StkVec<[vk::ShaderStageFlags; 8]>,
}
struct Model {
vtx_buf: Buf,
idx_buf: Buf,
model: data::model::Model,
}
struct Texture {
info: ImageInfo,
view: vk::ImageView,
imag: vk::Image,
dmem: vk::DeviceMemory,
}
pub struct Renderer {
rt: RuntimeData,
sc: SwapchainData,
st: StaticData,
conf: Conf,
cur_c_frame: usize,
}
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum Err {
// vulkan errors
#[error(transparent)]
Vk(#[from] vk::Result),
#[error(transparent)]
Instance(#[from] ash::InstanceError),
#[error(transparent)]
Loading(#[from] ash::LoadingError),
// missing stuff
#[error("No suitable devices available")]
NoDevice,
#[error("Graphics queues are not available on this device")]
NoGfxQueue,
#[error("Surface queues are not available on this device")]
NoSrfQueue,
#[error("Property `{0}' not available")]
NoProperty(String),
#[error("No memory type with flags `{0:?}' and type `{1}'")]
NoMemoryType(vk::MemoryPropertyFlags, u32),
// other errors
#[error(transparent)]
Hal(#[from] crate::hal::Err),
#[error(transparent)]
Nul(#[from] std::ffi::NulError),
}
impl StaticData {
unsafe fn new(
window: &Window, conf: &Conf, shaders: &[data::shader::Module],
) -> Result<Self, Err> {
let ent = unsafe { ash::Entry::new()? };
// create the instance
let extensions = window.vulkan_instance_extensions()?;
let app_info = vk::ApplicationInfo {
p_engine_name: crate::meta::ffi::NAME,
api_version: vk::make_version(1, 0, 0),
..Default::default()
};
let mut layers = StkVec::<[_; 1]>::new();
if conf.validation_layers {
layers.push(c_str!("VK_LAYER_KHRONOS_validation"));
}
let create_info = vk::InstanceCreateInfo {
p_application_info: &app_info,
enabled_extension_count: extensions.len().cast(),
pp_enabled_extension_names: extensions.as_ptr(),
..unsafe { enable_instance_layers(&ent, &layers)? }
};
let ins = unsafe { ent.create_instance(&create_info, None)? };
let srf = khr::Surface::new(&ent, &ins);
// create the surface
let surface = window.vulkan_create_surface(&ins)?;
// get the physical device
let physical = {
let devices = unsafe { ins.enumerate_physical_devices()? };
*devices.get(conf.device).ok_or(Err::NoDevice)?
};
// set up queues
let qf = unsafe { get_qfs(&ins, &srf, surface, physical)? };
let queue_priority = 1.0;
let queue_create_info = [
vk::DeviceQueueCreateInfo {
queue_family_index: qf.gfx,
queue_count: 1,
p_queue_priorities: &queue_priority,
..Default::default()
},
vk::DeviceQueueCreateInfo {
queue_family_index: qf.srf,
queue_count: 1,
p_queue_priorities: &queue_priority,
..Default::default()
},
];
// create the device
let device_features = vk::PhysicalDeviceFeatures {
sampler_anisotropy: vk::TRUE,
..Default::default()
};
let extensions = [c_str!("VK_KHR_swapchain")];
let create_info = vk::DeviceCreateInfo {
queue_create_info_count: queue_create_info.len().cast(),
p_queue_create_infos: queue_create_info.as_ptr(),
p_enabled_features: &device_features,
..unsafe { enable_device_extensions(&ins, physical, &extensions)? }
};
let dev = unsafe { ins.create_device(physical, &create_info, None)? };
let swp = khr::Swapchain::new(&ins, &dev);
// get the queues
let queue_gfx = unsafe { dev.get_device_queue(qf.gfx, 0) };
let queue_srf = unsafe { dev.get_device_queue(qf.srf, 0) };
// compile shader modules
let shader_modules =
vec_r![shaders, |shd| unsafe { Shader::new(&dev, shd) }]?;
// create the command pool
let create_info = vk::CommandPoolCreateInfo {
queue_family_index: qf.gfx,
flags: vk::CommandPoolCreateFlags::TRANSIENT
| vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER,
..Default::default()
};
let cmd_pool = unsafe { dev.create_command_pool(&create_info, None)? };
// create frame semaphores
let concur_frames = conf.concurrent_frames.get();
let sem_img = stkvec_r![unsafe { new_semaphore(&dev) }; concur_frames]?;
let sem_ren = stkvec_r![unsafe { new_semaphore(&dev) }; concur_frames]?;
let fen_frm = stkvec_r![unsafe { new_fence(&dev) }; concur_frames]?;
let desc_layout = unsafe { new_descriptor_set_layout(&dev)? };
let pipe_layout = unsafe { new_pipeline_layout(&dev, &[desc_layout])? };
Ok(Self {
pipe_layout,
desc_layout,
fen_frm,
sem_ren,
sem_img,
cmd_pool,
shader_modules,
queue_srf,
queue_gfx,
qf,
physical,
surface,
swp,
dev,
srf,
ins,
ent,
})
}
unsafe fn new_sc(&self, conf: &Conf) -> Result<SwapchainData, Err> {
// get all of the information about the swapchain we need before
// we create it
let capabilities = unsafe {
self.srf.get_physical_device_surface_capabilities(
self.physical,
self.surface,
)?
};
let formats = unsafe {
self
.srf
.get_physical_device_surface_formats(self.physical, self.surface)?
};
let modes = unsafe {
self.srf.get_physical_device_surface_present_modes(
self.physical,
self.surface,
)?
};
let sc_extent = if capabilities.current_extent.width != u32::MAX {
capabilities.current_extent
} else {
vk::Extent2D {
width: capabilities
.min_image_extent
.width
.max(capabilities.max_image_extent.width),
height: capabilities
.min_image_extent
.height
.max(capabilities.max_image_extent.height),
}
};
let format = *formats
.iter()
.find(|format| {
format.format == vk::Format::B8G8R8A8_UNORM
&& format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR
})
.unwrap_or_else(|| &formats[0]);
let mode = *modes
.iter()
.find(|&&mode| mode == conf.swap_mode.into())
.unwrap_or(&vk::PresentModeKHR::FIFO);
let min_image_count = capabilities.min_image_count + 1;
let min_image_count = if capabilities.max_image_count > 0
&& min_image_count > capabilities.max_image_count
{
capabilities.max_image_count
} else {
min_image_count
};
// create the swapchain
let queue_family_indices = [self.qf.gfx, self.qf.srf];
let create_info = vk::SwapchainCreateInfoKHR {
min_image_count,
present_mode: mode,
image_extent: sc_extent,
surface: self.surface,
image_format: format.format,
image_color_space: format.color_space,
image_array_layers: 1,
image_usage: vk::ImageUsageFlags::COLOR_ATTACHMENT,
image_sharing_mode: if self.qf.gfx != self.qf.srf {
vk::SharingMode::CONCURRENT
} else {
vk::SharingMode::EXCLUSIVE
},
queue_family_index_count: queue_family_indices.len().cast(),
p_queue_family_indices: queue_family_indices.as_ptr(),
pre_transform: capabilities.current_transform,
composite_alpha: vk::CompositeAlphaFlagsKHR::OPAQUE,
clipped: vk::TRUE,
..Default::default()
};
let swapchain =
unsafe { self.swp.create_swapchain(&create_info, None)? };
// create a depth texture
let depth_im = unsafe { self.new_tex_depth(sc_extent)? };
// create the render pass
let attachments = [
vk::AttachmentDescription {
format: format.format,
flags: vk::AttachmentDescriptionFlags::empty(),
samples: vk::SampleCountFlags::TYPE_1,
load_op: vk::AttachmentLoadOp::CLEAR,
store_op: vk::AttachmentStoreOp::STORE,
stencil_load_op: vk::AttachmentLoadOp::DONT_CARE,
stencil_store_op: vk::AttachmentStoreOp::DONT_CARE,
initial_layout: vk::ImageLayout::UNDEFINED,
final_layout: vk::ImageLayout::PRESENT_SRC_KHR,
},
vk::AttachmentDescription {
format: depth_im.info.format,
flags: vk::AttachmentDescriptionFlags::empty(),
samples: vk::SampleCountFlags::TYPE_1,
load_op: vk::AttachmentLoadOp::CLEAR,
store_op: vk::AttachmentStoreOp::DONT_CARE,
stencil_load_op: vk::AttachmentLoadOp::DONT_CARE,
stencil_store_op: vk::AttachmentStoreOp::DONT_CARE,
initial_layout: vk::ImageLayout::UNDEFINED,
final_layout: vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
},
];
let swapchain_attachment_ref = vk::AttachmentReference {
attachment: 0,
layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
};
let depth_attachment_ref = vk::AttachmentReference {
attachment: 1,
layout: vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
};
let subpasses = [vk::SubpassDescription {
pipeline_bind_point: vk::PipelineBindPoint::GRAPHICS,
color_attachment_count: 1,
p_color_attachments: &swapchain_attachment_ref,
p_depth_stencil_attachment: &depth_attachment_ref,
..Default::default()
}];
let dependencies = [vk::SubpassDependency {
src_subpass: vk::SUBPASS_EXTERNAL,
dst_subpass: 0,
src_stage_mask: vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
dst_stage_mask: vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT,
src_access_mask: vk::AccessFlags::empty(),
dst_access_mask: vk::AccessFlags::COLOR_ATTACHMENT_READ
| vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
dependency_flags: vk::DependencyFlags::empty(),
}];
let create_info = vk::RenderPassCreateInfo {
attachment_count: attachments.len().cast(),
p_attachments: attachments.as_ptr(),
subpass_count: subpasses.len().cast(),
p_subpasses: subpasses.as_ptr(),
dependency_count: dependencies.len().cast(),
p_dependencies: dependencies.as_ptr(),
..Default::default()
};
let render_pass =
unsafe { self.dev.create_render_pass(&create_info, None)? };
// create the pipeline
let shader_stages = self
.shader_modules
.iter()
.flat_map(|shd| shd.stage_infos())
.collect::<Vec<_>>();
let depth_stencil_state = vk::PipelineDepthStencilStateCreateInfo {
depth_test_enable: vk::TRUE,
depth_write_enable: vk::TRUE,
depth_compare_op: vk::CompareOp::LESS,
depth_bounds_test_enable: vk::FALSE,
stencil_test_enable: vk::FALSE,
min_depth_bounds: 0.0,
max_depth_bounds: 1.0,
..Default::default()
};
let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo {
topology: vk::PrimitiveTopology::TRIANGLE_LIST,
primitive_restart_enable: vk::FALSE,
..Default::default()
};
let rasterization_state = vk::PipelineRasterizationStateCreateInfo {
polygon_mode: vk::PolygonMode::FILL,
line_width: 1.0,
cull_mode: vk::CullModeFlags::BACK,
front_face: vk::FrontFace::CLOCKWISE,
..Default::default()
};
let multisample_state = vk::PipelineMultisampleStateCreateInfo {
sample_shading_enable: vk::FALSE,
rasterization_samples: vk::SampleCountFlags::TYPE_1,
min_sample_shading: 1.0,
..Default::default()
};
let color_blend_attachments = [vk::PipelineColorBlendAttachmentState {
blend_enable: vk::TRUE,
src_color_blend_factor: vk::BlendFactor::SRC_ALPHA,
dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA,
color_blend_op: vk::BlendOp::ADD,
src_alpha_blend_factor: vk::BlendFactor::ONE,
dst_alpha_blend_factor: vk::BlendFactor::ZERO,
alpha_blend_op: vk::BlendOp::ADD,
color_write_mask: vk::ColorComponentFlags::all(),
}];
let vertex_input_state = vk::PipelineVertexInputStateCreateInfo {
vertex_binding_description_count: VTX_BIND_DESC.len().cast(),
p_vertex_binding_descriptions: VTX_BIND_DESC.as_ptr(),
vertex_attribute_description_count: VTX_ATTR_DESC.len().cast(),
p_vertex_attribute_descriptions: VTX_ATTR_DESC.as_ptr(),
..Default::default()
};
let scissors =
[vk::Rect2D { extent: sc_extent, offset: vk::Offset2D::default() }];
let viewports = [vk::Viewport {
x: 0.0,
y: 0.0,
width: sc_extent.width.cast(),
height: sc_extent.height.cast(),
min_depth: 0.0,
max_depth: 1.0,
}];
let viewport_state = vk::PipelineViewportStateCreateInfo {
viewport_count: viewports.len().cast(),
p_viewports: viewports.as_ptr(),
scissor_count: scissors.len().cast(),
p_scissors: scissors.as_ptr(),
..Default::default()
};
let color_blend_state = vk::PipelineColorBlendStateCreateInfo {
attachment_count: color_blend_attachments.len().cast(),
p_attachments: color_blend_attachments.as_ptr(),
..Default::default()
};
let create_info = [vk::GraphicsPipelineCreateInfo {
layout: self.pipe_layout,
render_pass,
stage_count: shader_stages.len().cast(),
p_stages: shader_stages.as_ptr(),
p_vertex_input_state: &vertex_input_state,
p_input_assembly_state: &input_assembly_state,
p_viewport_state: &viewport_state,
p_rasterization_state: &rasterization_state,
p_multisample_state: &multisample_state,
p_depth_stencil_state: &depth_stencil_state,
p_color_blend_state: &color_blend_state,
..Default::default()
}];
let pipeline = unsafe {
self
.dev
.create_graphics_pipelines(
vk::PipelineCache::null(),
&create_info,
None,
)
.map_err(|(pipelines, res)| {
for pipeline in pipelines {
self.dev.destroy_pipeline(pipeline, None);
}
res
})?[0]
};
// get the swapchain images
let sc_img_in = ImageInfo {
extent: stkvec![vk::Extent3D {
width: sc_extent.width,
height: sc_extent.height,
depth: 1,
}],
aspect: vk::ImageAspectFlags::COLOR,
im_typ: vk::ImageType::TYPE_2D,
vw_typ: vk::ImageViewType::TYPE_2D,
format: format.format,
use_fl: vk::ImageUsageFlags::COLOR_ATTACHMENT,
};
let sc_images = StkVec::from_vec(unsafe {
self.swp.get_swapchain_images(swapchain)?
});
let n_sc_imgs = sc_images.len();
let sc_img_vw = stkvec_r![&sc_images, |&img| unsafe {
new_image_view(&self.dev, img, &sc_img_in)
}]?;
let sc_img_fn = stkvec![None; n_sc_imgs];
// create framebuffers for the swapchain
let framebuffers = stkvec_r![&sc_img_vw, |&view| unsafe {
new_framebuffer(
&self.dev,
render_pass,
&[view, depth_im.view],
sc_extent,
)
}]?;
// create the uniform buffers
let ufm_bufs =
stkvec_r![8; unsafe { self.new_buf(&Buf::UFM) }; n_sc_imgs]?;
let bon_bufs =
stkvec_r![8; unsafe { self.new_buf(&Buf::BON) }; n_sc_imgs]?;
// create the descriptor pool
let size_info = get_desc_pool_sizes(n_sc_imgs.cast());
let create_info = vk::DescriptorPoolCreateInfo {
pool_size_count: size_info.len().cast(),
p_pool_sizes: size_info.as_ptr(),
max_sets: n_sc_imgs.cast(),
..Default::default()
};
let desc_pool =
unsafe { self.dev.create_descriptor_pool(&create_info, None)? };
let set_layouts = vec![self.desc_layout; n_sc_imgs];
let alloc_info = vk::DescriptorSetAllocateInfo {
descriptor_pool: desc_pool,
descriptor_set_count: set_layouts.len().cast(),
p_set_layouts: set_layouts.as_ptr(),
..Default::default()
};
let desc_sets =
unsafe { self.dev.allocate_descriptor_sets(&alloc_info)? };
let mut write_descriptors =
StkVec::<[_; 24]>::with_capacity(desc_sets.len() * 3);
for (&dst_set, ufm, bon) in crate::types::iter::ClosedZip((
desc_sets.iter(),
ufm_bufs.iter(),
bon_bufs.iter(),
)) {
write_descriptors.extend_from_slice(&get_write_descriptors(
dst_set, &ufm.info, &bon.info,
));
}
unsafe { self.dev.update_descriptor_sets(&write_descriptors, &[]) };
let create_info = vk::CommandBufferAllocateInfo {
command_pool: self.cmd_pool,
level: vk::CommandBufferLevel::PRIMARY,
command_buffer_count: n_sc_imgs.cast(),
..Default::default()
};
let cmd_bufs =
unsafe { self.dev.allocate_command_buffers(&create_info)? };
Ok(SwapchainData {
cmd_bufs,
desc_sets,
desc_pool,
bon_bufs,
ufm_bufs,
framebuffers,
sc_extent,
sc_img_fn,
sc_img_vw,
n_sc_imgs,
sc_images,
sc_img_in,
pipeline,
render_pass,
depth_im,
swapchain,
})
}
unsafe fn seize_device(&self) {
if let Err(e) = unsafe { self.dev.device_wait_idle() } {
log::warn!("Error seizing renderer state: {}", e);
}
}
unsafe fn destroy(&self) {
unsafe {
self.dev.destroy_pipeline_layout(self.pipe_layout, None);
self.dev.destroy_descriptor_set_layout(self.desc_layout, None);
for &fen in self.fen_frm.iter() {
self.dev.destroy_fence(fen, None);
}
for &sem in self.sem_ren.iter().chain(self.sem_img.iter()) {
self.dev.destroy_semaphore(sem, None);
}
self.dev.destroy_command_pool(self.cmd_pool, None);
for shd in self.shader_modules.iter() {
shd.destroy(&self.dev);
}
self.dev.destroy_device(None);
self.srf.destroy_surface(self.surface, None);
self.ins.destroy_instance(None);
}
}
}
impl Renderer {
pub fn new(
window: &Window, conf: &Conf, shaders: &[data::shader::Module],
) -> Result<Self, Err> {
unsafe {
let st = StaticData::new(window, conf, shaders)?;
let sc = st.new_sc(conf)?;
let rt = RuntimeData { models: Default::default() };
Ok(Self { sc, st, rt, conf: *conf, cur_c_frame: 0 })
}
}
pub fn draw_frame(&mut self) -> Result<(), Err> {
match unsafe { self.draw_frame_raw() } {
| Ok(()) => {}
| Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => unsafe {
self.sc.destroy(&self.st);
self.sc = self.st.new_sc(&self.conf)?;
},
| Err(res) => {
log::warn!("Error rendering frame: {}", res);
}
}
self.cur_c_frame = (self.cur_c_frame + 1) % self.conf.concurrent_frames;
Ok(())
}
unsafe fn draw_frame_raw(&mut self) -> Result<(), vk::Result> {
use crate::math::*;
const CLEAR_VALUES: [vk::ClearValue; 2] = [
vk::ClearValue {
color: vk::ClearColorValue { float32: [0.101, 0.078, 0.113, 1.0] },
},
vk::ClearValue {
depth_stencil: vk::ClearDepthStencilValue {
depth: 1.0,
stencil: 0,
},
},
];
// synchronize and set up this fence
let sem_img = self.st.sem_img[self.cur_c_frame];
let sem_ren = self.st.sem_ren[self.cur_c_frame];
let fen_frm = self.st.fen_frm[self.cur_c_frame];
unsafe {
self.st.dev.wait_for_fences(&[fen_frm], true, u64::MAX)?;
}
let image_index: usize = unsafe {
self
.st
.swp
.acquire_next_image(
self.sc.swapchain,
u64::MAX,
sem_img,
vk::Fence::null(),
)?
.0
.cast()
};
if let Some(fence) = self.sc.sc_img_fn[image_index] {
unsafe {
self.st.dev.wait_for_fences(&[fence], true, u64::MAX)?;
}
}
self.sc.sc_img_fn[image_index] = Some(fen_frm);
// write uniforms
/*
let time_1 = time_ms as f32 / 1_000.0;
let pos = Vec3::new(0.0, 2.0, 0.0);
let rot = TAU * time_1 / 10.0;
let object = Mat4::from_scale_rotation_translation(
Vec3::splat(0.025),
Quat::from_rotation_z(rot),
pos,
);
*/
let pos = Vec3::ZERO;
let object = Mat4::IDENTITY;
let camera = Mat4::look_at_rh(Vec3::new(1.0, 1.0, 2.0), pos, Vec3::Z);
let projec = Mat4::perspective_rh_gl(
PI_2,
f32::conv(self.sc.sc_extent.width)
/ f32::conv(self.sc.sc_extent.height),
0.01,
100_000.0,
) * Mat4::from_cols(Vec4::X, -Vec4::Y, Vec4::Z, Vec4::W);
let uniforms = Uniforms { object, camera, projec };
unsafe {
self.st.buf_write_ref(&self.sc.ufm_bufs[image_index], &uniforms)?;
}
/*
self.st.buf_write_array(
&self.sc.bon_bufs[image_index],
&sc_data.info.model.frame_matrices(
(time_ms / 16 % sc_data.info.model.model().num_frames() as u128)
as usize,
),
)?;
*/
// write command buffer
let framebuffer = self.sc.framebuffers[image_index];
let desc_set = self.sc.desc_sets[image_index];
let cmd_buf = self.sc.cmd_bufs[image_index];
let begin_info = vk::RenderPassBeginInfo {
framebuffer,
render_pass: self.sc.render_pass,
render_area: vk::Rect2D {
extent: self.sc.sc_extent,
..Default::default()
},
clear_value_count: CLEAR_VALUES.len().cast(),
p_clear_values: CLEAR_VALUES.as_ptr(),
..Default::default()
};
unsafe {
self.st.dev.begin_command_buffer(
cmd_buf,
&vk::CommandBufferBeginInfo::default(),
)?;
self.st.dev.cmd_begin_render_pass(
cmd_buf,
&begin_info,
vk::SubpassContents::INLINE,
);
self.st.dev.cmd_bind_pipeline(
cmd_buf,
vk::PipelineBindPoint::GRAPHICS,
self.sc.pipeline,
);
self.st.dev.cmd_bind_descriptor_sets(
cmd_buf,
vk::PipelineBindPoint::GRAPHICS,
self.st.pipe_layout,
0,
&[desc_set],
&[],
);
self.st.dev.cmd_end_render_pass(cmd_buf);
self.st.dev.end_command_buffer(cmd_buf)?;
}
// submit
let wait_stg = vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT;
let submit_info = [vk::SubmitInfo {
wait_semaphore_count: 1,
p_wait_semaphores: &sem_img,
p_wait_dst_stage_mask: &wait_stg,
command_buffer_count: 1,
p_command_buffers: &cmd_buf,
signal_semaphore_count: 1,
p_signal_semaphores: &sem_ren,
..Default::default()
}];
unsafe {
self.st.dev.reset_fences(&[fen_frm])?;
self.st.dev.queue_submit(self.st.queue_gfx, &submit_info, fen_frm)?;
}
// present to swapchain
let image_index_present = image_index.cast();
let present_info = vk::PresentInfoKHR {
wait_semaphore_count: 1,
p_wait_semaphores: &sem_ren,
swapchain_count: 1,
p_swapchains: &self.sc.swapchain,
p_image_indices: &image_index_present,
..Default::default()
};
unsafe {
self.st.swp.queue_present(self.st.queue_srf, &present_info)?;
self.st.dev.queue_wait_idle(self.st.queue_srf)?;
}
Ok(())
}
}
impl SwapchainData {
unsafe fn destroy(&self, st: &StaticData) {
unsafe {
st.seize_device();
st.dev.destroy_descriptor_pool(self.desc_pool, None);
for buf in self.bon_bufs.iter().chain(self.ufm_bufs.iter()) {
buf.destroy(&st.dev);
}
for &fb in self.framebuffers.iter() {
st.dev.destroy_framebuffer(fb, None);
}
st.dev.destroy_pipeline(self.pipeline, None);
st.dev.destroy_render_pass(self.render_pass, None);
self.depth_im.destroy(&st.dev);
for &view in self.sc_img_vw.iter() {
st.dev.destroy_image_view(view, None);
}
st.swp.destroy_swapchain(self.swapchain, None);
}
}
}
// While this is not in fact conformant to specifications, it
// should be OK to only destroy data when successfully
// constructed. In the case of an error the whole program will
// crash anyway.
impl Drop for Renderer {
fn drop(&mut self) {
unsafe {
self.sc.destroy(&self.st);
self.st.destroy();
}
}
}
/// Creates a semaphore.
unsafe fn new_semaphore(
dev: &ash::Device,
) -> Result<vk::Semaphore, vk::Result> {
let create_info = vk::SemaphoreCreateInfo::default();
unsafe { dev.create_semaphore(&create_info, None) }
}
/// Creates a fence.
unsafe fn new_fence(dev: &ash::Device) -> Result<vk::Fence, vk::Result> {
let create_info = vk::FenceCreateInfo {
flags: vk::FenceCreateFlags::SIGNALED,
..Default::default()
};
unsafe { dev.create_fence(&create_info, None) }
}
/// Creates a descriptor set layout.
unsafe fn new_descriptor_set_layout(
dev: &ash::Device,
) -> Result<vk::DescriptorSetLayout, vk::Result> {
let create_info = vk::DescriptorSetLayoutCreateInfo {
binding_count: BIND_DESC.len().cast(),
p_bindings: BIND_DESC.as_ptr(),
..Default::default()
};
unsafe { dev.create_descriptor_set_layout(&create_info, None) }
}
/// Creates a pipeline layout.
unsafe fn new_pipeline_layout(
dev: &ash::Device, layouts: &[vk::DescriptorSetLayout],
) -> Result<vk::PipelineLayout, vk::Result> {
let create_info = vk::PipelineLayoutCreateInfo {
set_layout_count: layouts.len().cast(),
p_set_layouts: layouts.as_ptr(),
..Default::default()
};
unsafe { dev.create_pipeline_layout(&create_info, None) }
}
/// Creates an image view.
unsafe fn new_image_view(
dev: &ash::Device, image: vk::Image, info: &ImageInfo,
) -> Result<vk::ImageView, vk::Result> {
let create_info = vk::ImageViewCreateInfo {
format: info.format,
image,
view_type: info.vw_typ,
components: vk::ComponentMapping {
r: vk::ComponentSwizzle::IDENTITY,
g: vk::ComponentSwizzle::IDENTITY,
b: vk::ComponentSwizzle::IDENTITY,
a: vk::ComponentSwizzle::IDENTITY,
},
subresource_range: vk::ImageSubresourceRange {
aspect_mask: info.aspect,
base_mip_level: 0,
level_count: info.extent.len().cast(),
base_array_layer: 0,
layer_count: 1,
},
..Default::default()
};
unsafe { dev.create_image_view(&create_info, None) }
}
/// Creates a framebuffer.
unsafe fn new_framebuffer(
dev: &ash::Device, render_pass: vk::RenderPass,
attachments: &[vk::ImageView], extent: vk::Extent2D,
) -> Result<vk::Framebuffer, vk::Result> {
let create_info = vk::FramebufferCreateInfo {
render_pass,
attachment_count: attachments.len().cast(),
p_attachments: attachments.as_ptr(),
width: extent.width,
height: extent.height,
layers: 1,
..Default::default()
};
unsafe { dev.create_framebuffer(&create_info, None) }
}
/// Ensures that certain properties are available for a given runtime
/// set of properties.
unsafe fn ensure_properties<T, F>(
props: &[T], names: &[Nts], func: F,
) -> Result<(), Err>
where
F: Fn(&T) -> Nts,
{
for name in names {
unsafe {
let name = CStr::from_ptr(*name);
let any = props.iter().any(|x| CStr::from_ptr(func(x)) == name);
if !any {
return Err(Err::NoProperty(name.to_string_lossy().to_string()));
}
}
}
Ok(())
}
/// Enables extensions for device creation.
unsafe fn enable_device_extensions(
ins: &ash::Instance, physical: vk::PhysicalDevice, extensions: &[Nts],
) -> Result<vk::DeviceCreateInfo, Err> {
if !extensions.is_empty() {
unsafe {
let props = ins.enumerate_device_extension_properties(physical)?;
ensure_properties(&props, extensions, |x| x.extension_name.as_ptr())?;
}
}
Ok(vk::DeviceCreateInfo {
enabled_extension_count: extensions.len().cast(),
pp_enabled_extension_names: extensions.as_ptr(),
..Default::default()
})
}
/// Enables layers for instance creation.
unsafe fn enable_instance_layers(
ent: &ash::Entry, layers: &[Nts],
) -> Result<vk::InstanceCreateInfo, Err> {
if !layers.is_empty() {
unsafe {
let props = ent.enumerate_instance_layer_properties()?;
ensure_properties(&props, layers, |x| x.layer_name.as_ptr())?;
}
}
Ok(vk::InstanceCreateInfo {
enabled_layer_count: layers.len().cast(),
pp_enabled_layer_names: layers.as_ptr(),
..Default::default()
})
}
/// Returns queue family indices for suitable, required queues.
unsafe fn get_qfs(
ins: &ash::Instance, srf: &khr::Surface, surface: vk::SurfaceKHR,
physical: vk::PhysicalDevice,
) -> Result<QueueFamilies, Err> {
let mut q_gfx = None;
let mut q_srf = None;
let queues =
unsafe { ins.get_physical_device_queue_family_properties(physical) };
for (queue, i) in queues.iter().zip(0..queues.len().cast()) {
let surface_support = unsafe {
srf.get_physical_device_surface_support(physical, i, surface)
.unwrap_or(false)
};
if queue.queue_flags.contains(vk::QueueFlags::GRAPHICS) {
q_gfx = Some(i);
}
if surface_support {
q_srf = Some(i);
}
}
Ok(QueueFamilies {
gfx: q_gfx.ok_or(Err::NoGfxQueue)?,
srf: q_srf.ok_or(Err::NoSrfQueue)?,
})
}
struct BufferInfo {
size: vk::DeviceSize,
usage: vk::BufferUsageFlags,
props: vk::MemoryPropertyFlags,
}
#[repr(u32)]
enum BindIden {
Ufm = 0,
Bon,
//Smp,
}
const BIND_DESC: &[vk::DescriptorSetLayoutBinding] = &[
vk::DescriptorSetLayoutBinding {
binding: BindIden::Ufm as u32,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::VERTEX,
p_immutable_samplers: std::ptr::null(),
},
vk::DescriptorSetLayoutBinding {
binding: BindIden::Bon as u32,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::VERTEX,
p_immutable_samplers: std::ptr::null(),
},
/*
vk::DescriptorSetLayoutBinding {
binding: BindIden::Smp as u32,
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::FRAGMENT,
p_immutable_samplers: std::ptr::null(),
},
*/
];
const fn get_desc_pool_sizes(n_sc_imgs: u32) -> [vk::DescriptorPoolSize; 2] {
[
vk::DescriptorPoolSize {
ty: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: n_sc_imgs,
},
vk::DescriptorPoolSize {
ty: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: n_sc_imgs,
},
/*
vk::DescriptorPoolSize {
ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
descriptor_count: n_sc_imgs,
},
*/
]
}
fn get_write_descriptors(
dst_set: vk::DescriptorSet, ufm_buf_info: &vk::DescriptorBufferInfo,
bon_buf_info: &vk::DescriptorBufferInfo, /*smp_img_info: vk::DescriptorImageInfo*/
) -> [vk::WriteDescriptorSet; 2] {
[
vk::WriteDescriptorSet {
dst_set,
dst_binding: BindIden::Ufm as u32,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
p_buffer_info: ufm_buf_info,
..Default::default()
},
vk::WriteDescriptorSet {
dst_set,
dst_binding: BindIden::Bon as u32,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
p_buffer_info: bon_buf_info,
..Default::default()
},
/*
vk::WriteDescriptorSet {
dst_set,
dst_binding: BindIden::Smp as u32,
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
descriptor_count: 1,
p_image_info: smp_img_info,
..Default::default()
},
*/
]
}
const VTX_BIND_DESC: &[vk::VertexInputBindingDescription] =
&[vk::VertexInputBindingDescription {
binding: 0,
stride: size_of::<Vertex>() as u32,
input_rate: vk::VertexInputRate::VERTEX,
}];
const VTX_ATTR_DESC: &[vk::VertexInputAttributeDescription] = &[
vk::VertexInputAttributeDescription {
location: Vertex::FIELDS.pos.indx as u32,
binding: 0,
format: vk::Format::R32G32B32_SFLOAT,
offset: Vertex::FIELDS.pos.offs as u32,
},
vk::VertexInputAttributeDescription {
location: Vertex::FIELDS.tex.indx as u32,
binding: 0,
format: vk::Format::R32G32B32_SFLOAT,
offset: Vertex::FIELDS.tex.offs as u32,
},
vk::VertexInputAttributeDescription {
location: Vertex::FIELDS.nrm.indx as u32,
binding: 0,
format: vk::Format::R32G32B32_SFLOAT,
offset: Vertex::FIELDS.nrm.offs as u32,
},
vk::VertexInputAttributeDescription {
location: Vertex::FIELDS.tan.indx as u32,
binding: 0,
format: vk::Format::R32G32B32A32_SFLOAT,
offset: Vertex::FIELDS.tan.offs as u32,
},
vk::VertexInputAttributeDescription {
location: Vertex::FIELDS.idx.indx as u32,
binding: 0,
format: vk::Format::R32G32B32A32_SFLOAT,
offset: Vertex::FIELDS.idx.offs as u32,
},
vk::VertexInputAttributeDescription {
location: Vertex::FIELDS.wgt.indx as u32,
binding: 0,
format: vk::Format::R32G32B32A32_SFLOAT,
offset: Vertex::FIELDS.wgt.offs as u32,
},
vk::VertexInputAttributeDescription {
location: Vertex::FIELDS.clr.indx as u32,
binding: 0,
format: vk::Format::R32G32B32A32_SFLOAT,
offset: Vertex::FIELDS.clr.offs as u32,
},
];
// EOF