Browse Source

start rewriting the renderer

master
Alison Watson 1 year ago
parent
commit
f03bf5b5ae
  1. 2
      source/framework/conf.rs
  2. 66
      source/framework/hal/win.rs
  3. 6
      source/framework/lib.rs
  4. 833
      source/framework/render.rs
  5. 52
      source/framework/render/descriptor_set_layout.rs
  6. 42
      source/framework/render/misc.rs
  7. 77
      source/main_test/entry.rs

2
source/framework/conf.rs

@ -1,7 +1,7 @@
#[blonkus_ma::serialize_config]
#[derive(Default)]
pub struct Conf {
pub render: crate::render::Conf,
pub render: crate::render::conf::Conf,
}
#[derive(Error, Debug)]

66
source/framework/hal/win.rs

@ -15,8 +15,8 @@ impl<'a> Window<'a> {
pub fn new(
_hal: &'a ctx::Context, title: ffi::Nts, w: i16, h: i16,
) -> Result<Self, Err> {
let handle = unsafe {
sdl::SDL_CreateWindow(
unsafe {
let handle = sdl::SDL_CreateWindow(
title,
sdl::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
sdl::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
@ -25,58 +25,54 @@ impl<'a> Window<'a> {
sdl::SDL_WindowFlags::SDL_WINDOW_SHOWN as u32
| sdl::SDL_WindowFlags::SDL_WINDOW_VULKAN as u32
| sdl::SDL_WindowFlags::SDL_WINDOW_RESIZABLE as u32,
)
};
if !handle.is_null() {
Ok(Self { hal: PhantomData, handle })
} else {
Err(unsafe { Err::new_sdl() })
);
if !handle.is_null() {
Ok(Self { hal: PhantomData, handle })
} else {
Err(Err::new_sdl())
}
}
}
pub fn vulkan_instance_extensions(&self) -> Result<Vec<ffi::Nts>, Err> {
pub unsafe fn vulkan_instance_extensions(
&self,
) -> Result<Vec<ffi::Nts>, Err> {
let mut count = 0;
let res = unsafe {
sdl::SDL_Vulkan_GetInstanceExtensions(
self.handle,
&mut count,
std::ptr::null_mut(),
)
};
let res = sdl::SDL_Vulkan_GetInstanceExtensions(
self.handle,
&mut count,
std::ptr::null_mut(),
);
if res != sdl::SDL_bool::SDL_FALSE {
let mut names = vec![std::ptr::null(); count as usize];
let res = unsafe {
sdl::SDL_Vulkan_GetInstanceExtensions(
self.handle,
&mut count,
names.as_mut_ptr(),
)
};
let res = sdl::SDL_Vulkan_GetInstanceExtensions(
self.handle,
&mut count,
names.as_mut_ptr(),
);
if res != sdl::SDL_bool::SDL_FALSE {
Ok(names)
} else {
Err(unsafe { Err::new_sdl() })
Err(Err::new_sdl())
}
} else {
Err(unsafe { Err::new_sdl() })
Err(Err::new_sdl())
}
}
pub fn vulkan_create_surface(
&self, instance: &crate::render::Instance,
pub unsafe fn vulkan_create_surface(
&self, instance: &ash::Instance,
) -> Result<vk::SurfaceKHR, Err> {
let mut surface = 0;
let res = unsafe {
sdl::SDL_Vulkan_CreateSurface(
self.handle,
(**instance).handle().as_raw() as usize,
&mut surface,
)
};
let res = sdl::SDL_Vulkan_CreateSurface(
self.handle,
instance.handle().as_raw() as usize,
&mut surface,
);
if res != sdl::SDL_bool::SDL_FALSE {
Ok(vk::SurfaceKHR::from_raw(surface))
} else {
Err(unsafe { Err::new_sdl() })
Err(Err::new_sdl())
}
}
}

6
source/framework/lib.rs

@ -14,6 +14,12 @@
#![allow(clippy::type_complexity)]
#![cfg_attr(test, allow(dead_code))]
macro_rules! vec_r {
($exp:expr; $num:expr) => {
(0..$num).map($exp).collect::<Result<Vec<_>, _>>()
};
}
#[macro_use]
pub mod ffi;

833
source/framework/render.rs

@ -1,56 +1,783 @@
mod buffer;
mod cmd;
mod conf;
mod descriptorlayout;
mod descriptorpool;
mod device;
mod fence;
mod framebuffer;
mod image;
mod imageview;
mod instance;
mod model;
mod pipeline;
mod pipelinelayout;
mod properties;
mod queue;
mod renderpass;
mod sampler;
mod semaphore;
mod shader;
mod spir;
mod surface;
mod swapchain;
pub mod misc;
pub use self::{
buffer::Buffer,
cmd::{CommandBuffers, CommandPool},
conf::{Conf, PresentMode},
descriptorlayout::DescriptorSetLayout,
descriptorpool::DescriptorPool,
device::{
Device, ErrAllocMem, ErrDeviceCreate, ErrPhysicalDeviceGet, GetDevice,
PhysicalDevice,
},
fence::Fence,
framebuffer::Framebuffer,
image::{Image, IndepImage, OwnedImage},
imageview::ImageView,
instance::{ErrInstanceCreate, Instance},
model::Model,
pipeline::Pipeline,
pipelinelayout::PipelineLayout,
properties::{ensure_properties, ErrProperty},
queue::{ErrQueueFamilyCollect, Queue, QueueFamilyInfo, QueueIndex},
renderpass::RenderPass,
sampler::Sampler,
semaphore::Semaphore,
shader::ShaderModule,
spir::Spir,
surface::Surface,
swapchain::Swapchain,
mod descriptor_set_layout;
mod misc;
pub mod conf;
pub mod spir;
use self::{conf::Conf, descriptor_set_layout::new_descriptor_set_layout};
use crate::hal::win::Window;
use ash::{
extensions::khr,
version::{DeviceV1_0, EntryV1_0, InstanceV1_0},
vk,
};
use std::{ffi::CStr, sync::Arc};
struct Functions {
ent: ash::Entry,
ins: ash::Instance,
srf: khr::Surface,
dev: ash::Device,
swp: khr::Swapchain,
}
struct StaticData {
fns: Arc<Functions>,
surface: vk::SurfaceKHR,
physical: vk::PhysicalDevice,
qf: QueueFamilies,
queue_gfx: vk::Queue,
queue_srf: vk::Queue,
cmd_pool: vk::CommandPool,
sem_img: Vec<vk::Semaphore>,
sem_ren: Vec<vk::Semaphore>,
fen_frm: Vec<vk::Fence>,
desc_layout: vk::DescriptorSetLayout,
pipe_layout: vk::PipelineLayout,
}
struct SwapchainData {
fns: Arc<Functions>,
swapchain: vk::SwapchainKHR,
sc_images: Vec<vk::Image>,
sc_img_in: ImageInfo,
sc_img_vw: Vec<vk::ImageView>,
sc_img_fn: Vec<Option<vk::Fence>>,
depth_im: Texture,
}
struct ImageInfo {
extent: Vec<vk::Extent3D>,
im_typ: vk::ImageType,
vw_typ: vk::ImageViewType,
aspect: vk::ImageAspectFlags,
format: vk::Format,
use_fl: vk::ImageUsageFlags,
}
struct QueueFamilies {
gfx: u32,
srf: u32,
}
pub struct Texture {
fns: Arc<Functions>,
imag: vk::Image,
dmem: vk::DeviceMemory,
info: ImageInfo,
view: vk::ImageView,
}
pub struct Renderer {
st: StaticData,
sc: SwapchainData,
}
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ErrRenderer {
// 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),
}
impl StaticData {
unsafe fn new(window: &Window, conf: &Conf) -> Result<Self, ErrRenderer> {
let ent = 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 = Vec::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() as u32,
pp_enabled_extension_names: extensions.as_ptr(),
..enable_instance_layers(&ent, &layers)?
};
let ins = 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 = ins.enumerate_physical_devices()?;
*devices.get(conf.device).ok_or(ErrRenderer::NoDevice)?
};
// set up queues
let qf = get_qfs(&ins, &srf, surface, physical)?;
const QUEUE_PRIORITY: [f32; 1] = [1.0];
let queue_create_info = [
vk::DeviceQueueCreateInfo {
queue_family_index: qf.gfx,
queue_count: 1,
p_queue_priorities: QUEUE_PRIORITY.as_ptr(),
..Default::default()
},
vk::DeviceQueueCreateInfo {
queue_family_index: qf.srf,
queue_count: 1,
p_queue_priorities: QUEUE_PRIORITY.as_ptr(),
..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() as u32,
p_queue_create_infos: queue_create_info.as_ptr(),
p_enabled_features: &device_features,
..enable_device_extensions(&ins, physical, &extensions)?
};
let dev = ins.create_device(physical, &create_info, None)?;
let swp = khr::Swapchain::new(&ins, &dev);
// get the queues
let queue_gfx = dev.get_device_queue(qf.gfx, 0);
let queue_srf = dev.get_device_queue(qf.srf, 0);
// create the command pool
let create_info = vk::CommandPoolCreateInfo {
queue_family_index: qf.gfx,
..Default::default()
};
let cmd_pool = dev.create_command_pool(&create_info, None)?;
// create frame semaphores
let concur_frames = conf.concurrent_frames.get();
let sem_img = vec_r![|_| new_semaphore(&dev); concur_frames]?;
let sem_ren = vec_r![|_| new_semaphore(&dev); concur_frames]?;
let fen_frm = vec_r![|_| new_fence(&dev); concur_frames]?;
let desc_layout = new_descriptor_set_layout(&dev)?;
let pipe_layout = new_pipeline_layout(&dev, &[desc_layout])?;
Ok(Self {
fns: Arc::new(Functions { ent, ins, srf, dev, swp }),
surface,
physical,
qf,
queue_gfx,
queue_srf,
cmd_pool,
sem_img,
sem_ren,
fen_frm,
desc_layout,
pipe_layout,
})
}
unsafe fn seize_device(&self) {
if let Err(e) = self.fns.dev.device_wait_idle() {
eprintln!("Error seizing renderer state: {}", e);
}
}
unsafe fn alloc_mem(
&self, memory_reqs: vk::MemoryRequirements,
memory_flags: vk::MemoryPropertyFlags,
) -> Result<vk::DeviceMemory, ErrRenderer> {
let memory_props =
self.fns.ins.get_physical_device_memory_properties(self.physical);
let memory_type_index = get_memory_type(
memory_props,
memory_flags,
memory_reqs.memory_type_bits,
)?;
let allocate_info = vk::MemoryAllocateInfo {
memory_type_index,
allocation_size: memory_reqs.size,
..Default::default()
};
Ok(self.fns.dev.allocate_memory(&allocate_info, None)?)
}
unsafe fn transient_buffer<F>(&self, f: F) -> Result<(), vk::Result>
where
F: FnOnce(vk::CommandBuffer) -> Result<(), vk::Result>,
{
let create_info = vk::CommandBufferAllocateInfo {
command_pool: self.cmd_pool,
level: vk::CommandBufferLevel::PRIMARY,
command_buffer_count: 1,
..Default::default()
};
let handles = self.fns.dev.allocate_command_buffers(&create_info)?;
let begin_info = vk::CommandBufferBeginInfo {
flags: vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT,
..Default::default()
};
self.fns.dev.begin_command_buffer(handles[0], &begin_info)?;
f(handles[0])?;
self.fns.dev.end_command_buffer(handles[0])?;
let submit_info = [vk::SubmitInfo {
command_buffer_count: handles.len() as u32,
p_command_buffers: handles.as_ptr(),
..Default::default()
}];
self.fns.dev.queue_submit(
self.queue_gfx,
&submit_info,
vk::Fence::null(),
)?;
self.fns.dev.queue_wait_idle(self.queue_gfx)?;
self.fns.dev.free_command_buffers(self.cmd_pool, &handles);
Ok(())
}
}
impl SwapchainData {
unsafe fn new(st: &StaticData, conf: &Conf) -> Result<Self, ErrRenderer> {
let fns = st.fns.clone();
let capabilities = fns
.srf
.get_physical_device_surface_capabilities(st.physical, st.surface)?;
let formats = fns
.srf
.get_physical_device_surface_formats(st.physical, st.surface)?;
let modes = fns
.srf
.get_physical_device_surface_present_modes(st.physical, st.surface)?;
let 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_else(|| &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
};
let queue_family_indices = [st.qf.gfx, st.qf.srf];
let create_info = vk::SwapchainCreateInfoKHR {
min_image_count,
present_mode: mode,
image_extent: extent,
surface: st.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 st.qf.gfx != st.qf.srf {
vk::SharingMode::CONCURRENT
} else {
vk::SharingMode::EXCLUSIVE
},
queue_family_index_count: queue_family_indices.len() as u32,
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 = fns.swp.create_swapchain(&create_info, None)?;
let sc_images = fns.swp.get_swapchain_images(swapchain)?;
let sc_img_in = ImageInfo {
extent: vec![vk::Extent3D {
width: extent.width,
height: 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_img_vw = vec_r![
|i| new_image_view(&fns.dev, sc_images[i], &sc_img_in);
sc_images.len()
]?;
let sc_img_fn = vec![None; sc_images.len()];
let depth_im = Texture::create_depth_raw(st, extent)?;
Ok(Self {
fns,
swapchain,
sc_images,
sc_img_in,
sc_img_vw,
sc_img_fn,
depth_im,
})
}
}
impl Texture {
unsafe fn create_depth_raw(
st: &StaticData, extent: vk::Extent2D,
) -> Result<Self, ErrRenderer> {
let fns = st.fns.clone();
let info = ImageInfo {
extent: vec![vk::Extent3D {
width: extent.width,
height: extent.height,
depth: 1,
}],
im_typ: vk::ImageType::TYPE_2D,
vw_typ: vk::ImageViewType::TYPE_2D,
aspect: vk::ImageAspectFlags::DEPTH | vk::ImageAspectFlags::STENCIL,
format: vk::Format::D32_SFLOAT_S8_UINT,
use_fl: vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT,
};
let imag = new_image(&fns.dev, &info)?;
let dmem = st.alloc_mem(
fns.dev.get_image_memory_requirements(imag),
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?;
let view = new_image_view(&fns.dev, imag, &info)?;
let tex = Self { fns, imag, dmem, info, view };
tex.fns.dev.bind_image_memory(imag, dmem, 0)?;
tex.layout_barrier(st, &BARRIER_DPTH)?;
Ok(tex)
}
unsafe fn layout_barrier(
&self, st: &StaticData, barrier_info: &BarrierInfo,
) -> Result<(), vk::Result> {
let barrier = vk::ImageMemoryBarrier {
src_access_mask: barrier_info.src_access_mask,
dst_access_mask: barrier_info.dst_access_mask,
old_layout: barrier_info.old_layout,
new_layout: barrier_info.new_layout,
src_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED,
image: self.imag,
subresource_range: vk::ImageSubresourceRange {
aspect_mask: self.info.aspect,
base_mip_level: 0,
level_count: self.info.extent.len() as u32,
base_array_layer: 0,
layer_count: 1,
},
..Default::default()
};
st.transient_buffer(|cbuf| {
st.fns.dev.cmd_pipeline_barrier(
cbuf,
barrier_info.src_stage,
barrier_info.dst_stage,
vk::DependencyFlags::empty(),
&[],
&[],
&[barrier],
);
Ok(())
})
}
}
impl Renderer {
pub fn new(window: &Window, conf: &Conf) -> Result<Self, ErrRenderer> {
unsafe {
let st = StaticData::new(window, conf)?;
let sc = SwapchainData::new(&st, conf)?;
Ok(Self { st, sc })
}
}
}
// 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 StaticData {
fn drop(&mut self) {
unsafe {
self.seize_device();
self.fns.dev.destroy_pipeline_layout(self.pipe_layout, None);
self.fns.dev.destroy_descriptor_set_layout(self.desc_layout, None);
for &fen in &self.fen_frm {
self.fns.dev.destroy_fence(fen, None);
}
for &sem in &self.sem_ren {
self.fns.dev.destroy_semaphore(sem, None);
}
for &sem in &self.sem_img {
self.fns.dev.destroy_semaphore(sem, None);
}
self.fns.dev.destroy_command_pool(self.cmd_pool, None);
self.fns.dev.destroy_device(None);
self.fns.srf.destroy_surface(self.surface, None);
self.fns.ins.destroy_instance(None);
}
}
}
impl Drop for SwapchainData {
fn drop(&mut self) {
unsafe {
self.fns.swp.destroy_swapchain(self.swapchain, None);
for &view in &self.sc_img_vw {
self.fns.dev.destroy_image_view(view, None);
}
for &fen in &self.sc_img_fn {
if let Some(fen) = fen {
self.fns.dev.destroy_fence(fen, None);
}
}
}
}
}
impl Drop for Texture {
fn drop(&mut self) {
unsafe {
self.fns.dev.destroy_image(self.imag, None);
self.fns.dev.free_memory(self.dmem, None);
}
}
}
fn get_memory_type(
memory_props: vk::PhysicalDeviceMemoryProperties,
filter_flags: vk::MemoryPropertyFlags, filter_types: u32,
) -> Result<u32, ErrRenderer> {
let count = memory_props.memory_type_count as usize;
let iter = memory_props.memory_types.iter().take(count).enumerate();
for (i, memory_type) in iter {
let has_flags = memory_type.property_flags.contains(filter_flags);
let has_types = filter_types & 1 << i;
if has_flags && has_types != 0 {
return Ok(i as u32);
}
}
Err(ErrRenderer::NoMemoryType(filter_flags, filter_types))
}
/// Creates a semaphore.
unsafe fn new_semaphore(
dev: &ash::Device,
) -> Result<vk::Semaphore, vk::Result> {
let create_info = vk::SemaphoreCreateInfo::default();
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()
};
dev.create_fence(&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() as u32,
p_set_layouts: layouts.as_ptr(),
..Default::default()
};
dev.create_pipeline_layout(&create_info, None)
}
/// Creates an image.
unsafe fn new_image(
dev: &ash::Device, info: &ImageInfo,
) -> Result<vk::Image, vk::Result> {
let create_info = vk::ImageCreateInfo {
image_type: info.im_typ,
format: info.format,
extent: info.extent[0],
mip_levels: info.extent.len() as u32,
array_layers: 1,
samples: vk::SampleCountFlags::TYPE_1,
tiling: vk::ImageTiling::OPTIMAL,
usage: info.use_fl,
sharing_mode: vk::SharingMode::EXCLUSIVE,
initial_layout: vk::ImageLayout::UNDEFINED,
..Default::default()
};
dev.create_image(&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() as u32,
base_array_layer: 0,
layer_count: 1,
},
..Default::default()
};
dev.create_image_view(&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: &[crate::ffi::Nts], func: F,
) -> Result<(), ErrRenderer>
where
F: Fn(&T) -> crate::ffi::Nts,
{
for name in names {
let name = CStr::from_ptr(*name);
let any = props.iter().any(|x| CStr::from_ptr(func(x)) == name);
if !any {
return Err(ErrRenderer::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: &[crate::ffi::Nts],
) -> Result<vk::DeviceCreateInfo, ErrRenderer> {
if !extensions.is_empty() {
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() as u32,
pp_enabled_extension_names: extensions.as_ptr(),
..Default::default()
})
}
/// Enables layers for instance creation.
unsafe fn enable_instance_layers(
ent: &ash::Entry, layers: &[crate::ffi::Nts],
) -> Result<vk::InstanceCreateInfo, ErrRenderer> {
if !layers.is_empty() {
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() as u32,
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, ErrRenderer> {
let mut q_gfx = None;
let mut q_srf = None;
let queues = ins.get_physical_device_queue_family_properties(physical);
for (i, queue) in queues.iter().enumerate() {
let i = i as u32;
let surface_support = 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(ErrRenderer::NoGfxQueue)?,
srf: q_srf.ok_or(ErrRenderer::NoSrfQueue)?,
})
}
struct BarrierInfo {
src_access_mask: vk::AccessFlags,
dst_access_mask: vk::AccessFlags,
old_layout: vk::ImageLayout,
new_layout: vk::ImageLayout,
src_stage: vk::PipelineStageFlags,
dst_stage: vk::PipelineStageFlags,
}
const BARRIER_XFER: BarrierInfo = BarrierInfo {
src_access_mask: vk::AccessFlags::empty(),
dst_access_mask: vk::AccessFlags::TRANSFER_WRITE,
old_layout: vk::ImageLayout::UNDEFINED,
new_layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
src_stage: vk::PipelineStageFlags::TOP_OF_PIPE,
dst_stage: vk::PipelineStageFlags::TRANSFER,
};
const BARRIER_DPTH: BarrierInfo = BarrierInfo {
src_access_mask: vk::AccessFlags::empty(),
dst_access_mask: vk::AccessFlags::from_raw(
vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ.as_raw()
| vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE.as_raw(),
),
old_layout: vk::ImageLayout::UNDEFINED,
new_layout: vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
src_stage: vk::PipelineStageFlags::TOP_OF_PIPE,
dst_stage: vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS,
};
const BARRIER_FRAG: BarrierInfo = BarrierInfo {
src_access_mask: vk::AccessFlags::TRANSFER_WRITE,
dst_access_mask: vk::AccessFlags::SHADER_READ,
old_layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
new_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
src_stage: vk::PipelineStageFlags::TRANSFER,
dst_stage: vk::PipelineStageFlags::FRAGMENT_SHADER,
};
// EOF

52
source/framework/render/descriptor_set_layout.rs

@ -0,0 +1,52 @@
use crate::{data::uniforms::Uniforms, math::Mat4};
use ash::{version::DeviceV1_0, vk};
use std::mem::size_of;
pub(super) const UFM_BIND_SIZE: vk::DeviceSize = size_of::<Uniforms>() as _;
pub(super) const BON_BIND_SIZE: vk::DeviceSize = size_of::<[Mat4; 128]>() as _;
#[repr(u32)]
enum BindIden {
Ufm,
Bon,
Smp,
}
const BIND_DESC: [vk::DescriptorSetLayoutBinding; 3] = [
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(),
},
];
/// Creates a descriptor set layout.
pub(super) unsafe fn new_descriptor_set_layout(
dev: &ash::Device,
) -> Result<vk::DescriptorSetLayout, vk::Result> {
let create_info = vk::DescriptorSetLayoutCreateInfo {
binding_count: BIND_DESC.len() as u32,
p_bindings: BIND_DESC.as_ptr(),
..Default::default()
};
dev.create_descriptor_set_layout(&create_info, None)
}
// EOF

42
source/framework/render/misc.rs

@ -1,54 +1,20 @@
use crate::{
data::{uniforms::Uniforms, vertex::Vertex},
math::Mat4,
};
use crate::data::vertex::Vertex;
use ash::vk;
use std::mem::size_of;
/// Returns the size of `data` as a `vk::DeviceSize`.
pub const fn dev_size_of<T>(data: &[T]) -> ash::vk::DeviceSize {
pub(super) const fn dev_size_of<T>(data: &[T]) -> ash::vk::DeviceSize {
(size_of::<T>() * data.len()) as ash::vk::DeviceSize
}
pub const UFM_BIND_SIZE: vk::DeviceSize = size_of::<Uniforms>() as _;
pub const BON_BIND_SIZE: vk::DeviceSize = size_of::<[Mat4; 128]>() as _;
pub const UFM_BIND_IDEN: u32 = 0;
pub const BON_BIND_IDEN: u32 = 1;
pub const SMP_BIND_IDEN: u32 = 2;
pub const DSC_BIND_DESC: [vk::DescriptorSetLayoutBinding; 3] = [
vk::DescriptorSetLayoutBinding {
binding: UFM_BIND_IDEN,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::VERTEX,
p_immutable_samplers: std::ptr::null(),
},
vk::DescriptorSetLayoutBinding {
binding: BON_BIND_IDEN,
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::VERTEX,
p_immutable_samplers: std::ptr::null(),
},
vk::DescriptorSetLayoutBinding {
binding: SMP_BIND_IDEN,
descriptor_type: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
descriptor_count: 1,
stage_flags: vk::ShaderStageFlags::FRAGMENT,
p_immutable_samplers: std::ptr::null(),
},
];
pub const VTX_BIND_DESC: [vk::VertexInputBindingDescription; 1] =
pub(super) const VTX_BIND_DESC: [vk::VertexInputBindingDescription; 1] =
[vk::VertexInputBindingDescription {
binding: 0,
stride: size_of::<Vertex>() as u32,
input_rate: vk::VertexInputRate::VERTEX,
}];
pub const VTX_ATTR_DESC: [vk::VertexInputAttributeDescription; 7] = [
pub(super) const VTX_ATTR_DESC: [vk::VertexInputAttributeDescription; 7] = [
vk::VertexInputAttributeDescription {
location: 0,
binding: 0,

77
source/main_test/entry.rs

@ -8,18 +8,11 @@ use blonkus_fw::{
data::{self, vfs},
hal,
math::*,
meta,
render::{
self, misc, Buffer, CommandBuffers, CommandPool, DescriptorPool,
DescriptorSetLayout, Device, ErrAllocMem, Fence, Framebuffer, GetDevice,
Image, ImageView, IndepImage, Instance, Model, PhysicalDevice, Pipeline,
PipelineLayout, Queue, QueueFamilyInfo, RenderPass, Sampler, Semaphore,
ShaderModule, Spir, Surface, Swapchain,
},
vire,
meta, vire,
};
use std::{io::Cursor, rc::Rc};
/*
struct SwapchainInfo<'a> {
device: Rc<Device>,
cmd_pool: Rc<CommandPool>,
@ -58,29 +51,6 @@ impl GetDevice for SwapchainData<'_, '_> {
impl<'a> SwapchainData<'a, '_> {
fn create(sc_info: SwapchainInfo<'a>) -> Result<Self, ErrAllocMem> {
let device = sc_info.get_device();
let swapchain = Swapchain::create(
sc_info.queue_graphics.clone(),
sc_info.queue_surface.clone(),
sc_info.surface.clone(),
sc_info.conf,
)?;
let images = Swapchain::get_images(swapchain.clone())?;
let image_f = vec![None; images.len()];
let image_views = ImageView::create_all(&images)?;
let depth_buffer = Image::from_indep(IndepImage::create_depth(
&sc_info.cmd_pool,
swapchain.extent.width,
swapchain.extent.height,
)?);
let depth_view = ImageView::create(depth_buffer.clone())?;
let render_pass = RenderPass::create(
device.clone(),
swapchain.format,
@ -327,13 +297,7 @@ fn draw_frame<'b>(
Ok(())
}
fn seize_device(device: &Device) {
let seize = unsafe { device.device_wait_idle() };
if let Err(e) = seize {
eprintln!("Error seizing renderer state: {}", e);
}
}
*/
pub fn run(conf: &conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
let start_time = std::time::Instant::now();
@ -356,27 +320,10 @@ pub fn run(conf: &conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
ctx.execute()?;
*/
let concur_frames = conf.render.concurrent_frames.into();
let hal = hal::ctx::Context::new()?;
let window = hal::win::Window::new(&hal, meta::ffi::NAME, 640, 480)?;
let entry = unsafe { ash::Entry::new()? };
let instance = Instance::create(&conf.render, entry, &window)?;
let physical = PhysicalDevice::get(instance.clone(), &conf.render)?;
let surface = Surface::create(instance, &window)?;
let qf_info = QueueFamilyInfo::collect(&physical, &surface)?;
let device = Device::create(physical, &qf_info)?;
let queue_graphics = Queue::get(device.clone(), qf_info.gfx_index);
let queue_surface = Queue::get(device.clone(), qf_info.srf_index);
let cmd_pool = CommandPool::create(queue_graphics.clone())?;
/*
let img = {
let arc = vfs::Arc::read_tar(
&mut vfs.get("scientist/hltex000.texture")?.data(),
@ -394,14 +341,6 @@ pub fn run(conf: &conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
))?;
let model = Model::create(&cmd_pool, model.0, model.1)?;
let image_avail_s = Semaphore::create_all(device.clone(), concur_frames)?;
let render_fini_s = Semaphore::create_all(device.clone(), concur_frames)?;
let frame_f = Fence::create_all(device.clone(), concur_frames)?;
let desc_layout = DescriptorSetLayout::create(device.clone())?;
let layout = PipelineLayout::create(desc_layout)?;
let spir_vert = Spir::read(MAIN_VERT);
let spir_frag = Spir::read(MAIN_FRAG);
@ -426,6 +365,7 @@ pub fn run(conf: &conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
let mut sc_data = SwapchainData::create(sc_info)?;
let mut cur_c_frame = 0;
*/
'main_loop: loop {
// FIXME: can remove allow once this has more events
@ -436,6 +376,7 @@ pub fn run(conf: &conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
}
}
/*
let frame = draw_frame(
&mut sc_data,
&image_avail_s[cur_c_frame],
@ -456,14 +397,10 @@ pub fn run(conf: &conf::Conf) -> Result<(), Box<dyn std::error::Error>> {
}
cur_c_frame = (cur_c_frame + 1) % concur_frames;
*/
}
seize_device(sc_data.get_device());
Ok(())
}
const MAIN_VERT: &[u8] = include_bytes!(concat!("../../glsl/main.vert.o"));
const MAIN_FRAG: &[u8] = include_bytes!(concat!("../../glsl/main.frag.o"));
// EOF

Loading…
Cancel
Save