diff --git a/include/librashader.h b/include/librashader.h index ce10e8a..dde9a3c 100644 --- a/include/librashader.h +++ b/include/librashader.h @@ -268,6 +268,9 @@ typedef struct libra_device_vk_t { /// A raw `VkDevice` handle /// for the device attached to the instance that will perform rendering. VkDevice device; + /// The queue to use, if this is `NULL`, then + /// a suitable queue will be chosen. + VkQueue queue; /// The entry loader for the Vulkan library. PFN_vkGetInstanceProcAddr entry; } libra_device_vk_t; diff --git a/librashader-capi/cbindgen.toml b/librashader-capi/cbindgen.toml index 3dcb0af..f56e582 100644 --- a/librashader-capi/cbindgen.toml +++ b/librashader-capi/cbindgen.toml @@ -173,6 +173,7 @@ include = [ exclude = [ "Option_ID3D11DeviceContext", + "Option_PFN_vkGetInstanceProcAddr", "PMTLCommandQueue", "PMTLCommandBuffer", "PMTLTexture" @@ -198,6 +199,7 @@ exclude = [ "CommandBuffer" = "VkCommandBuffer" "Format" = "VkFormat" "Image" = "VkImage" +"Queue" = "VkQueue" # hack to get proper pointer indirection for COM pointers # we don't need one for ID3D11DeviceContext. @@ -214,6 +216,9 @@ exclude = [ # hack to force cbindgen to not generate option type for nullable ID3D11DeviceContext. "Option_ID3D11DeviceContext" = "ID3D11DeviceContext *" +# hack to force cbindgen to not generate option type for nullable PFN_vkGetInstanceProcAddr. +"Option_PFN_vkGetInstanceProcAddr" = "PFN_vkGetInstanceProcAddr" + # hack to get proper pointer indirection for COM pointers "ID3D12Device" = "ID3D12Device *" "ID3D12Resource" = "ID3D12Resource *" diff --git a/librashader-capi/src/runtime/vk/filter_chain.rs b/librashader-capi/src/runtime/vk/filter_chain.rs index 83df49d..5ddb0c2 100644 --- a/librashader-capi/src/runtime/vk/filter_chain.rs +++ b/librashader-capi/src/runtime/vk/filter_chain.rs @@ -15,9 +15,9 @@ use std::slice; use librashader::runtime::FilterChainParameters; use librashader::runtime::{Size, Viewport}; -use ash::vk; - use crate::LIBRASHADER_API_VERSION; +use ash::vk; +use ash::vk::Handle; pub use ash::vk::PFN_vkGetInstanceProcAddr; /// A Vulkan instance function loader that the Vulkan filter chain needs to be initialized with. @@ -49,8 +49,11 @@ pub struct libra_device_vk_t { /// A raw `VkDevice` handle /// for the device attached to the instance that will perform rendering. pub device: vk::Device, + /// The queue to use, if this is `NULL`, then + /// a suitable queue will be chosen. This must be a graphics queue. + pub queue: vk::Queue, /// The entry loader for the Vulkan library. - pub entry: vk::PFN_vkGetInstanceProcAddr, + pub entry: Option, } impl From for VulkanImage { @@ -65,11 +68,18 @@ impl From for VulkanImage { impl From for VulkanInstance { fn from(value: libra_device_vk_t) -> Self { + let queue = if value.queue.is_null() { + None + } else { + Some(value.queue) + }; + VulkanInstance { device: value.device, instance: value.instance, physical_device: value.physical_device, get_instance_proc_addr: value.entry, + queue, } } } diff --git a/librashader-runtime-vk/src/error.rs b/librashader-runtime-vk/src/error.rs index 2529c68..0f76642 100644 --- a/librashader-runtime-vk/src/error.rs +++ b/librashader-runtime-vk/src/error.rs @@ -10,6 +10,8 @@ use thiserror::Error; #[derive(Error, Debug)] #[non_exhaustive] pub enum FilterChainError { + #[error("a vulkan handle that is required to be not null is null")] + HandleIsNull, #[error("shader preset parse error")] ShaderPresetError(#[from] ParsePresetError), #[error("shader preprocess error")] diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index 4b12343..af0b7df 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -13,39 +13,38 @@ use crate::{error, memory, util}; use ash::vk; use librashader_common::{ImageFormat, Size, Viewport}; +use ash::vk::Handle; use gpu_allocator::vulkan::Allocator; +use librashader_cache::CachedCompilation; use librashader_common::map::FastHashMap; +use librashader_presets::context::VideoDriver; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; use librashader_reflect::back::targets::SPIRV; use librashader_reflect::back::{CompileReflectShader, CompileShader}; use librashader_reflect::front::SpirvCompilation; +use librashader_reflect::reflect::cross::SpirvCross; use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact}; use librashader_reflect::reflect::semantics::ShaderSemantics; use librashader_reflect::reflect::ReflectShader; use librashader_runtime::binding::BindingUtil; +use librashader_runtime::framebuffer::FramebufferInit; use librashader_runtime::image::{Image, ImageError, UVDirection, BGRA8}; use librashader_runtime::quad::QuadType; +use librashader_runtime::render_target::RenderTarget; +use librashader_runtime::scaling::ScaleFramebuffer; use librashader_runtime::uniforms::UniformStorage; use parking_lot::Mutex; +use rayon::prelude::*; use std::collections::VecDeque; use std::convert::Infallible; use std::path::Path; use std::sync::Arc; -use librashader_cache::CachedCompilation; -use librashader_presets::context::VideoDriver; -use librashader_reflect::reflect::cross::SpirvCross; -use librashader_runtime::framebuffer::FramebufferInit; -use librashader_runtime::render_target::RenderTarget; -use librashader_runtime::scaling::ScaleFramebuffer; -use rayon::prelude::*; - /// A Vulkan device and metadata that is required by the shader runtime. pub struct VulkanObjects { pub(crate) device: Arc, pub(crate) alloc: Arc>, queue: vk::Queue, - // pub(crate) memory_properties: vk::PhysicalDeviceMemoryProperties, } /// A collection of handles needed to access the Vulkan instance. @@ -58,27 +57,43 @@ pub struct VulkanInstance { /// A `VkPhysicalDevice` handle. pub physical_device: vk::PhysicalDevice, /// A function pointer to the Vulkan library entry point. - pub get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr, + /// If this is `None`, [`FilterChainError::HandleIsNull`] will be returned. + pub get_instance_proc_addr: Option, + /// The graphics queue to use to submit commands. If this is `None`, + /// a queue will be chosen. + pub queue: Option, } impl TryFrom for VulkanObjects { type Error = FilterChainError; fn try_from(vulkan: VulkanInstance) -> Result { + if vulkan.queue.is_some_and(|q| q.is_null()) + || vulkan.device.is_null() + || vulkan.instance.is_null() + { + return Err(FilterChainError::HandleIsNull); + }; + + let Some(get_instance_proc_addr) = vulkan.get_instance_proc_addr else { + return Err(FilterChainError::HandleIsNull); + }; + unsafe { let instance = ash::Instance::load( &ash::StaticFn { - get_instance_proc_addr: vulkan.get_instance_proc_addr, + get_instance_proc_addr, }, vulkan.instance, ); let device = ash::Device::load(instance.fp_v1_0(), vulkan.device); - let queue = get_graphics_queue(&instance, &device, vulkan.physical_device); - - // let memory_properties = - // instance.get_physical_device_memory_properties(vulkan.physical_device); + let queue = vulkan.queue.unwrap_or(get_graphics_queue( + &instance, + &device, + vulkan.physical_device, + )); let alloc = memory::create_allocator(device.clone(), instance, vulkan.physical_device)?; @@ -86,8 +101,6 @@ impl TryFrom for VulkanObjects { device: Arc::new(device), alloc, queue, - // memory_properties, - // debug, }) } } @@ -97,20 +110,47 @@ impl TryFrom<(vk::PhysicalDevice, ash::Instance, ash::Device)> for VulkanObjects type Error = FilterChainError; fn try_from(value: (vk::PhysicalDevice, ash::Instance, ash::Device)) -> error::Result { + if value.0.is_null() { + return Err(FilterChainError::HandleIsNull); + } + let device = value.2; let queue = get_graphics_queue(&value.1, &device, value.0); - // let memory_properties = value.1.get_physical_device_memory_properties(value.0); - let alloc = memory::create_allocator(device.clone(), value.1, value.0)?; Ok(VulkanObjects { alloc, device: Arc::new(device), queue, - // memory_properties, - // debug: value.3, + }) + } +} + +impl TryFrom<(vk::PhysicalDevice, ash::Instance, ash::Device, vk::Queue)> for VulkanObjects { + type Error = FilterChainError; + + fn try_from( + value: (vk::PhysicalDevice, ash::Instance, ash::Device, vk::Queue), + ) -> error::Result { + if value.0.is_null() { + return Err(FilterChainError::HandleIsNull); + } + + let device = value.2; + let queue = if value.3.is_null() { + get_graphics_queue(&value.1, &device, value.0) + } else { + value.3 + }; + + let alloc = memory::create_allocator(device.clone(), value.1, value.0)?; + + Ok(VulkanObjects { + alloc, + device: Arc::new(device), + queue, }) } } diff --git a/librashader-runtime-vk/tests/hello_triangle/mod.rs b/librashader-runtime-vk/tests/hello_triangle/mod.rs index 9241c7c..53a950d 100644 --- a/librashader-runtime-vk/tests/hello_triangle/mod.rs +++ b/librashader-runtime-vk/tests/hello_triangle/mod.rs @@ -237,6 +237,16 @@ impl VulkanWindow { // vk::QUEUE_FAMILY_IGNORED // ); + let viewport = Viewport::new_render_target_sized_origin( + VulkanImage { + size: vulkan.swapchain.extent.into(), + image: swapchain_image, + format: vulkan.swapchain.format.format, + }, + None, + ) + .unwrap(); + filter .frame( &VulkanImage { @@ -244,17 +254,7 @@ impl VulkanWindow { image: framebuffer_image, format: vulkan.swapchain.format.format, }, - &Viewport { - x: 0.0, - y: 0.0, - output: VulkanImage { - size: vulkan.swapchain.extent.into(), - image: swapchain_image, - format: vulkan.swapchain.format.format, - }, - mvp: None, - size: vulkan.swapchain.extent.into(), - }, + &viewport, cmd, frame, Some(&FrameOptionsVulkan {