rt: abstract framebuffer scaling into common code
This commit is contained in:
parent
5ffcf005a0
commit
c8a1d4d196
|
@ -25,7 +25,9 @@ use crate::util::d3d11_compile_bound_shader;
|
|||
use crate::{error, util, D3D11OutputView};
|
||||
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
|
||||
use librashader_runtime::binding::{BindingUtil, TextureInput};
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use librashader_runtime::quad::{QuadType, IDENTITY_MVP};
|
||||
use librashader_runtime::scaling::{scale_framebuffers, scale_framebuffers_with_context_callback};
|
||||
use librashader_runtime::uniforms::UniformStorage;
|
||||
use rayon::prelude::*;
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
|
@ -445,33 +447,15 @@ impl FilterChainD3D11 {
|
|||
};
|
||||
|
||||
let mut source = original.clone();
|
||||
let mut iterator = passes.iter_mut().enumerate().peekable();
|
||||
|
||||
// rescale render buffers to ensure all bindings are valid.
|
||||
let mut source_size = source.size();
|
||||
while let Some((index, pass)) = iterator.next() {
|
||||
let should_mipmap = iterator
|
||||
.peek()
|
||||
.map_or(false, |(_, p)| p.config.mipmap_input);
|
||||
|
||||
let next_size = self.output_framebuffers[index].scale(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
&viewport.output.size,
|
||||
&source_size,
|
||||
should_mipmap,
|
||||
)?;
|
||||
|
||||
self.feedback_framebuffers[index].scale(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
&viewport.output.size,
|
||||
&source_size,
|
||||
should_mipmap,
|
||||
)?;
|
||||
|
||||
source_size = next_size;
|
||||
}
|
||||
scale_framebuffers::<(), _, _, _>(
|
||||
source.size(),
|
||||
viewport.output.size,
|
||||
&mut self.output_framebuffers,
|
||||
&mut self.feedback_framebuffers,
|
||||
&passes,
|
||||
)?;
|
||||
|
||||
let passes_len = passes.len();
|
||||
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
||||
|
|
|
@ -10,6 +10,7 @@ use librashader_reflect::reflect::ShaderReflection;
|
|||
use rustc_hash::FxHashMap;
|
||||
|
||||
use librashader_runtime::binding::{BindSemantics, TextureInput};
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use librashader_runtime::quad::QuadType;
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
ID3D11Buffer, ID3D11InputLayout, ID3D11PixelShader, ID3D11SamplerState,
|
||||
|
@ -80,19 +81,18 @@ impl BindSemantics for FilterPass {
|
|||
}
|
||||
}
|
||||
|
||||
// slang_process.cpp 229
|
||||
impl FilterPass {
|
||||
pub fn get_format(&self) -> ImageFormat {
|
||||
let 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
|
||||
}
|
||||
impl FilterPassMeta for FilterPass {
|
||||
fn source_format(&self) -> ImageFormat {
|
||||
self.source.format
|
||||
}
|
||||
|
||||
fn config(&self) -> &ShaderPassConfig {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
// slang_process.cpp 229
|
||||
impl FilterPass {
|
||||
// framecount should be pre-modded
|
||||
fn build_semantics<'a>(
|
||||
&mut self,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::error;
|
||||
use crate::error::assume_d3d11_init;
|
||||
use crate::error::{assume_d3d11_init, FilterChainError};
|
||||
use crate::texture::D3D11InputView;
|
||||
use crate::util::d3d11_get_closest_format;
|
||||
use librashader_common::{ImageFormat, Size};
|
||||
use librashader_presets::Scale2D;
|
||||
use librashader_runtime::scaling::{MipmapSize, ViewportSize};
|
||||
use librashader_runtime::scaling::{MipmapSize, ScaleableFramebuffer, ViewportSize};
|
||||
use windows::core::Interface;
|
||||
use windows::Win32::Graphics::Direct3D::D3D_SRV_DIMENSION_TEXTURE2D;
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
|
@ -251,3 +251,20 @@ pub const fn default_viewport(size: Size<u32>) -> D3D11_VIEWPORT {
|
|||
MaxDepth: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ScaleableFramebuffer<T> for OwnedFramebuffer {
|
||||
type Error = FilterChainError;
|
||||
type Context = ();
|
||||
|
||||
fn scale(
|
||||
&mut self,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
should_mipmap: bool,
|
||||
_context: Self::Context,
|
||||
) -> Result<Size<u32>, Self::Error> {
|
||||
self.scale(scaling, format, viewport_size, source_size, should_mipmap)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ mod tests {
|
|||
// "../test/null.slangp",
|
||||
// const FILTER_PATH: &str = "../test/slang-shaders/scalefx/scalefx-9x.slangp";
|
||||
|
||||
const FILTER_PATH: &str = "../test/slang-shaders/crt/zfast-crt.slangp";
|
||||
const FILTER_PATH: &str = "../test/slang-shaders/crt/crt-royale.slangp";
|
||||
const IMAGE_PATH: &str = "../test/finalfightlong.png";
|
||||
// #[test]
|
||||
// fn triangle_d3d11_args() {
|
||||
|
|
|
@ -46,7 +46,8 @@ use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_UNKNOWN;
|
|||
use windows::Win32::System::Threading::{CreateEventA, ResetEvent, WaitForSingleObject};
|
||||
use windows::Win32::System::WindowsProgramming::INFINITE;
|
||||
|
||||
use librashader_runtime::scaling::MipmapSize;
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use librashader_runtime::scaling::{scale_framebuffers_with_context_callback, MipmapSize};
|
||||
use rayon::prelude::*;
|
||||
|
||||
const MIPMAP_RESERVED_WORKHEAP_DESCRIPTORS: usize = 1024;
|
||||
|
@ -593,46 +594,29 @@ impl FilterChainD3D12 {
|
|||
);
|
||||
|
||||
// rescale render buffers to ensure all bindings are valid.
|
||||
let mut source_size = source.size();
|
||||
let mut iterator = passes.iter_mut().enumerate().peekable();
|
||||
while let Some((index, pass)) = iterator.next() {
|
||||
let should_mipmap = iterator
|
||||
.peek()
|
||||
.map_or(false, |(_, p)| p.config.mipmap_input);
|
||||
|
||||
let next_size = self.output_framebuffers[index].scale(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
&viewport.output.size,
|
||||
&source_size,
|
||||
should_mipmap,
|
||||
)?;
|
||||
|
||||
self.feedback_framebuffers[index].scale(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
&viewport.output.size,
|
||||
&source_size,
|
||||
should_mipmap,
|
||||
)?;
|
||||
|
||||
source_size = next_size;
|
||||
|
||||
// refresh inputs
|
||||
self.common.feedback_textures[index] = Some(
|
||||
self.feedback_framebuffers[index].create_shader_resource_view(
|
||||
&mut self.staging_heap,
|
||||
pass.config.filter,
|
||||
pass.config.wrap_mode,
|
||||
)?,
|
||||
);
|
||||
self.common.output_textures[index] =
|
||||
Some(self.output_framebuffers[index].create_shader_resource_view(
|
||||
scale_framebuffers_with_context_callback::<(), _, _, _, _>(
|
||||
source.size(),
|
||||
viewport.output.size,
|
||||
&mut self.output_framebuffers,
|
||||
&mut self.feedback_framebuffers,
|
||||
&passes,
|
||||
(),
|
||||
|index: usize, pass: &FilterPass, output: &OwnedImage, feedback: &OwnedImage| {
|
||||
// refresh inputs
|
||||
self.common.feedback_textures[index] = Some(feedback.create_shader_resource_view(
|
||||
&mut self.staging_heap,
|
||||
pass.config.filter,
|
||||
pass.config.wrap_mode,
|
||||
)?);
|
||||
}
|
||||
self.common.output_textures[index] = Some(output.create_shader_resource_view(
|
||||
&mut self.staging_heap,
|
||||
pass.config.filter,
|
||||
pass.config.wrap_mode,
|
||||
)?);
|
||||
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
let passes_len = passes.len();
|
||||
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
||||
|
|
|
@ -12,6 +12,7 @@ use librashader_presets::ShaderPassConfig;
|
|||
use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, UniformBinding};
|
||||
use librashader_reflect::reflect::ShaderReflection;
|
||||
use librashader_runtime::binding::{BindSemantics, TextureInput};
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use librashader_runtime::quad::QuadType;
|
||||
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
@ -74,18 +75,17 @@ impl BindSemantics<NoUniformBinder, Option<()>, RawD3D12Buffer, RawD3D12Buffer>
|
|||
}
|
||||
}
|
||||
|
||||
impl FilterPass {
|
||||
pub fn get_format(&self) -> ImageFormat {
|
||||
let 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
|
||||
}
|
||||
impl FilterPassMeta for FilterPass {
|
||||
fn source_format(&self) -> ImageFormat {
|
||||
self.source.format
|
||||
}
|
||||
|
||||
fn config(&self) -> &ShaderPassConfig {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterPass {
|
||||
// framecount should be pre-modded
|
||||
fn build_semantics<'a>(
|
||||
&mut self,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap, RenderTargetHeap};
|
||||
use crate::error::assume_d3d12_init;
|
||||
use crate::error::{assume_d3d12_init, FilterChainError};
|
||||
use crate::texture::{D3D12OutputView, InputTexture};
|
||||
use crate::util::d3d12_get_closest_format;
|
||||
use crate::{error, util};
|
||||
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
||||
use librashader_presets::Scale2D;
|
||||
use librashader_runtime::scaling::{MipmapSize, ViewportSize};
|
||||
use librashader_runtime::scaling::{MipmapSize, ScaleableFramebuffer, ViewportSize};
|
||||
use std::ops::Deref;
|
||||
use windows::Win32::Foundation::RECT;
|
||||
use windows::Win32::Graphics::Direct3D12::{
|
||||
|
@ -305,3 +305,20 @@ impl OwnedImage {
|
|||
Ok(size)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ScaleableFramebuffer<T> for OwnedImage {
|
||||
type Error = FilterChainError;
|
||||
type Context = ();
|
||||
|
||||
fn scale(
|
||||
&mut self,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
should_mipmap: bool,
|
||||
_context: Self::Context,
|
||||
) -> Result<Size<u32>, Self::Error> {
|
||||
self.scale(scaling, format, viewport_size, source_size, should_mipmap)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ use librashader_reflect::reflect::semantics::{BindingMeta, ShaderSemantics, Unif
|
|||
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
|
||||
use librashader_reflect::reflect::ReflectShader;
|
||||
use librashader_runtime::binding::BindingUtil;
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use librashader_runtime::scaling::scale_framebuffers;
|
||||
use rustc_hash::FxHashMap;
|
||||
use spirv_cross::spirv::Decoration;
|
||||
use std::collections::VecDeque;
|
||||
|
@ -378,32 +380,14 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
|||
|
||||
let mut source = original;
|
||||
|
||||
let mut source_size = source.image.size;
|
||||
// rescale render buffers to ensure all bindings are valid.
|
||||
let mut iterator = passes.iter_mut().enumerate().peekable();
|
||||
while let Some((index, pass)) = iterator.next() {
|
||||
let should_mipmap = iterator
|
||||
.peek()
|
||||
.map_or(false, |(_, p)| p.config.mipmap_input);
|
||||
|
||||
let next_size = self.output_framebuffers[index].scale::<T::FramebufferInterface>(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
viewport,
|
||||
&source_size,
|
||||
should_mipmap,
|
||||
)?;
|
||||
|
||||
self.feedback_framebuffers[index].scale::<T::FramebufferInterface>(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
viewport,
|
||||
&source_size,
|
||||
should_mipmap,
|
||||
)?;
|
||||
|
||||
source_size = next_size
|
||||
}
|
||||
scale_framebuffers::<T::FramebufferInterface, _, _, _>(
|
||||
source.image.size,
|
||||
viewport.output.size,
|
||||
&mut self.output_framebuffers,
|
||||
&mut self.feedback_framebuffers,
|
||||
&passes,
|
||||
)?;
|
||||
|
||||
let passes_len = passes.len();
|
||||
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
||||
|
|
|
@ -8,6 +8,7 @@ use librashader_preprocess::ShaderSource;
|
|||
use librashader_presets::ShaderPassConfig;
|
||||
use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, UniformBinding};
|
||||
use librashader_runtime::binding::{BindSemantics, ContextOffset, TextureInput};
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::binding::{GlUniformBinder, GlUniformStorage, UniformLocation, VariableLocation};
|
||||
|
@ -147,18 +148,17 @@ impl<T: GLInterface> FilterPass<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: GLInterface> FilterPass<T> {
|
||||
pub fn get_format(&self) -> ImageFormat {
|
||||
let 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
|
||||
}
|
||||
impl<T: GLInterface> FilterPassMeta for FilterPass<T> {
|
||||
fn source_format(&self) -> ImageFormat {
|
||||
self.source.format
|
||||
}
|
||||
|
||||
fn config(&self) -> &ShaderPassConfig {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: GLInterface> FilterPass<T> {
|
||||
// framecount should be pre-modded
|
||||
fn build_semantics(
|
||||
&mut self,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::error::Result;
|
||||
use crate::error::{FilterChainError, Result};
|
||||
use crate::framebuffer::GLImage;
|
||||
use crate::gl::FramebufferInterface;
|
||||
use crate::texture::InputTexture;
|
||||
use gl::types::{GLenum, GLuint};
|
||||
use librashader_common::{FilterMode, ImageFormat, Size, Viewport, WrapMode};
|
||||
use librashader_presets::Scale2D;
|
||||
use librashader_runtime::scaling::ScaleableFramebuffer;
|
||||
|
||||
/// A handle to an OpenGL FBO and its backing texture with format and size information.
|
||||
///
|
||||
|
@ -50,7 +51,7 @@ impl Framebuffer {
|
|||
&mut self,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport: &Viewport<&Framebuffer>,
|
||||
viewport: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
mipmap: bool,
|
||||
) -> Result<Size<u32>> {
|
||||
|
@ -92,3 +93,20 @@ impl Drop for Framebuffer {
|
|||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
impl<T: FramebufferInterface> ScaleableFramebuffer<T> for Framebuffer {
|
||||
type Error = FilterChainError;
|
||||
type Context = ();
|
||||
|
||||
fn scale(
|
||||
&mut self,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
should_mipmap: bool,
|
||||
_context: Self::Context,
|
||||
) -> Result<Size<u32>> {
|
||||
self.scale::<T>(scaling, format, viewport_size, source_size, should_mipmap)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ impl FramebufferInterface for Gl3Framebuffer {
|
|||
fb: &mut Framebuffer,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport: &Viewport<&Framebuffer>,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
mipmap: bool,
|
||||
) -> Result<Size<u32>> {
|
||||
|
@ -45,7 +45,7 @@ impl FramebufferInterface for Gl3Framebuffer {
|
|||
return Ok(fb.size);
|
||||
}
|
||||
|
||||
let size = source_size.scale_viewport(scaling, viewport.output.size);
|
||||
let size = source_size.scale_viewport(scaling, *viewport_size);
|
||||
|
||||
if fb.size != size || (mipmap && fb.max_levels == 1) || (!mipmap && fb.max_levels != 1) {
|
||||
fb.size = size;
|
||||
|
|
|
@ -35,7 +35,7 @@ impl FramebufferInterface for Gl46Framebuffer {
|
|||
fb: &mut Framebuffer,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport: &Viewport<&Framebuffer>,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
mipmap: bool,
|
||||
) -> Result<Size<u32>> {
|
||||
|
@ -43,7 +43,7 @@ impl FramebufferInterface for Gl46Framebuffer {
|
|||
return Ok(fb.size);
|
||||
}
|
||||
|
||||
let size = source_size.scale_viewport(scaling, viewport.output.size);
|
||||
let size = source_size.scale_viewport(scaling, *viewport_size);
|
||||
|
||||
if fb.size != size || (mipmap && fb.max_levels == 1) || (!mipmap && fb.max_levels != 1) {
|
||||
fb.size = size;
|
||||
|
|
|
@ -41,7 +41,7 @@ pub trait FramebufferInterface {
|
|||
fb: &mut Framebuffer,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport: &Viewport<&Framebuffer>,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
mipmap: bool,
|
||||
) -> Result<Size<u32>>;
|
||||
|
|
|
@ -31,7 +31,10 @@ use std::collections::VecDeque;
|
|||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use librashader_runtime::scaling::scale_framebuffers_with_context_callback;
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// A Vulkan device and metadata that is required by the shader runtime.
|
||||
pub struct VulkanObjects {
|
||||
pub(crate) device: Arc<ash::Device>,
|
||||
|
@ -613,59 +616,28 @@ impl FilterChainVulkan {
|
|||
);
|
||||
|
||||
// rescale render buffers to ensure all bindings are valid.
|
||||
let mut source_size = source.image.size;
|
||||
let mut iterator = passes.iter_mut().enumerate().peekable();
|
||||
while let Some((index, pass)) = iterator.next() {
|
||||
let should_mipmap = iterator
|
||||
.peek()
|
||||
.map_or(false, |(_, p)| p.config.mipmap_input);
|
||||
|
||||
// needs a barrier to SHADER_READ_ONLY_OPTIMAL otherwise any non-filled in output framebuffers
|
||||
// (like the final one which is just held there and not ever written to, but needs to be
|
||||
// there for indexing) will always stay in UNDEFINED.
|
||||
//
|
||||
// since scaling is hopefully a rare occurrence (since it's tested for if the output size
|
||||
// requires changing) it should be ok.
|
||||
let next_size = self.output_framebuffers[index].scale(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
&viewport.output.size,
|
||||
&source_size,
|
||||
should_mipmap,
|
||||
Some(OwnedImageLayout {
|
||||
dst_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||
dst_access: vk::AccessFlags::SHADER_READ,
|
||||
src_stage: vk::PipelineStageFlags::TOP_OF_PIPE,
|
||||
dst_stage: vk::PipelineStageFlags::FRAGMENT_SHADER,
|
||||
cmd,
|
||||
}),
|
||||
)?;
|
||||
|
||||
self.feedback_framebuffers[index].scale(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
&viewport.output.size,
|
||||
&source_size,
|
||||
should_mipmap,
|
||||
Some(OwnedImageLayout {
|
||||
dst_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||
dst_access: vk::AccessFlags::SHADER_READ,
|
||||
src_stage: vk::PipelineStageFlags::TOP_OF_PIPE,
|
||||
dst_stage: vk::PipelineStageFlags::FRAGMENT_SHADER,
|
||||
cmd,
|
||||
}),
|
||||
)?;
|
||||
|
||||
source_size = next_size;
|
||||
// refresh inputs
|
||||
self.common.feedback_inputs[index] = Some(
|
||||
self.feedback_framebuffers[index]
|
||||
.as_input(pass.config.filter, pass.config.wrap_mode),
|
||||
);
|
||||
self.common.output_inputs[index] = Some(
|
||||
self.output_framebuffers[index].as_input(pass.config.filter, pass.config.wrap_mode),
|
||||
);
|
||||
}
|
||||
scale_framebuffers_with_context_callback::<(), _, _, _, _>(
|
||||
source.image.size,
|
||||
viewport.output.size,
|
||||
&mut self.output_framebuffers,
|
||||
&mut self.feedback_framebuffers,
|
||||
&passes,
|
||||
Some(OwnedImageLayout {
|
||||
dst_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||
dst_access: vk::AccessFlags::SHADER_READ,
|
||||
src_stage: vk::PipelineStageFlags::TOP_OF_PIPE,
|
||||
dst_stage: vk::PipelineStageFlags::FRAGMENT_SHADER,
|
||||
cmd,
|
||||
}),
|
||||
|index: usize, pass: &FilterPass, output: &OwnedImage, feedback: &OwnedImage| {
|
||||
// refresh inputs
|
||||
self.common.feedback_inputs[index] =
|
||||
Some(feedback.as_input(pass.config.filter, pass.config.wrap_mode));
|
||||
self.common.output_inputs[index] =
|
||||
Some(output.as_input(pass.config.filter, pass.config.wrap_mode));
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
let passes_len = passes.len();
|
||||
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
||||
|
|
|
@ -14,6 +14,7 @@ use librashader_reflect::reflect::semantics::{
|
|||
};
|
||||
use librashader_reflect::reflect::ShaderReflection;
|
||||
use librashader_runtime::binding::{BindSemantics, TextureInput};
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use librashader_runtime::quad::QuadType;
|
||||
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage, UniformStorageAccess};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
@ -73,18 +74,17 @@ impl BindSemantics<NoUniformBinder, Option<()>, RawVulkanBuffer> for FilterPass
|
|||
}
|
||||
}
|
||||
|
||||
impl FilterPass {
|
||||
pub fn get_format(&self) -> ImageFormat {
|
||||
let 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
|
||||
}
|
||||
impl FilterPassMeta for FilterPass {
|
||||
fn source_format(&self) -> ImageFormat {
|
||||
self.source.format
|
||||
}
|
||||
|
||||
fn config(&self) -> &ShaderPassConfig {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterPass {
|
||||
pub(crate) fn draw(
|
||||
&mut self,
|
||||
cmd: vk::CommandBuffer,
|
||||
|
|
|
@ -45,7 +45,7 @@ mod tests {
|
|||
dbg!("finished");
|
||||
let filter = FilterChainVulkan::load_from_path(
|
||||
&base,
|
||||
"../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
|
||||
"../test/slang-shaders/crt/crt-royale.slangp",
|
||||
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__2__ADV-NO-REFLECT.slangp",
|
||||
// "../test/basic.slangp",
|
||||
Some(&FilterChainOptionsVulkan {
|
||||
|
|
|
@ -5,9 +5,10 @@ use crate::{error, util};
|
|||
use ash::vk;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::error::FilterChainError;
|
||||
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
||||
use librashader_presets::Scale2D;
|
||||
use librashader_runtime::scaling::{MipmapSize, ViewportSize};
|
||||
use librashader_runtime::scaling::{MipmapSize, ScaleableFramebuffer, ViewportSize};
|
||||
|
||||
pub struct OwnedImage {
|
||||
pub device: Arc<ash::Device>,
|
||||
|
@ -19,6 +20,7 @@ pub struct OwnedImage {
|
|||
pub levels: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct OwnedImageLayout {
|
||||
pub(crate) dst_layout: vk::ImageLayout,
|
||||
pub(crate) dst_access: vk::AccessFlags,
|
||||
|
@ -533,3 +535,27 @@ impl AsRef<InputImage> for InputImage {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ScaleableFramebuffer<T> for OwnedImage {
|
||||
type Error = FilterChainError;
|
||||
type Context = Option<OwnedImageLayout>;
|
||||
|
||||
fn scale(
|
||||
&mut self,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
should_mipmap: bool,
|
||||
context: Self::Context,
|
||||
) -> Result<Size<u32>, Self::Error> {
|
||||
self.scale(
|
||||
scaling,
|
||||
format,
|
||||
viewport_size,
|
||||
source_size,
|
||||
should_mipmap,
|
||||
context,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
18
librashader-runtime/src/filter_pass.rs
Normal file
18
librashader-runtime/src/filter_pass.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use librashader_common::ImageFormat;
|
||||
use librashader_presets::ShaderPassConfig;
|
||||
|
||||
pub trait FilterPassMeta {
|
||||
fn source_format(&self) -> ImageFormat;
|
||||
fn config(&self) -> &ShaderPassConfig;
|
||||
|
||||
fn get_format(&self) -> ImageFormat {
|
||||
let 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,3 +28,5 @@ pub mod binding;
|
|||
|
||||
/// VBO helper utilities
|
||||
pub mod quad;
|
||||
|
||||
pub mod filter_pass;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::filter_pass::FilterPassMeta;
|
||||
use crate::scaling;
|
||||
use librashader_common::Size;
|
||||
use librashader_common::{ImageFormat, Size};
|
||||
use librashader_presets::{Scale2D, ScaleFactor, ScaleType, Scaling};
|
||||
use num_traits::AsPrimitive;
|
||||
use std::ops::Mul;
|
||||
|
@ -93,3 +94,92 @@ where
|
|||
height: height.round().as_(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for owned framebuffer objects that can be scaled.
|
||||
pub trait ScaleableFramebuffer<T> {
|
||||
type Error;
|
||||
type Context: Copy;
|
||||
/// Scale the framebuffer according to the provided parameters, returning the new size.
|
||||
fn scale(
|
||||
&mut self,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
should_mipmap: bool,
|
||||
context: Self::Context,
|
||||
) -> Result<Size<u32>, Self::Error>;
|
||||
}
|
||||
|
||||
/// Scale framebuffers according to the pass configs, source and viewport size.
|
||||
pub fn scale_framebuffers<T, F, E, P>(
|
||||
source_size: Size<u32>,
|
||||
viewport_size: Size<u32>,
|
||||
output: &mut [F],
|
||||
feedback: &mut [F],
|
||||
passes: &[P],
|
||||
) -> Result<(), E>
|
||||
where
|
||||
F: ScaleableFramebuffer<T, Context = (), Error = E>,
|
||||
P: FilterPassMeta,
|
||||
{
|
||||
scale_framebuffers_with_context_callback(
|
||||
source_size,
|
||||
viewport_size,
|
||||
output,
|
||||
feedback,
|
||||
passes,
|
||||
(),
|
||||
|_, _, _, _| Ok(()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Scale framebuffers according to the pass configs, source and viewport size
|
||||
/// passing a context into the scale function and a callback for each framebuffer rescale.
|
||||
pub fn scale_framebuffers_with_context_callback<T, F, E, C, P>(
|
||||
source_size: Size<u32>,
|
||||
viewport_size: Size<u32>,
|
||||
output: &mut [F],
|
||||
feedback: &mut [F],
|
||||
passes: &[P],
|
||||
context: C,
|
||||
mut callback: impl FnMut(usize, &P, &F, &F) -> Result<(), E>,
|
||||
) -> Result<(), E>
|
||||
where
|
||||
F: ScaleableFramebuffer<T, Context = C, Error = E>,
|
||||
C: Copy,
|
||||
P: FilterPassMeta,
|
||||
{
|
||||
assert_eq!(output.len(), feedback.len());
|
||||
let mut iterator = passes.iter().enumerate().peekable();
|
||||
let mut target_size = source_size;
|
||||
while let Some((index, pass)) = iterator.next() {
|
||||
let should_mipmap = iterator
|
||||
.peek()
|
||||
.map_or(false, |(_, p)| p.config().mipmap_input);
|
||||
|
||||
let next_size = output[index].scale(
|
||||
pass.config().scaling.clone(),
|
||||
pass.get_format(),
|
||||
&viewport_size,
|
||||
&target_size,
|
||||
should_mipmap,
|
||||
context,
|
||||
)?;
|
||||
|
||||
feedback[index].scale(
|
||||
pass.config().scaling.clone(),
|
||||
pass.get_format(),
|
||||
&viewport_size,
|
||||
&target_size,
|
||||
should_mipmap,
|
||||
context,
|
||||
)?;
|
||||
|
||||
target_size = next_size;
|
||||
|
||||
callback(index, &pass, &output[index], &feedback[index])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue