vk: do own queue selection and fix error type

This commit is contained in:
chyyran 2023-01-13 01:19:41 -05:00
parent 455b56ce8e
commit 40b9f08234
8 changed files with 123 additions and 79 deletions

View file

@ -1,3 +1,25 @@
use std::error::Error; use librashader_preprocess::PreprocessError;
use librashader_presets::ParsePresetError;
use librashader_reflect::error::{ShaderCompileError, ShaderReflectError};
use librashader_runtime::image::ImageError;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, Box<dyn Error>>; #[derive(Error, Debug)]
pub enum FilterChainError {
#[error("SPIRV reflection error")]
SpirvCrossReflectError(#[from] spirv_cross::ErrorCode),
#[error("shader preset parse error")]
ShaderPresetError(#[from] ParsePresetError),
#[error("shader preprocess error")]
ShaderPreprocessError(#[from] PreprocessError),
#[error("shader compile error")]
ShaderCompileError(#[from] ShaderCompileError),
#[error("shader reflect error")]
ShaderReflectError(#[from] ShaderReflectError),
#[error("lut loading error")]
LutLoadError(#[from] ImageError),
#[error("vulkan error")]
VulkanResult(#[from] ash::vk::Result),
}
pub type Result<T> = std::result::Result<T, FilterChainError>;

View file

@ -4,18 +4,14 @@ use crate::framebuffer::OutputImage;
use crate::luts::LutTexture; use crate::luts::LutTexture;
use crate::render_target::{RenderTarget, DEFAULT_MVP}; use crate::render_target::{RenderTarget, DEFAULT_MVP};
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::{InputImage, OwnedImage, OwnedImageLayout, VulkanImage}; use crate::texture::{InputImage, OwnedImage, VulkanImage};
use crate::ubo_ring::VkUboRing; use crate::ubo_ring::VkUboRing;
use crate::viewport::Viewport; use crate::viewport::Viewport;
use crate::vulkan_state::VulkanGraphicsPipeline; use crate::vulkan_state::VulkanGraphicsPipeline;
use crate::{error, util}; use crate::{error, util};
use ash::extensions::ext::DebugUtils; use ash::extensions::ext::DebugUtils;
use ash::vk::{ use ash::vk;
CommandPoolCreateFlags, DebugUtilsObjectNameInfoEXT, Handle, PFN_vkGetInstanceProcAddr, Queue, use librashader_common::{ImageFormat, Size};
StaticFn,
};
use ash::{vk, Device, Entry};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::targets::SpirV; use librashader_reflect::back::targets::SpirV;
@ -29,16 +25,15 @@ use librashader_runtime::image::{Image, UVDirection};
use librashader_runtime::uniforms::UniformStorage; use librashader_runtime::uniforms::UniformStorage;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::error::Error;
use std::ffi::CStr;
use std::path::Path; use std::path::Path;
use crate::error::FilterChainError;
use crate::queue_selection::get_graphics_queue;
pub struct Vulkan { pub struct Vulkan {
// physical_device: vk::PhysicalDevice, // physical_device: vk::PhysicalDevice,
pub(crate) device: ash::Device, pub(crate) device: ash::Device,
// instance: ash::Instance, // instance: ash::Instance,
queue: vk::Queue, queue: vk::Queue,
command_pool: vk::CommandPool,
pipeline_cache: vk::PipelineCache, pipeline_cache: vk::PipelineCache,
pub(crate) memory_properties: vk::PhysicalDeviceMemoryProperties, pub(crate) memory_properties: vk::PhysicalDeviceMemoryProperties,
// debug: DebugUtils, // debug: DebugUtils,
@ -51,57 +46,47 @@ type ShaderPassMeta = (
); );
#[derive(Clone)] #[derive(Clone)]
pub struct VulkanInfo<'a> { pub struct VulkanInfo {
// physical_device: &'a vk::PhysicalDevice, device: vk::Device,
device: &'a vk::Device, instance: vk::Instance,
instance: &'a vk::Instance, physical_device: vk::PhysicalDevice,
queue: &'a vk::Queue, get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
memory_properties: &'a vk::PhysicalDeviceMemoryProperties,
get_instance_proc_addr: PFN_vkGetInstanceProcAddr,
} }
impl TryFrom<VulkanInfo<'_>> for Vulkan { impl TryFrom<VulkanInfo> for Vulkan {
type Error = Box<dyn Error>; type Error = FilterChainError;
fn try_from(vulkan: VulkanInfo) -> Result<Self, Box<dyn Error>> { fn try_from(vulkan: VulkanInfo) -> Result<Self, FilterChainError> {
unsafe { unsafe {
let instance = ash::Instance::load( let instance = ash::Instance::load(
&StaticFn { &vk::StaticFn {
get_instance_proc_addr: vulkan.get_instance_proc_addr, get_instance_proc_addr: vulkan.get_instance_proc_addr,
}, },
vulkan.instance.clone(), vulkan.instance,
); );
let device = ash::Device::load(instance.fp_v1_0(), vulkan.device.clone()); let device = ash::Device::load(instance.fp_v1_0(), vulkan.device);
let pipeline_cache = unsafe { let pipeline_cache = unsafe {
device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None)? device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None)?
}; };
// the queue is only used for lut loading.. we may want to select our own queue.
let command_pool = unsafe {
device.create_command_pool(
&vk::CommandPoolCreateInfo::builder()
.flags(CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
.build(),
None,
)?
};
let debug = DebugUtils::new( let debug = DebugUtils::new(
&Entry::from_static_fn(StaticFn { &ash::Entry::from_static_fn(vk::StaticFn {
get_instance_proc_addr: vulkan.get_instance_proc_addr, get_instance_proc_addr: vulkan.get_instance_proc_addr,
}), }),
&instance, &instance,
); );
let queue = get_graphics_queue(&instance, &device, vulkan.physical_device);
let memory_properties = instance.get_physical_device_memory_properties(vulkan.physical_device);
Ok(Vulkan { Ok(Vulkan {
device, device,
// instance, // instance,
queue: vulkan.queue.clone(), queue,
command_pool,
pipeline_cache, pipeline_cache,
memory_properties: vulkan.memory_properties.clone(), memory_properties,
// debug, // debug,
}) })
} }
@ -110,44 +95,36 @@ impl TryFrom<VulkanInfo<'_>> for Vulkan {
impl impl
TryFrom<( TryFrom<(
vk::PhysicalDevice,
ash::Instance,
ash::Device, ash::Device,
vk::Queue,
vk::PhysicalDeviceMemoryProperties,
DebugUtils,
)> for Vulkan )> for Vulkan
{ {
type Error = Box<dyn Error>; type Error = FilterChainError;
fn try_from( fn try_from(
value: ( value: (
Device, vk::PhysicalDevice,
Queue, ash::Instance,
vk::PhysicalDeviceMemoryProperties, ash::Device,
DebugUtils,
), ),
) -> error::Result<Self> { ) -> error::Result<Self> {
unsafe { unsafe {
let device = value.0; let device = value.2;
let pipeline_cache = unsafe { let pipeline_cache = unsafe {
device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None)? device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None)?
}; };
let command_pool = unsafe { let queue = get_graphics_queue(&value.1, &device, value.0);
device.create_command_pool(
&vk::CommandPoolCreateInfo::builder() let memory_properties = value.1.get_physical_device_memory_properties(value.0);
.flags(CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
.build(),
None,
)?
};
Ok(Vulkan { Ok(Vulkan {
device, device,
queue: value.1, queue,
command_pool,
pipeline_cache, pipeline_cache,
memory_properties: value.2, memory_properties,
// debug: value.3, // debug: value.3,
}) })
} }
@ -227,7 +204,7 @@ pub type FilterChainOptionsVulkan = ();
impl FilterChainVulkan { impl FilterChainVulkan {
/// Load the shader preset at the given path into a filter chain. /// Load the shader preset at the given path into a filter chain.
pub fn load_from_path( pub fn load_from_path(
vulkan: impl TryInto<Vulkan, Error = Box<dyn Error>>, vulkan: impl TryInto<Vulkan, Error = FilterChainError>,
path: impl AsRef<Path>, path: impl AsRef<Path>,
options: Option<&FilterChainOptionsVulkan>, options: Option<&FilterChainOptionsVulkan>,
) -> error::Result<FilterChainVulkan> { ) -> error::Result<FilterChainVulkan> {
@ -237,7 +214,7 @@ impl FilterChainVulkan {
} }
pub fn load_from_preset( pub fn load_from_preset(
vulkan: impl TryInto<Vulkan, Error = Box<dyn Error>>, vulkan: impl TryInto<Vulkan, Error = FilterChainError>,
preset: ShaderPreset, preset: ShaderPreset,
options: Option<&FilterChainOptionsVulkan>, options: Option<&FilterChainOptionsVulkan>,
) -> error::Result<FilterChainVulkan> { ) -> error::Result<FilterChainVulkan> {
@ -325,7 +302,7 @@ impl FilterChainVulkan {
}), }),
); );
} }
Ok::<_, Box<dyn Error>>((shader, source, reflect)) Ok::<_, FilterChainError>((shader, source, reflect))
}) })
.into_iter() .into_iter()
.collect::<error::Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>( .collect::<error::Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>(
@ -431,11 +408,21 @@ impl FilterChainVulkan {
textures: &[TextureConfig], textures: &[TextureConfig],
) -> error::Result<FxHashMap<usize, LutTexture>> { ) -> error::Result<FxHashMap<usize, LutTexture>> {
let mut luts = FxHashMap::default(); let mut luts = FxHashMap::default();
let command_pool = unsafe {
vulkan.device.create_command_pool(
&vk::CommandPoolCreateInfo::builder()
.flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
.build(),
None,
)?
};
let command_buffer = unsafe { let command_buffer = unsafe {
// panic safety: command buffer count = 1 // panic safety: command buffer count = 1
vulkan.device.allocate_command_buffers( vulkan.device.allocate_command_buffers(
&vk::CommandBufferAllocateInfo::builder() &vk::CommandBufferAllocateInfo::builder()
.command_pool(vulkan.command_pool) .command_pool(command_pool)
.level(vk::CommandBufferLevel::PRIMARY) .level(vk::CommandBufferLevel::PRIMARY)
.command_buffer_count(1) .command_buffer_count(1)
.build(), .build(),
@ -454,7 +441,7 @@ impl FilterChainVulkan {
for (index, texture) in textures.iter().enumerate() { for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path, UVDirection::TopLeft)?; let image = Image::load(&texture.path, UVDirection::TopLeft)?;
let texture = LutTexture::new(vulkan, &command_buffer, image, texture)?; let texture = LutTexture::new(vulkan, command_buffer, image, texture)?;
luts.insert(index, texture); luts.insert(index, texture);
} }
@ -468,9 +455,13 @@ impl FilterChainVulkan {
.device .device
.queue_submit(vulkan.queue, &submits, vk::Fence::null())?; .queue_submit(vulkan.queue, &submits, vk::Fence::null())?;
vulkan.device.queue_wait_idle(vulkan.queue)?; vulkan.device.queue_wait_idle(vulkan.queue)?;
vulkan vulkan
.device .device
.free_command_buffers(vulkan.command_pool, &buffers); .free_command_buffers(command_pool, &buffers);
vulkan.device
.destroy_command_pool(command_pool, None);
} }
Ok(luts) Ok(luts)
} }

View file

@ -347,8 +347,7 @@ impl VulkanWindow {
.queue_present(vulkan.base.graphics_queue, &present_info) .queue_present(vulkan.base.graphics_queue, &present_info)
.unwrap(); .unwrap();
//oops i pooped my pants
// std::mem::forget(intermediates);
vulkan.base.device.device_wait_idle().unwrap(); vulkan.base.device.device_wait_idle().unwrap();
drop(intermediates) drop(intermediates)
} }

View file

@ -8,6 +8,7 @@ use crate::hello_triangle::physicaldevice::{find_queue_family, pick_physical_dev
use crate::hello_triangle::surface::VulkanSurface; use crate::hello_triangle::surface::VulkanSurface;
use ash::prelude::VkResult; use ash::prelude::VkResult;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use crate::error::FilterChainError;
const WINDOW_TITLE: &'static [u8] = b"librashader Vulkan\0"; const WINDOW_TITLE: &'static [u8] = b"librashader Vulkan\0";
const KHRONOS_VALIDATION: &'static [u8] = b"VK_LAYER_KHRONOS_validation\0"; const KHRONOS_VALIDATION: &'static [u8] = b"VK_LAYER_KHRONOS_validation\0";
@ -162,14 +163,13 @@ impl Drop for VulkanBase {
} }
impl TryFrom<&VulkanBase> for Vulkan { impl TryFrom<&VulkanBase> for Vulkan {
type Error = Box<dyn Error>; type Error = FilterChainError;
fn try_from(value: &VulkanBase) -> Result<Self, Self::Error> { fn try_from(value: &VulkanBase) -> Result<Self, Self::Error> {
Vulkan::try_from(( Vulkan::try_from((
value.physical_device,
value.instance.clone(),
value.device.clone(), value.device.clone(),
value.graphics_queue.clone(),
value.mem_props,
value.debug.loader.clone(),
)) ))
} }
} }

View file

@ -3,10 +3,10 @@
#![feature(strict_provenance)] #![feature(strict_provenance)]
mod draw_quad; mod draw_quad;
mod error;
mod filter_chain; mod filter_chain;
mod filter_pass; mod filter_pass;
mod framebuffer; mod framebuffer;
#[cfg(test)]
mod hello_triangle; mod hello_triangle;
mod luts; mod luts;
mod render_target; mod render_target;
@ -17,6 +17,14 @@ mod util;
mod viewport; mod viewport;
mod vulkan_primitives; mod vulkan_primitives;
mod vulkan_state; mod vulkan_state;
mod queue_selection;
pub use filter_chain::FilterChainFrameIntermediates;
pub use filter_chain::FilterChainVulkan;
pub use viewport::Viewport;
pub mod error;
pub mod options;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View file

@ -16,7 +16,7 @@ pub struct LutTexture {
impl LutTexture { impl LutTexture {
pub fn new( pub fn new(
vulkan: &Vulkan, vulkan: &Vulkan,
cmd: &vk::CommandBuffer, cmd: vk::CommandBuffer,
image: Image<BGRA8>, image: Image<BGRA8>,
config: &TextureConfig, config: &TextureConfig,
) -> error::Result<LutTexture> { ) -> error::Result<LutTexture> {
@ -97,7 +97,7 @@ impl LutTexture {
unsafe { unsafe {
util::vulkan_image_layout_transition_levels( util::vulkan_image_layout_transition_levels(
&vulkan.device, &vulkan.device,
*cmd, cmd,
texture, texture,
vk::REMAINING_MIP_LEVELS, vk::REMAINING_MIP_LEVELS,
vk::ImageLayout::UNDEFINED, vk::ImageLayout::UNDEFINED,
@ -115,7 +115,7 @@ impl LutTexture {
); );
vulkan.device.cmd_copy_buffer_to_image( vulkan.device.cmd_copy_buffer_to_image(
*cmd, cmd,
staging.handle, staging.handle,
texture, texture,
if config.mipmap { if config.mipmap {
@ -183,7 +183,7 @@ impl LutTexture {
unsafe { unsafe {
util::vulkan_image_layout_transition_levels( util::vulkan_image_layout_transition_levels(
&vulkan.device, &vulkan.device,
*cmd, cmd,
texture, texture,
vk::REMAINING_MIP_LEVELS, vk::REMAINING_MIP_LEVELS,
vk::ImageLayout::GENERAL, vk::ImageLayout::GENERAL,
@ -198,13 +198,13 @@ impl LutTexture {
// todo: respect mipmap filter? // todo: respect mipmap filter?
vulkan.device.cmd_blit_image( vulkan.device.cmd_blit_image(
*cmd, cmd,
texture, texture,
vk::ImageLayout::GENERAL, vk::ImageLayout::GENERAL,
texture, texture,
vk::ImageLayout::GENERAL, vk::ImageLayout::GENERAL,
&image_blit, &image_blit,
vk::Filter::LINEAR, config.filter_mode.into(),
); );
} }
} }
@ -212,7 +212,7 @@ impl LutTexture {
unsafe { unsafe {
util::vulkan_image_layout_transition_levels( util::vulkan_image_layout_transition_levels(
&vulkan.device, &vulkan.device,
*cmd, cmd,
texture, texture,
vk::REMAINING_MIP_LEVELS, vk::REMAINING_MIP_LEVELS,
if config.mipmap { if config.mipmap {

View file

View file

@ -0,0 +1,24 @@
use ash::vk;
fn find_graphics_queue_family(
instance: &ash::Instance,
physical_device: vk::PhysicalDevice,
) -> u32 {
let queue_families =
unsafe { instance.get_physical_device_queue_family_properties(physical_device) };
// find the most specialized transfer queue.
for (index, queue_family) in queue_families.iter().enumerate() {
if queue_family.queue_count > 0
&& queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS)
{
return index as u32
}
}
return 0
}
pub fn get_graphics_queue(instance: &ash::Instance, device: &ash::Device, physical_device: vk::PhysicalDevice) -> vk::Queue {
let queue_family = find_graphics_queue_family(instance, physical_device);
unsafe { device.get_device_queue(queue_family, 0) }
}