rt: fix history framebuffer requirements and unify framebuffer initialization logic

This commit is contained in:
chyyran 2023-02-11 00:20:35 -05:00
parent 115382d8f0
commit 3c15a3a523
25 changed files with 341 additions and 368 deletions

View file

@ -5,7 +5,7 @@ use librashader_presets::{ShaderPreset, TextureConfig};
use librashader_reflect::back::targets::HLSL;
use librashader_reflect::back::{CompileReflectShader, CompileShader};
use librashader_reflect::front::GlslangCompilation;
use librashader_reflect::reflect::semantics::{BindingMeta, ShaderSemantics};
use librashader_reflect::reflect::semantics::ShaderSemantics;
use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::image::{Image, UVDirection};
use rustc_hash::FxHashMap;
@ -16,7 +16,7 @@ use std::path::Path;
use crate::draw_quad::DrawQuad;
use crate::error::{assume_d3d11_init, FilterChainError};
use crate::filter_pass::{ConstantBufferBinding, FilterPass};
use crate::framebuffer::OwnedFramebuffer;
use crate::framebuffer::OwnedImage;
use crate::graphics_pipeline::D3D11State;
use crate::options::{FilterChainOptionsD3D11, FrameOptionsD3D11};
use crate::samplers::SamplerSet;
@ -24,6 +24,7 @@ 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::framebuffer::FramebufferInit;
use librashader_runtime::quad::QuadType;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
@ -49,9 +50,9 @@ type ShaderPassMeta =
pub struct FilterChainD3D11 {
pub(crate) common: FilterCommon,
passes: Vec<FilterPass>,
output_framebuffers: Box<[OwnedFramebuffer]>,
feedback_framebuffers: Box<[OwnedFramebuffer]>,
history_framebuffers: VecDeque<OwnedFramebuffer>,
output_framebuffers: Box<[OwnedImage]>,
feedback_framebuffers: Box<[OwnedImage]>,
history_framebuffers: VecDeque<OwnedImage>,
state: D3D11State,
}
@ -102,45 +103,34 @@ impl FilterChainD3D11 {
let immediate_context = unsafe { device.GetImmediateContext()? };
// initialize output framebuffers
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || {
OwnedFramebuffer::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false)
});
// resolve all results
let output_framebuffers = output_framebuffers
.into_iter()
.collect::<error::Result<Vec<OwnedFramebuffer>>>()?;
let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), || None);
//
// // initialize feedback framebuffers
let mut feedback_framebuffers = Vec::new();
feedback_framebuffers.resize_with(filters.len(), || {
OwnedFramebuffer::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false)
});
// resolve all results
let feedback_framebuffers = feedback_framebuffers
.into_iter()
.collect::<error::Result<Vec<OwnedFramebuffer>>>()?;
let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), || None);
// load luts
let luts = FilterChainD3D11::load_luts(device, &immediate_context, &preset.textures)?;
let (history_framebuffers, history_textures) =
FilterChainD3D11::init_history(device, &filters)?;
let framebuffer_gen =
|| OwnedImage::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false);
let input_gen = || None;
let framebuffer_init = FramebufferInit::new(
filters.iter().map(|f| &f.reflection.meta),
&framebuffer_gen,
&input_gen,
);
// initialize output framebuffers
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
// initialize feedback framebuffers
let (feedback_framebuffers, feedback_textures) =
framebuffer_init.init_output_framebuffers()?;
// initialize history
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
let draw_quad = DrawQuad::new(device)?;
let state = D3D11State::new(device)?;
Ok(FilterChainD3D11 {
passes: filters,
output_framebuffers: output_framebuffers.into_boxed_slice(),
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
output_framebuffers,
feedback_framebuffers,
history_framebuffers,
common: FilterCommon {
d3d11: Direct3D11 {
@ -158,8 +148,8 @@ impl FilterChainD3D11 {
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
luts,
samplers,
output_textures: output_textures.into_boxed_slice(),
feedback_textures: feedback_textures.into_boxed_slice(),
output_textures,
feedback_textures,
history_textures,
draw_quad,
},
@ -283,37 +273,6 @@ impl FilterChainD3D11 {
Ok(filters)
}
fn init_history(
device: &ID3D11Device,
filters: &Vec<FilterPass>,
) -> error::Result<(VecDeque<OwnedFramebuffer>, Box<[Option<InputTexture>]>)> {
let required_images =
BindingMeta::calculate_required_history(filters.iter().map(|f| &f.reflection.meta));
// not using frame history;
if required_images <= 1 {
// println!("[history] not using frame history");
return Ok((VecDeque::new(), Box::new([])));
}
// history0 is aliased with the original
// eprintln!("[history] using frame history with {required_images} images");
let mut framebuffers = VecDeque::with_capacity(required_images);
framebuffers.resize_with(required_images, || {
OwnedFramebuffer::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false)
});
let framebuffers = framebuffers
.into_iter()
.collect::<error::Result<VecDeque<OwnedFramebuffer>>>()?;
let mut history_textures = Vec::new();
history_textures.resize_with(required_images, || None);
Ok((framebuffers, history_textures.into_boxed_slice()))
}
fn push_history(
&mut self,
ctx: &ID3D11DeviceContext,
@ -394,20 +353,6 @@ impl FilterChainD3D11 {
let filter = passes[0].config.filter;
let wrap_mode = passes[0].config.wrap_mode;
for ((texture, fbo), pass) in self
.common
.feedback_textures
.iter_mut()
.zip(self.feedback_framebuffers.iter())
.zip(passes.iter())
{
*texture = Some(InputTexture::from_framebuffer(
fbo,
pass.config.wrap_mode,
pass.config.filter,
)?);
}
for (texture, fbo) in self
.common
.history_textures
@ -426,7 +371,7 @@ impl FilterChainD3D11 {
let mut source = original.clone();
// rescale render buffers to ensure all bindings are valid.
OwnedFramebuffer::scale_framebuffers(
OwnedImage::scale_framebuffers(
source.size(),
viewport.output.size,
&mut self.output_framebuffers,
@ -435,6 +380,22 @@ impl FilterChainD3D11 {
None,
)?;
// Refresh inputs for feedback textures.
// Don't need to do this for outputs because they are yet to be bound.
for ((texture, fbo), pass) in self
.common
.feedback_textures
.iter_mut()
.zip(self.feedback_framebuffers.iter())
.zip(passes.iter())
{
*texture = Some(InputTexture::from_framebuffer(
fbo,
pass.config.wrap_mode,
pass.config.filter,
)?);
}
let passes_len = passes.len();
let (pass, last) = passes.split_at_mut(passes_len - 1);

View file

@ -21,7 +21,7 @@ use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC};
static CLEAR: &[f32; 4] = &[0.0f32, 0.0, 0.0, 0.0];
#[derive(Debug, Clone)]
pub(crate) struct OwnedFramebuffer {
pub(crate) struct OwnedImage {
render: ID3D11Texture2D,
pub(crate) size: Size<u32>,
format: DXGI_FORMAT,
@ -29,13 +29,13 @@ pub(crate) struct OwnedFramebuffer {
max_mipmap: u32,
}
impl OwnedFramebuffer {
impl OwnedImage {
pub fn new(
device: &ID3D11Device,
size: Size<u32>,
format: ImageFormat,
mipmap: bool,
) -> error::Result<OwnedFramebuffer> {
) -> error::Result<OwnedImage> {
unsafe {
let format = d3d11_get_closest_format(
device,
@ -49,7 +49,7 @@ impl OwnedFramebuffer {
device.CreateTexture2D(&desc, None, Some(&mut render))?;
assume_d3d11_init!(render, "CreateTexture2D");
Ok(OwnedFramebuffer {
Ok(OwnedImage {
render,
size,
format,
@ -245,7 +245,7 @@ fn default_desc(size: Size<u32>, format: DXGI_FORMAT, mip_levels: u32) -> D3D11_
}
}
impl ScaleFramebuffer for OwnedFramebuffer {
impl ScaleFramebuffer for OwnedImage {
type Error = FilterChainError;
type Context = ();

View file

@ -568,7 +568,7 @@ pub mod d3d11_hello_triangle {
// eprintln!("w: {} h: {}", backbuffer_desc.Width, backbuffer_desc.Height);
self.filter
.frame(
Some(&resources.deferred_context),
None,
D3D11InputView {
handle: srv,
size: Size {
@ -593,12 +593,12 @@ pub mod d3d11_hello_triangle {
)
.unwrap();
let mut command_list = None;
resources
.deferred_context
.FinishCommandList(false, Some(&mut command_list))?;
let command_list = command_list.unwrap();
self.context.ExecuteCommandList(&command_list, false);
// let mut command_list = None;
// resources
// .deferred_context
// .FinishCommandList(false, Some(&mut command_list))?;
// let command_list = command_list.unwrap();
// self.context.ExecuteCommandList(&command_list, false);
// self.context.CopyResource(&resources.backbuffer, &backup);
}

View file

@ -38,8 +38,10 @@ mod tests {
// const FILTER_PATH: &str =
// "../test/slang-shaders/handheld/console-border/gbc-lcd-grid-v2.slangp";
// "../test/null.slangp",
const FILTER_PATH: &str =
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV-GLASS.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV-GLASS.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/test/history.slangp";
const FILTER_PATH: &str = "../test/slang-shaders/test/feedback.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/crt/crt-royale.slangp";
const IMAGE_PATH: &str = "../triangle.png";

View file

@ -13,7 +13,7 @@ use windows::Win32::Graphics::Direct3D11::{
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
use crate::error::{assume_d3d11_init, Result};
use crate::framebuffer::OwnedFramebuffer;
use crate::framebuffer::OwnedImage;
/// An image view for use as a shader resource.
///
@ -46,7 +46,7 @@ pub struct InputTexture {
impl InputTexture {
pub(crate) fn from_framebuffer(
fbo: &OwnedFramebuffer,
fbo: &OwnedImage,
wrap_mode: WrapMode,
filter: FilterMode,
) -> Result<Self> {

View file

@ -20,7 +20,7 @@ use librashader_reflect::back::targets::{DXIL, HLSL};
use librashader_reflect::back::{CompileReflectShader, CompileShader};
use librashader_reflect::front::GlslangCompilation;
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_reflect::reflect::semantics::{BindingMeta, ShaderSemantics, MAX_BINDINGS_COUNT};
use librashader_reflect::reflect::semantics::{ShaderSemantics, MAX_BINDINGS_COUNT};
use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::binding::{BindingUtil, TextureInput};
use librashader_runtime::image::{Image, UVDirection};
@ -46,6 +46,7 @@ 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::framebuffer::FramebufferInit;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
use rayon::prelude::*;
@ -190,44 +191,31 @@ impl FilterChainD3D12 {
options.map_or(false, |o| o.force_hlsl_pipeline),
)?;
let framebuffer_gen =
|| OwnedImage::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false);
let input_gen = || None;
let framebuffer_init = FramebufferInit::new(
filters.iter().map(|f| &f.reflection.meta),
&framebuffer_gen,
&input_gen,
);
// initialize output framebuffers
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || {
OwnedImage::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false)
});
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
// resolve all results
let output_framebuffers = output_framebuffers
.into_iter()
.collect::<error::Result<Vec<OwnedImage>>>()?;
let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), || None);
// initialize feedback framebuffers
let (feedback_framebuffers, feedback_textures) =
framebuffer_init.init_output_framebuffers()?;
// let mut output_textures = Vec::new();
// output_textures.resize_with(filters.len(), || None);
//
// // initialize feedback framebuffers
let mut feedback_framebuffers = Vec::new();
feedback_framebuffers.resize_with(filters.len(), || {
OwnedImage::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false)
});
// resolve all results
let feedback_framebuffers = feedback_framebuffers
.into_iter()
.collect::<error::Result<Vec<OwnedImage>>>()?;
let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), || None);
let (history_framebuffers, history_textures) =
FilterChainD3D12::init_history(device, &filters)?;
// initialize history
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
Ok(FilterChainD3D12 {
common: FilterCommon {
d3d12: device.clone(),
samplers,
output_textures: output_textures.into_boxed_slice(),
feedback_textures: feedback_textures.into_boxed_slice(),
output_textures,
feedback_textures,
luts,
mipmap_gen,
root_signature,
@ -245,8 +233,8 @@ impl FilterChainD3D12 {
staging_heap,
rtv_heap,
passes: filters,
output_framebuffers: output_framebuffers.into_boxed_slice(),
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
output_framebuffers,
feedback_framebuffers,
history_framebuffers,
work_heap: texture_heap,
sampler_heap,
@ -256,37 +244,6 @@ impl FilterChainD3D12 {
})
}
fn init_history(
device: &ID3D12Device,
filters: &Vec<FilterPass>,
) -> error::Result<(VecDeque<OwnedImage>, Box<[Option<InputTexture>]>)> {
let required_images =
BindingMeta::calculate_required_history(filters.iter().map(|f| &f.reflection.meta));
// not using frame history;
if required_images <= 1 {
// println!("[history] not using frame history");
return Ok((VecDeque::new(), Box::new([])));
}
// history0 is aliased with the original
// eprintln!("[history] using frame history with {required_images} images");
let mut framebuffers = VecDeque::with_capacity(required_images);
framebuffers.resize_with(required_images, || {
OwnedImage::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false)
});
let framebuffers = framebuffers
.into_iter()
.collect::<error::Result<VecDeque<OwnedImage>>>()?;
let mut history_textures = Vec::new();
history_textures.resize_with(required_images, || None);
Ok((framebuffers, history_textures.into_boxed_slice()))
}
fn load_luts(
device: &ID3D12Device,
heap: &mut D3D12DescriptorHeap<CpuStagingHeap>,

View file

@ -35,7 +35,9 @@ mod tests {
let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
// "../test/slang-shaders/crt/crt-lottes.slangp",
// "../test/basic.slangp",
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV-GLASS.slangp",
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV-GLASS.slangp",
"../test/slang-shaders/test/feedback.slangp",
// "../test/slang-shaders/test/history.slangp",
// "../test/slang-shaders/crt/crt-royale.slangp",
// "../test/slang-shaders/vhs/VHSPro.slangp",
&SampleCommandLine {

View file

@ -1,25 +1,26 @@
use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation};
use crate::error::FilterChainError;
use crate::filter_pass::{FilterPass, UniformOffset};
use crate::gl::{DrawQuad, Framebuffer, FramebufferInterface, GLInterface, LoadLut, UboRing};
use crate::gl::{DrawQuad, FramebufferInterface, GLFramebuffer, GLInterface, LoadLut, UboRing};
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
use crate::samplers::SamplerSet;
use crate::texture::InputTexture;
use crate::util::{gl_get_version, gl_u16_to_version};
use crate::{error, util, GLImage};
use gl::types::{GLint, GLuint};
use librashader_common::{FilterMode, Viewport, WrapMode};
use librashader_common::Viewport;
use librashader_presets::ShaderPreset;
use librashader_reflect::back::cross::GlslVersion;
use librashader_reflect::back::targets::GLSL;
use librashader_reflect::back::{CompileReflectShader, CompileShader};
use librashader_reflect::front::GlslangCompilation;
use librashader_reflect::reflect::semantics::{BindingMeta, ShaderSemantics, UniformMeta};
use librashader_reflect::reflect::semantics::{ShaderSemantics, UniformMeta};
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::binding::BindingUtil;
use librashader_runtime::framebuffer::FramebufferInit;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
use rustc_hash::FxHashMap;
@ -38,9 +39,9 @@ pub(crate) struct FilterChainImpl<T: GLInterface> {
pub(crate) common: FilterCommon,
passes: Box<[FilterPass<T>]>,
draw_quad: T::DrawQuad,
output_framebuffers: Box<[Framebuffer]>,
feedback_framebuffers: Box<[Framebuffer]>,
history_framebuffers: VecDeque<Framebuffer>,
output_framebuffers: Box<[GLFramebuffer]>,
feedback_framebuffers: Box<[GLFramebuffer]>,
history_framebuffers: VecDeque<GLFramebuffer>,
}
pub(crate) struct FilterCommon {
@ -120,31 +121,40 @@ impl<T: GLInterface> FilterChainImpl<T> {
let samplers = SamplerSet::new();
// initialize output framebuffers
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1));
let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), InputTexture::default);
// initialize feedback framebuffers
let mut feedback_framebuffers = Vec::new();
feedback_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1));
let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), InputTexture::default);
// load luts
let luts = T::LoadLut::load_luts(&preset.textures)?;
let (history_framebuffers, history_textures) =
FilterChainImpl::init_history(&filters, default_filter, default_wrap);
let framebuffer_gen = || Ok::<_, FilterChainError>(T::FramebufferInterface::new(1));
let input_gen = || InputTexture {
image: Default::default(),
filter: default_filter,
mip_filter: default_filter,
wrap_mode: default_wrap,
};
let framebuffer_init = FramebufferInit::new(
filters.iter().map(|f| &f.reflection.meta),
&framebuffer_gen,
&input_gen,
);
// initialize output framebuffers
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
// initialize feedback framebuffers
let (feedback_framebuffers, feedback_textures) =
framebuffer_init.init_output_framebuffers()?;
// initialize history
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
// create vertex objects
let draw_quad = T::DrawQuad::new();
Ok(FilterChainImpl {
passes: filters,
output_framebuffers: output_framebuffers.into_boxed_slice(),
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
output_framebuffers,
feedback_framebuffers,
history_framebuffers,
draw_quad,
common: FilterCommon {
@ -159,8 +169,8 @@ impl<T: GLInterface> FilterChainImpl<T> {
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
luts,
samplers,
output_textures: output_textures.into_boxed_slice(),
feedback_textures: feedback_textures.into_boxed_slice(),
output_textures,
feedback_textures,
history_textures,
},
})
@ -274,37 +284,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
Ok(filters.into_boxed_slice())
}
fn init_history(
filters: &[FilterPass<T>],
filter: FilterMode,
wrap_mode: WrapMode,
) -> (VecDeque<Framebuffer>, Box<[InputTexture]>) {
let required_images =
BindingMeta::calculate_required_history(filters.iter().map(|f| &f.reflection.meta));
// not using frame history;
if required_images <= 1 {
// println!("[history] not using frame history");
return (VecDeque::new(), Box::new([]));
}
// history0 is aliased with the original
// eprintln!("[history] using frame history with {required_images} images");
let mut framebuffers = VecDeque::with_capacity(required_images);
framebuffers.resize_with(required_images, || T::FramebufferInterface::new(1));
let mut history_textures = Vec::new();
history_textures.resize_with(required_images, || InputTexture {
image: Default::default(),
filter,
mip_filter: filter,
wrap_mode,
});
(framebuffers, history_textures.into_boxed_slice())
}
fn push_history(&mut self, input: &GLImage) -> error::Result<()> {
if let Some(mut back) = self.history_framebuffers.pop_back() {
if back.size != input.size || (input.format != 0 && input.format != back.format) {
@ -313,7 +292,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
}
back.copy_from::<T::FramebufferInterface>(input)?;
self.history_framebuffers.push_front(back)
}
@ -326,7 +304,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
pub fn frame(
&mut self,
frame_count: usize,
viewport: &Viewport<&Framebuffer>,
viewport: &Viewport<&GLFramebuffer>,
input: &GLImage,
options: Option<&FrameOptionsGL>,
) -> error::Result<()> {
@ -364,18 +342,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
texture.image = fbo.as_texture(filter, wrap_mode).image;
}
for ((texture, fbo), pass) in self
.common
.feedback_textures
.iter_mut()
.zip(self.feedback_framebuffers.iter())
.zip(passes.iter())
{
texture.image = fbo
.as_texture(pass.config.filter, pass.config.wrap_mode)
.image;
}
// shader_gl3: 2067
let original = InputTexture {
image: *input,
@ -387,7 +353,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
let mut source = original;
// rescale render buffers to ensure all bindings are valid.
<Framebuffer as ScaleFramebuffer<T::FramebufferInterface>>::scale_framebuffers(
<GLFramebuffer as ScaleFramebuffer<T::FramebufferInterface>>::scale_framebuffers(
source.image.size,
viewport.output.size,
&mut self.output_framebuffers,
@ -396,6 +362,20 @@ impl<T: GLInterface> FilterChainImpl<T> {
None,
)?;
// Refresh inputs for feedback textures.
// Don't need to do this for outputs because they are yet to be bound.
for ((texture, fbo), pass) in self
.common
.feedback_textures
.iter_mut()
.zip(self.feedback_framebuffers.iter())
.zip(passes.iter())
{
texture.image = fbo
.as_texture(pass.config.filter, pass.config.wrap_mode)
.image;
}
let passes_len = passes.len();
let (pass, last) = passes.split_at_mut(passes_len - 1);

View file

@ -5,7 +5,7 @@ use crate::error::{FilterChainError, Result};
use crate::filter_chain::filter_impl::FilterChainImpl;
use crate::filter_chain::inner::FilterChainDispatch;
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
use crate::{Framebuffer, GLImage};
use crate::{GLFramebuffer, GLImage};
use librashader_presets::ShaderPreset;
mod filter_impl;
@ -61,7 +61,7 @@ impl FilterChainGL {
pub fn frame(
&mut self,
input: &GLImage,
viewport: &Viewport<&Framebuffer>,
viewport: &Viewport<&GLFramebuffer>,
frame_count: usize,
options: Option<&FrameOptionsGL>,
) -> Result<()> {

View file

@ -14,7 +14,7 @@ use crate::binding::{GlUniformBinder, GlUniformStorage, UniformLocation, Variabl
use crate::filter_chain::FilterCommon;
use crate::gl::{BindTexture, GLInterface, UboRing};
use crate::samplers::SamplerSet;
use crate::Framebuffer;
use crate::GLFramebuffer;
use crate::texture::InputTexture;
@ -29,7 +29,7 @@ impl UniformOffset {
}
}
pub struct FilterPass<T: GLInterface> {
pub(crate) struct FilterPass<T: GLInterface> {
pub reflection: ShaderReflection,
pub program: GLuint,
pub ubo_location: UniformLocation<GLuint>,
@ -81,10 +81,10 @@ impl<T: GLInterface> FilterPass<T> {
parent: &FilterCommon,
frame_count: u32,
frame_direction: i32,
viewport: &Viewport<&Framebuffer>,
viewport: &Viewport<&GLFramebuffer>,
original: &InputTexture,
source: &InputTexture,
output: RenderTarget<Framebuffer, GLint>,
output: RenderTarget<GLFramebuffer, GLint>,
) {
let framebuffer = output.output;
@ -93,7 +93,7 @@ impl<T: GLInterface> FilterPass<T> {
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.fbo);
gl::UseProgram(self.program);
}
@ -165,7 +165,7 @@ impl<T: GLInterface> FilterPass<T> {
frame_count: u32,
frame_direction: i32,
fb_size: Size<u32>,
viewport: &Viewport<&Framebuffer>,
viewport: &Viewport<&GLFramebuffer>,
original: &InputTexture,
source: &InputTexture,
) {

View file

@ -11,9 +11,9 @@ use librashader_runtime::scaling::ScaleFramebuffer;
///
/// Generally for use as render targets.
#[derive(Debug)]
pub struct Framebuffer {
pub struct GLFramebuffer {
pub(crate) image: GLuint,
pub(crate) handle: GLuint,
pub(crate) fbo: GLuint,
pub(crate) size: Size<u32>,
pub(crate) format: GLenum,
pub(crate) max_levels: u32,
@ -21,7 +21,7 @@ pub struct Framebuffer {
pub(crate) is_raw: bool,
}
impl Framebuffer {
impl GLFramebuffer {
/// Create a framebuffer from an already initialized texture and framebuffer.
///
/// The framebuffer will not be deleted when this struct is dropped.
@ -31,14 +31,14 @@ impl Framebuffer {
format: GLenum,
size: Size<u32>,
miplevels: u32,
) -> Framebuffer {
Framebuffer {
) -> GLFramebuffer {
GLFramebuffer {
image: texture,
size,
format,
max_levels: miplevels,
mip_levels: miplevels,
handle: fbo,
fbo: fbo,
is_raw: true,
}
}
@ -76,15 +76,15 @@ impl Framebuffer {
}
}
impl Drop for Framebuffer {
impl Drop for GLFramebuffer {
fn drop(&mut self) {
if self.is_raw {
return;
}
unsafe {
if self.handle != 0 {
gl::DeleteFramebuffers(1, &self.handle);
if self.fbo != 0 {
gl::DeleteFramebuffers(1, &self.fbo);
}
if self.image != 0 {
gl::DeleteTextures(1, &self.image);
@ -93,7 +93,7 @@ impl Drop for Framebuffer {
}
}
//
impl<T: FramebufferInterface> ScaleFramebuffer<T> for Framebuffer {
impl<T: FramebufferInterface> ScaleFramebuffer<T> for GLFramebuffer {
type Error = FilterChainError;
type Context = ();

View file

@ -1,6 +1,6 @@
use crate::error::{FilterChainError, Result};
use crate::framebuffer::GLImage;
use crate::gl::framebuffer::Framebuffer;
use crate::gl::framebuffer::GLFramebuffer;
use crate::gl::FramebufferInterface;
use gl::types::{GLenum, GLint, GLsizei};
use librashader_common::{ImageFormat, Size};
@ -11,7 +11,7 @@ use librashader_runtime::scaling::{MipmapSize, ViewportSize};
pub struct Gl3Framebuffer;
impl FramebufferInterface for Gl3Framebuffer {
fn new(max_levels: u32) -> Framebuffer {
fn new(max_levels: u32) -> GLFramebuffer {
let mut framebuffer = 0;
unsafe {
gl::GenFramebuffers(1, &mut framebuffer);
@ -19,7 +19,7 @@ impl FramebufferInterface for Gl3Framebuffer {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Framebuffer {
GLFramebuffer {
image: 0,
size: Size {
width: 1,
@ -28,13 +28,13 @@ impl FramebufferInterface for Gl3Framebuffer {
format: 0,
max_levels,
mip_levels: 0,
handle: framebuffer,
fbo: framebuffer,
is_raw: false,
}
}
fn scale(
fb: &mut Framebuffer,
fb: &mut GLFramebuffer,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
@ -66,10 +66,10 @@ impl FramebufferInterface for Gl3Framebuffer {
}
Ok(size)
}
fn clear<const REBIND: bool>(fb: &Framebuffer) {
fn clear<const REBIND: bool>(fb: &GLFramebuffer) {
unsafe {
if REBIND {
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo);
}
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
@ -79,14 +79,14 @@ impl FramebufferInterface for Gl3Framebuffer {
}
}
}
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()> {
fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()> {
// todo: may want to use a shader and draw a quad to be faster.
if image.size != fb.size || image.format != fb.format {
Self::init(fb, image.size, image.format)?;
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo);
gl::FramebufferTexture2D(
gl::READ_FRAMEBUFFER,
@ -149,7 +149,7 @@ impl FramebufferInterface for Gl3Framebuffer {
Ok(())
}
fn init(fb: &mut Framebuffer, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
fn init(fb: &mut GLFramebuffer, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if fb.is_raw {
return Ok(());
}
@ -157,7 +157,7 @@ impl FramebufferInterface for Gl3Framebuffer {
fb.size = size;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo);
// reset the framebuffer image
if fb.image != 0 {

View file

@ -10,7 +10,7 @@ use librashader_common::{Size, Viewport};
use crate::filter_chain::FilterChainGL;
use crate::framebuffer::GLImage;
use crate::Framebuffer;
use crate::GLFramebuffer;
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;
@ -464,7 +464,7 @@ void main()
let (fb_width, fb_height) = window.get_framebuffer_size();
let (vp_width, vp_height) = window.get_size();
let output = Framebuffer::new_from_raw(
let output = GLFramebuffer::new_from_raw(
output_texture,
output_framebuffer_handle,
gl::RGBA8,

View file

@ -1,6 +1,6 @@
use crate::error::{FilterChainError, Result};
use crate::framebuffer::GLImage;
use crate::gl::framebuffer::Framebuffer;
use crate::gl::framebuffer::GLFramebuffer;
use crate::gl::FramebufferInterface;
use gl::types::{GLenum, GLint, GLsizei};
use librashader_common::{ImageFormat, Size};
@ -11,13 +11,13 @@ use librashader_runtime::scaling::{MipmapSize, ViewportSize};
pub struct Gl46Framebuffer;
impl FramebufferInterface for Gl46Framebuffer {
fn new(max_levels: u32) -> Framebuffer {
fn new(max_levels: u32) -> GLFramebuffer {
let mut framebuffer = 0;
unsafe {
gl::CreateFramebuffers(1, &mut framebuffer);
}
Framebuffer {
GLFramebuffer {
image: 0,
size: Size {
width: 1,
@ -26,13 +26,13 @@ impl FramebufferInterface for Gl46Framebuffer {
format: 0,
max_levels,
mip_levels: 0,
handle: framebuffer,
fbo: framebuffer,
is_raw: false,
}
}
fn scale(
fb: &mut Framebuffer,
fb: &mut GLFramebuffer,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
@ -66,17 +66,17 @@ impl FramebufferInterface for Gl46Framebuffer {
}
Ok(size)
}
fn clear<const REBIND: bool>(fb: &Framebuffer) {
fn clear<const REBIND: bool>(fb: &GLFramebuffer) {
unsafe {
gl::ClearNamedFramebufferfv(
fb.handle,
fb.fbo,
gl::COLOR,
0,
[0.0f32, 0.0, 0.0, 0.0].as_ptr().cast(),
);
}
}
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()> {
fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()> {
// todo: confirm this behaviour for unbound image.
if image.handle == 0 {
return Ok(());
@ -90,11 +90,11 @@ impl FramebufferInterface for Gl46Framebuffer {
unsafe {
// gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1);
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT0);
gl::NamedFramebufferDrawBuffer(fb.fbo, gl::COLOR_ATTACHMENT0);
gl::BlitNamedFramebuffer(
image.handle,
fb.handle,
fb.fbo,
0,
0,
image.size.width as GLint,
@ -110,7 +110,7 @@ impl FramebufferInterface for Gl46Framebuffer {
Ok(())
}
fn init(fb: &mut Framebuffer, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
fn init(fb: &mut GLFramebuffer, mut size: Size<u32>, format: impl Into<GLenum>) -> Result<()> {
if fb.is_raw {
return Ok(());
}
@ -120,7 +120,7 @@ impl FramebufferInterface for Gl46Framebuffer {
unsafe {
// reset the framebuffer image
if fb.image != 0 {
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, 0, 0);
gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, 0, 0);
gl::DeleteTextures(1, &fb.image);
}
@ -149,13 +149,13 @@ impl FramebufferInterface for Gl46Framebuffer {
size.height as GLsizei,
);
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, fb.image, 0);
gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, fb.image, 0);
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
if status != gl::FRAMEBUFFER_COMPLETE {
match status {
gl::FRAMEBUFFER_UNSUPPORTED => {
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, 0, 0);
gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, 0, 0);
gl::DeleteTextures(1, &fb.image);
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image);
@ -174,7 +174,7 @@ impl FramebufferInterface for Gl46Framebuffer {
size.width as GLsizei,
size.height as GLsizei,
);
gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, fb.image, 0);
gl::NamedFramebufferTexture(fb.fbo, gl::COLOR_ATTACHMENT0, fb.image, 0);
// fb.init =
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
}

View file

@ -10,7 +10,7 @@ use librashader_common::{Size, Viewport};
use crate::filter_chain::FilterChainGL;
use crate::framebuffer::GLImage;
use crate::Framebuffer;
use crate::GLFramebuffer;
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;
@ -455,7 +455,7 @@ void main()
let (fb_width, fb_height) = window.get_framebuffer_size();
let (vp_width, vp_height) = window.get_size();
let output = Framebuffer::new_from_raw(
let output = GLFramebuffer::new_from_raw(
output_texture,
output_framebuffer_handle,
gl::RGBA8,

View file

@ -7,7 +7,7 @@ use crate::error::Result;
use crate::framebuffer::GLImage;
use crate::samplers::SamplerSet;
use crate::texture::InputTexture;
pub use framebuffer::Framebuffer;
pub use framebuffer::GLFramebuffer;
use gl::types::{GLenum, GLuint};
use librashader_common::{ImageFormat, Size};
use librashader_presets::{Scale2D, TextureConfig};
@ -15,17 +15,17 @@ use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
use librashader_runtime::uniforms::UniformStorageAccess;
use rustc_hash::FxHashMap;
pub trait LoadLut {
pub(crate) trait LoadLut {
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, InputTexture>>;
}
pub trait DrawQuad {
pub(crate) trait DrawQuad {
fn new() -> Self;
fn bind_vertices(&self);
fn unbind_vertices(&self);
}
pub trait UboRing<const SIZE: usize> {
pub(crate) trait UboRing<const SIZE: usize> {
fn new(buffer_size: u32) -> Self;
fn bind_for_frame(
&mut self,
@ -35,27 +35,27 @@ pub trait UboRing<const SIZE: usize> {
);
}
pub trait FramebufferInterface {
fn new(max_levels: u32) -> Framebuffer;
pub(crate) trait FramebufferInterface {
fn new(max_levels: u32) -> GLFramebuffer;
fn scale(
fb: &mut Framebuffer,
fb: &mut GLFramebuffer,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
source_size: &Size<u32>,
mipmap: bool,
) -> Result<Size<u32>>;
fn clear<const REBIND: bool>(fb: &Framebuffer);
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()>;
fn init(fb: &mut Framebuffer, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>;
fn clear<const REBIND: bool>(fb: &GLFramebuffer);
fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()>;
fn init(fb: &mut GLFramebuffer, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>;
}
pub trait BindTexture {
pub(crate) trait BindTexture {
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture);
fn gen_mipmaps(texture: &InputTexture);
}
pub trait GLInterface {
pub(crate) trait GLInterface {
type FramebufferInterface: FramebufferInterface;
type UboRing: UboRing<16>;
type DrawQuad: DrawQuad;

View file

@ -21,7 +21,7 @@ mod texture;
pub mod error;
pub mod options;
pub use crate::gl::Framebuffer;
pub use crate::gl::GLFramebuffer;
pub use filter_chain::FilterChainGL;
pub use framebuffer::GLImage;
@ -52,7 +52,9 @@ mod tests {
let (glfw, window, events, shader, vao) = gl::gl46::hello_triangle::setup();
let mut filter = FilterChainGL::load_from_path(
// "../test/slang-shaders/vhs/VHSPro.slangp",
"../test/slang-shaders/crt/crt-royale.slangp",
// "../test/slang-shaders/test/history.slangp",
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
"../test/slang-shaders/test/feedback.slangp",
Some(&FilterChainOptionsGL {
glsl_version: 0,
use_dsa: true,

View file

@ -3,13 +3,14 @@ use crate::framebuffer::GLImage;
use librashader_common::{FilterMode, WrapMode};
#[derive(Default, Debug, Copy, Clone)]
pub struct InputTexture {
pub(crate) struct InputTexture {
pub image: GLImage,
pub filter: FilterMode,
pub mip_filter: FilterMode,
pub wrap_mode: WrapMode,
}
/// An OpenGL texture bound as a shader resource.
impl InputTexture {
pub fn is_bound(&self) -> bool {
self.image.handle != 0

View file

@ -19,7 +19,7 @@ use librashader_reflect::back::targets::SPIRV;
use librashader_reflect::back::{CompileReflectShader, CompileShader};
use librashader_reflect::front::GlslangCompilation;
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_reflect::reflect::semantics::{BindingMeta, ShaderSemantics};
use librashader_reflect::reflect::semantics::ShaderSemantics;
use librashader_reflect::reflect::ReflectShader;
use librashader_runtime::binding::BindingUtil;
use librashader_runtime::image::{Image, UVDirection};
@ -31,6 +31,7 @@ use std::collections::VecDeque;
use std::path::Path;
use std::sync::Arc;
use librashader_runtime::framebuffer::FramebufferInit;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
use rayon::prelude::*;
@ -145,8 +146,8 @@ pub(crate) struct FilterCommon {
pub(crate) luts: FxHashMap<usize, LutTexture>,
pub samplers: SamplerSet,
pub(crate) draw_quad: DrawQuad,
pub output_inputs: Box<[Option<InputImage>]>,
pub feedback_inputs: Box<[Option<InputImage>]>,
pub output_textures: Box<[Option<InputImage>]>,
pub feedback_textures: Box<[Option<InputImage>]>,
pub history_textures: Box<[Option<InputImage>]>,
pub config: FilterMutable,
pub device: Arc<ash::Device>,
@ -256,28 +257,24 @@ impl FilterChainVulkan {
let luts = FilterChainVulkan::load_luts(&device, &preset.textures)?;
let samplers = SamplerSet::new(&device.device)?;
let (history_framebuffers, history_textures) =
FilterChainVulkan::init_history(&device, &filters)?;
let framebuffer_gen =
|| OwnedImage::new(&device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, 1);
let input_gen = || None;
let framebuffer_init = FramebufferInit::new(
filters.iter().map(|f| &f.reflection.meta),
&framebuffer_gen,
&input_gen,
);
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || {
OwnedImage::new(&device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, 1)
});
// initialize output framebuffers
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
let mut feedback_framebuffers = Vec::new();
feedback_framebuffers.resize_with(filters.len(), || {
OwnedImage::new(&device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, 1)
});
// initialize feedback framebuffers
let (feedback_framebuffers, feedback_textures) =
framebuffer_init.init_output_framebuffers()?;
let output_framebuffers: error::Result<Vec<OwnedImage>> =
output_framebuffers.into_iter().collect();
let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), || None);
let feedback_framebuffers: error::Result<Vec<OwnedImage>> =
feedback_framebuffers.into_iter().collect();
let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), || None);
// initialize history
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
let mut intermediates = Vec::new();
intermediates.resize_with(frames_in_flight as usize, || {
@ -298,14 +295,14 @@ impl FilterChainVulkan {
},
draw_quad: DrawQuad::new(&device.device, &device.alloc)?,
device: device.device.clone(),
output_inputs: output_textures.into_boxed_slice(),
feedback_inputs: feedback_textures.into_boxed_slice(),
output_textures,
feedback_textures,
history_textures,
},
passes: filters,
vulkan: device,
output_framebuffers: output_framebuffers?.into_boxed_slice(),
feedback_framebuffers: feedback_framebuffers?.into_boxed_slice(),
output_framebuffers,
feedback_framebuffers,
history_framebuffers,
residuals: intermediates.into_boxed_slice(),
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
@ -374,6 +371,7 @@ impl FilterChainVulkan {
graphics_pipeline,
// ubo_ring,
frames_in_flight,
internal_frame_count: 0,
})
})
.collect();
@ -443,36 +441,6 @@ impl FilterChainVulkan {
Ok(luts)
}
fn init_history(
vulkan: &VulkanObjects,
filters: &[FilterPass],
) -> error::Result<(VecDeque<OwnedImage>, Box<[Option<InputImage>]>)> {
let required_images =
BindingMeta::calculate_required_history(filters.iter().map(|f| &f.reflection.meta));
// not using frame history;
if required_images <= 1 {
// println!("[history] not using frame history");
return Ok((VecDeque::new(), Box::new([])));
}
// history0 is aliased with the original
// eprintln!("[history] using frame history with {required_images} images");
let mut images = Vec::with_capacity(required_images);
images.resize_with(required_images, || {
OwnedImage::new(vulkan, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, 1)
});
let images: error::Result<Vec<OwnedImage>> = images.into_iter().collect();
let images = VecDeque::from(images?);
let mut image_views = Vec::new();
image_views.resize_with(required_images, || None);
Ok((images, image_views.into_boxed_slice()))
}
// image must be in SHADER_READ_OPTIMAL
pub fn push_history(
&mut self,
@ -640,9 +608,9 @@ impl FilterChainVulkan {
output: &OwnedImage,
feedback: &OwnedImage| {
// refresh inputs
self.common.feedback_inputs[index] =
self.common.feedback_textures[index] =
Some(feedback.as_input(pass.config.filter, pass.config.wrap_mode));
self.common.output_inputs[index] =
self.common.output_textures[index] =
Some(output.as_input(pass.config.filter, pass.config.wrap_mode));
Ok(())
}),
@ -682,7 +650,7 @@ impl FilterChainVulkan {
out.output.end_pass(cmd);
}
source = self.common.output_inputs[index].clone().unwrap();
source = self.common.output_textures[index].clone().unwrap();
intermediates.dispose_outputs(output_image);
intermediates.dispose_framebuffers(residual_fb);
}

View file

@ -32,6 +32,7 @@ pub struct FilterPass {
pub graphics_pipeline: VulkanGraphicsPipeline,
// pub ubo_ring: VkUboRing,
pub frames_in_flight: u32,
pub internal_frame_count: usize,
}
impl TextureInput for InputImage {
@ -100,7 +101,7 @@ impl FilterPass {
vbo_type: QuadType,
) -> error::Result<Option<vk::Framebuffer>> {
let mut descriptor = self.graphics_pipeline.layout.descriptor_sets
[(frame_count % self.frames_in_flight) as usize];
[self.internal_frame_count % self.frames_in_flight as usize];
self.build_semantics(
pass_index,
@ -193,6 +194,7 @@ impl FilterPass {
parent.draw_quad.draw_quad(cmd, vbo_type);
self.graphics_pipeline.end_rendering(&parent.device, cmd);
}
self.internal_frame_count += 1;
Ok(residual)
}
@ -223,10 +225,10 @@ impl FilterPass {
source,
&self.uniform_bindings,
&self.reflection.meta.texture_meta,
parent.output_inputs[0..pass_index]
parent.output_textures[0..pass_index]
.iter()
.map(|o| o.as_ref()),
parent.feedback_inputs.iter().map(|o| o.as_ref()),
parent.feedback_textures.iter().map(|o| o.as_ref()),
parent.history_textures.iter().map(|o| o.as_ref()),
parent.luts.iter().map(|(u, i)| (*u, i.as_ref())),
&self.source.parameters,

View file

@ -44,7 +44,8 @@ mod tests {
let filter = FilterChainVulkan::load_from_path(
&base,
// "../test/slang-shaders/crt/crt-royale.slangp",
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__2__ADV-NO-REFLECT.slangp",
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV-GLASS.slangp",
"../test/slang-shaders/test/feedback.slangp",
// "../test/basic.slangp",
Some(&FilterChainOptionsVulkan {
frames_in_flight: 3,

View file

@ -310,19 +310,21 @@ impl BindingUtil for BindingMeta {
for pass in pass_meta {
// If a shader uses history size, but not history, we still need to keep the texture.
let texture_count = pass
let texture_max_index = pass
.texture_meta
.iter()
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
.count();
let texture_size_count = pass
.map(|(semantic, _)| semantic.index)
.fold(0, std::cmp::max);
let texture_size_max_index = pass
.texture_size_meta
.iter()
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
.count();
.map(|(semantic, _)| semantic.index)
.fold(0, std::cmp::max);
required_images = std::cmp::max(required_images, texture_count);
required_images = std::cmp::max(required_images, texture_size_count);
required_images = std::cmp::max(required_images, texture_max_index);
required_images = std::cmp::max(required_images, texture_size_max_index);
}
required_images

View file

@ -0,0 +1,92 @@
use crate::binding::BindingUtil;
use librashader_reflect::reflect::semantics::BindingMeta;
use std::collections::VecDeque;
/// Helper to initialize framebuffers in a graphics API agnostic way.
pub struct FramebufferInit<'a, F, I, E> {
owned_generator: &'a dyn Fn() -> Result<F, E>,
input_generator: &'a dyn Fn() -> I,
required_history: usize,
filters_count: usize,
}
impl<'a, F, I, E> FramebufferInit<'a, F, I, E> {
/// Create a new framebuffer initializer with the given
/// closures to create owned framebuffers and image views.
pub fn new(
filters: impl Iterator<Item = &'a BindingMeta> + ExactSizeIterator,
owned_generator: &'a dyn Fn() -> Result<F, E>,
input_generator: &'a dyn Fn() -> I,
) -> Self {
let filters_count = filters.len();
let required_history = BindingMeta::calculate_required_history(filters);
Self {
owned_generator,
input_generator,
filters_count,
required_history,
}
}
/// Initialize history framebuffers and views.
pub fn init_history(&self) -> Result<(VecDeque<F>, Box<[I]>), E> {
init_history(
self.required_history,
self.owned_generator,
self.input_generator,
)
}
/// Initialize output framebuffers and views.
pub fn init_output_framebuffers(&self) -> Result<(Box<[F]>, Box<[I]>), E> {
init_output_framebuffers(
self.filters_count,
self.owned_generator,
self.input_generator,
)
}
}
fn init_history<'a, F, I, E>(
required_images: usize,
owned_generator: impl Fn() -> Result<F, E>,
input_generator: impl Fn() -> I,
) -> Result<(VecDeque<F>, Box<[I]>), E> {
if required_images <= 1 {
return Ok((VecDeque::new(), Box::new([])));
}
let mut framebuffers = VecDeque::with_capacity(required_images);
framebuffers.resize_with(required_images, owned_generator);
let framebuffers = framebuffers
.into_iter()
.collect::<Result<VecDeque<F>, E>>()?;
let mut history_textures = Vec::new();
history_textures.resize_with(required_images, input_generator);
Ok((framebuffers, history_textures.into_boxed_slice()))
}
fn init_output_framebuffers<F, I, E>(
len: usize,
owned_generator: impl Fn() -> Result<F, E>,
input_generator: impl Fn() -> I,
) -> Result<(Box<[F]>, Box<[I]>), E> {
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(len, owned_generator);
// resolve all results
let output_framebuffers = output_framebuffers
.into_iter()
.collect::<Result<Vec<F>, E>>()?;
let mut output_textures = Vec::new();
output_textures.resize_with(len, input_generator);
Ok((
output_framebuffers.into_boxed_slice(),
output_textures.into_boxed_slice(),
))
}

View file

@ -34,3 +34,6 @@ pub mod filter_pass;
/// Common types for render targets.
pub mod render_target;
/// Helpers for handling framebuffers.
pub mod framebuffer;

View file

@ -214,7 +214,7 @@ pub mod runtime {
pub use librashader_runtime_gl::{
error,
options::{FilterChainOptionsGL as FilterChainOptions, FrameOptionsGL as FrameOptions},
FilterChainGL as FilterChain, Framebuffer, GLImage,
FilterChainGL as FilterChain, GLFramebuffer, GLImage,
};
#[doc(hidden)]