From 02b3b8baff006dad70f0827758a0e4a66e257267 Mon Sep 17 00:00:00 2001 From: chyyran Date: Wed, 11 Jan 2023 17:28:09 -0500 Subject: [PATCH] vk: fix image format conversions --- librashader-presets/src/preset.rs | 15 ++- librashader-runtime-d3d11/src/filter_pass.rs | 13 ++- librashader-runtime-gl/src/filter_pass.rs | 13 ++- librashader-runtime-vk/src/filter_chain.rs | 42 ++++++- librashader-runtime-vk/src/filter_pass.rs | 13 ++- librashader-runtime-vk/src/framebuffer.rs | 20 ++-- .../src/hello_triangle/mod.rs | 110 +++++++++--------- 7 files changed, 140 insertions(+), 86 deletions(-) diff --git a/librashader-presets/src/preset.rs b/librashader-presets/src/preset.rs index 4cb7e11..a4a5be6 100644 --- a/librashader-presets/src/preset.rs +++ b/librashader-presets/src/preset.rs @@ -1,5 +1,5 @@ use crate::error::ParsePresetError; -use librashader_common::{FilterMode, WrapMode}; +use librashader_common::{FilterMode, ImageFormat, WrapMode}; use std::ops::Mul; use std::path::PathBuf; use std::str::FromStr; @@ -29,6 +29,19 @@ pub struct ShaderPassConfig { pub scaling: Scale2D, } +impl ShaderPassConfig { + /// If the framebuffer expects a different format than what was defined in the + /// shader source, returns such format. + pub fn get_format_override(&self) -> Option { + if self.srgb_framebuffer { + return Some(ImageFormat::R8G8B8A8Srgb) + } else if self.float_framebuffer { + return Some(ImageFormat::R16G16B16A16Sfloat) + } + return None + } +} + #[repr(i32)] #[derive(Default, Copy, Clone, Debug)] /// The scaling type for the shader pass. diff --git a/librashader-runtime-d3d11/src/filter_pass.rs b/librashader-runtime-d3d11/src/filter_pass.rs index bb21c26..e67edd9 100644 --- a/librashader-runtime-d3d11/src/filter_pass.rs +++ b/librashader-runtime-d3d11/src/filter_pass.rs @@ -54,13 +54,14 @@ const NULL_TEXTURES: &[Option; 16] = &[ // slang_process.cpp 229 impl FilterPass { pub fn get_format(&self) -> ImageFormat { - let mut fb_format = ImageFormat::R8G8B8A8Unorm; - if self.config.srgb_framebuffer { - fb_format = ImageFormat::R8G8B8A8Srgb; - } else if self.config.float_framebuffer { - fb_format = ImageFormat::R16G16B16A16Sfloat; + let mut fb_format = self.source.format; + if let Some(format) = self.config.get_format_override() { + format + } else if fb_format == ImageFormat::Unknown { + ImageFormat::R8G8B8A8Unorm + } else { + fb_format } - fb_format } fn bind_texture( diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 95540e8..b309d04 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -104,13 +104,14 @@ impl FilterPass { impl FilterPass { pub fn get_format(&self) -> ImageFormat { - let mut fb_format = ImageFormat::R8G8B8A8Unorm; - if self.config.srgb_framebuffer { - fb_format = ImageFormat::R8G8B8A8Srgb; - } else if self.config.float_framebuffer { - fb_format = ImageFormat::R16G16B16A16Sfloat; + let mut fb_format = self.source.format; + if let Some(format) = self.config.get_format_override() { + format + } else if fb_format == ImageFormat::Unknown { + ImageFormat::R8G8B8A8Unorm + } else { + fb_format } - fb_format } // framecount should be pre-modded diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index fb4bd19..30d580b 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -367,6 +367,11 @@ impl FilterChainVulkan { source.format = ImageFormat::R8G8B8A8Unorm } + // preset overrides shader + if let Some(format) = config.get_format_override() { + source.format = format; + } + let graphics_pipeline = VulkanGraphicsPipeline::new( &vulkan.device, &vulkan.pipeline_cache, @@ -463,6 +468,10 @@ impl FilterChainVulkan { let passes = &mut self.passes[0..self.common.config.passes_enabled]; let mut intermediates = FilterChainFrameIntermediates::new(&self.vulkan.device); + if passes.is_empty() { + return Ok(intermediates); + } + let original_image_view = unsafe { let create_info = vk::ImageViewCreateInfo::builder() @@ -510,7 +519,10 @@ impl FilterChainVulkan { } - for (index, pass) in passes.iter_mut().enumerate() { + let passes_len = passes.len(); + let (pass, last) = passes.split_at_mut(passes_len - 1); + + for (index, pass) in pass.iter_mut().enumerate() { let target = &self.output_framebuffers[index]; // todo: use proper mode // todo: the output framebuffers can only be dropped after command queue submission. @@ -519,7 +531,8 @@ impl FilterChainVulkan { x: 0.0, y: 0.0, mvp: DEFAULT_MVP, - output: OutputFramebuffer::new(&self.vulkan, &pass.graphics_pipeline.render_pass, target.image.image, target.image.size)?, + output: OutputFramebuffer::new(&self.vulkan, &pass.graphics_pipeline.render_pass, + target.image.clone())?, }; pass.draw(cmd, index, &self.common, count as u32, 0, viewport, &original, &source, &out)?; @@ -527,7 +540,8 @@ impl FilterChainVulkan { out.output.end_pass(cmd); source = target.as_input(pass.config.filter, pass.config.wrap_mode)?; - let prev_frame_output = self.common.output_textures[index].replace(source.clone()); + let prev_frame_output = self.common + .output_textures[index].replace(source.clone()); if let Some(prev_frame_output) = prev_frame_output { intermediates.dispose_input(prev_frame_output); } @@ -535,6 +549,28 @@ impl FilterChainVulkan { intermediates.dispose_outputs(out.output); } + // try to hint the optimizer + assert_eq!(last.len(), 1); + if let Some(pass) = last.iter_mut().next() { + source.filter_mode = pass.config.filter; + source.mip_filter = pass.config.filter; + + let out = RenderTarget { + x: viewport.x, + y: viewport.y, + mvp: viewport.mvp.unwrap_or(DEFAULT_MVP), + output: OutputFramebuffer::new(&self.vulkan, + &pass.graphics_pipeline.render_pass, + viewport.output.clone())?, + }; + + pass.draw(cmd, passes_len - 1, + &self.common, + count as u32, + 0, viewport, &original, &source, &out)?; + + intermediates.dispose_outputs(out.output); + } Ok(intermediates) } } diff --git a/librashader-runtime-vk/src/filter_pass.rs b/librashader-runtime-vk/src/filter_pass.rs index 64ddb84..f75f92b 100644 --- a/librashader-runtime-vk/src/filter_pass.rs +++ b/librashader-runtime-vk/src/filter_pass.rs @@ -58,13 +58,14 @@ impl FilterPass { } pub fn get_format(&self) -> ImageFormat { - let mut fb_format = ImageFormat::R8G8B8A8Unorm; - if self.config.srgb_framebuffer { - fb_format = ImageFormat::R8G8B8A8Srgb; - } else if self.config.float_framebuffer { - fb_format = ImageFormat::R16G16B16A16Sfloat; + let mut fb_format = self.source.format; + if let Some(format) = self.config.get_format_override() { + format + } else if fb_format == ImageFormat::Unknown { + ImageFormat::R8G8B8A8Unorm + } else { + fb_format } - fb_format } pub(crate) fn draw( diff --git a/librashader-runtime-vk/src/framebuffer.rs b/librashader-runtime-vk/src/framebuffer.rs index 178ef43..9c18e43 100644 --- a/librashader-runtime-vk/src/framebuffer.rs +++ b/librashader-runtime-vk/src/framebuffer.rs @@ -1,7 +1,7 @@ use crate::{error, util}; use crate::filter_chain::Vulkan; use crate::renderpass::VulkanRenderPass; -use crate::texture::OwnedTexture; +use crate::texture::{OwnedTexture, VulkanImage}; use ash::vk; use ash::vk::{ImageAspectFlags, ImageViewType}; use librashader_common::Size; @@ -16,7 +16,8 @@ pub(crate) struct OutputFramebuffer { } impl OutputFramebuffer { - pub fn new(vulkan: &Vulkan, render_pass: &VulkanRenderPass, image: vk::Image, size: Size) -> error::Result { + pub fn new(vulkan: &Vulkan, render_pass: &VulkanRenderPass, + image: VulkanImage) -> error::Result { let image_subresource = vk::ImageSubresourceRange::builder() .base_mip_level(0) .base_array_layer(0) @@ -34,21 +35,22 @@ impl OutputFramebuffer { let mut view_info = vk::ImageViewCreateInfo::builder() .view_type(ImageViewType::TYPE_2D) - .format(render_pass.format.into()) - .image(image.clone()) + .format(image.format) + .image(image.image.clone()) .subresource_range(image_subresource) .components(swizzle_components) .build(); - let image_view = unsafe { vulkan.device.create_image_view(&view_info, None)? }; + let image_view = unsafe { vulkan.device.create_image_view( + &view_info, None)? }; let framebuffer = unsafe { vulkan.device.create_framebuffer( &vk::FramebufferCreateInfo::builder() .render_pass(render_pass.handle) .attachments(&[image_view]) - .width(size.width) - .height(size.height) + .width(image.size.width) + .height(image.size.height) .layers(1) .build(), None, @@ -57,8 +59,8 @@ impl OutputFramebuffer { Ok(OutputFramebuffer { device: vulkan.device.clone(), - size, - image, + size: image.size, + image: image.image, framebuffer, image_view, }) diff --git a/librashader-runtime-vk/src/hello_triangle/mod.rs b/librashader-runtime-vk/src/hello_triangle/mod.rs index 9124f5b..309d7c3 100644 --- a/librashader-runtime-vk/src/hello_triangle/mod.rs +++ b/librashader-runtime-vk/src/hello_triangle/mod.rs @@ -223,67 +223,67 @@ impl VulkanWindow { }, cmd, None) .unwrap(); - eprintln!("{:x}", framebuffer_image.as_raw()); - // todo: output image will remove need for ImageLayout::GENERAL - // todo: make `frame` render into swapchain image rather than blit. - util::vulkan_image_layout_transition_levels( - &vulkan.base.device, - cmd, - framebuffer_image, - 1, - vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - vk::AccessFlags::SHADER_READ, - vk::AccessFlags::TRANSFER_READ, - vk::PipelineStageFlags::VERTEX_SHADER, - vk::PipelineStageFlags::TRANSFER, - vk::QUEUE_FAMILY_IGNORED, - vk::QUEUE_FAMILY_IGNORED, - ); - - let blit_subresource = vk::ImageSubresourceLayers::builder() - .layer_count(1) - .aspect_mask(vk::ImageAspectFlags::COLOR) - .build(); - - let src_offsets = [ - vk::Offset3D { x: 0, y: 0, z: 0 }, - vk::Offset3D { - x: vulkan.swapchain.extent.width as i32, - y: vulkan.swapchain.extent.height as i32, - z: 1, - }, - ]; - - let dst_offsets = [ - vk::Offset3D { x: 0, y: 0, z: 0 }, - vk::Offset3D { - x: vulkan.swapchain.extent.width as i32, - y: vulkan.swapchain.extent.height as i32, - z: 1, - }, - ]; - vulkan.base.device.cmd_blit_image( - cmd, - framebuffer_image, - vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - swapchain_image, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - &[vk::ImageBlit { - src_subresource: blit_subresource, - src_offsets, - dst_subresource: blit_subresource, - dst_offsets, - }], - vk::Filter::LINEAR, - ); + // eprintln!("{:x}", framebuffer_image.as_raw()); + // // todo: output image will remove need for ImageLayout::GENERAL + // // todo: make `frame` render into swapchain image rather than blit. + // util::vulkan_image_layout_transition_levels( + // &vulkan.base.device, + // cmd, + // framebuffer_image, + // 1, + // vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + // vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + // vk::AccessFlags::SHADER_READ, + // vk::AccessFlags::TRANSFER_READ, + // vk::PipelineStageFlags::VERTEX_SHADER, + // vk::PipelineStageFlags::TRANSFER, + // vk::QUEUE_FAMILY_IGNORED, + // vk::QUEUE_FAMILY_IGNORED, + // ); + // + // let blit_subresource = vk::ImageSubresourceLayers::builder() + // .layer_count(1) + // .aspect_mask(vk::ImageAspectFlags::COLOR) + // .build(); + // + // let src_offsets = [ + // vk::Offset3D { x: 0, y: 0, z: 0 }, + // vk::Offset3D { + // x: vulkan.swapchain.extent.width as i32, + // y: vulkan.swapchain.extent.height as i32, + // z: 1, + // }, + // ]; + // + // let dst_offsets = [ + // vk::Offset3D { x: 0, y: 0, z: 0 }, + // vk::Offset3D { + // x: vulkan.swapchain.extent.width as i32, + // y: vulkan.swapchain.extent.height as i32, + // z: 1, + // }, + // ]; + // vulkan.base.device.cmd_blit_image( + // cmd, + // framebuffer_image, + // vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + // swapchain_image, + // vk::ImageLayout::TRANSFER_DST_OPTIMAL, + // &[vk::ImageBlit { + // src_subresource: blit_subresource, + // src_offsets, + // dst_subresource: blit_subresource, + // dst_offsets, + // }], + // vk::Filter::LINEAR, + // ); util::vulkan_image_layout_transition_levels( &vulkan.base.device, cmd, swapchain_image, 1, - vk::ImageLayout::TRANSFER_DST_OPTIMAL, + vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, vk::ImageLayout::PRESENT_SRC_KHR, vk::AccessFlags::empty(), vk::AccessFlags::TRANSFER_READ,