From f7e6a92018647df4681e2563cbaeaa4d52e2ef54 Mon Sep 17 00:00:00 2001 From: Janis Date: Sun, 22 Dec 2024 02:02:27 +0100 Subject: [PATCH] command buffer abstraction, images/buffers start --- crates/renderer/src/buffers.rs | 88 ++++++++++ crates/renderer/src/commands.rs | 110 +++++++++++-- crates/renderer/src/images.rs | 25 ++- crates/renderer/src/lib.rs | 47 +++--- crates/renderer/src/render_graph.rs | 40 ++++- crates/renderer/src/util.rs | 241 ++++++++++++++++++++++++++++ 6 files changed, 516 insertions(+), 35 deletions(-) create mode 100644 crates/renderer/src/buffers.rs create mode 100644 crates/renderer/src/util.rs diff --git a/crates/renderer/src/buffers.rs b/crates/renderer/src/buffers.rs new file mode 100644 index 0000000..0e3e977 --- /dev/null +++ b/crates/renderer/src/buffers.rs @@ -0,0 +1,88 @@ +use std::{ops::Deref, sync::Arc}; + +use ash::{prelude::VkResult, vk}; +use vk_mem::Alloc; + +use crate::Device; + +pub struct Buffer { + device: Device, + buffer: vk::Buffer, + allocation: vk_mem::Allocation, + usage: vk::BufferUsageFlags, + size: u64, +} + +impl Drop for Buffer { + fn drop(&mut self) { + unsafe { + self.device + .alloc() + .destroy_buffer(self.buffer, &mut self.allocation); + } + } +} + +impl Buffer { + pub fn new( + device: Device, + size: usize, + usage: vk::BufferUsageFlags, + queue_families: &[u32], + memory_usage: vk_mem::MemoryUsage, + alloc_flags: vk_mem::AllocationCreateFlags, + ) -> VkResult> { + let sharing_mode = if queue_families.len() > 1 { + vk::SharingMode::EXCLUSIVE + } else { + vk::SharingMode::CONCURRENT + }; + + let (buffer, allocation) = unsafe { + device.alloc().create_buffer( + &vk::BufferCreateInfo::default() + .usage(usage) + .queue_family_indices(queue_families) + .sharing_mode(sharing_mode), + &vk_mem::AllocationCreateInfo { + flags: alloc_flags, + usage: memory_usage, + ..Default::default() + }, + )? + }; + + let buffer = Self { + device, + buffer, + allocation, + usage, + size: size as u64, + }; + + Ok(Arc::new(buffer)) + } + + pub fn map(&mut self) -> VkResult> { + let bytes = unsafe { + let data = self.device.alloc().map_memory(&mut self.allocation)?; + let slice = core::slice::from_raw_parts(data, self.size as usize); + + slice + }; + + Ok(MappedBuffer { bytes }) + } +} + +pub struct MappedBuffer<'a> { + bytes: &'a [u8], +} + +impl Deref for MappedBuffer<'_> { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.bytes + } +} diff --git a/crates/renderer/src/commands.rs b/crates/renderer/src/commands.rs index a828988..819a271 100644 --- a/crates/renderer/src/commands.rs +++ b/crates/renderer/src/commands.rs @@ -1,20 +1,28 @@ use std::{future::Future, marker::PhantomData, sync::Arc}; -use crate::sync::{self, FenceFuture}; +use crate::{ + buffers::Buffer, + images::{Image2D, QueueOwnership}, + sync::{self, FenceFuture}, + util::{FormatExt, MutexExt}, +}; use super::{Device, Queue}; use ash::{prelude::*, vk}; +use parking_lot::Mutex; pub struct SingleUseCommandPool { device: Device, - pool: vk::CommandPool, + pool: Mutex, queue: Queue, } impl Drop for SingleUseCommandPool { fn drop(&mut self) { unsafe { - self.device.dev().destroy_command_pool(self.pool, None); + self.pool.with_locked(|&pool| { + self.device.dev().destroy_command_pool(pool, None); + }); } } } @@ -30,7 +38,7 @@ impl SingleUseCommandPool { Ok(Arc::new(Self { device, - pool, + pool: Mutex::new(pool), queue, })) } @@ -43,8 +51,9 @@ impl SingleUseCommandPool { &self.queue } - pub fn pool(&self) -> vk::CommandPool { - self.pool + /// get the underlying pool, bypassing the mutex + pub unsafe fn pool(&self) -> vk::CommandPool { + self.pool.data_ptr().read() } } @@ -54,12 +63,14 @@ pub struct SingleUseCommand { buffer: vk::CommandBuffer, } +impl !Sync for SingleUseCommand {} + impl Drop for SingleUseCommand { fn drop(&mut self) { unsafe { - self.device - .dev() - .free_command_buffers(self.pool.pool(), &[self.buffer]) + self.pool.pool.with_locked(|&pool| { + self.device.dev().free_command_buffers(pool, &[self.buffer]) + }) }; } } @@ -91,10 +102,89 @@ impl SingleUseCommand { }) } - pub fn buffer(&self) -> vk::CommandBuffer { + /// Safety: commandbuffer must not be accessed from multiple threads at the same time + pub unsafe fn buffer(&self) -> vk::CommandBuffer { self.buffer } + //pub fn copy_buffer_to_image(&self, image: &Image2D, buffer: &Buffer, ) + + pub fn image_barrier( + &self, + image: vk::Image, + aspects: vk::ImageAspectFlags, + src_stage: vk::PipelineStageFlags2, + src_access: vk::AccessFlags2, + dst_stage: vk::PipelineStageFlags2, + dst_access: vk::AccessFlags2, + old_layout: vk::ImageLayout, + new_layout: vk::ImageLayout, + queue_ownership_op: Option, + ) { + let (src_family, dst_family) = queue_ownership_op + .map(|t| (t.src, t.dst)) + .unwrap_or((vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED)); + + let barrier = vk::ImageMemoryBarrier2::default() + .image(image) + .subresource_range( + vk::ImageSubresourceRange::default() + .aspect_mask(aspects) + .base_mip_level(0) + .base_array_layer(0) + .level_count(vk::REMAINING_MIP_LEVELS) + .layer_count(vk::REMAINING_ARRAY_LAYERS), + ) + .src_stage_mask(src_stage) + .src_access_mask(src_access) + .dst_stage_mask(dst_stage) + .dst_access_mask(dst_access) + .dst_queue_family_index(dst_family) + .src_queue_family_index(src_family) + .old_layout(old_layout) + .new_layout(new_layout); + + unsafe { + self.device.dev().cmd_pipeline_barrier2( + self.buffer, + &vk::DependencyInfo::default() + .dependency_flags(vk::DependencyFlags::BY_REGION) + .image_memory_barriers(core::slice::from_ref(&barrier)), + ); + } + } + + pub fn clear_color_image( + &self, + image: vk::Image, + format: vk::Format, + layout: vk::ImageLayout, + color: crate::Rgba, + subresources: &[vk::ImageSubresourceRange], + ) { + let clear_colors = match format.get_component_kind() { + crate::util::FormatComponentKind::Float => vk::ClearColorValue { + float32: color.into_f32(), + }, + crate::util::FormatComponentKind::UInt => vk::ClearColorValue { + uint32: color.into_u32(), + }, + crate::util::FormatComponentKind::SInt => vk::ClearColorValue { + int32: color.into_i32(), + }, + }; + + unsafe { + self.device.dev().cmd_clear_color_image( + self.buffer, + image, + layout, + &clear_colors, + subresources, + ); + } + } + pub fn submit_fence( &self, wait: Option<(vk::Semaphore, vk::PipelineStageFlags)>, diff --git a/crates/renderer/src/images.rs b/crates/renderer/src/images.rs index 1182ae1..d50c37d 100644 --- a/crates/renderer/src/images.rs +++ b/crates/renderer/src/images.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use crate::buffers::Buffer; + use super::{Device, Queue}; use ash::{prelude::*, vk}; use vk_mem::Alloc; @@ -70,6 +72,16 @@ impl Image2D { })) } + pub fn format(&self) -> vk::Format { + self.format + } + + pub fn copy_from_buffer(&self, buffer: &Buffer) { + unsafe { + // self.device.dev().cmd_copy_buffer_to_image(command_buffer, src_buffer, dst_image, dst_image_layout, regions); + } + } + pub fn view( self: &Arc, device: &Device, @@ -121,8 +133,8 @@ impl Drop for ImageView2D { impl ImageView2D {} pub struct QueueOwnership { - src: u32, - dst: u32, + pub src: u32, + pub dst: u32, } pub fn image_barrier<'a>( @@ -159,3 +171,12 @@ pub fn image_barrier<'a>( .old_layout(old_layout) .new_layout(new_layout) } + +pub const SUBRESOURCERANGE_COLOR_ALL: vk::ImageSubresourceRange = + vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: vk::REMAINING_MIP_LEVELS, + base_array_layer: 0, + layer_count: vk::REMAINING_ARRAY_LAYERS, + }; diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index 1cf1afc..186171b 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -33,11 +33,14 @@ use raw_window_handle::{DisplayHandle, RawDisplayHandle}; use tinyvec::{array_vec, ArrayVec}; use tracing::info; +mod buffers; mod commands; mod images; mod render_graph; - mod sync; +mod util; + +use render_graph::Rgba; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -720,6 +723,7 @@ pub struct SwapchainFrame { pub swapchain: Arc, pub index: u32, pub image: vk::Image, + pub format: vk::Format, pub view: vk::ImageView, pub acquire: vk::Semaphore, pub release: vk::Semaphore, @@ -1042,6 +1046,7 @@ impl Swapchain { SwapchainFrame { index: idx as u32, swapchain: self.clone(), + format: self.format, image, view, acquire, @@ -2043,7 +2048,6 @@ impl Renderer { if let Some(ctx) = self.window_contexts.get(window) { let cmd = pool.alloc()?; - let buffer = cmd.buffer(); let (frame, suboptimal) = smol::block_on( ctx.current_swapchain.read().clone().acquire_image(), @@ -2074,6 +2078,7 @@ impl Renderer { ctx.surface.surface.as_raw(), ) .gen::<[f32; 3]>(); + let clear_color = Rgba([r, g, b, 1.0]); let clear_values = vk::ClearColorValue { float32: [r, g, b, 1.0], }; @@ -2095,21 +2100,25 @@ impl Renderer { .dependency_flags(vk::DependencyFlags::BY_REGION) .image_memory_barriers(&barriers); - dev.dev().cmd_pipeline_barrier2(buffer, &dependency_info); - dev.dev().cmd_clear_color_image( - buffer, + cmd.image_barrier( frame.image, + vk::ImageAspectFlags::COLOR, + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::empty(), + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::TRANSFER_WRITE, + vk::ImageLayout::UNDEFINED, vk::ImageLayout::TRANSFER_DST_OPTIMAL, - &clear_values, - &[vk::ImageSubresourceRange::default() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .base_mip_level(0) - .base_array_layer(0) - .level_count(vk::REMAINING_MIP_LEVELS) - .layer_count(vk::REMAINING_ARRAY_LAYERS)], + None, ); - - let barriers = [images::image_barrier( + cmd.clear_color_image( + frame.image, + frame.format, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + clear_color, + &[images::SUBRESOURCERANGE_COLOR_ALL], + ); + cmd.image_barrier( frame.image, vk::ImageAspectFlags::COLOR, vk::PipelineStageFlags2::TRANSFER, @@ -2119,16 +2128,10 @@ impl Renderer { vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::PRESENT_SRC_KHR, None, - )]; - - let dependency_info = vk::DependencyInfo::default() - .dependency_flags(vk::DependencyFlags::BY_REGION) - .image_memory_barriers(&barriers); - - dev.dev().cmd_pipeline_barrier2(buffer, &dependency_info); + ); let future = cmd.submit_async( - Some((frame.acquire, vk::PipelineStageFlags::ALL_COMMANDS)), + Some((frame.acquire, vk::PipelineStageFlags::TRANSFER)), Some(frame.release), Arc::new(sync::Fence::create(dev.clone())?), )?; diff --git a/crates/renderer/src/render_graph.rs b/crates/renderer/src/render_graph.rs index f48d7c8..b70db29 100644 --- a/crates/renderer/src/render_graph.rs +++ b/crates/renderer/src/render_graph.rs @@ -1,6 +1,44 @@ +use std::hash::Hash; + use ash::vk; -struct Rgba([f32; 4]); +#[derive(Debug, Clone, Copy)] +pub struct Rgba(pub [f32; 4]); + +impl std::hash::Hash for Rgba { + fn hash(&self, state: &mut H) { + fn hash_f32(state: &mut H, f: f32) { + let classify = f.classify(); + match classify { + std::num::FpCategory::Nan => (classify as u8).hash(state), + std::num::FpCategory::Infinite | std::num::FpCategory::Zero => { + (classify as u8, f.signum() as i8).hash(state) + } + std::num::FpCategory::Subnormal + | std::num::FpCategory::Normal => f.to_bits().hash(state), + } + } + self.0.map(|f| hash_f32(state, f)); + } +} + +impl Rgba { + pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self { + Self([r, g, b, a]) + } + pub fn into_u32(&self) -> [u32; 4] { + self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as u32) + } + pub fn into_f32(&self) -> [f32; 4] { + self.0 + } + pub fn into_snorm(&self) -> [f32; 4] { + self.0.map(|f| (f - 0.5) * 2.0) + } + pub fn into_i32(&self) -> [i32; 4] { + self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as i32 - 128) + } +} enum LoadOp { Clear(Rgba), diff --git a/crates/renderer/src/util.rs b/crates/renderer/src/util.rs new file mode 100644 index 0000000..82400ef --- /dev/null +++ b/crates/renderer/src/util.rs @@ -0,0 +1,241 @@ +use std::ops::Deref; + +use ash::vk; + +pub trait MutexExt<'a, T: 'a> { + type Guard: Deref + 'a; + fn lock(&'a self) -> Self::Guard; + fn with_locked R>(&'a self, f: F) -> R { + let lock = MutexExt::lock(self); + f(&*lock) + } +} + +impl<'a, T: 'a> MutexExt<'a, T> for parking_lot::Mutex { + type Guard = parking_lot::MutexGuard<'a, T>; + fn lock(&'a self) -> Self::Guard { + self.lock() + } +} + +pub trait FormatExt { + fn get_component_kind(&self) -> FormatComponentKind; + fn is_f32(&self) -> bool; + fn is_u32(&self) -> bool; + fn is_i32(&self) -> bool; +} + +#[derive(Debug, PartialEq, Eq)] +pub enum FormatComponentKind { + Float, + UInt, + SInt, +} + +fn format_to_primitive(format: vk::Format) -> FormatComponentKind { + use FormatComponentKind::*; + match format { + vk::Format::BC6H_SFLOAT_BLOCK => Float, + vk::Format::D32_SFLOAT => Float, + vk::Format::R16G16B16A16_SFLOAT => Float, + vk::Format::R16G16B16_SFLOAT => Float, + vk::Format::R16G16_SFLOAT => Float, + vk::Format::R16_SFLOAT => Float, + vk::Format::R32G32B32A32_SFLOAT => Float, + vk::Format::R32G32B32_SFLOAT => Float, + vk::Format::R32G32_SFLOAT => Float, + vk::Format::R32_SFLOAT => Float, + vk::Format::R64G64B64A64_SFLOAT => Float, + vk::Format::R64G64B64_SFLOAT => Float, + vk::Format::R64G64_SFLOAT => Float, + vk::Format::R64_SFLOAT => Float, + vk::Format::D32_SFLOAT_S8_UINT => Float, + vk::Format::A2B10G10R10_SINT_PACK32 => SInt, + vk::Format::A2R10G10B10_SINT_PACK32 => SInt, + vk::Format::A8B8G8R8_SINT_PACK32 => SInt, + vk::Format::B8G8R8A8_SINT => SInt, + vk::Format::B8G8R8_SINT => SInt, + vk::Format::R16G16B16A16_SINT => SInt, + vk::Format::R16G16B16_SINT => SInt, + vk::Format::R16G16_SINT => SInt, + vk::Format::R16_SINT => SInt, + vk::Format::R32G32B32A32_SINT => SInt, + vk::Format::R32G32B32_SINT => SInt, + vk::Format::R32G32_SINT => SInt, + vk::Format::R32_SINT => SInt, + vk::Format::R64G64B64A64_SINT => SInt, + vk::Format::R64G64B64_SINT => SInt, + vk::Format::R64G64_SINT => SInt, + vk::Format::R64_SINT => SInt, + vk::Format::R8G8B8A8_SINT => SInt, + vk::Format::R8G8B8_SINT => SInt, + vk::Format::R8G8_SINT => SInt, + vk::Format::R8_SINT => SInt, + vk::Format::A2B10G10R10_SNORM_PACK32 => Float, + vk::Format::A2R10G10B10_SNORM_PACK32 => Float, + vk::Format::A8B8G8R8_SNORM_PACK32 => Float, + vk::Format::B8G8R8A8_SNORM => Float, + vk::Format::B8G8R8_SNORM => Float, + vk::Format::BC4_SNORM_BLOCK => Float, + vk::Format::BC5_SNORM_BLOCK => Float, + vk::Format::EAC_R11G11_SNORM_BLOCK => Float, + vk::Format::EAC_R11_SNORM_BLOCK => Float, + vk::Format::R16G16B16A16_SNORM => Float, + vk::Format::R16G16B16_SNORM => Float, + vk::Format::R16G16_SNORM => Float, + vk::Format::R16_SNORM => Float, + vk::Format::R8G8B8A8_SNORM => Float, + vk::Format::R8G8B8_SNORM => Float, + vk::Format::R8G8_SNORM => Float, + vk::Format::R8_SNORM => Float, + vk::Format::A8B8G8R8_SRGB_PACK32 => Float, + vk::Format::ASTC_10X10_SRGB_BLOCK => Float, + vk::Format::ASTC_10X5_SRGB_BLOCK => Float, + vk::Format::ASTC_10X6_SRGB_BLOCK => Float, + vk::Format::ASTC_10X8_SRGB_BLOCK => Float, + vk::Format::ASTC_12X10_SRGB_BLOCK => Float, + vk::Format::ASTC_12X12_SRGB_BLOCK => Float, + vk::Format::ASTC_4X4_SRGB_BLOCK => Float, + vk::Format::ASTC_5X4_SRGB_BLOCK => Float, + vk::Format::ASTC_5X5_SRGB_BLOCK => Float, + vk::Format::ASTC_6X5_SRGB_BLOCK => Float, + vk::Format::ASTC_6X6_SRGB_BLOCK => Float, + vk::Format::ASTC_8X5_SRGB_BLOCK => Float, + vk::Format::ASTC_8X6_SRGB_BLOCK => Float, + vk::Format::ASTC_8X8_SRGB_BLOCK => Float, + vk::Format::B8G8R8A8_SRGB => Float, + vk::Format::B8G8R8_SRGB => Float, + vk::Format::BC1_RGBA_SRGB_BLOCK => Float, + vk::Format::BC1_RGB_SRGB_BLOCK => Float, + vk::Format::BC2_SRGB_BLOCK => Float, + vk::Format::BC3_SRGB_BLOCK => Float, + vk::Format::BC7_SRGB_BLOCK => Float, + vk::Format::ETC2_R8G8B8A1_SRGB_BLOCK => Float, + vk::Format::ETC2_R8G8B8A8_SRGB_BLOCK => Float, + vk::Format::ETC2_R8G8B8_SRGB_BLOCK => Float, + vk::Format::R8G8B8A8_SRGB => Float, + vk::Format::R8G8B8_SRGB => Float, + vk::Format::R8G8_SRGB => Float, + vk::Format::R8_SRGB => Float, + vk::Format::A2B10G10R10_SSCALED_PACK32 => Float, + vk::Format::A2R10G10B10_SSCALED_PACK32 => Float, + vk::Format::A8B8G8R8_SSCALED_PACK32 => Float, + vk::Format::B8G8R8A8_SSCALED => Float, + vk::Format::B8G8R8_SSCALED => Float, + vk::Format::R16G16B16A16_SSCALED => Float, + vk::Format::R16G16B16_SSCALED => Float, + vk::Format::R16G16_SSCALED => Float, + vk::Format::R16_SSCALED => Float, + vk::Format::R8G8B8A8_SSCALED => Float, + vk::Format::R8G8B8_SSCALED => Float, + vk::Format::R8G8_SSCALED => Float, + vk::Format::R8_SSCALED => Float, + vk::Format::B10G11R11_UFLOAT_PACK32 => Float, + vk::Format::BC6H_UFLOAT_BLOCK => Float, + vk::Format::E5B9G9R9_UFLOAT_PACK32 => Float, + vk::Format::A2B10G10R10_UINT_PACK32 => UInt, + vk::Format::A2R10G10B10_UINT_PACK32 => UInt, + vk::Format::A8B8G8R8_UINT_PACK32 => UInt, + vk::Format::B8G8R8A8_UINT => UInt, + vk::Format::B8G8R8_UINT => UInt, + vk::Format::R16G16B16A16_UINT => UInt, + vk::Format::R16G16B16_UINT => UInt, + vk::Format::R16G16_UINT => UInt, + vk::Format::R16_UINT => UInt, + vk::Format::R32G32B32A32_UINT => UInt, + vk::Format::R32G32B32_UINT => UInt, + vk::Format::R32G32_UINT => UInt, + vk::Format::R32_UINT => UInt, + vk::Format::R64G64B64A64_UINT => UInt, + vk::Format::R64G64B64_UINT => UInt, + vk::Format::R64G64_UINT => UInt, + vk::Format::R64_UINT => UInt, + vk::Format::R8G8B8A8_UINT => UInt, + vk::Format::R8G8B8_UINT => UInt, + vk::Format::R8G8_UINT => UInt, + vk::Format::R8_UINT => UInt, + vk::Format::S8_UINT => UInt, + vk::Format::A1R5G5B5_UNORM_PACK16 => Float, + vk::Format::A2B10G10R10_UNORM_PACK32 => Float, + vk::Format::A2R10G10B10_UNORM_PACK32 => Float, + vk::Format::A8B8G8R8_UNORM_PACK32 => Float, + vk::Format::ASTC_10X10_UNORM_BLOCK => Float, + vk::Format::ASTC_10X5_UNORM_BLOCK => Float, + vk::Format::ASTC_10X6_UNORM_BLOCK => Float, + vk::Format::ASTC_10X8_UNORM_BLOCK => Float, + vk::Format::ASTC_12X10_UNORM_BLOCK => Float, + vk::Format::ASTC_12X12_UNORM_BLOCK => Float, + vk::Format::ASTC_4X4_UNORM_BLOCK => Float, + vk::Format::ASTC_5X4_UNORM_BLOCK => Float, + vk::Format::ASTC_5X5_UNORM_BLOCK => Float, + vk::Format::ASTC_6X5_UNORM_BLOCK => Float, + vk::Format::ASTC_6X6_UNORM_BLOCK => Float, + vk::Format::ASTC_8X5_UNORM_BLOCK => Float, + vk::Format::ASTC_8X6_UNORM_BLOCK => Float, + vk::Format::ASTC_8X8_UNORM_BLOCK => Float, + vk::Format::B4G4R4A4_UNORM_PACK16 => Float, + vk::Format::B5G5R5A1_UNORM_PACK16 => Float, + vk::Format::B5G6R5_UNORM_PACK16 => Float, + vk::Format::B8G8R8A8_UNORM => Float, + vk::Format::B8G8R8_UNORM => Float, + vk::Format::BC1_RGBA_UNORM_BLOCK => Float, + vk::Format::BC1_RGB_UNORM_BLOCK => Float, + vk::Format::BC2_UNORM_BLOCK => Float, + vk::Format::BC3_UNORM_BLOCK => Float, + vk::Format::BC4_UNORM_BLOCK => Float, + vk::Format::BC5_UNORM_BLOCK => Float, + vk::Format::BC7_UNORM_BLOCK => Float, + vk::Format::D16_UNORM => Float, + vk::Format::D16_UNORM_S8_UINT => Float, + vk::Format::D24_UNORM_S8_UINT => Float, + vk::Format::EAC_R11G11_UNORM_BLOCK => Float, + vk::Format::EAC_R11_UNORM_BLOCK => Float, + vk::Format::ETC2_R8G8B8A1_UNORM_BLOCK => Float, + vk::Format::ETC2_R8G8B8A8_UNORM_BLOCK => Float, + vk::Format::ETC2_R8G8B8_UNORM_BLOCK => Float, + vk::Format::R16G16B16A16_UNORM => Float, + vk::Format::R16G16B16_UNORM => Float, + vk::Format::R16G16_UNORM => Float, + vk::Format::R16_UNORM => Float, + vk::Format::R4G4B4A4_UNORM_PACK16 => Float, + vk::Format::R4G4_UNORM_PACK8 => Float, + vk::Format::R5G5B5A1_UNORM_PACK16 => Float, + vk::Format::R5G6B5_UNORM_PACK16 => Float, + vk::Format::R8G8B8A8_UNORM => Float, + vk::Format::R8G8B8_UNORM => Float, + vk::Format::R8G8_UNORM => Float, + vk::Format::R8_UNORM => Float, + vk::Format::X8_D24_UNORM_PACK32 => Float, + vk::Format::A2B10G10R10_USCALED_PACK32 => Float, + vk::Format::A2R10G10B10_USCALED_PACK32 => Float, + vk::Format::A8B8G8R8_USCALED_PACK32 => Float, + vk::Format::B8G8R8A8_USCALED => Float, + vk::Format::B8G8R8_USCALED => Float, + vk::Format::R16G16B16A16_USCALED => Float, + vk::Format::R16G16B16_USCALED => Float, + vk::Format::R16G16_USCALED => Float, + vk::Format::R16_USCALED => Float, + vk::Format::R8G8B8A8_USCALED => Float, + vk::Format::R8G8B8_USCALED => Float, + vk::Format::R8G8_USCALED => Float, + vk::Format::R8_USCALED => Float, + _ => unimplemented!(), + } +} + +impl FormatExt for vk::Format { + fn get_component_kind(&self) -> FormatComponentKind { + format_to_primitive(*self) + } + fn is_f32(&self) -> bool { + format_to_primitive(*self) == FormatComponentKind::Float + } + + fn is_u32(&self) -> bool { + format_to_primitive(*self) == FormatComponentKind::UInt + } + + fn is_i32(&self) -> bool { + format_to_primitive(*self) == FormatComponentKind::SInt + } +}