rt: fix history framebuffer requirements and unify framebuffer initialization logic
This commit is contained in:
parent
115382d8f0
commit
3c15a3a523
|
@ -5,7 +5,7 @@ use librashader_presets::{ShaderPreset, TextureConfig};
|
||||||
use librashader_reflect::back::targets::HLSL;
|
use librashader_reflect::back::targets::HLSL;
|
||||||
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
||||||
use librashader_reflect::front::GlslangCompilation;
|
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_reflect::reflect::ReflectShader;
|
||||||
use librashader_runtime::image::{Image, UVDirection};
|
use librashader_runtime::image::{Image, UVDirection};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
@ -16,7 +16,7 @@ use std::path::Path;
|
||||||
use crate::draw_quad::DrawQuad;
|
use crate::draw_quad::DrawQuad;
|
||||||
use crate::error::{assume_d3d11_init, FilterChainError};
|
use crate::error::{assume_d3d11_init, FilterChainError};
|
||||||
use crate::filter_pass::{ConstantBufferBinding, FilterPass};
|
use crate::filter_pass::{ConstantBufferBinding, FilterPass};
|
||||||
use crate::framebuffer::OwnedFramebuffer;
|
use crate::framebuffer::OwnedImage;
|
||||||
use crate::graphics_pipeline::D3D11State;
|
use crate::graphics_pipeline::D3D11State;
|
||||||
use crate::options::{FilterChainOptionsD3D11, FrameOptionsD3D11};
|
use crate::options::{FilterChainOptionsD3D11, FrameOptionsD3D11};
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
|
@ -24,6 +24,7 @@ use crate::util::d3d11_compile_bound_shader;
|
||||||
use crate::{error, util, D3D11OutputView};
|
use crate::{error, util, D3D11OutputView};
|
||||||
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
|
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
|
||||||
use librashader_runtime::binding::{BindingUtil, TextureInput};
|
use librashader_runtime::binding::{BindingUtil, TextureInput};
|
||||||
|
use librashader_runtime::framebuffer::FramebufferInit;
|
||||||
use librashader_runtime::quad::QuadType;
|
use librashader_runtime::quad::QuadType;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use librashader_runtime::scaling::ScaleFramebuffer;
|
use librashader_runtime::scaling::ScaleFramebuffer;
|
||||||
|
@ -49,9 +50,9 @@ type ShaderPassMeta =
|
||||||
pub struct FilterChainD3D11 {
|
pub struct FilterChainD3D11 {
|
||||||
pub(crate) common: FilterCommon,
|
pub(crate) common: FilterCommon,
|
||||||
passes: Vec<FilterPass>,
|
passes: Vec<FilterPass>,
|
||||||
output_framebuffers: Box<[OwnedFramebuffer]>,
|
output_framebuffers: Box<[OwnedImage]>,
|
||||||
feedback_framebuffers: Box<[OwnedFramebuffer]>,
|
feedback_framebuffers: Box<[OwnedImage]>,
|
||||||
history_framebuffers: VecDeque<OwnedFramebuffer>,
|
history_framebuffers: VecDeque<OwnedImage>,
|
||||||
state: D3D11State,
|
state: D3D11State,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,45 +103,34 @@ impl FilterChainD3D11 {
|
||||||
|
|
||||||
let immediate_context = unsafe { device.GetImmediateContext()? };
|
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
|
// load luts
|
||||||
let luts = FilterChainD3D11::load_luts(device, &immediate_context, &preset.textures)?;
|
let luts = FilterChainD3D11::load_luts(device, &immediate_context, &preset.textures)?;
|
||||||
|
|
||||||
let (history_framebuffers, history_textures) =
|
let framebuffer_gen =
|
||||||
FilterChainD3D11::init_history(device, &filters)?;
|
|| 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 draw_quad = DrawQuad::new(device)?;
|
||||||
let state = D3D11State::new(device)?;
|
let state = D3D11State::new(device)?;
|
||||||
Ok(FilterChainD3D11 {
|
Ok(FilterChainD3D11 {
|
||||||
passes: filters,
|
passes: filters,
|
||||||
output_framebuffers: output_framebuffers.into_boxed_slice(),
|
output_framebuffers,
|
||||||
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
|
feedback_framebuffers,
|
||||||
history_framebuffers,
|
history_framebuffers,
|
||||||
common: FilterCommon {
|
common: FilterCommon {
|
||||||
d3d11: Direct3D11 {
|
d3d11: Direct3D11 {
|
||||||
|
@ -158,8 +148,8 @@ impl FilterChainD3D11 {
|
||||||
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
|
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
|
||||||
luts,
|
luts,
|
||||||
samplers,
|
samplers,
|
||||||
output_textures: output_textures.into_boxed_slice(),
|
output_textures,
|
||||||
feedback_textures: feedback_textures.into_boxed_slice(),
|
feedback_textures,
|
||||||
history_textures,
|
history_textures,
|
||||||
draw_quad,
|
draw_quad,
|
||||||
},
|
},
|
||||||
|
@ -283,37 +273,6 @@ impl FilterChainD3D11 {
|
||||||
Ok(filters)
|
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(
|
fn push_history(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &ID3D11DeviceContext,
|
ctx: &ID3D11DeviceContext,
|
||||||
|
@ -394,20 +353,6 @@ impl FilterChainD3D11 {
|
||||||
let filter = passes[0].config.filter;
|
let filter = passes[0].config.filter;
|
||||||
let wrap_mode = passes[0].config.wrap_mode;
|
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
|
for (texture, fbo) in self
|
||||||
.common
|
.common
|
||||||
.history_textures
|
.history_textures
|
||||||
|
@ -426,7 +371,7 @@ impl FilterChainD3D11 {
|
||||||
let mut source = original.clone();
|
let mut source = original.clone();
|
||||||
|
|
||||||
// rescale render buffers to ensure all bindings are valid.
|
// rescale render buffers to ensure all bindings are valid.
|
||||||
OwnedFramebuffer::scale_framebuffers(
|
OwnedImage::scale_framebuffers(
|
||||||
source.size(),
|
source.size(),
|
||||||
viewport.output.size,
|
viewport.output.size,
|
||||||
&mut self.output_framebuffers,
|
&mut self.output_framebuffers,
|
||||||
|
@ -435,6 +380,22 @@ impl FilterChainD3D11 {
|
||||||
None,
|
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 passes_len = passes.len();
|
||||||
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
||||||
|
|
||||||
|
|
|
@ -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];
|
static CLEAR: &[f32; 4] = &[0.0f32, 0.0, 0.0, 0.0];
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct OwnedFramebuffer {
|
pub(crate) struct OwnedImage {
|
||||||
render: ID3D11Texture2D,
|
render: ID3D11Texture2D,
|
||||||
pub(crate) size: Size<u32>,
|
pub(crate) size: Size<u32>,
|
||||||
format: DXGI_FORMAT,
|
format: DXGI_FORMAT,
|
||||||
|
@ -29,13 +29,13 @@ pub(crate) struct OwnedFramebuffer {
|
||||||
max_mipmap: u32,
|
max_mipmap: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OwnedFramebuffer {
|
impl OwnedImage {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &ID3D11Device,
|
device: &ID3D11Device,
|
||||||
size: Size<u32>,
|
size: Size<u32>,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
mipmap: bool,
|
mipmap: bool,
|
||||||
) -> error::Result<OwnedFramebuffer> {
|
) -> error::Result<OwnedImage> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let format = d3d11_get_closest_format(
|
let format = d3d11_get_closest_format(
|
||||||
device,
|
device,
|
||||||
|
@ -49,7 +49,7 @@ impl OwnedFramebuffer {
|
||||||
device.CreateTexture2D(&desc, None, Some(&mut render))?;
|
device.CreateTexture2D(&desc, None, Some(&mut render))?;
|
||||||
assume_d3d11_init!(render, "CreateTexture2D");
|
assume_d3d11_init!(render, "CreateTexture2D");
|
||||||
|
|
||||||
Ok(OwnedFramebuffer {
|
Ok(OwnedImage {
|
||||||
render,
|
render,
|
||||||
size,
|
size,
|
||||||
format,
|
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 Error = FilterChainError;
|
||||||
type Context = ();
|
type Context = ();
|
||||||
|
|
||||||
|
|
|
@ -568,7 +568,7 @@ pub mod d3d11_hello_triangle {
|
||||||
// eprintln!("w: {} h: {}", backbuffer_desc.Width, backbuffer_desc.Height);
|
// eprintln!("w: {} h: {}", backbuffer_desc.Width, backbuffer_desc.Height);
|
||||||
self.filter
|
self.filter
|
||||||
.frame(
|
.frame(
|
||||||
Some(&resources.deferred_context),
|
None,
|
||||||
D3D11InputView {
|
D3D11InputView {
|
||||||
handle: srv,
|
handle: srv,
|
||||||
size: Size {
|
size: Size {
|
||||||
|
@ -593,12 +593,12 @@ pub mod d3d11_hello_triangle {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut command_list = None;
|
// let mut command_list = None;
|
||||||
resources
|
// resources
|
||||||
.deferred_context
|
// .deferred_context
|
||||||
.FinishCommandList(false, Some(&mut command_list))?;
|
// .FinishCommandList(false, Some(&mut command_list))?;
|
||||||
let command_list = command_list.unwrap();
|
// let command_list = command_list.unwrap();
|
||||||
self.context.ExecuteCommandList(&command_list, false);
|
// self.context.ExecuteCommandList(&command_list, false);
|
||||||
// self.context.CopyResource(&resources.backbuffer, &backup);
|
// self.context.CopyResource(&resources.backbuffer, &backup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,10 @@ mod tests {
|
||||||
// const FILTER_PATH: &str =
|
// const FILTER_PATH: &str =
|
||||||
// "../test/slang-shaders/handheld/console-border/gbc-lcd-grid-v2.slangp";
|
// "../test/slang-shaders/handheld/console-border/gbc-lcd-grid-v2.slangp";
|
||||||
// "../test/null.slangp",
|
// "../test/null.slangp",
|
||||||
const FILTER_PATH: &str =
|
// const FILTER_PATH: &str = "../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";
|
|
||||||
|
// 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 FILTER_PATH: &str = "../test/slang-shaders/crt/crt-royale.slangp";
|
||||||
const IMAGE_PATH: &str = "../triangle.png";
|
const IMAGE_PATH: &str = "../triangle.png";
|
||||||
|
|
|
@ -13,7 +13,7 @@ use windows::Win32::Graphics::Direct3D11::{
|
||||||
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
|
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
|
||||||
|
|
||||||
use crate::error::{assume_d3d11_init, Result};
|
use crate::error::{assume_d3d11_init, Result};
|
||||||
use crate::framebuffer::OwnedFramebuffer;
|
use crate::framebuffer::OwnedImage;
|
||||||
|
|
||||||
/// An image view for use as a shader resource.
|
/// An image view for use as a shader resource.
|
||||||
///
|
///
|
||||||
|
@ -46,7 +46,7 @@ pub struct InputTexture {
|
||||||
|
|
||||||
impl InputTexture {
|
impl InputTexture {
|
||||||
pub(crate) fn from_framebuffer(
|
pub(crate) fn from_framebuffer(
|
||||||
fbo: &OwnedFramebuffer,
|
fbo: &OwnedImage,
|
||||||
wrap_mode: WrapMode,
|
wrap_mode: WrapMode,
|
||||||
filter: FilterMode,
|
filter: FilterMode,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use librashader_reflect::back::targets::{DXIL, HLSL};
|
||||||
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
||||||
use librashader_reflect::front::GlslangCompilation;
|
use librashader_reflect::front::GlslangCompilation;
|
||||||
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
|
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_reflect::reflect::ReflectShader;
|
||||||
use librashader_runtime::binding::{BindingUtil, TextureInput};
|
use librashader_runtime::binding::{BindingUtil, TextureInput};
|
||||||
use librashader_runtime::image::{Image, UVDirection};
|
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::Threading::{CreateEventA, ResetEvent, WaitForSingleObject};
|
||||||
use windows::Win32::System::WindowsProgramming::INFINITE;
|
use windows::Win32::System::WindowsProgramming::INFINITE;
|
||||||
|
|
||||||
|
use librashader_runtime::framebuffer::FramebufferInit;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use librashader_runtime::scaling::ScaleFramebuffer;
|
use librashader_runtime::scaling::ScaleFramebuffer;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
@ -190,44 +191,31 @@ impl FilterChainD3D12 {
|
||||||
options.map_or(false, |o| o.force_hlsl_pipeline),
|
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
|
// initialize output framebuffers
|
||||||
let mut output_framebuffers = Vec::new();
|
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
|
||||||
output_framebuffers.resize_with(filters.len(), || {
|
|
||||||
OwnedImage::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false)
|
|
||||||
});
|
|
||||||
|
|
||||||
// resolve all results
|
// initialize feedback framebuffers
|
||||||
let output_framebuffers = output_framebuffers
|
let (feedback_framebuffers, feedback_textures) =
|
||||||
.into_iter()
|
framebuffer_init.init_output_framebuffers()?;
|
||||||
.collect::<error::Result<Vec<OwnedImage>>>()?;
|
|
||||||
let mut output_textures = Vec::new();
|
|
||||||
output_textures.resize_with(filters.len(), || None);
|
|
||||||
|
|
||||||
// let mut output_textures = Vec::new();
|
// initialize history
|
||||||
// output_textures.resize_with(filters.len(), || None);
|
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
|
||||||
//
|
|
||||||
// // 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)?;
|
|
||||||
|
|
||||||
Ok(FilterChainD3D12 {
|
Ok(FilterChainD3D12 {
|
||||||
common: FilterCommon {
|
common: FilterCommon {
|
||||||
d3d12: device.clone(),
|
d3d12: device.clone(),
|
||||||
samplers,
|
samplers,
|
||||||
output_textures: output_textures.into_boxed_slice(),
|
output_textures,
|
||||||
feedback_textures: feedback_textures.into_boxed_slice(),
|
feedback_textures,
|
||||||
luts,
|
luts,
|
||||||
mipmap_gen,
|
mipmap_gen,
|
||||||
root_signature,
|
root_signature,
|
||||||
|
@ -245,8 +233,8 @@ impl FilterChainD3D12 {
|
||||||
staging_heap,
|
staging_heap,
|
||||||
rtv_heap,
|
rtv_heap,
|
||||||
passes: filters,
|
passes: filters,
|
||||||
output_framebuffers: output_framebuffers.into_boxed_slice(),
|
output_framebuffers,
|
||||||
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
|
feedback_framebuffers,
|
||||||
history_framebuffers,
|
history_framebuffers,
|
||||||
work_heap: texture_heap,
|
work_heap: texture_heap,
|
||||||
sampler_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(
|
fn load_luts(
|
||||||
device: &ID3D12Device,
|
device: &ID3D12Device,
|
||||||
heap: &mut D3D12DescriptorHeap<CpuStagingHeap>,
|
heap: &mut D3D12DescriptorHeap<CpuStagingHeap>,
|
||||||
|
|
|
@ -35,7 +35,9 @@ mod tests {
|
||||||
let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
|
let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
|
||||||
// "../test/slang-shaders/crt/crt-lottes.slangp",
|
// "../test/slang-shaders/crt/crt-lottes.slangp",
|
||||||
// "../test/basic.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/crt/crt-royale.slangp",
|
||||||
// "../test/slang-shaders/vhs/VHSPro.slangp",
|
// "../test/slang-shaders/vhs/VHSPro.slangp",
|
||||||
&SampleCommandLine {
|
&SampleCommandLine {
|
||||||
|
|
|
@ -1,25 +1,26 @@
|
||||||
use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation};
|
use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation};
|
||||||
use crate::error::FilterChainError;
|
use crate::error::FilterChainError;
|
||||||
use crate::filter_pass::{FilterPass, UniformOffset};
|
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::options::{FilterChainOptionsGL, FrameOptionsGL};
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
use crate::texture::InputTexture;
|
use crate::texture::InputTexture;
|
||||||
use crate::util::{gl_get_version, gl_u16_to_version};
|
use crate::util::{gl_get_version, gl_u16_to_version};
|
||||||
use crate::{error, util, GLImage};
|
use crate::{error, util, GLImage};
|
||||||
use gl::types::{GLint, GLuint};
|
use gl::types::{GLint, GLuint};
|
||||||
use librashader_common::{FilterMode, Viewport, WrapMode};
|
use librashader_common::Viewport;
|
||||||
|
|
||||||
use librashader_presets::ShaderPreset;
|
use librashader_presets::ShaderPreset;
|
||||||
use librashader_reflect::back::cross::GlslVersion;
|
use librashader_reflect::back::cross::GlslVersion;
|
||||||
use librashader_reflect::back::targets::GLSL;
|
use librashader_reflect::back::targets::GLSL;
|
||||||
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
||||||
use librashader_reflect::front::GlslangCompilation;
|
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::presets::{CompilePresetTarget, ShaderPassArtifact};
|
||||||
use librashader_reflect::reflect::ReflectShader;
|
use librashader_reflect::reflect::ReflectShader;
|
||||||
use librashader_runtime::binding::BindingUtil;
|
use librashader_runtime::binding::BindingUtil;
|
||||||
|
use librashader_runtime::framebuffer::FramebufferInit;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use librashader_runtime::scaling::ScaleFramebuffer;
|
use librashader_runtime::scaling::ScaleFramebuffer;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
@ -38,9 +39,9 @@ pub(crate) struct FilterChainImpl<T: GLInterface> {
|
||||||
pub(crate) common: FilterCommon,
|
pub(crate) common: FilterCommon,
|
||||||
passes: Box<[FilterPass<T>]>,
|
passes: Box<[FilterPass<T>]>,
|
||||||
draw_quad: T::DrawQuad,
|
draw_quad: T::DrawQuad,
|
||||||
output_framebuffers: Box<[Framebuffer]>,
|
output_framebuffers: Box<[GLFramebuffer]>,
|
||||||
feedback_framebuffers: Box<[Framebuffer]>,
|
feedback_framebuffers: Box<[GLFramebuffer]>,
|
||||||
history_framebuffers: VecDeque<Framebuffer>,
|
history_framebuffers: VecDeque<GLFramebuffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct FilterCommon {
|
pub(crate) struct FilterCommon {
|
||||||
|
@ -120,31 +121,40 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
|
|
||||||
let samplers = SamplerSet::new();
|
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
|
// load luts
|
||||||
let luts = T::LoadLut::load_luts(&preset.textures)?;
|
let luts = T::LoadLut::load_luts(&preset.textures)?;
|
||||||
|
|
||||||
let (history_framebuffers, history_textures) =
|
let framebuffer_gen = || Ok::<_, FilterChainError>(T::FramebufferInterface::new(1));
|
||||||
FilterChainImpl::init_history(&filters, default_filter, default_wrap);
|
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
|
// create vertex objects
|
||||||
let draw_quad = T::DrawQuad::new();
|
let draw_quad = T::DrawQuad::new();
|
||||||
|
|
||||||
Ok(FilterChainImpl {
|
Ok(FilterChainImpl {
|
||||||
passes: filters,
|
passes: filters,
|
||||||
output_framebuffers: output_framebuffers.into_boxed_slice(),
|
output_framebuffers,
|
||||||
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
|
feedback_framebuffers,
|
||||||
history_framebuffers,
|
history_framebuffers,
|
||||||
draw_quad,
|
draw_quad,
|
||||||
common: FilterCommon {
|
common: FilterCommon {
|
||||||
|
@ -159,8 +169,8 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
|
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
|
||||||
luts,
|
luts,
|
||||||
samplers,
|
samplers,
|
||||||
output_textures: output_textures.into_boxed_slice(),
|
output_textures,
|
||||||
feedback_textures: feedback_textures.into_boxed_slice(),
|
feedback_textures,
|
||||||
history_textures,
|
history_textures,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -274,37 +284,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
Ok(filters.into_boxed_slice())
|
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<()> {
|
fn push_history(&mut self, input: &GLImage) -> error::Result<()> {
|
||||||
if let Some(mut back) = self.history_framebuffers.pop_back() {
|
if let Some(mut back) = self.history_framebuffers.pop_back() {
|
||||||
if back.size != input.size || (input.format != 0 && input.format != back.format) {
|
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)?;
|
back.copy_from::<T::FramebufferInterface>(input)?;
|
||||||
|
|
||||||
self.history_framebuffers.push_front(back)
|
self.history_framebuffers.push_front(back)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +304,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
pub fn frame(
|
pub fn frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
frame_count: usize,
|
frame_count: usize,
|
||||||
viewport: &Viewport<&Framebuffer>,
|
viewport: &Viewport<&GLFramebuffer>,
|
||||||
input: &GLImage,
|
input: &GLImage,
|
||||||
options: Option<&FrameOptionsGL>,
|
options: Option<&FrameOptionsGL>,
|
||||||
) -> error::Result<()> {
|
) -> error::Result<()> {
|
||||||
|
@ -364,18 +342,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
texture.image = fbo.as_texture(filter, wrap_mode).image;
|
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
|
// shader_gl3: 2067
|
||||||
let original = InputTexture {
|
let original = InputTexture {
|
||||||
image: *input,
|
image: *input,
|
||||||
|
@ -387,7 +353,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
let mut source = original;
|
let mut source = original;
|
||||||
|
|
||||||
// rescale render buffers to ensure all bindings are valid.
|
// 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,
|
source.image.size,
|
||||||
viewport.output.size,
|
viewport.output.size,
|
||||||
&mut self.output_framebuffers,
|
&mut self.output_framebuffers,
|
||||||
|
@ -396,6 +362,20 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
None,
|
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 passes_len = passes.len();
|
||||||
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::error::{FilterChainError, Result};
|
||||||
use crate::filter_chain::filter_impl::FilterChainImpl;
|
use crate::filter_chain::filter_impl::FilterChainImpl;
|
||||||
use crate::filter_chain::inner::FilterChainDispatch;
|
use crate::filter_chain::inner::FilterChainDispatch;
|
||||||
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
|
use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
|
||||||
use crate::{Framebuffer, GLImage};
|
use crate::{GLFramebuffer, GLImage};
|
||||||
use librashader_presets::ShaderPreset;
|
use librashader_presets::ShaderPreset;
|
||||||
|
|
||||||
mod filter_impl;
|
mod filter_impl;
|
||||||
|
@ -61,7 +61,7 @@ impl FilterChainGL {
|
||||||
pub fn frame(
|
pub fn frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
input: &GLImage,
|
input: &GLImage,
|
||||||
viewport: &Viewport<&Framebuffer>,
|
viewport: &Viewport<&GLFramebuffer>,
|
||||||
frame_count: usize,
|
frame_count: usize,
|
||||||
options: Option<&FrameOptionsGL>,
|
options: Option<&FrameOptionsGL>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::binding::{GlUniformBinder, GlUniformStorage, UniformLocation, Variabl
|
||||||
use crate::filter_chain::FilterCommon;
|
use crate::filter_chain::FilterCommon;
|
||||||
use crate::gl::{BindTexture, GLInterface, UboRing};
|
use crate::gl::{BindTexture, GLInterface, UboRing};
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
use crate::Framebuffer;
|
use crate::GLFramebuffer;
|
||||||
|
|
||||||
use crate::texture::InputTexture;
|
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 reflection: ShaderReflection,
|
||||||
pub program: GLuint,
|
pub program: GLuint,
|
||||||
pub ubo_location: UniformLocation<GLuint>,
|
pub ubo_location: UniformLocation<GLuint>,
|
||||||
|
@ -81,10 +81,10 @@ impl<T: GLInterface> FilterPass<T> {
|
||||||
parent: &FilterCommon,
|
parent: &FilterCommon,
|
||||||
frame_count: u32,
|
frame_count: u32,
|
||||||
frame_direction: i32,
|
frame_direction: i32,
|
||||||
viewport: &Viewport<&Framebuffer>,
|
viewport: &Viewport<&GLFramebuffer>,
|
||||||
original: &InputTexture,
|
original: &InputTexture,
|
||||||
source: &InputTexture,
|
source: &InputTexture,
|
||||||
output: RenderTarget<Framebuffer, GLint>,
|
output: RenderTarget<GLFramebuffer, GLint>,
|
||||||
) {
|
) {
|
||||||
let framebuffer = output.output;
|
let framebuffer = output.output;
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ impl<T: GLInterface> FilterPass<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.fbo);
|
||||||
gl::UseProgram(self.program);
|
gl::UseProgram(self.program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ impl<T: GLInterface> FilterPass<T> {
|
||||||
frame_count: u32,
|
frame_count: u32,
|
||||||
frame_direction: i32,
|
frame_direction: i32,
|
||||||
fb_size: Size<u32>,
|
fb_size: Size<u32>,
|
||||||
viewport: &Viewport<&Framebuffer>,
|
viewport: &Viewport<&GLFramebuffer>,
|
||||||
original: &InputTexture,
|
original: &InputTexture,
|
||||||
source: &InputTexture,
|
source: &InputTexture,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -11,9 +11,9 @@ use librashader_runtime::scaling::ScaleFramebuffer;
|
||||||
///
|
///
|
||||||
/// Generally for use as render targets.
|
/// Generally for use as render targets.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Framebuffer {
|
pub struct GLFramebuffer {
|
||||||
pub(crate) image: GLuint,
|
pub(crate) image: GLuint,
|
||||||
pub(crate) handle: GLuint,
|
pub(crate) fbo: GLuint,
|
||||||
pub(crate) size: Size<u32>,
|
pub(crate) size: Size<u32>,
|
||||||
pub(crate) format: GLenum,
|
pub(crate) format: GLenum,
|
||||||
pub(crate) max_levels: u32,
|
pub(crate) max_levels: u32,
|
||||||
|
@ -21,7 +21,7 @@ pub struct Framebuffer {
|
||||||
pub(crate) is_raw: bool,
|
pub(crate) is_raw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Framebuffer {
|
impl GLFramebuffer {
|
||||||
/// Create a framebuffer from an already initialized texture and framebuffer.
|
/// Create a framebuffer from an already initialized texture and framebuffer.
|
||||||
///
|
///
|
||||||
/// The framebuffer will not be deleted when this struct is dropped.
|
/// The framebuffer will not be deleted when this struct is dropped.
|
||||||
|
@ -31,14 +31,14 @@ impl Framebuffer {
|
||||||
format: GLenum,
|
format: GLenum,
|
||||||
size: Size<u32>,
|
size: Size<u32>,
|
||||||
miplevels: u32,
|
miplevels: u32,
|
||||||
) -> Framebuffer {
|
) -> GLFramebuffer {
|
||||||
Framebuffer {
|
GLFramebuffer {
|
||||||
image: texture,
|
image: texture,
|
||||||
size,
|
size,
|
||||||
format,
|
format,
|
||||||
max_levels: miplevels,
|
max_levels: miplevels,
|
||||||
mip_levels: miplevels,
|
mip_levels: miplevels,
|
||||||
handle: fbo,
|
fbo: fbo,
|
||||||
is_raw: true,
|
is_raw: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,15 +76,15 @@ impl Framebuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Framebuffer {
|
impl Drop for GLFramebuffer {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.is_raw {
|
if self.is_raw {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.handle != 0 {
|
if self.fbo != 0 {
|
||||||
gl::DeleteFramebuffers(1, &self.handle);
|
gl::DeleteFramebuffers(1, &self.fbo);
|
||||||
}
|
}
|
||||||
if self.image != 0 {
|
if self.image != 0 {
|
||||||
gl::DeleteTextures(1, &self.image);
|
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 Error = FilterChainError;
|
||||||
type Context = ();
|
type Context = ();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::error::{FilterChainError, Result};
|
use crate::error::{FilterChainError, Result};
|
||||||
use crate::framebuffer::GLImage;
|
use crate::framebuffer::GLImage;
|
||||||
use crate::gl::framebuffer::Framebuffer;
|
use crate::gl::framebuffer::GLFramebuffer;
|
||||||
use crate::gl::FramebufferInterface;
|
use crate::gl::FramebufferInterface;
|
||||||
use gl::types::{GLenum, GLint, GLsizei};
|
use gl::types::{GLenum, GLint, GLsizei};
|
||||||
use librashader_common::{ImageFormat, Size};
|
use librashader_common::{ImageFormat, Size};
|
||||||
|
@ -11,7 +11,7 @@ use librashader_runtime::scaling::{MipmapSize, ViewportSize};
|
||||||
pub struct Gl3Framebuffer;
|
pub struct Gl3Framebuffer;
|
||||||
|
|
||||||
impl FramebufferInterface for Gl3Framebuffer {
|
impl FramebufferInterface for Gl3Framebuffer {
|
||||||
fn new(max_levels: u32) -> Framebuffer {
|
fn new(max_levels: u32) -> GLFramebuffer {
|
||||||
let mut framebuffer = 0;
|
let mut framebuffer = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::GenFramebuffers(1, &mut framebuffer);
|
gl::GenFramebuffers(1, &mut framebuffer);
|
||||||
|
@ -19,7 +19,7 @@ impl FramebufferInterface for Gl3Framebuffer {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Framebuffer {
|
GLFramebuffer {
|
||||||
image: 0,
|
image: 0,
|
||||||
size: Size {
|
size: Size {
|
||||||
width: 1,
|
width: 1,
|
||||||
|
@ -28,13 +28,13 @@ impl FramebufferInterface for Gl3Framebuffer {
|
||||||
format: 0,
|
format: 0,
|
||||||
max_levels,
|
max_levels,
|
||||||
mip_levels: 0,
|
mip_levels: 0,
|
||||||
handle: framebuffer,
|
fbo: framebuffer,
|
||||||
is_raw: false,
|
is_raw: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale(
|
fn scale(
|
||||||
fb: &mut Framebuffer,
|
fb: &mut GLFramebuffer,
|
||||||
scaling: Scale2D,
|
scaling: Scale2D,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
viewport_size: &Size<u32>,
|
viewport_size: &Size<u32>,
|
||||||
|
@ -66,10 +66,10 @@ impl FramebufferInterface for Gl3Framebuffer {
|
||||||
}
|
}
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
fn clear<const REBIND: bool>(fb: &Framebuffer) {
|
fn clear<const REBIND: bool>(fb: &GLFramebuffer) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if REBIND {
|
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::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
|
||||||
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
|
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.
|
// todo: may want to use a shader and draw a quad to be faster.
|
||||||
if image.size != fb.size || image.format != fb.format {
|
if image.size != fb.size || image.format != fb.format {
|
||||||
Self::init(fb, image.size, image.format)?;
|
Self::init(fb, image.size, image.format)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo);
|
||||||
|
|
||||||
gl::FramebufferTexture2D(
|
gl::FramebufferTexture2D(
|
||||||
gl::READ_FRAMEBUFFER,
|
gl::READ_FRAMEBUFFER,
|
||||||
|
@ -149,7 +149,7 @@ impl FramebufferInterface for Gl3Framebuffer {
|
||||||
|
|
||||||
Ok(())
|
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 {
|
if fb.is_raw {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ impl FramebufferInterface for Gl3Framebuffer {
|
||||||
fb.size = size;
|
fb.size = size;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle);
|
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo);
|
||||||
|
|
||||||
// reset the framebuffer image
|
// reset the framebuffer image
|
||||||
if fb.image != 0 {
|
if fb.image != 0 {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use librashader_common::{Size, Viewport};
|
||||||
use crate::filter_chain::FilterChainGL;
|
use crate::filter_chain::FilterChainGL;
|
||||||
use crate::framebuffer::GLImage;
|
use crate::framebuffer::GLImage;
|
||||||
|
|
||||||
use crate::Framebuffer;
|
use crate::GLFramebuffer;
|
||||||
|
|
||||||
const WIDTH: u32 = 800;
|
const WIDTH: u32 = 800;
|
||||||
const HEIGHT: u32 = 600;
|
const HEIGHT: u32 = 600;
|
||||||
|
@ -464,7 +464,7 @@ void main()
|
||||||
let (fb_width, fb_height) = window.get_framebuffer_size();
|
let (fb_width, fb_height) = window.get_framebuffer_size();
|
||||||
let (vp_width, vp_height) = window.get_size();
|
let (vp_width, vp_height) = window.get_size();
|
||||||
|
|
||||||
let output = Framebuffer::new_from_raw(
|
let output = GLFramebuffer::new_from_raw(
|
||||||
output_texture,
|
output_texture,
|
||||||
output_framebuffer_handle,
|
output_framebuffer_handle,
|
||||||
gl::RGBA8,
|
gl::RGBA8,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::error::{FilterChainError, Result};
|
use crate::error::{FilterChainError, Result};
|
||||||
use crate::framebuffer::GLImage;
|
use crate::framebuffer::GLImage;
|
||||||
use crate::gl::framebuffer::Framebuffer;
|
use crate::gl::framebuffer::GLFramebuffer;
|
||||||
use crate::gl::FramebufferInterface;
|
use crate::gl::FramebufferInterface;
|
||||||
use gl::types::{GLenum, GLint, GLsizei};
|
use gl::types::{GLenum, GLint, GLsizei};
|
||||||
use librashader_common::{ImageFormat, Size};
|
use librashader_common::{ImageFormat, Size};
|
||||||
|
@ -11,13 +11,13 @@ use librashader_runtime::scaling::{MipmapSize, ViewportSize};
|
||||||
pub struct Gl46Framebuffer;
|
pub struct Gl46Framebuffer;
|
||||||
|
|
||||||
impl FramebufferInterface for Gl46Framebuffer {
|
impl FramebufferInterface for Gl46Framebuffer {
|
||||||
fn new(max_levels: u32) -> Framebuffer {
|
fn new(max_levels: u32) -> GLFramebuffer {
|
||||||
let mut framebuffer = 0;
|
let mut framebuffer = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::CreateFramebuffers(1, &mut framebuffer);
|
gl::CreateFramebuffers(1, &mut framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Framebuffer {
|
GLFramebuffer {
|
||||||
image: 0,
|
image: 0,
|
||||||
size: Size {
|
size: Size {
|
||||||
width: 1,
|
width: 1,
|
||||||
|
@ -26,13 +26,13 @@ impl FramebufferInterface for Gl46Framebuffer {
|
||||||
format: 0,
|
format: 0,
|
||||||
max_levels,
|
max_levels,
|
||||||
mip_levels: 0,
|
mip_levels: 0,
|
||||||
handle: framebuffer,
|
fbo: framebuffer,
|
||||||
is_raw: false,
|
is_raw: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scale(
|
fn scale(
|
||||||
fb: &mut Framebuffer,
|
fb: &mut GLFramebuffer,
|
||||||
scaling: Scale2D,
|
scaling: Scale2D,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
viewport_size: &Size<u32>,
|
viewport_size: &Size<u32>,
|
||||||
|
@ -66,17 +66,17 @@ impl FramebufferInterface for Gl46Framebuffer {
|
||||||
}
|
}
|
||||||
Ok(size)
|
Ok(size)
|
||||||
}
|
}
|
||||||
fn clear<const REBIND: bool>(fb: &Framebuffer) {
|
fn clear<const REBIND: bool>(fb: &GLFramebuffer) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::ClearNamedFramebufferfv(
|
gl::ClearNamedFramebufferfv(
|
||||||
fb.handle,
|
fb.fbo,
|
||||||
gl::COLOR,
|
gl::COLOR,
|
||||||
0,
|
0,
|
||||||
[0.0f32, 0.0, 0.0, 0.0].as_ptr().cast(),
|
[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.
|
// todo: confirm this behaviour for unbound image.
|
||||||
if image.handle == 0 {
|
if image.handle == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -90,11 +90,11 @@ impl FramebufferInterface for Gl46Framebuffer {
|
||||||
unsafe {
|
unsafe {
|
||||||
// gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1);
|
// gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1);
|
||||||
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
|
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
|
||||||
gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT0);
|
gl::NamedFramebufferDrawBuffer(fb.fbo, gl::COLOR_ATTACHMENT0);
|
||||||
|
|
||||||
gl::BlitNamedFramebuffer(
|
gl::BlitNamedFramebuffer(
|
||||||
image.handle,
|
image.handle,
|
||||||
fb.handle,
|
fb.fbo,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
image.size.width as GLint,
|
image.size.width as GLint,
|
||||||
|
@ -110,7 +110,7 @@ impl FramebufferInterface for Gl46Framebuffer {
|
||||||
|
|
||||||
Ok(())
|
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 {
|
if fb.is_raw {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ impl FramebufferInterface for Gl46Framebuffer {
|
||||||
unsafe {
|
unsafe {
|
||||||
// reset the framebuffer image
|
// reset the framebuffer image
|
||||||
if fb.image != 0 {
|
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);
|
gl::DeleteTextures(1, &fb.image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,13 +149,13 @@ impl FramebufferInterface for Gl46Framebuffer {
|
||||||
size.height 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);
|
||||||
|
|
||||||
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
|
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
|
||||||
if status != gl::FRAMEBUFFER_COMPLETE {
|
if status != gl::FRAMEBUFFER_COMPLETE {
|
||||||
match status {
|
match status {
|
||||||
gl::FRAMEBUFFER_UNSUPPORTED => {
|
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::DeleteTextures(1, &fb.image);
|
||||||
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image);
|
gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image);
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ impl FramebufferInterface for Gl46Framebuffer {
|
||||||
size.width as GLsizei,
|
size.width as GLsizei,
|
||||||
size.height 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 =
|
// fb.init =
|
||||||
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
|
// gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use librashader_common::{Size, Viewport};
|
||||||
use crate::filter_chain::FilterChainGL;
|
use crate::filter_chain::FilterChainGL;
|
||||||
use crate::framebuffer::GLImage;
|
use crate::framebuffer::GLImage;
|
||||||
|
|
||||||
use crate::Framebuffer;
|
use crate::GLFramebuffer;
|
||||||
|
|
||||||
const WIDTH: u32 = 800;
|
const WIDTH: u32 = 800;
|
||||||
const HEIGHT: u32 = 600;
|
const HEIGHT: u32 = 600;
|
||||||
|
@ -455,7 +455,7 @@ void main()
|
||||||
let (fb_width, fb_height) = window.get_framebuffer_size();
|
let (fb_width, fb_height) = window.get_framebuffer_size();
|
||||||
let (vp_width, vp_height) = window.get_size();
|
let (vp_width, vp_height) = window.get_size();
|
||||||
|
|
||||||
let output = Framebuffer::new_from_raw(
|
let output = GLFramebuffer::new_from_raw(
|
||||||
output_texture,
|
output_texture,
|
||||||
output_framebuffer_handle,
|
output_framebuffer_handle,
|
||||||
gl::RGBA8,
|
gl::RGBA8,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::error::Result;
|
||||||
use crate::framebuffer::GLImage;
|
use crate::framebuffer::GLImage;
|
||||||
use crate::samplers::SamplerSet;
|
use crate::samplers::SamplerSet;
|
||||||
use crate::texture::InputTexture;
|
use crate::texture::InputTexture;
|
||||||
pub use framebuffer::Framebuffer;
|
pub use framebuffer::GLFramebuffer;
|
||||||
use gl::types::{GLenum, GLuint};
|
use gl::types::{GLenum, GLuint};
|
||||||
use librashader_common::{ImageFormat, Size};
|
use librashader_common::{ImageFormat, Size};
|
||||||
use librashader_presets::{Scale2D, TextureConfig};
|
use librashader_presets::{Scale2D, TextureConfig};
|
||||||
|
@ -15,17 +15,17 @@ use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
|
||||||
use librashader_runtime::uniforms::UniformStorageAccess;
|
use librashader_runtime::uniforms::UniformStorageAccess;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
pub trait LoadLut {
|
pub(crate) trait LoadLut {
|
||||||
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, InputTexture>>;
|
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, InputTexture>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DrawQuad {
|
pub(crate) trait DrawQuad {
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
fn bind_vertices(&self);
|
fn bind_vertices(&self);
|
||||||
fn unbind_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 new(buffer_size: u32) -> Self;
|
||||||
fn bind_for_frame(
|
fn bind_for_frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -35,27 +35,27 @@ pub trait UboRing<const SIZE: usize> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FramebufferInterface {
|
pub(crate) trait FramebufferInterface {
|
||||||
fn new(max_levels: u32) -> Framebuffer;
|
fn new(max_levels: u32) -> GLFramebuffer;
|
||||||
fn scale(
|
fn scale(
|
||||||
fb: &mut Framebuffer,
|
fb: &mut GLFramebuffer,
|
||||||
scaling: Scale2D,
|
scaling: Scale2D,
|
||||||
format: ImageFormat,
|
format: ImageFormat,
|
||||||
viewport_size: &Size<u32>,
|
viewport_size: &Size<u32>,
|
||||||
source_size: &Size<u32>,
|
source_size: &Size<u32>,
|
||||||
mipmap: bool,
|
mipmap: bool,
|
||||||
) -> Result<Size<u32>>;
|
) -> Result<Size<u32>>;
|
||||||
fn clear<const REBIND: bool>(fb: &Framebuffer);
|
fn clear<const REBIND: bool>(fb: &GLFramebuffer);
|
||||||
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()>;
|
fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()>;
|
||||||
fn init(fb: &mut Framebuffer, size: Size<u32>, format: impl Into<GLenum>) -> 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 bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture);
|
||||||
fn gen_mipmaps(texture: &InputTexture);
|
fn gen_mipmaps(texture: &InputTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GLInterface {
|
pub(crate) trait GLInterface {
|
||||||
type FramebufferInterface: FramebufferInterface;
|
type FramebufferInterface: FramebufferInterface;
|
||||||
type UboRing: UboRing<16>;
|
type UboRing: UboRing<16>;
|
||||||
type DrawQuad: DrawQuad;
|
type DrawQuad: DrawQuad;
|
||||||
|
|
|
@ -21,7 +21,7 @@ mod texture;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod options;
|
pub mod options;
|
||||||
|
|
||||||
pub use crate::gl::Framebuffer;
|
pub use crate::gl::GLFramebuffer;
|
||||||
pub use filter_chain::FilterChainGL;
|
pub use filter_chain::FilterChainGL;
|
||||||
pub use framebuffer::GLImage;
|
pub use framebuffer::GLImage;
|
||||||
|
|
||||||
|
@ -52,7 +52,9 @@ mod tests {
|
||||||
let (glfw, window, events, shader, vao) = gl::gl46::hello_triangle::setup();
|
let (glfw, window, events, shader, vao) = gl::gl46::hello_triangle::setup();
|
||||||
let mut filter = FilterChainGL::load_from_path(
|
let mut filter = FilterChainGL::load_from_path(
|
||||||
// "../test/slang-shaders/vhs/VHSPro.slangp",
|
// "../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 {
|
Some(&FilterChainOptionsGL {
|
||||||
glsl_version: 0,
|
glsl_version: 0,
|
||||||
use_dsa: true,
|
use_dsa: true,
|
||||||
|
|
|
@ -3,13 +3,14 @@ use crate::framebuffer::GLImage;
|
||||||
use librashader_common::{FilterMode, WrapMode};
|
use librashader_common::{FilterMode, WrapMode};
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone)]
|
#[derive(Default, Debug, Copy, Clone)]
|
||||||
pub struct InputTexture {
|
pub(crate) struct InputTexture {
|
||||||
pub image: GLImage,
|
pub image: GLImage,
|
||||||
pub filter: FilterMode,
|
pub filter: FilterMode,
|
||||||
pub mip_filter: FilterMode,
|
pub mip_filter: FilterMode,
|
||||||
pub wrap_mode: WrapMode,
|
pub wrap_mode: WrapMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An OpenGL texture bound as a shader resource.
|
||||||
impl InputTexture {
|
impl InputTexture {
|
||||||
pub fn is_bound(&self) -> bool {
|
pub fn is_bound(&self) -> bool {
|
||||||
self.image.handle != 0
|
self.image.handle != 0
|
||||||
|
|
|
@ -19,7 +19,7 @@ use librashader_reflect::back::targets::SPIRV;
|
||||||
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
||||||
use librashader_reflect::front::GlslangCompilation;
|
use librashader_reflect::front::GlslangCompilation;
|
||||||
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
|
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_reflect::reflect::ReflectShader;
|
||||||
use librashader_runtime::binding::BindingUtil;
|
use librashader_runtime::binding::BindingUtil;
|
||||||
use librashader_runtime::image::{Image, UVDirection};
|
use librashader_runtime::image::{Image, UVDirection};
|
||||||
|
@ -31,6 +31,7 @@ use std::collections::VecDeque;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use librashader_runtime::framebuffer::FramebufferInit;
|
||||||
use librashader_runtime::render_target::RenderTarget;
|
use librashader_runtime::render_target::RenderTarget;
|
||||||
use librashader_runtime::scaling::ScaleFramebuffer;
|
use librashader_runtime::scaling::ScaleFramebuffer;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
@ -145,8 +146,8 @@ pub(crate) struct FilterCommon {
|
||||||
pub(crate) luts: FxHashMap<usize, LutTexture>,
|
pub(crate) luts: FxHashMap<usize, LutTexture>,
|
||||||
pub samplers: SamplerSet,
|
pub samplers: SamplerSet,
|
||||||
pub(crate) draw_quad: DrawQuad,
|
pub(crate) draw_quad: DrawQuad,
|
||||||
pub output_inputs: Box<[Option<InputImage>]>,
|
pub output_textures: Box<[Option<InputImage>]>,
|
||||||
pub feedback_inputs: Box<[Option<InputImage>]>,
|
pub feedback_textures: Box<[Option<InputImage>]>,
|
||||||
pub history_textures: Box<[Option<InputImage>]>,
|
pub history_textures: Box<[Option<InputImage>]>,
|
||||||
pub config: FilterMutable,
|
pub config: FilterMutable,
|
||||||
pub device: Arc<ash::Device>,
|
pub device: Arc<ash::Device>,
|
||||||
|
@ -256,28 +257,24 @@ impl FilterChainVulkan {
|
||||||
let luts = FilterChainVulkan::load_luts(&device, &preset.textures)?;
|
let luts = FilterChainVulkan::load_luts(&device, &preset.textures)?;
|
||||||
let samplers = SamplerSet::new(&device.device)?;
|
let samplers = SamplerSet::new(&device.device)?;
|
||||||
|
|
||||||
let (history_framebuffers, history_textures) =
|
let framebuffer_gen =
|
||||||
FilterChainVulkan::init_history(&device, &filters)?;
|
|| 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();
|
// initialize output framebuffers
|
||||||
output_framebuffers.resize_with(filters.len(), || {
|
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
|
||||||
OwnedImage::new(&device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, 1)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut feedback_framebuffers = Vec::new();
|
// initialize feedback framebuffers
|
||||||
feedback_framebuffers.resize_with(filters.len(), || {
|
let (feedback_framebuffers, feedback_textures) =
|
||||||
OwnedImage::new(&device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, 1)
|
framebuffer_init.init_output_framebuffers()?;
|
||||||
});
|
|
||||||
|
|
||||||
let output_framebuffers: error::Result<Vec<OwnedImage>> =
|
// initialize history
|
||||||
output_framebuffers.into_iter().collect();
|
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
|
||||||
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);
|
|
||||||
|
|
||||||
let mut intermediates = Vec::new();
|
let mut intermediates = Vec::new();
|
||||||
intermediates.resize_with(frames_in_flight as usize, || {
|
intermediates.resize_with(frames_in_flight as usize, || {
|
||||||
|
@ -298,14 +295,14 @@ impl FilterChainVulkan {
|
||||||
},
|
},
|
||||||
draw_quad: DrawQuad::new(&device.device, &device.alloc)?,
|
draw_quad: DrawQuad::new(&device.device, &device.alloc)?,
|
||||||
device: device.device.clone(),
|
device: device.device.clone(),
|
||||||
output_inputs: output_textures.into_boxed_slice(),
|
output_textures,
|
||||||
feedback_inputs: feedback_textures.into_boxed_slice(),
|
feedback_textures,
|
||||||
history_textures,
|
history_textures,
|
||||||
},
|
},
|
||||||
passes: filters,
|
passes: filters,
|
||||||
vulkan: device,
|
vulkan: device,
|
||||||
output_framebuffers: output_framebuffers?.into_boxed_slice(),
|
output_framebuffers,
|
||||||
feedback_framebuffers: feedback_framebuffers?.into_boxed_slice(),
|
feedback_framebuffers,
|
||||||
history_framebuffers,
|
history_framebuffers,
|
||||||
residuals: intermediates.into_boxed_slice(),
|
residuals: intermediates.into_boxed_slice(),
|
||||||
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
|
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
|
||||||
|
@ -374,6 +371,7 @@ impl FilterChainVulkan {
|
||||||
graphics_pipeline,
|
graphics_pipeline,
|
||||||
// ubo_ring,
|
// ubo_ring,
|
||||||
frames_in_flight,
|
frames_in_flight,
|
||||||
|
internal_frame_count: 0,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -443,36 +441,6 @@ impl FilterChainVulkan {
|
||||||
Ok(luts)
|
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
|
// image must be in SHADER_READ_OPTIMAL
|
||||||
pub fn push_history(
|
pub fn push_history(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -640,9 +608,9 @@ impl FilterChainVulkan {
|
||||||
output: &OwnedImage,
|
output: &OwnedImage,
|
||||||
feedback: &OwnedImage| {
|
feedback: &OwnedImage| {
|
||||||
// refresh inputs
|
// refresh inputs
|
||||||
self.common.feedback_inputs[index] =
|
self.common.feedback_textures[index] =
|
||||||
Some(feedback.as_input(pass.config.filter, pass.config.wrap_mode));
|
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));
|
Some(output.as_input(pass.config.filter, pass.config.wrap_mode));
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
|
@ -682,7 +650,7 @@ impl FilterChainVulkan {
|
||||||
out.output.end_pass(cmd);
|
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_outputs(output_image);
|
||||||
intermediates.dispose_framebuffers(residual_fb);
|
intermediates.dispose_framebuffers(residual_fb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub struct FilterPass {
|
||||||
pub graphics_pipeline: VulkanGraphicsPipeline,
|
pub graphics_pipeline: VulkanGraphicsPipeline,
|
||||||
// pub ubo_ring: VkUboRing,
|
// pub ubo_ring: VkUboRing,
|
||||||
pub frames_in_flight: u32,
|
pub frames_in_flight: u32,
|
||||||
|
pub internal_frame_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextureInput for InputImage {
|
impl TextureInput for InputImage {
|
||||||
|
@ -100,7 +101,7 @@ impl FilterPass {
|
||||||
vbo_type: QuadType,
|
vbo_type: QuadType,
|
||||||
) -> error::Result<Option<vk::Framebuffer>> {
|
) -> error::Result<Option<vk::Framebuffer>> {
|
||||||
let mut descriptor = self.graphics_pipeline.layout.descriptor_sets
|
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(
|
self.build_semantics(
|
||||||
pass_index,
|
pass_index,
|
||||||
|
@ -193,6 +194,7 @@ impl FilterPass {
|
||||||
parent.draw_quad.draw_quad(cmd, vbo_type);
|
parent.draw_quad.draw_quad(cmd, vbo_type);
|
||||||
self.graphics_pipeline.end_rendering(&parent.device, cmd);
|
self.graphics_pipeline.end_rendering(&parent.device, cmd);
|
||||||
}
|
}
|
||||||
|
self.internal_frame_count += 1;
|
||||||
Ok(residual)
|
Ok(residual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,10 +225,10 @@ impl FilterPass {
|
||||||
source,
|
source,
|
||||||
&self.uniform_bindings,
|
&self.uniform_bindings,
|
||||||
&self.reflection.meta.texture_meta,
|
&self.reflection.meta.texture_meta,
|
||||||
parent.output_inputs[0..pass_index]
|
parent.output_textures[0..pass_index]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|o| o.as_ref()),
|
.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.history_textures.iter().map(|o| o.as_ref()),
|
||||||
parent.luts.iter().map(|(u, i)| (*u, i.as_ref())),
|
parent.luts.iter().map(|(u, i)| (*u, i.as_ref())),
|
||||||
&self.source.parameters,
|
&self.source.parameters,
|
||||||
|
|
|
@ -44,7 +44,8 @@ mod tests {
|
||||||
let filter = FilterChainVulkan::load_from_path(
|
let filter = FilterChainVulkan::load_from_path(
|
||||||
&base,
|
&base,
|
||||||
// "../test/slang-shaders/crt/crt-royale.slangp",
|
// "../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",
|
// "../test/basic.slangp",
|
||||||
Some(&FilterChainOptionsVulkan {
|
Some(&FilterChainOptionsVulkan {
|
||||||
frames_in_flight: 3,
|
frames_in_flight: 3,
|
||||||
|
|
|
@ -310,19 +310,21 @@ impl BindingUtil for BindingMeta {
|
||||||
|
|
||||||
for pass in pass_meta {
|
for pass in pass_meta {
|
||||||
// If a shader uses history size, but not history, we still need to keep the texture.
|
// 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
|
.texture_meta
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
|
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
|
||||||
.count();
|
.map(|(semantic, _)| semantic.index)
|
||||||
let texture_size_count = pass
|
.fold(0, std::cmp::max);
|
||||||
|
let texture_size_max_index = pass
|
||||||
.texture_size_meta
|
.texture_size_meta
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
|
.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_max_index);
|
||||||
required_images = std::cmp::max(required_images, texture_size_count);
|
required_images = std::cmp::max(required_images, texture_size_max_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
required_images
|
required_images
|
||||||
|
|
92
librashader-runtime/src/framebuffer.rs
Normal file
92
librashader-runtime/src/framebuffer.rs
Normal 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(),
|
||||||
|
))
|
||||||
|
}
|
|
@ -34,3 +34,6 @@ pub mod filter_pass;
|
||||||
|
|
||||||
/// Common types for render targets.
|
/// Common types for render targets.
|
||||||
pub mod render_target;
|
pub mod render_target;
|
||||||
|
|
||||||
|
/// Helpers for handling framebuffers.
|
||||||
|
pub mod framebuffer;
|
||||||
|
|
|
@ -214,7 +214,7 @@ pub mod runtime {
|
||||||
pub use librashader_runtime_gl::{
|
pub use librashader_runtime_gl::{
|
||||||
error,
|
error,
|
||||||
options::{FilterChainOptionsGL as FilterChainOptions, FrameOptionsGL as FrameOptions},
|
options::{FilterChainOptionsGL as FilterChainOptions, FrameOptionsGL as FrameOptions},
|
||||||
FilterChainGL as FilterChain, Framebuffer, GLImage,
|
FilterChainGL as FilterChain, GLFramebuffer, GLImage,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
Loading…
Reference in a new issue