From 666588ef0d7036ea566e7802a4247e6cadac84e0 Mon Sep 17 00:00:00 2001 From: chyyran Date: Wed, 11 Sep 2024 23:44:33 -0400 Subject: [PATCH] rt(vk): draw final pass to output targets --- librashader-runtime-d3d11/src/filter_chain.rs | 1 + librashader-runtime-d3d12/tests/triangle.rs | 4 +- librashader-runtime-vk/src/filter_chain.rs | 41 +++++++++--- librashader-runtime-vk/src/filter_pass.rs | 32 +++++++--- .../src/graphics_pipeline.rs | 62 +++++++++++++------ librashader-runtime-vk/src/render_pass.rs | 7 ++- librashader-runtime-vk/tests/triangle.rs | 6 +- 7 files changed, 113 insertions(+), 40 deletions(-) diff --git a/librashader-runtime-d3d11/src/filter_chain.rs b/librashader-runtime-d3d11/src/filter_chain.rs index 7ca2256..f6e4122 100644 --- a/librashader-runtime-d3d11/src/filter_chain.rs +++ b/librashader-runtime-d3d11/src/filter_chain.rs @@ -518,6 +518,7 @@ impl FilterChainD3D11 { QuadType::Final, )?; + pass.draw( &ctx, index, diff --git a/librashader-runtime-d3d12/tests/triangle.rs b/librashader-runtime-d3d12/tests/triangle.rs index db45df4..9bf9b8c 100644 --- a/librashader-runtime-d3d12/tests/triangle.rs +++ b/librashader-runtime-d3d12/tests/triangle.rs @@ -10,9 +10,9 @@ fn triangle_d3d12() { // "../test/basic.slangp", // "../test/shaders_slang/handheld/console-border/gbc-lcd-grid-v2.slangp", // "../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp", - "../test/shaders_slang/test/feedback.slangp", + // "../test/shaders_slang/test/feedback.slangp", // "../test/shaders_slang/test/history.slangp", - // "../test/shaders_slang/crt/crt-royale.slangp", + "../test/shaders_slang/crt/crt-geom-deluxe.slangp", // "../test/slang-shaders/vhs/VHSPro.slangp", &SampleCommandLine { use_warp_device: false, diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index 669d609..3f2e674 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -678,6 +678,7 @@ impl FilterChainVulkan { let residual_fb = pass.draw( cmd, + target.image.format, index, &self.common, pass.config.get_frame_count(frame_count), @@ -687,6 +688,7 @@ impl FilterChainVulkan { &source, &out, QuadType::Offscreen, + false, )?; if target.max_miplevels > 1 && !self.disable_mipmaps { @@ -703,12 +705,12 @@ impl FilterChainVulkan { // try to hint the optimizer assert_eq!(last.len(), 1); if let Some(pass) = last.iter_mut().next() { - if let Some(format) = pass + let index = passes_len - 1; + if pass .graphics_pipeline - .render_pass - .as_ref() - .map(|r| r.format) - && format != viewport.output.format + .render_passes + .get(&viewport.output.format) + .is_none() { // need to recompile pass.graphics_pipeline.recompile(viewport.output.format)?; @@ -718,12 +720,15 @@ impl FilterChainVulkan { source.wrap_mode = pass.config.wrap_mode; source.mip_filter = pass.config.filter; - let output_image = OutputImage::new(&self.vulkan.device, viewport.output.clone())?; + let target = &self.output_framebuffers[index]; + + let output_image = OutputImage::new(&self.vulkan.device, target.image.clone())?; let out = RenderTarget::viewport_with_output(&output_image, viewport); let residual_fb = pass.draw( cmd, - passes_len - 1, + target.image.format, + index, &self.common, pass.config.get_frame_count(frame_count), options, @@ -732,6 +737,28 @@ impl FilterChainVulkan { &source, &out, QuadType::Final, + true, + )?; + out.output.end_pass(&self.vulkan.device, cmd); + intermediates.dispose_outputs(output_image); + intermediates.dispose_framebuffers(residual_fb); + + let output_image = OutputImage::new(&self.vulkan.device, viewport.output.clone())?; + let out = RenderTarget::viewport_with_output(&output_image, viewport); + + let residual_fb = pass.draw( + cmd, + viewport.output.format, + index, + &self.common, + pass.config.get_frame_count(frame_count), + options, + viewport, + &original, + &source, + &out, + QuadType::Final, + false, )?; intermediates.dispose_outputs(output_image); diff --git a/librashader-runtime-vk/src/filter_pass.rs b/librashader-runtime-vk/src/filter_pass.rs index b6499d6..cb3d7f6 100644 --- a/librashader-runtime-vk/src/filter_pass.rs +++ b/librashader-runtime-vk/src/filter_pass.rs @@ -87,6 +87,7 @@ impl FilterPass { pub(crate) fn draw( &mut self, cmd: vk::CommandBuffer, + format: vk::Format, pass_index: usize, parent: &FilterCommon, frame_count: u32, @@ -96,9 +97,15 @@ impl FilterPass { source: &InputImage, output: &RenderTarget, vbo_type: QuadType, + use_alt_descriptors: bool, ) -> error::Result> { - let mut descriptor = self.graphics_pipeline.layout.descriptor_sets - [parent.internal_frame_count % self.frames_in_flight as usize]; + let mut descriptor = if use_alt_descriptors { + self.graphics_pipeline.layout.descriptor_sets_alt + [parent.internal_frame_count % self.frames_in_flight as usize] + } else { + self.graphics_pipeline.layout.descriptor_sets + [parent.internal_frame_count % self.frames_in_flight as usize] + }; self.build_semantics( pass_index, @@ -113,6 +120,15 @@ impl FilterPass { source, ); + let Some(pipeline) = self + .graphics_pipeline + .pipelines + .get(&format) + .or_else(|| self.graphics_pipeline.pipelines.values().next()) + else { + panic!("No available render pipelines found") + }; + if let Some(ubo) = &self.reflection.ubo { self.uniform_storage.inner_ubo().bind_to_descriptor_set( descriptor, @@ -123,14 +139,14 @@ impl FilterPass { output.output.begin_pass(&parent.device, cmd); - let residual = self.graphics_pipeline.begin_rendering(output, cmd)?; + let residual = self + .graphics_pipeline + .begin_rendering(output, format, cmd)?; unsafe { - parent.device.cmd_bind_pipeline( - cmd, - vk::PipelineBindPoint::GRAPHICS, - self.graphics_pipeline.pipeline, - ); + parent + .device + .cmd_bind_pipeline(cmd, vk::PipelineBindPoint::GRAPHICS, *pipeline); parent.device.cmd_bind_descriptor_sets( cmd, diff --git a/librashader-runtime-vk/src/graphics_pipeline.rs b/librashader-runtime-vk/src/graphics_pipeline.rs index 8eeb774..1eefb67 100644 --- a/librashader-runtime-vk/src/graphics_pipeline.rs +++ b/librashader-runtime-vk/src/graphics_pipeline.rs @@ -7,6 +7,7 @@ use crate::render_pass::VulkanRenderPass; use ash::vk::PushConstantRange; use bytemuck::offset_of; use librashader_cache::cache_pipeline; +use librashader_common::map::FastHashMap; use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::reflect::semantics::{BufferReflection, TextureBinding}; use librashader_reflect::reflect::ShaderReflection; @@ -14,6 +15,7 @@ use librashader_runtime::quad::VertexInput; use librashader_runtime::render_target::RenderTarget; use std::ffi::CStr; use std::sync::Arc; + const ENTRY_POINT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"main\0") }; pub struct PipelineDescriptors<'a> { @@ -93,6 +95,8 @@ impl PipelineDescriptors<'_> { pub struct PipelineLayoutObjects { pub layout: vk::PipelineLayout, pub descriptor_sets: Vec, + pub descriptor_sets_alt: Vec, + pub _pool: vk::DescriptorPool, pub _descriptor_set_layout: [vk::DescriptorSetLayout; 1], } @@ -127,7 +131,7 @@ impl PipelineLayoutObjects { let layout = unsafe { device.create_pipeline_layout(&pipeline_create_info, None)? }; let pool_info = vk::DescriptorPoolCreateInfo::default() - .max_sets(replicas) + .max_sets(replicas * 2) .pool_sizes(&descriptors.pool_sizes); let pool = unsafe { device.create_descriptor_pool(&pool_info, None)? }; @@ -145,10 +149,24 @@ impl PipelineLayoutObjects { let descriptor_sets: Vec = descriptor_sets.into_iter().flatten().collect(); + let mut descriptor_sets_alt = Vec::new(); + let alloc_info = vk::DescriptorSetAllocateInfo::default() + .descriptor_pool(pool) + .set_layouts(&descriptor_set_layout); + + for _ in 0..replicas { + let set = unsafe { device.allocate_descriptor_sets(&alloc_info)? }; + descriptor_sets_alt.push(set) + } + + let descriptor_sets_alt: Vec = + descriptor_sets_alt.into_iter().flatten().collect(); + Ok(PipelineLayoutObjects { layout, _descriptor_set_layout: descriptor_set_layout, descriptor_sets, + descriptor_sets_alt, _pool: pool, }) } @@ -179,12 +197,13 @@ impl Drop for VulkanShaderModule { pub struct VulkanGraphicsPipeline { pub layout: PipelineLayoutObjects, - pub pipeline: vk::Pipeline, - pub render_pass: Option, + pub pipelines: FastHashMap, + pub render_passes: FastHashMap>, device: Arc, vertex: VulkanShaderModule, fragment: VulkanShaderModule, cache: vk::PipelineCache, + use_render_pass: bool, } impl VulkanGraphicsPipeline { @@ -315,11 +334,13 @@ impl VulkanGraphicsPipeline { let fragment_module = VulkanShaderModule::new(device, &fragment_info)?; let mut render_pass = None; + let mut use_render_pass = false; if render_pass_format != vk::Format::UNDEFINED { render_pass = Some(VulkanRenderPass::create_render_pass( device, render_pass_format, )?); + use_render_pass = true; } let (pipeline, pipeline_cache) = cache_pipeline( @@ -348,25 +369,32 @@ impl VulkanGraphicsPipeline { bypass_cache, )?; + let mut pipelines = FastHashMap::default(); + let mut render_passes = FastHashMap::default(); + + pipelines.insert(render_pass_format, pipeline); + render_passes.insert(render_pass_format, render_pass); + Ok(VulkanGraphicsPipeline { device: Arc::clone(device), layout: pipeline_layout, - pipeline, - render_pass, + pipelines, + render_passes, vertex: vertex_module, fragment: fragment_module, cache: pipeline_cache, + use_render_pass, }) } pub(crate) fn recompile(&mut self, format: vk::Format) -> error::Result<()> { - let mut new_renderpass = if self.render_pass.is_some() { + let new_renderpass = if self.use_render_pass { Some(VulkanRenderPass::create_render_pass(&self.device, format)?) } else { None }; - let mut new_pipeline = Self::create_pipeline( + let new_pipeline = Self::create_pipeline( &self.device, &self.cache, &self.layout, @@ -375,23 +403,19 @@ impl VulkanGraphicsPipeline { new_renderpass.as_ref(), )?; - std::mem::swap(&mut self.render_pass, &mut new_renderpass); - std::mem::swap(&mut self.pipeline, &mut new_pipeline); + self.render_passes.insert(format, new_renderpass); + self.pipelines.insert(format, new_pipeline); - unsafe { - if new_pipeline != vk::Pipeline::null() { - self.device.destroy_pipeline(new_pipeline, None) - } - } Ok(()) } #[inline(always)] pub(crate) fn begin_rendering( &self, output: &RenderTarget, + format: vk::Format, cmd: vk::CommandBuffer, ) -> error::Result> { - if let Some(render_pass) = &self.render_pass { + if let Some(Some(render_pass)) = &self.render_passes.get(&format) { let attachments = [output.output.image_view]; let framebuffer = unsafe { self.device.create_framebuffer( @@ -452,7 +476,7 @@ impl VulkanGraphicsPipeline { pub(crate) fn end_rendering(&self, cmd: vk::CommandBuffer) { unsafe { - if self.render_pass.is_none() { + if !self.use_render_pass { self.device.cmd_end_rendering(cmd); } else { self.device.cmd_end_render_pass(cmd) @@ -464,8 +488,10 @@ impl VulkanGraphicsPipeline { impl Drop for VulkanGraphicsPipeline { fn drop(&mut self) { unsafe { - if self.pipeline != vk::Pipeline::null() { - self.device.destroy_pipeline(self.pipeline, None) + for (_, pipeline) in self.pipelines.iter_mut() { + if *pipeline != vk::Pipeline::null() { + self.device.destroy_pipeline(*pipeline, None) + } } if self.cache != vk::PipelineCache::null() { diff --git a/librashader-runtime-vk/src/render_pass.rs b/librashader-runtime-vk/src/render_pass.rs index e66ccad..bd154a2 100644 --- a/librashader-runtime-vk/src/render_pass.rs +++ b/librashader-runtime-vk/src/render_pass.rs @@ -6,7 +6,7 @@ use ash::vk::{ pub struct VulkanRenderPass { pub handle: vk::RenderPass, - pub format: vk::Format, + pub _format: vk::Format, } impl VulkanRenderPass { @@ -38,7 +38,10 @@ impl VulkanRenderPass { unsafe { let rp = device.create_render_pass(&renderpass_info, None)?; - Ok(Self { handle: rp, format }) + Ok(Self { + handle: rp, + _format: format, + }) } } } diff --git a/librashader-runtime-vk/tests/triangle.rs b/librashader-runtime-vk/tests/triangle.rs index 0952d86..408385c 100644 --- a/librashader-runtime-vk/tests/triangle.rs +++ b/librashader-runtime-vk/tests/triangle.rs @@ -11,15 +11,15 @@ fn triangle_vk() { unsafe { let filter = FilterChainVulkan::load_from_path( - "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", + "../test/shaders_slang/test/feedback.slangp", + // "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", // "../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp", &base, - // "../test/slang-shaders/test/feedback.slancargogp", // "../test/basic.slangp", Some(&FilterChainOptionsVulkan { frames_in_flight: 3, force_no_mipmaps: false, - use_dynamic_rendering: true, + use_dynamic_rendering: false, disable_cache: true, }), )