]> git.nega.tv - josh/narcissus/commitdiff
narcissus-gpu: Move conversion functions into their own module
authorJoshua Simmons <josh@nega.tv>
Mon, 17 Jul 2023 16:14:23 +0000 (18:14 +0200)
committerJoshua Simmons <josh@nega.tv>
Mon, 17 Jul 2023 16:14:23 +0000 (18:14 +0200)
libs/narcissus-gpu/src/backend/vulkan/convert.rs [new file with mode: 0644]
libs/narcissus-gpu/src/backend/vulkan/mod.rs

diff --git a/libs/narcissus-gpu/src/backend/vulkan/convert.rs b/libs/narcissus-gpu/src/backend/vulkan/convert.rs
new file mode 100644 (file)
index 0000000..129ff98
--- /dev/null
@@ -0,0 +1,304 @@
+//! Conversions between narcissus-gpu exposed types and vulkan types
+
+use narcissus_core::default;
+use vulkan_sys as vk;
+
+use crate::{
+    BindingType, BlendMode, BufferUsageFlags, ClearValue, CompareOp, CullingMode, FrontFace,
+    ImageAspectFlags, ImageDimension, ImageFormat, ImageSubresourceLayers, ImageSubresourceRange,
+    IndexType, LoadOp, PolygonMode, ShaderStageFlags, StencilOp, StencilOpState, StoreOp, Topology,
+};
+
+#[must_use]
+pub fn vulkan_bool32(b: bool) -> vk::Bool32 {
+    match b {
+        false => vk::Bool32::False,
+        true => vk::Bool32::True,
+    }
+}
+
+#[must_use]
+pub fn vulkan_format(format: ImageFormat) -> vk::Format {
+    match format {
+        ImageFormat::R8_SRGB => vk::Format::R8_SRGB,
+        ImageFormat::R8_UNORM => vk::Format::R8_UNORM,
+        ImageFormat::RGBA8_SRGB => vk::Format::R8G8B8A8_SRGB,
+        ImageFormat::RGBA8_UNORM => vk::Format::R8G8B8A8_UNORM,
+        ImageFormat::BGRA8_SRGB => vk::Format::B8G8R8A8_SRGB,
+        ImageFormat::BGRA8_UNORM => vk::Format::B8G8R8A8_UNORM,
+        ImageFormat::DEPTH_F32 => vk::Format::D32_SFLOAT,
+    }
+}
+
+pub fn vulkan_aspect_for_format(format: ImageFormat) -> vk::ImageAspectFlags {
+    match format {
+        ImageFormat::R8_SRGB
+        | ImageFormat::R8_UNORM
+        | ImageFormat::BGRA8_SRGB
+        | ImageFormat::BGRA8_UNORM
+        | ImageFormat::RGBA8_SRGB
+        | ImageFormat::RGBA8_UNORM => vk::ImageAspectFlags::COLOR,
+        ImageFormat::DEPTH_F32 => vk::ImageAspectFlags::DEPTH,
+    }
+}
+
+pub fn vulkan_aspect(aspect: ImageAspectFlags) -> vk::ImageAspectFlags {
+    let mut aspect_flags = default();
+    if aspect.contains(ImageAspectFlags::COLOR) {
+        aspect_flags |= vk::ImageAspectFlags::COLOR;
+    }
+    if aspect.contains(ImageAspectFlags::DEPTH) {
+        aspect_flags |= vk::ImageAspectFlags::DEPTH;
+    }
+    if aspect.contains(ImageAspectFlags::STENCIL) {
+        aspect_flags |= vk::ImageAspectFlags::STENCIL;
+    }
+    aspect_flags
+}
+
+pub fn vulkan_buffer_usage_flags(usage: BufferUsageFlags) -> vk::BufferUsageFlags {
+    let mut usage_flags = vk::BufferUsageFlags::default();
+    if usage.contains(BufferUsageFlags::UNIFORM) {
+        usage_flags |= vk::BufferUsageFlags::UNIFORM_BUFFER;
+    }
+    if usage.contains(BufferUsageFlags::STORAGE) {
+        usage_flags |= vk::BufferUsageFlags::STORAGE_BUFFER;
+    }
+    if usage.contains(BufferUsageFlags::INDEX) {
+        usage_flags |= vk::BufferUsageFlags::INDEX_BUFFER;
+    }
+    if usage.contains(BufferUsageFlags::TRANSFER) {
+        usage_flags |= vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::TRANSFER_DST;
+    }
+    usage_flags
+}
+
+#[must_use]
+pub fn vulkan_clear_value(clear_value: ClearValue) -> vk::ClearValue {
+    match clear_value {
+        ClearValue::ColorF32(value) => vk::ClearValue {
+            color: vk::ClearColorValue { f32: value },
+        },
+        ClearValue::ColorU32(value) => vk::ClearValue {
+            color: vk::ClearColorValue { u32: value },
+        },
+        ClearValue::ColorI32(value) => vk::ClearValue {
+            color: vk::ClearColorValue { i32: value },
+        },
+        ClearValue::DepthStencil { depth, stencil } => vk::ClearValue {
+            depth_stencil: vk::ClearDepthStencilValue { depth, stencil },
+        },
+    }
+}
+
+#[must_use]
+pub fn vulkan_load_op(load_op: LoadOp) -> (vk::AttachmentLoadOp, vk::ClearValue) {
+    match load_op {
+        LoadOp::Load => (vk::AttachmentLoadOp::Load, vk::ClearValue::default()),
+        LoadOp::Clear(clear_value) => {
+            (vk::AttachmentLoadOp::Clear, vulkan_clear_value(clear_value))
+        }
+        LoadOp::DontCare => (vk::AttachmentLoadOp::DontCare, vk::ClearValue::default()),
+    }
+}
+
+#[must_use]
+pub fn vulkan_store_op(store_op: StoreOp) -> vk::AttachmentStoreOp {
+    match store_op {
+        StoreOp::Store => vk::AttachmentStoreOp::Store,
+        StoreOp::DontCare => vk::AttachmentStoreOp::DontCare,
+    }
+}
+
+#[must_use]
+pub fn vulkan_shader_stage_flags(stage_flags: ShaderStageFlags) -> vk::ShaderStageFlags {
+    let mut flags = vk::ShaderStageFlags::default();
+    if stage_flags.contains(ShaderStageFlags::COMPUTE) {
+        flags |= vk::ShaderStageFlags::COMPUTE;
+    }
+    if stage_flags.contains(ShaderStageFlags::FRAGMENT) {
+        flags |= vk::ShaderStageFlags::FRAGMENT;
+    }
+    if stage_flags.contains(ShaderStageFlags::VERTEX) {
+        flags |= vk::ShaderStageFlags::VERTEX;
+    }
+    flags
+}
+
+#[must_use]
+pub fn vulkan_descriptor_type(binding_type: BindingType) -> vk::DescriptorType {
+    match binding_type {
+        BindingType::Sampler => vk::DescriptorType::Sampler,
+        BindingType::Image => vk::DescriptorType::SampledImage,
+        BindingType::UniformBuffer => vk::DescriptorType::UniformBuffer,
+        BindingType::StorageBuffer => vk::DescriptorType::StorageBuffer,
+        BindingType::DynamicUniformBuffer => vk::DescriptorType::UniformBufferDynamic,
+        BindingType::DynamicStorageBuffer => vk::DescriptorType::StorageBufferDynamic,
+    }
+}
+
+#[must_use]
+pub fn vulkan_index_type(index_type: IndexType) -> vk::IndexType {
+    match index_type {
+        IndexType::U16 => vk::IndexType::Uint16,
+        IndexType::U32 => vk::IndexType::Uint32,
+    }
+}
+
+#[must_use]
+pub fn vulkan_primitive_topology(primitive_topology: Topology) -> vk::PrimitiveTopology {
+    match primitive_topology {
+        Topology::Points => vk::PrimitiveTopology::PointList,
+        Topology::Lines => vk::PrimitiveTopology::LineList,
+        Topology::LineStrip => vk::PrimitiveTopology::LineStrip,
+        Topology::Triangles => vk::PrimitiveTopology::TriangleList,
+        Topology::TriangleStrip => vk::PrimitiveTopology::TriangleStrip,
+    }
+}
+
+#[must_use]
+pub fn vulkan_polygon_mode(polygon_mode: PolygonMode) -> vk::PolygonMode {
+    match polygon_mode {
+        PolygonMode::Fill => vk::PolygonMode::Fill,
+        PolygonMode::Line => vk::PolygonMode::Line,
+        PolygonMode::Point => vk::PolygonMode::Point,
+    }
+}
+
+#[must_use]
+pub fn vulkan_cull_mode(culling_mode: CullingMode) -> vk::CullModeFlags {
+    match culling_mode {
+        CullingMode::None => vk::CullModeFlags::NONE,
+        CullingMode::Front => vk::CullModeFlags::FRONT,
+        CullingMode::Back => vk::CullModeFlags::BACK,
+    }
+}
+
+#[must_use]
+pub fn vulkan_front_face(front_face: FrontFace) -> vk::FrontFace {
+    match front_face {
+        FrontFace::Clockwise => vk::FrontFace::Clockwise,
+        FrontFace::CounterClockwise => vk::FrontFace::CounterClockwise,
+    }
+}
+
+#[must_use]
+pub fn vulkan_compare_op(compare_op: CompareOp) -> vk::CompareOp {
+    match compare_op {
+        CompareOp::Never => vk::CompareOp::Never,
+        CompareOp::Less => vk::CompareOp::Less,
+        CompareOp::Equal => vk::CompareOp::Equal,
+        CompareOp::LessOrEqual => vk::CompareOp::LessOrEqual,
+        CompareOp::Greater => vk::CompareOp::Greater,
+        CompareOp::NotEqual => vk::CompareOp::NotEqual,
+        CompareOp::GreaterOrEqual => vk::CompareOp::GreaterOrEqual,
+        CompareOp::Always => vk::CompareOp::Always,
+    }
+}
+
+#[must_use]
+pub fn vulkan_stencil_op(stencil_op: StencilOp) -> vk::StencilOp {
+    match stencil_op {
+        StencilOp::Keep => vk::StencilOp::Keep,
+        StencilOp::Zero => vk::StencilOp::Zero,
+        StencilOp::Replace => vk::StencilOp::Replace,
+        StencilOp::IncrementAndClamp => vk::StencilOp::IncrementAndClamp,
+        StencilOp::DecrementAndClamp => vk::StencilOp::DecrementAndClamp,
+        StencilOp::Invert => vk::StencilOp::Invert,
+        StencilOp::IncrementAndWrap => vk::StencilOp::IncrementAndWrap,
+        StencilOp::DecrementAndWrap => vk::StencilOp::DecrementAndWrap,
+    }
+}
+
+#[must_use]
+pub fn vulkan_stencil_op_state(stencil_op_state: StencilOpState) -> vk::StencilOpState {
+    vk::StencilOpState {
+        fail_op: vulkan_stencil_op(stencil_op_state.fail_op),
+        pass_op: vulkan_stencil_op(stencil_op_state.pass_op),
+        depth_fail_op: vulkan_stencil_op(stencil_op_state.depth_fail_op),
+        compare_op: vulkan_compare_op(stencil_op_state.compare_op),
+        compare_mask: stencil_op_state.compare_mask,
+        write_mask: stencil_op_state.write_mask,
+        reference: stencil_op_state.reference,
+    }
+}
+
+#[must_use]
+pub fn vulkan_blend_mode(blend_mode: BlendMode) -> vk::PipelineColorBlendAttachmentState {
+    match blend_mode {
+        BlendMode::Opaque => vk::PipelineColorBlendAttachmentState {
+            color_write_mask: vk::ColorComponentFlags::R
+                | vk::ColorComponentFlags::G
+                | vk::ColorComponentFlags::B
+                | vk::ColorComponentFlags::A,
+            ..default()
+        },
+        BlendMode::Mask => todo!(),
+        BlendMode::Translucent => vk::PipelineColorBlendAttachmentState {
+            blend_enable: vk::Bool32::True,
+            src_color_blend_factor: vk::BlendFactor::SrcAlpha,
+            dst_color_blend_factor: vk::BlendFactor::OneMinusSrcAlpha,
+            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::R
+                | vk::ColorComponentFlags::G
+                | vk::ColorComponentFlags::B
+                | vk::ColorComponentFlags::A,
+        },
+        BlendMode::Premultiplied => vk::PipelineColorBlendAttachmentState {
+            blend_enable: vk::Bool32::True,
+            src_color_blend_factor: vk::BlendFactor::One,
+            dst_color_blend_factor: vk::BlendFactor::OneMinusSrcAlpha,
+            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::R
+                | vk::ColorComponentFlags::G
+                | vk::ColorComponentFlags::B
+                | vk::ColorComponentFlags::A,
+        },
+        BlendMode::Additive => todo!(),
+        BlendMode::Modulate => todo!(),
+    }
+}
+
+#[must_use]
+pub fn vulkan_image_view_type(
+    layer_count: u32,
+    image_dimension: ImageDimension,
+) -> vk::ImageViewType {
+    match (layer_count, image_dimension) {
+        (1, ImageDimension::Type1d) => vk::ImageViewType::Type1d,
+        (1, ImageDimension::Type2d) => vk::ImageViewType::Type2d,
+        (1, ImageDimension::Type3d) => vk::ImageViewType::Type3d,
+        (6, ImageDimension::TypeCube) => vk::ImageViewType::TypeCube,
+        (_, ImageDimension::Type1d) => vk::ImageViewType::Type1dArray,
+        (_, ImageDimension::Type2d) => vk::ImageViewType::Type2dArray,
+        (_, ImageDimension::TypeCube) => vk::ImageViewType::TypeCubeArray,
+        _ => panic!("unsupported view type"),
+    }
+}
+
+pub fn vulkan_subresource_layers(
+    subresource_layers: &ImageSubresourceLayers,
+) -> vk::ImageSubresourceLayers {
+    vk::ImageSubresourceLayers {
+        aspect_mask: vulkan_aspect(subresource_layers.aspect),
+        mip_level: subresource_layers.mip_level,
+        base_array_layer: subresource_layers.base_array_layer,
+        layer_count: subresource_layers.array_layer_count,
+    }
+}
+
+pub fn vulkan_subresource_range(subresource: &ImageSubresourceRange) -> vk::ImageSubresourceRange {
+    vk::ImageSubresourceRange {
+        aspect_mask: vulkan_aspect(subresource.aspect),
+        base_mip_level: subresource.base_mip_level,
+        level_count: subresource.mip_level_count,
+        base_array_layer: subresource.base_array_layer,
+        layer_count: subresource.array_layer_count,
+    }
+}
index b721c5d2b82dd6c838d600bf35975b15dba09fee..b8e2d7b32d8349cb90d139a9512b9f58bc30d4d0 100644 (file)
@@ -18,23 +18,22 @@ use crate::{
     delay_queue::DelayQueue,
     frame_counter::FrameCounter,
     tlsf::{self, Tlsf},
-    Bind, BindGroupLayout, BindGroupLayoutDesc, BindingType, BlendMode, Buffer, BufferArg,
-    BufferDesc, BufferImageCopy, BufferUsageFlags, ClearValue, CmdBuffer, CompareOp,
-    ComputePipelineDesc, CullingMode, Device, Extent2d, Extent3d, Frame, FrontFace, GlobalBarrier,
-    GpuConcurrent, GraphicsPipelineDesc, Image, ImageAspectFlags, ImageBarrier, ImageBlit,
-    ImageDesc, ImageDimension, ImageFormat, ImageLayout, ImageSubresourceLayers,
-    ImageSubresourceRange, ImageUsageFlags, ImageViewDesc, IndexType, LoadOp, MemoryLocation,
-    Offset2d, Offset3d, Pipeline, PolygonMode, Sampler, SamplerAddressMode, SamplerCompareOp,
-    SamplerDesc, SamplerFilter, ShaderStageFlags, StencilOp, StencilOpState, StoreOp,
-    SwapchainOutOfDateError, ThreadToken, Topology, TransientBuffer, TypedBind,
+    Bind, BindGroupLayout, BindGroupLayoutDesc, Buffer, BufferArg, BufferDesc, BufferImageCopy,
+    BufferUsageFlags, CmdBuffer, ComputePipelineDesc, Device, Extent2d, Extent3d, Frame,
+    GlobalBarrier, GpuConcurrent, GraphicsPipelineDesc, Image, ImageBarrier, ImageBlit, ImageDesc,
+    ImageDimension, ImageFormat, ImageLayout, ImageUsageFlags, ImageViewDesc, IndexType,
+    MemoryLocation, Offset2d, Offset3d, Pipeline, Sampler, SamplerAddressMode, SamplerCompareOp,
+    SamplerDesc, SamplerFilter, SwapchainOutOfDateError, ThreadToken, TransientBuffer, TypedBind,
 };
 
 mod barrier;
+mod convert;
 mod libc;
 mod wsi;
 
 use self::{
     barrier::{vulkan_image_memory_barrier, vulkan_memory_barrier},
+    convert::*,
     wsi::{VulkanWsi, VulkanWsiFrame},
 };
 
@@ -147,297 +146,6 @@ impl From<Offset3d> for vk::Offset3d {
     }
 }
 
-#[must_use]
-fn vulkan_bool32(b: bool) -> vk::Bool32 {
-    match b {
-        false => vk::Bool32::False,
-        true => vk::Bool32::True,
-    }
-}
-
-#[must_use]
-fn vulkan_format(format: ImageFormat) -> vk::Format {
-    match format {
-        ImageFormat::R8_SRGB => vk::Format::R8_SRGB,
-        ImageFormat::R8_UNORM => vk::Format::R8_UNORM,
-        ImageFormat::RGBA8_SRGB => vk::Format::R8G8B8A8_SRGB,
-        ImageFormat::RGBA8_UNORM => vk::Format::R8G8B8A8_UNORM,
-        ImageFormat::BGRA8_SRGB => vk::Format::B8G8R8A8_SRGB,
-        ImageFormat::BGRA8_UNORM => vk::Format::B8G8R8A8_UNORM,
-        ImageFormat::DEPTH_F32 => vk::Format::D32_SFLOAT,
-    }
-}
-
-fn vulkan_aspect_for_format(format: ImageFormat) -> vk::ImageAspectFlags {
-    match format {
-        ImageFormat::R8_SRGB
-        | ImageFormat::R8_UNORM
-        | ImageFormat::BGRA8_SRGB
-        | ImageFormat::BGRA8_UNORM
-        | ImageFormat::RGBA8_SRGB
-        | ImageFormat::RGBA8_UNORM => vk::ImageAspectFlags::COLOR,
-        ImageFormat::DEPTH_F32 => vk::ImageAspectFlags::DEPTH,
-    }
-}
-
-fn vulkan_aspect(aspect: ImageAspectFlags) -> vk::ImageAspectFlags {
-    let mut aspect_flags = default();
-    if aspect.contains(ImageAspectFlags::COLOR) {
-        aspect_flags |= vk::ImageAspectFlags::COLOR;
-    }
-    if aspect.contains(ImageAspectFlags::DEPTH) {
-        aspect_flags |= vk::ImageAspectFlags::DEPTH;
-    }
-    if aspect.contains(ImageAspectFlags::STENCIL) {
-        aspect_flags |= vk::ImageAspectFlags::STENCIL;
-    }
-    aspect_flags
-}
-
-fn vulkan_buffer_usage_flags(usage: BufferUsageFlags) -> vk::BufferUsageFlags {
-    let mut usage_flags = vk::BufferUsageFlags::default();
-    if usage.contains(BufferUsageFlags::UNIFORM) {
-        usage_flags |= vk::BufferUsageFlags::UNIFORM_BUFFER;
-    }
-    if usage.contains(BufferUsageFlags::STORAGE) {
-        usage_flags |= vk::BufferUsageFlags::STORAGE_BUFFER;
-    }
-    if usage.contains(BufferUsageFlags::INDEX) {
-        usage_flags |= vk::BufferUsageFlags::INDEX_BUFFER;
-    }
-    if usage.contains(BufferUsageFlags::TRANSFER) {
-        usage_flags |= vk::BufferUsageFlags::TRANSFER_SRC | vk::BufferUsageFlags::TRANSFER_DST;
-    }
-    usage_flags
-}
-
-#[must_use]
-fn vulkan_clear_value(clear_value: ClearValue) -> vk::ClearValue {
-    match clear_value {
-        ClearValue::ColorF32(value) => vk::ClearValue {
-            color: vk::ClearColorValue { f32: value },
-        },
-        ClearValue::ColorU32(value) => vk::ClearValue {
-            color: vk::ClearColorValue { u32: value },
-        },
-        ClearValue::ColorI32(value) => vk::ClearValue {
-            color: vk::ClearColorValue { i32: value },
-        },
-        ClearValue::DepthStencil { depth, stencil } => vk::ClearValue {
-            depth_stencil: vk::ClearDepthStencilValue { depth, stencil },
-        },
-    }
-}
-
-#[must_use]
-fn vulkan_load_op(load_op: LoadOp) -> (vk::AttachmentLoadOp, vk::ClearValue) {
-    match load_op {
-        LoadOp::Load => (vk::AttachmentLoadOp::Load, vk::ClearValue::default()),
-        LoadOp::Clear(clear_value) => {
-            (vk::AttachmentLoadOp::Clear, vulkan_clear_value(clear_value))
-        }
-        LoadOp::DontCare => (vk::AttachmentLoadOp::DontCare, vk::ClearValue::default()),
-    }
-}
-
-#[must_use]
-fn vulkan_store_op(store_op: StoreOp) -> vk::AttachmentStoreOp {
-    match store_op {
-        StoreOp::Store => vk::AttachmentStoreOp::Store,
-        StoreOp::DontCare => vk::AttachmentStoreOp::DontCare,
-    }
-}
-
-#[must_use]
-fn vulkan_shader_stage_flags(stage_flags: ShaderStageFlags) -> vk::ShaderStageFlags {
-    let mut flags = vk::ShaderStageFlags::default();
-    if stage_flags.contains(ShaderStageFlags::COMPUTE) {
-        flags |= vk::ShaderStageFlags::COMPUTE;
-    }
-    if stage_flags.contains(ShaderStageFlags::FRAGMENT) {
-        flags |= vk::ShaderStageFlags::FRAGMENT;
-    }
-    if stage_flags.contains(ShaderStageFlags::VERTEX) {
-        flags |= vk::ShaderStageFlags::VERTEX;
-    }
-    flags
-}
-
-#[must_use]
-fn vulkan_descriptor_type(binding_type: BindingType) -> vk::DescriptorType {
-    match binding_type {
-        BindingType::Sampler => vk::DescriptorType::Sampler,
-        BindingType::Image => vk::DescriptorType::SampledImage,
-        BindingType::UniformBuffer => vk::DescriptorType::UniformBuffer,
-        BindingType::StorageBuffer => vk::DescriptorType::StorageBuffer,
-        BindingType::DynamicUniformBuffer => vk::DescriptorType::UniformBufferDynamic,
-        BindingType::DynamicStorageBuffer => vk::DescriptorType::StorageBufferDynamic,
-    }
-}
-
-#[must_use]
-fn vulkan_index_type(index_type: IndexType) -> vk::IndexType {
-    match index_type {
-        IndexType::U16 => vk::IndexType::Uint16,
-        IndexType::U32 => vk::IndexType::Uint32,
-    }
-}
-
-#[must_use]
-fn vulkan_primitive_topology(primitive_topology: Topology) -> vk::PrimitiveTopology {
-    match primitive_topology {
-        Topology::Points => vk::PrimitiveTopology::PointList,
-        Topology::Lines => vk::PrimitiveTopology::LineList,
-        Topology::LineStrip => vk::PrimitiveTopology::LineStrip,
-        Topology::Triangles => vk::PrimitiveTopology::TriangleList,
-        Topology::TriangleStrip => vk::PrimitiveTopology::TriangleStrip,
-    }
-}
-
-#[must_use]
-fn vulkan_polygon_mode(polygon_mode: PolygonMode) -> vk::PolygonMode {
-    match polygon_mode {
-        PolygonMode::Fill => vk::PolygonMode::Fill,
-        PolygonMode::Line => vk::PolygonMode::Line,
-        PolygonMode::Point => vk::PolygonMode::Point,
-    }
-}
-
-#[must_use]
-fn vulkan_cull_mode(culling_mode: CullingMode) -> vk::CullModeFlags {
-    match culling_mode {
-        CullingMode::None => vk::CullModeFlags::NONE,
-        CullingMode::Front => vk::CullModeFlags::FRONT,
-        CullingMode::Back => vk::CullModeFlags::BACK,
-    }
-}
-
-#[must_use]
-fn vulkan_front_face(front_face: FrontFace) -> vk::FrontFace {
-    match front_face {
-        FrontFace::Clockwise => vk::FrontFace::Clockwise,
-        FrontFace::CounterClockwise => vk::FrontFace::CounterClockwise,
-    }
-}
-
-#[must_use]
-fn vulkan_compare_op(compare_op: CompareOp) -> vk::CompareOp {
-    match compare_op {
-        CompareOp::Never => vk::CompareOp::Never,
-        CompareOp::Less => vk::CompareOp::Less,
-        CompareOp::Equal => vk::CompareOp::Equal,
-        CompareOp::LessOrEqual => vk::CompareOp::LessOrEqual,
-        CompareOp::Greater => vk::CompareOp::Greater,
-        CompareOp::NotEqual => vk::CompareOp::NotEqual,
-        CompareOp::GreaterOrEqual => vk::CompareOp::GreaterOrEqual,
-        CompareOp::Always => vk::CompareOp::Always,
-    }
-}
-
-#[must_use]
-fn vulkan_stencil_op(stencil_op: StencilOp) -> vk::StencilOp {
-    match stencil_op {
-        StencilOp::Keep => vk::StencilOp::Keep,
-        StencilOp::Zero => vk::StencilOp::Zero,
-        StencilOp::Replace => vk::StencilOp::Replace,
-        StencilOp::IncrementAndClamp => vk::StencilOp::IncrementAndClamp,
-        StencilOp::DecrementAndClamp => vk::StencilOp::DecrementAndClamp,
-        StencilOp::Invert => vk::StencilOp::Invert,
-        StencilOp::IncrementAndWrap => vk::StencilOp::IncrementAndWrap,
-        StencilOp::DecrementAndWrap => vk::StencilOp::DecrementAndWrap,
-    }
-}
-
-#[must_use]
-fn vulkan_stencil_op_state(stencil_op_state: StencilOpState) -> vk::StencilOpState {
-    vk::StencilOpState {
-        fail_op: vulkan_stencil_op(stencil_op_state.fail_op),
-        pass_op: vulkan_stencil_op(stencil_op_state.pass_op),
-        depth_fail_op: vulkan_stencil_op(stencil_op_state.depth_fail_op),
-        compare_op: vulkan_compare_op(stencil_op_state.compare_op),
-        compare_mask: stencil_op_state.compare_mask,
-        write_mask: stencil_op_state.write_mask,
-        reference: stencil_op_state.reference,
-    }
-}
-
-#[must_use]
-fn vulkan_blend_mode(blend_mode: BlendMode) -> vk::PipelineColorBlendAttachmentState {
-    match blend_mode {
-        BlendMode::Opaque => vk::PipelineColorBlendAttachmentState {
-            color_write_mask: vk::ColorComponentFlags::R
-                | vk::ColorComponentFlags::G
-                | vk::ColorComponentFlags::B
-                | vk::ColorComponentFlags::A,
-            ..default()
-        },
-        BlendMode::Mask => todo!(),
-        BlendMode::Translucent => vk::PipelineColorBlendAttachmentState {
-            blend_enable: vk::Bool32::True,
-            src_color_blend_factor: vk::BlendFactor::SrcAlpha,
-            dst_color_blend_factor: vk::BlendFactor::OneMinusSrcAlpha,
-            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::R
-                | vk::ColorComponentFlags::G
-                | vk::ColorComponentFlags::B
-                | vk::ColorComponentFlags::A,
-        },
-        BlendMode::Premultiplied => vk::PipelineColorBlendAttachmentState {
-            blend_enable: vk::Bool32::True,
-            src_color_blend_factor: vk::BlendFactor::One,
-            dst_color_blend_factor: vk::BlendFactor::OneMinusSrcAlpha,
-            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::R
-                | vk::ColorComponentFlags::G
-                | vk::ColorComponentFlags::B
-                | vk::ColorComponentFlags::A,
-        },
-        BlendMode::Additive => todo!(),
-        BlendMode::Modulate => todo!(),
-    }
-}
-
-#[must_use]
-fn vulkan_image_view_type(layer_count: u32, image_dimension: ImageDimension) -> vk::ImageViewType {
-    match (layer_count, image_dimension) {
-        (1, ImageDimension::Type1d) => vk::ImageViewType::Type1d,
-        (1, ImageDimension::Type2d) => vk::ImageViewType::Type2d,
-        (1, ImageDimension::Type3d) => vk::ImageViewType::Type3d,
-        (6, ImageDimension::TypeCube) => vk::ImageViewType::TypeCube,
-        (_, ImageDimension::Type1d) => vk::ImageViewType::Type1dArray,
-        (_, ImageDimension::Type2d) => vk::ImageViewType::Type2dArray,
-        (_, ImageDimension::TypeCube) => vk::ImageViewType::TypeCubeArray,
-        _ => panic!("unsupported view type"),
-    }
-}
-
-fn vulkan_subresource_layers(
-    subresource_layers: &ImageSubresourceLayers,
-) -> vk::ImageSubresourceLayers {
-    vk::ImageSubresourceLayers {
-        aspect_mask: vulkan_aspect(subresource_layers.aspect),
-        mip_level: subresource_layers.mip_level,
-        base_array_layer: subresource_layers.base_array_layer,
-        layer_count: subresource_layers.array_layer_count,
-    }
-}
-
-fn vulkan_subresource_range(subresource: &ImageSubresourceRange) -> vk::ImageSubresourceRange {
-    vk::ImageSubresourceRange {
-        aspect_mask: vulkan_aspect(subresource.aspect),
-        base_mip_level: subresource.base_mip_level,
-        level_count: subresource.mip_level_count,
-        base_array_layer: subresource.base_array_layer,
-        layer_count: subresource.array_layer_count,
-    }
-}
-
 fn vulkan_shader_module(
     device_fn: &vk::DeviceFunctions,
     device: vk::Device,