diff --git a/Cargo.lock b/Cargo.lock index 4d3b202..fecc642 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -902,6 +902,7 @@ dependencies = [ "librashader-presets", "librashader-reflect", "librashader-runtime", + "num", "raw-window-handle 0.5.0", "rustc-hash", "spirv_cross", @@ -1128,6 +1129,40 @@ dependencies = [ "nom", ] +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +dependencies = [ + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1138,6 +1173,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.1" @@ -1145,6 +1191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", + "num-bigint", "num-integer", "num-traits", ] diff --git a/librashader-runtime-vk/Cargo.toml b/librashader-runtime-vk/Cargo.toml index 7dbc674..54129ae 100644 --- a/librashader-runtime-vk/Cargo.toml +++ b/librashader-runtime-vk/Cargo.toml @@ -26,6 +26,7 @@ thiserror = "1.0.37" ash = { version = "0.37.1+1.3.235", features = ["linked", "debug"] } [dev-dependencies] +num = "0.4.0" glfw = "0.49.0" winit = "0.27.5" raw-window-handle = "0.5" diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index 200263a..3a88006 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -11,7 +11,6 @@ use crate::ubo_ring::VkUboRing; use crate::viewport::Viewport; use crate::vulkan_state::VulkanGraphicsPipeline; use crate::{error, util}; -use ash::extensions::ext::DebugUtils; use ash::vk; use librashader_common::{ImageFormat, Size}; use librashader_preprocess::ShaderSource; @@ -28,6 +27,7 @@ use librashader_runtime::uniforms::UniformStorage; use rustc_hash::FxHashMap; use std::collections::VecDeque; use std::path::Path; +use crate::options::{FilterChainOptionsVulkan, FrameOptionsVulkan}; pub struct Vulkan { pub(crate) device: ash::Device, @@ -42,12 +42,17 @@ type ShaderPassMeta = ( CompilerBackend, Context = ()> + ReflectShader>, ); +/// A collection of handles needed to access the Vulkan instance. #[derive(Clone)] pub struct VulkanInfo { - device: vk::Device, - instance: vk::Instance, - physical_device: vk::PhysicalDevice, - get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr, + /// A `VkDevice` handle. + pub device: vk::Device, + /// A `VkInstance` handle. + pub instance: vk::Instance, + /// 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, } impl TryFrom for Vulkan { @@ -67,13 +72,6 @@ impl TryFrom for Vulkan { let pipeline_cache = device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None)?; - let _debug = DebugUtils::new( - &ash::Entry::from_static_fn(vk::StaticFn { - get_instance_proc_addr: vulkan.get_instance_proc_addr, - }), - &instance, - ); - let queue = get_graphics_queue(&instance, &device, vulkan.physical_device); let memory_properties = instance.get_physical_device_memory_properties(vulkan.physical_device); @@ -96,9 +94,7 @@ impl TryFrom<(vk::PhysicalDevice, ash::Instance, ash::Device)> for Vulkan { unsafe { let device = value.2; - let pipeline_cache = unsafe { - device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None)? - }; + let pipeline_cache = device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None)?; let queue = get_graphics_queue(&value.1, &device, value.0); @@ -117,11 +113,12 @@ impl TryFrom<(vk::PhysicalDevice, ash::Instance, ash::Device)> for Vulkan { pub struct FilterChainVulkan { pub(crate) common: FilterCommon, - pub(crate) passes: Box<[FilterPass]>, - pub(crate) vulkan: Vulkan, - pub(crate) output_framebuffers: Box<[OwnedImage]>, - pub(crate) feedback_framebuffers: Box<[OwnedImage]>, - pub(crate) history_framebuffers: VecDeque, + passes: Box<[FilterPass]>, + vulkan: Vulkan, + output_framebuffers: Box<[OwnedImage]>, + feedback_framebuffers: Box<[OwnedImage]>, + history_framebuffers: VecDeque, + disable_mipmaps: bool } pub struct FilterMutable { @@ -133,7 +130,6 @@ pub(crate) struct FilterCommon { pub(crate) luts: FxHashMap, pub samplers: SamplerSet, pub(crate) draw_quad: DrawQuad, - pub output_inputs: Box<[Option]>, pub feedback_inputs: Box<[Option]>, pub history_textures: Box<[Option]>, @@ -142,15 +138,15 @@ pub(crate) struct FilterCommon { } #[must_use] -pub struct FilterChainFrameIntermediates { +pub struct FrameIntermediates { device: ash::Device, image_views: Vec, owned: Vec, } -impl FilterChainFrameIntermediates { +impl FrameIntermediates { pub(crate) fn new(device: &ash::Device) -> Self { - FilterChainFrameIntermediates { + FrameIntermediates { device: device.clone(), image_views: Vec::new(), owned: Vec::new(), @@ -164,10 +160,9 @@ impl FilterChainFrameIntermediates { pub(crate) fn dispose_owned(&mut self, owned: OwnedImage) { self.owned.push(owned) } -} -impl Drop for FilterChainFrameIntermediates { - fn drop(&mut self) { + /// Dispose of the intermediate objects created during a frame. + pub fn dispose(self) { for image_view in &self.image_views { if *image_view != vk::ImageView::null() { unsafe { @@ -175,11 +170,10 @@ impl Drop for FilterChainFrameIntermediates { } } } + drop(self) } } -pub type FilterChainOptionsVulkan = (); - impl FilterChainVulkan { /// Load the shader preset at the given path into a filter chain. pub fn load_from_path( @@ -195,7 +189,7 @@ impl FilterChainVulkan { pub fn load_from_preset( vulkan: impl TryInto, preset: ShaderPreset, - _options: Option<&FilterChainOptionsVulkan>, + options: Option<&FilterChainOptionsVulkan>, ) -> error::Result { let (passes, semantics) = FilterChainVulkan::load_preset(preset.shaders, &preset.textures)?; let device = vulkan.try_into()?; @@ -252,6 +246,7 @@ impl FilterChainVulkan { output_framebuffers: output_framebuffers?.into_boxed_slice(), feedback_framebuffers: feedback_framebuffers?.into_boxed_slice(), history_framebuffers, + disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps), }) } @@ -496,7 +491,7 @@ impl FilterChainVulkan { pub fn push_history( &mut self, input: &VulkanImage, - intermediates: &mut FilterChainFrameIntermediates, + intermediates: &mut FrameIntermediates, cmd: vk::CommandBuffer, ) -> error::Result<()> { if let Some(mut back) = self.history_framebuffers.pop_back() { @@ -551,7 +546,7 @@ impl FilterChainVulkan { Ok(()) } - /// Process a frame with the input image. + /// Records shader rendering commands to the provided command buffer. /// /// * The input image must be in the `VK_SHADER_READ_ONLY_OPTIMAL`. /// * The output image must be in `VK_COLOR_ATTACHMENT_OPTIMAL`. @@ -559,18 +554,31 @@ impl FilterChainVulkan { /// librashader **will not** create a pipeline barrier for the final pass. The output image will /// remain in `VK_COLOR_ATTACHMENT_OPTIMAL` after all shader passes. The caller must transition /// the output image to the final layout. + /// + /// This function returns an [`FrameIntermediates`](crate::filter_chain::FrameIntermediates) struct, + /// which contains intermediate ImageViews. These may be disposed by calling + /// [`FrameIntermediates::dispose`](crate::filter_chain::FrameIntermediates::dispose), + /// only after they are no longer in use by the GPU, after queue submission. pub fn frame( &mut self, count: usize, viewport: &Viewport, input: &VulkanImage, cmd: vk::CommandBuffer, - _options: Option<()>, - ) -> error::Result { + options: Option, + ) -> error::Result { // limit number of passes to those enabled. let passes = &mut self.passes[0..self.common.config.passes_enabled]; - let mut intermediates = FilterChainFrameIntermediates::new(&self.vulkan.device); + if let Some(options) = &options { + if options.clear_history { + for history in &mut self.history_framebuffers { + history.clear(cmd); + } + } + } + + let mut intermediates = FrameIntermediates::new(&self.vulkan.device); if passes.is_empty() { return Ok(intermediates); } @@ -666,10 +674,10 @@ impl FilterChainVulkan { let passes_len = passes.len(); let (pass, last) = passes.split_at_mut(passes_len - 1); + let frame_direction = options.map(|f| f.frame_direction).unwrap_or(1); + for (index, pass) in pass.iter_mut().enumerate() { let target = &self.output_framebuffers[index]; - - // todo: use proper mode let out = RenderTarget { x: 0.0, y: 0.0, @@ -686,14 +694,14 @@ impl FilterChainVulkan { } else { count } as u32, - 0, + frame_direction, viewport, &original, &source, &out, )?; - if target.max_miplevels > 1 { + if target.max_miplevels > 1 && !self.disable_mipmaps { target.generate_mipmaps_and_end_pass(cmd); } else { out.output.end_pass(cmd); diff --git a/librashader-runtime-vk/src/hello_triangle/mod.rs b/librashader-runtime-vk/src/hello_triangle/mod.rs index cb3a343..e24b680 100644 --- a/librashader-runtime-vk/src/hello_triangle/mod.rs +++ b/librashader-runtime-vk/src/hello_triangle/mod.rs @@ -339,7 +339,7 @@ impl VulkanWindow { .unwrap(); vulkan.base.device.device_wait_idle().unwrap(); - drop(intermediates) + intermediates.dispose(); } } } diff --git a/librashader-runtime-vk/src/lib.rs b/librashader-runtime-vk/src/lib.rs index dcdc8ca..fd65d3f 100644 --- a/librashader-runtime-vk/src/lib.rs +++ b/librashader-runtime-vk/src/lib.rs @@ -20,7 +20,7 @@ mod viewport; mod vulkan_primitives; mod vulkan_state; -pub use filter_chain::FilterChainFrameIntermediates; +pub use filter_chain::FrameIntermediates; pub use filter_chain::FilterChainVulkan; pub use filter_chain::Vulkan; pub use filter_chain::VulkanInfo; diff --git a/librashader-runtime-vk/src/options.rs b/librashader-runtime-vk/src/options.rs index 8b13789..aaec1fb 100644 --- a/librashader-runtime-vk/src/options.rs +++ b/librashader-runtime-vk/src/options.rs @@ -1 +1,18 @@ +/// Options for each Vulkan shader frame. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct FrameOptionsVulkan { + /// Whether or not to clear the history buffers. + pub clear_history: bool, + /// The direction of the frame. 1 should be vertical. + pub frame_direction: i32, +} + +/// Options for filter chain creation. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct FilterChainOptionsVulkan { + /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. + pub force_no_mipmaps: bool, +} diff --git a/librashader-runtime-vk/src/vulkan_state.rs b/librashader-runtime-vk/src/vulkan_state.rs index d25e7be..701a62c 100644 --- a/librashader-runtime-vk/src/vulkan_state.rs +++ b/librashader-runtime-vk/src/vulkan_state.rs @@ -60,10 +60,6 @@ impl PipelineDescriptors { } } - pub fn binding_count(&self) -> usize { - self.layout_bindings.len() - } - pub fn bindings(&self) -> &[vk::DescriptorSetLayoutBinding] { self.layout_bindings.as_ref() }