vk: fix image format conversions

This commit is contained in:
chyyran 2023-01-11 17:28:09 -05:00
parent ace6774a15
commit 02b3b8baff
7 changed files with 140 additions and 86 deletions

View file

@ -1,5 +1,5 @@
use crate::error::ParsePresetError; use crate::error::ParsePresetError;
use librashader_common::{FilterMode, WrapMode}; use librashader_common::{FilterMode, ImageFormat, WrapMode};
use std::ops::Mul; use std::ops::Mul;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
@ -29,6 +29,19 @@ pub struct ShaderPassConfig {
pub scaling: Scale2D, 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<ImageFormat> {
if self.srgb_framebuffer {
return Some(ImageFormat::R8G8B8A8Srgb)
} else if self.float_framebuffer {
return Some(ImageFormat::R16G16B16A16Sfloat)
}
return None
}
}
#[repr(i32)] #[repr(i32)]
#[derive(Default, Copy, Clone, Debug)] #[derive(Default, Copy, Clone, Debug)]
/// The scaling type for the shader pass. /// The scaling type for the shader pass.

View file

@ -54,14 +54,15 @@ const NULL_TEXTURES: &[Option<ID3D11ShaderResourceView>; 16] = &[
// slang_process.cpp 229 // slang_process.cpp 229
impl FilterPass { impl FilterPass {
pub fn get_format(&self) -> ImageFormat { pub fn get_format(&self) -> ImageFormat {
let mut fb_format = ImageFormat::R8G8B8A8Unorm; let mut fb_format = self.source.format;
if self.config.srgb_framebuffer { if let Some(format) = self.config.get_format_override() {
fb_format = ImageFormat::R8G8B8A8Srgb; format
} else if self.config.float_framebuffer { } else if fb_format == ImageFormat::Unknown {
fb_format = ImageFormat::R16G16B16A16Sfloat; ImageFormat::R8G8B8A8Unorm
} } else {
fb_format fb_format
} }
}
fn bind_texture( fn bind_texture(
samplers: &SamplerSet, samplers: &SamplerSet,

View file

@ -104,14 +104,15 @@ impl<T: GLInterface> FilterPass<T> {
impl<T: GLInterface> FilterPass<T> { impl<T: GLInterface> FilterPass<T> {
pub fn get_format(&self) -> ImageFormat { pub fn get_format(&self) -> ImageFormat {
let mut fb_format = ImageFormat::R8G8B8A8Unorm; let mut fb_format = self.source.format;
if self.config.srgb_framebuffer { if let Some(format) = self.config.get_format_override() {
fb_format = ImageFormat::R8G8B8A8Srgb; format
} else if self.config.float_framebuffer { } else if fb_format == ImageFormat::Unknown {
fb_format = ImageFormat::R16G16B16A16Sfloat; ImageFormat::R8G8B8A8Unorm
} } else {
fb_format fb_format
} }
}
// framecount should be pre-modded // framecount should be pre-modded
fn build_semantics( fn build_semantics(

View file

@ -367,6 +367,11 @@ impl FilterChainVulkan {
source.format = ImageFormat::R8G8B8A8Unorm source.format = ImageFormat::R8G8B8A8Unorm
} }
// preset overrides shader
if let Some(format) = config.get_format_override() {
source.format = format;
}
let graphics_pipeline = VulkanGraphicsPipeline::new( let graphics_pipeline = VulkanGraphicsPipeline::new(
&vulkan.device, &vulkan.device,
&vulkan.pipeline_cache, &vulkan.pipeline_cache,
@ -463,6 +468,10 @@ impl FilterChainVulkan {
let passes = &mut self.passes[0..self.common.config.passes_enabled]; let passes = &mut self.passes[0..self.common.config.passes_enabled];
let mut intermediates = FilterChainFrameIntermediates::new(&self.vulkan.device); let mut intermediates = FilterChainFrameIntermediates::new(&self.vulkan.device);
if passes.is_empty() {
return Ok(intermediates);
}
let original_image_view = unsafe { let original_image_view = unsafe {
let create_info = vk::ImageViewCreateInfo::builder() 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]; let target = &self.output_framebuffers[index];
// todo: use proper mode // todo: use proper mode
// todo: the output framebuffers can only be dropped after command queue submission. // todo: the output framebuffers can only be dropped after command queue submission.
@ -519,7 +531,8 @@ impl FilterChainVulkan {
x: 0.0, x: 0.0,
y: 0.0, y: 0.0,
mvp: DEFAULT_MVP, 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)?; 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); out.output.end_pass(cmd);
source = target.as_input(pass.config.filter, pass.config.wrap_mode)?; 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 { if let Some(prev_frame_output) = prev_frame_output {
intermediates.dispose_input(prev_frame_output); intermediates.dispose_input(prev_frame_output);
} }
@ -535,6 +549,28 @@ impl FilterChainVulkan {
intermediates.dispose_outputs(out.output); 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) Ok(intermediates)
} }
} }

View file

@ -58,14 +58,15 @@ impl FilterPass {
} }
pub fn get_format(&self) -> ImageFormat { pub fn get_format(&self) -> ImageFormat {
let mut fb_format = ImageFormat::R8G8B8A8Unorm; let mut fb_format = self.source.format;
if self.config.srgb_framebuffer { if let Some(format) = self.config.get_format_override() {
fb_format = ImageFormat::R8G8B8A8Srgb; format
} else if self.config.float_framebuffer { } else if fb_format == ImageFormat::Unknown {
fb_format = ImageFormat::R16G16B16A16Sfloat; ImageFormat::R8G8B8A8Unorm
} } else {
fb_format fb_format
} }
}
pub(crate) fn draw( pub(crate) fn draw(
&mut self, &mut self,

View file

@ -1,7 +1,7 @@
use crate::{error, util}; use crate::{error, util};
use crate::filter_chain::Vulkan; use crate::filter_chain::Vulkan;
use crate::renderpass::VulkanRenderPass; use crate::renderpass::VulkanRenderPass;
use crate::texture::OwnedTexture; use crate::texture::{OwnedTexture, VulkanImage};
use ash::vk; use ash::vk;
use ash::vk::{ImageAspectFlags, ImageViewType}; use ash::vk::{ImageAspectFlags, ImageViewType};
use librashader_common::Size; use librashader_common::Size;
@ -16,7 +16,8 @@ pub(crate) struct OutputFramebuffer {
} }
impl OutputFramebuffer { impl OutputFramebuffer {
pub fn new(vulkan: &Vulkan, render_pass: &VulkanRenderPass, image: vk::Image, size: Size<u32>) -> error::Result<OutputFramebuffer> { pub fn new(vulkan: &Vulkan, render_pass: &VulkanRenderPass,
image: VulkanImage) -> error::Result<OutputFramebuffer> {
let image_subresource = vk::ImageSubresourceRange::builder() let image_subresource = vk::ImageSubresourceRange::builder()
.base_mip_level(0) .base_mip_level(0)
.base_array_layer(0) .base_array_layer(0)
@ -34,21 +35,22 @@ impl OutputFramebuffer {
let mut view_info = vk::ImageViewCreateInfo::builder() let mut view_info = vk::ImageViewCreateInfo::builder()
.view_type(ImageViewType::TYPE_2D) .view_type(ImageViewType::TYPE_2D)
.format(render_pass.format.into()) .format(image.format)
.image(image.clone()) .image(image.image.clone())
.subresource_range(image_subresource) .subresource_range(image_subresource)
.components(swizzle_components) .components(swizzle_components)
.build(); .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 { let framebuffer = unsafe {
vulkan.device.create_framebuffer( vulkan.device.create_framebuffer(
&vk::FramebufferCreateInfo::builder() &vk::FramebufferCreateInfo::builder()
.render_pass(render_pass.handle) .render_pass(render_pass.handle)
.attachments(&[image_view]) .attachments(&[image_view])
.width(size.width) .width(image.size.width)
.height(size.height) .height(image.size.height)
.layers(1) .layers(1)
.build(), .build(),
None, None,
@ -57,8 +59,8 @@ impl OutputFramebuffer {
Ok(OutputFramebuffer { Ok(OutputFramebuffer {
device: vulkan.device.clone(), device: vulkan.device.clone(),
size, size: image.size,
image, image: image.image,
framebuffer, framebuffer,
image_view, image_view,
}) })

View file

@ -223,67 +223,67 @@ impl VulkanWindow {
}, cmd, None) }, cmd, None)
.unwrap(); .unwrap();
eprintln!("{:x}", framebuffer_image.as_raw()); // eprintln!("{:x}", framebuffer_image.as_raw());
// todo: output image will remove need for ImageLayout::GENERAL // // todo: output image will remove need for ImageLayout::GENERAL
// todo: make `frame` render into swapchain image rather than blit. // // todo: make `frame` render into swapchain image rather than blit.
util::vulkan_image_layout_transition_levels( // util::vulkan_image_layout_transition_levels(
&vulkan.base.device, // &vulkan.base.device,
cmd, // cmd,
framebuffer_image, // framebuffer_image,
1, // 1,
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, // vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
vk::ImageLayout::TRANSFER_SRC_OPTIMAL, // vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
vk::AccessFlags::SHADER_READ, // vk::AccessFlags::SHADER_READ,
vk::AccessFlags::TRANSFER_READ, // vk::AccessFlags::TRANSFER_READ,
vk::PipelineStageFlags::VERTEX_SHADER, // vk::PipelineStageFlags::VERTEX_SHADER,
vk::PipelineStageFlags::TRANSFER, // vk::PipelineStageFlags::TRANSFER,
vk::QUEUE_FAMILY_IGNORED, // vk::QUEUE_FAMILY_IGNORED,
vk::QUEUE_FAMILY_IGNORED, // vk::QUEUE_FAMILY_IGNORED,
); // );
//
let blit_subresource = vk::ImageSubresourceLayers::builder() // let blit_subresource = vk::ImageSubresourceLayers::builder()
.layer_count(1) // .layer_count(1)
.aspect_mask(vk::ImageAspectFlags::COLOR) // .aspect_mask(vk::ImageAspectFlags::COLOR)
.build(); // .build();
//
let src_offsets = [ // let src_offsets = [
vk::Offset3D { x: 0, y: 0, z: 0 }, // vk::Offset3D { x: 0, y: 0, z: 0 },
vk::Offset3D { // vk::Offset3D {
x: vulkan.swapchain.extent.width as i32, // x: vulkan.swapchain.extent.width as i32,
y: vulkan.swapchain.extent.height as i32, // y: vulkan.swapchain.extent.height as i32,
z: 1, // z: 1,
}, // },
]; // ];
//
let dst_offsets = [ // let dst_offsets = [
vk::Offset3D { x: 0, y: 0, z: 0 }, // vk::Offset3D { x: 0, y: 0, z: 0 },
vk::Offset3D { // vk::Offset3D {
x: vulkan.swapchain.extent.width as i32, // x: vulkan.swapchain.extent.width as i32,
y: vulkan.swapchain.extent.height as i32, // y: vulkan.swapchain.extent.height as i32,
z: 1, // z: 1,
}, // },
]; // ];
vulkan.base.device.cmd_blit_image( // vulkan.base.device.cmd_blit_image(
cmd, // cmd,
framebuffer_image, // framebuffer_image,
vk::ImageLayout::TRANSFER_SRC_OPTIMAL, // vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
swapchain_image, // swapchain_image,
vk::ImageLayout::TRANSFER_DST_OPTIMAL, // vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&[vk::ImageBlit { // &[vk::ImageBlit {
src_subresource: blit_subresource, // src_subresource: blit_subresource,
src_offsets, // src_offsets,
dst_subresource: blit_subresource, // dst_subresource: blit_subresource,
dst_offsets, // dst_offsets,
}], // }],
vk::Filter::LINEAR, // vk::Filter::LINEAR,
); // );
util::vulkan_image_layout_transition_levels( util::vulkan_image_layout_transition_levels(
&vulkan.base.device, &vulkan.base.device,
cmd, cmd,
swapchain_image, swapchain_image,
1, 1,
vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
vk::ImageLayout::PRESENT_SRC_KHR, vk::ImageLayout::PRESENT_SRC_KHR,
vk::AccessFlags::empty(), vk::AccessFlags::empty(),
vk::AccessFlags::TRANSFER_READ, vk::AccessFlags::TRANSFER_READ,