gl: abstract output to render target

This commit is contained in:
chyyran 2022-11-19 23:16:19 -05:00
parent 19cd09d32b
commit e911d40429
7 changed files with 72 additions and 60 deletions

View file

@ -14,6 +14,7 @@ use librashader_reflect::back::CompileShader;
use crate::binding::{UniformBinding, UniformLocation, VariableLocation}; use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
use crate::filter_pass::FilterPass; use crate::filter_pass::FilterPass;
use crate::framebuffer::Framebuffer; use crate::framebuffer::Framebuffer;
use crate::render_target::RenderTarget;
use crate::util; use crate::util;
use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport}; use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport};
@ -97,23 +98,23 @@ impl FilterChain {
pub struct FilterChain { pub struct FilterChain {
passes: Vec<FilterPass>, passes: Vec<FilterPass>,
common: FilterCommon, common: FilterCommon,
pub quad_vao: GLuint, quad_vao: GLuint,
} }
pub struct FilterCommon { pub struct FilterCommon {
semantics: ReflectSemantics, semantics: ReflectSemantics,
preset: ShaderPreset, pub(crate) preset: ShaderPreset,
original_history: Vec<Framebuffer>, original_history: Vec<Framebuffer>,
history: Vec<Texture>, history: Vec<Texture>,
feedback: Vec<Texture>, feedback: Vec<Texture>,
luts: FxHashMap<usize, Texture>, pub(crate) luts: FxHashMap<usize, Texture>,
outputs: Vec<Framebuffer>, outputs: Vec<Framebuffer>,
pub quad_vbo: GLuint, pub(crate) quad_vbo: GLuint,
} }
impl FilterChain { impl FilterChain {
pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> { pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> {
let preset = librashader_presets::ShaderPreset::try_parse(path)?; let preset = ShaderPreset::try_parse(path)?;
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default(); let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> = Default::default(); let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> = Default::default();
@ -274,9 +275,6 @@ impl FilterChain {
push_buffer, push_buffer,
variable_bindings: locations, variable_bindings: locations,
source, source,
// no idea if this works.
// retroarch checks if feedback frames are used but we'll just init it tbh.
feedback_framebuffer: Framebuffer::new(1),
config: config.clone() config: config.clone()
}); });
} }
@ -382,7 +380,10 @@ impl FilterChain {
} }
pub fn frame(&mut self, count: u32, vp: &Viewport, input: GlImage, clear: bool) { pub fn frame(&mut self, count: u32, vp: &Viewport, input: GlImage, clear: bool) {
// if self.passes.is_empty() {
return;
}
unsafe { unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindVertexArray(self.quad_vao); gl::BindVertexArray(self.quad_vao);
@ -411,7 +412,7 @@ impl FilterChain {
let framebuffer_size = target.scale(pass.config.scaling.clone(), pass.get_format(), vp, &original, &source); let framebuffer_size = target.scale(pass.config.scaling.clone(), pass.get_format(), vp, &original, &source);
} }
let target = &self.common.outputs[index]; let target = &self.common.outputs[index];
pass.draw(&self.common, None, count, 1, vp, &original, &source, &target); pass.draw(&self.common, count, 1, vp, &original, &source, RenderTarget::new(target, None));
let target = target.as_texture(pass.config.filter, pass.config.wrap_mode); let target = target.as_texture(pass.config.filter, pass.config.wrap_mode);
// todo: update-pass-outputs // todo: update-pass-outputs
@ -423,7 +424,7 @@ impl FilterChain {
for pass in last { for pass in last {
source.filter = pass.config.filter; source.filter = pass.config.filter;
source.mip_filter = pass.config.filter; source.mip_filter = pass.config.filter;
pass.draw(&self.common, None, count, 1, vp, &original, &source, &vp.output); pass.draw(&self.common, count, 1, vp, &original, &source, RenderTarget::new(&vp.output, vp.mvp));
} }
unsafe { unsafe {

View file

@ -13,6 +13,7 @@ use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, Texture
use crate::framebuffer::Framebuffer; use crate::framebuffer::Framebuffer;
use crate::binding::{UniformBinding, UniformLocation, VariableLocation}; use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
use crate::filter_chain::{FilterChain, FilterCommon}; use crate::filter_chain::{FilterChain, FilterCommon};
use crate::render_target::RenderTarget;
use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport}; use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport};
pub struct FilterPass { pub struct FilterPass {
@ -24,7 +25,6 @@ pub struct FilterPass {
pub uniform_buffer: Box<[u8]>, pub uniform_buffer: Box<[u8]>,
pub push_buffer: Box<[u8]>, pub push_buffer: Box<[u8]>,
pub variable_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>, pub variable_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
pub feedback_framebuffer: Framebuffer,
pub source: ShaderSource, pub source: ShaderSource,
pub config: ShaderPassConfig pub config: ShaderPassConfig
} }
@ -107,14 +107,17 @@ impl FilterPass {
} }
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
pub fn draw(&mut self, parent: &FilterCommon, mvp: Option<&[f32]>, frame_count: u32, pub fn draw(&mut self, parent: &FilterCommon, frame_count: u32,
frame_direction: i32, viewport: &Viewport, original: &Texture, source: &Texture, output: &Framebuffer) { frame_direction: i32, viewport: &Viewport, original: &Texture, source: &Texture, output: RenderTarget) {
let framebuffer = output.framebuffer;
unsafe { unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, output.framebuffer); gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
gl::UseProgram(self.program); gl::UseProgram(self.program);
} }
self.build_semantics(parent, mvp, frame_count, frame_direction, output.size, viewport, original, source); self.build_semantics(parent, output.mvp, frame_count, frame_direction, framebuffer.size, viewport, original, source);
// shader_gl3:1514 // shader_gl3:1514
if self.ubo_location.vertex != gl::INVALID_INDEX && self.ubo_location.fragment != gl::INVALID_INDEX { if self.ubo_location.vertex != gl::INVALID_INDEX && self.ubo_location.fragment != gl::INVALID_INDEX {
@ -142,14 +145,14 @@ impl FilterPass {
// todo: final pass? // todo: final pass?
unsafe { unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, output.framebuffer); gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32); gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32);
gl::Clear(gl::COLOR_BUFFER_BIT); gl::Clear(gl::COLOR_BUFFER_BIT);
// //
gl::Viewport(0, 0, output.size.width as GLsizei, output.size.height as GLsizei); gl::Viewport(0, 0, framebuffer.size.width as GLsizei, framebuffer.size.height as GLsizei);
if output.format == gl::SRGB8_ALPHA8 { if framebuffer.format == gl::SRGB8_ALPHA8 {
gl::Enable(gl::FRAMEBUFFER_SRGB); gl::Enable(gl::FRAMEBUFFER_SRGB);
} else { } else {
gl::Disable(gl::FRAMEBUFFER_SRGB); gl::Disable(gl::FRAMEBUFFER_SRGB);
@ -161,6 +164,7 @@ impl FilterPass {
gl::EnableVertexAttribArray(0); gl::EnableVertexAttribArray(0);
gl::EnableVertexAttribArray(1); gl::EnableVertexAttribArray(1);
gl::BindBuffer(gl::ARRAY_BUFFER, parent.quad_vbo); gl::BindBuffer(gl::ARRAY_BUFFER, parent.quad_vbo);
/// the provided pointers are of OpenGL provenance with respect to the buffer bound to quad_vbo, /// the provided pointers are of OpenGL provenance with respect to the buffer bound to quad_vbo,
@ -187,14 +191,8 @@ impl FilterPass {
} }
// framecount should be pre-modded // framecount should be pre-modded
fn build_semantics(&mut self, parent: &FilterCommon, mvp: Option<&[f32]>, frame_count: u32, frame_direction: i32, fb_size: Size, viewport: &Viewport, original: &Texture, source: &Texture) { fn build_semantics(&mut self, parent: &FilterCommon, mvp: &[f32], frame_count: u32, frame_direction: i32, fb_size: Size, viewport: &Viewport, original: &Texture, source: &Texture) {
if let Some((_location, offset)) = self.variable_bindings.get(&VariableSemantics::MVP.into()) { if let Some((_location, offset)) = self.variable_bindings.get(&VariableSemantics::MVP.into()) {
let mvp = mvp.unwrap_or(&[
2f32, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, 0.0, 1.0
]);
let mvp_size = mvp.len() * std::mem::size_of::<f32>(); let mvp_size = mvp.len() * std::mem::size_of::<f32>();
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),

View file

@ -11,7 +11,7 @@ pub struct Framebuffer {
pub format: GLenum, pub format: GLenum,
pub max_levels: u32, pub max_levels: u32,
pub levels: u32, pub levels: u32,
pub framebuffer: GLuint, pub handle: GLuint,
pub init: bool pub init: bool
} }
@ -30,7 +30,7 @@ impl Framebuffer {
format: 0, format: 0,
max_levels, max_levels,
levels: 0, levels: 0,
framebuffer, handle: framebuffer,
init: false init: false
} }
} }
@ -42,7 +42,7 @@ impl Framebuffer {
format, format,
max_levels: miplevels, max_levels: miplevels,
levels: miplevels, levels: miplevels,
framebuffer: handle, handle: handle,
init: true init: true
} }
} }
@ -129,7 +129,7 @@ impl Framebuffer {
self.size = size; self.size = size;
unsafe { unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer); gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
// reset the framebuffer image // reset the framebuffer image
if self.image != 0 { if self.image != 0 {
@ -199,8 +199,8 @@ impl Framebuffer {
impl Drop for Framebuffer { impl Drop for Framebuffer {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
if self.framebuffer != 0 { if self.handle != 0 {
gl::DeleteFramebuffers(1, &self.framebuffer); gl::DeleteFramebuffers(1, &self.handle);
} }
if self.image != 0 { if self.image != 0 {
gl::DeleteTextures(1, &self.image); gl::DeleteTextures(1, &self.image);

View file

@ -418,7 +418,8 @@ void main()
filter.frame(0, &Viewport { filter.frame(0, &Viewport {
x: 0, x: 0,
y: 0, y: 0,
output: &fb output: &fb,
mvp: None
}, GlImage { }, GlImage {
handle: rendered_texture, handle: rendered_texture,
format: gl::RGBA8, format: gl::RGBA8,

View file

@ -6,33 +6,7 @@ mod util;
mod framebuffer; mod framebuffer;
mod binding; mod binding;
mod filter_chain; mod filter_chain;
mod render_target;
use std::collections::HashMap;
use std::error::Error;
use std::iter::Filter;
use std::ops::Deref;
use std::path::Path;
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
use glfw::Key::P;
use rustc_hash::FxHashMap;
use spirv_cross::spirv::Decoration;
use filter_pass::FilterPass;
use framebuffer::Framebuffer;
use librashader::{FilterMode, ShaderFormat, ShaderSource, WrapMode};
use librashader::image::Image;
use librashader_presets::{ShaderPassConfig, ShaderPreset};
use librashader_reflect::back::{CompileShader, ShaderCompilerOutput};
use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion};
use librashader_reflect::back::targets::{FromCompilation, GLSL};
use librashader_reflect::front::shaderc::GlslangCompilation;
use librashader_reflect::reflect::cross::CrossReflect;
use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, ShaderReflection, UniformSemantic};
use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureSemantics, UniformMeta, VariableMeta, VariableSemantics};
use librashader_reflect::reflect::{TextureSemanticMap, VariableSemanticMap};
use binding::{UniformLocation, VariableLocation};
use util::{GlImage, RingBuffer, Size, Texture, Viewport};
use crate::binding::UniformBinding;
#[cfg(test)] #[cfg(test)]

View file

@ -0,0 +1,37 @@
use crate::framebuffer::Framebuffer;
use crate::util::Viewport;
static DEFAULT_MVP: &[f32] = &[
2f32, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, 0.0, 1.0
];
#[derive(Debug, Copy, Clone)]
pub struct RenderTarget<'a> {
pub mvp: &'a [f32],
pub framebuffer: &'a Framebuffer
}
impl <'a> RenderTarget<'a> {
pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32]>) -> Self {
if let Some(mvp) = mvp {
RenderTarget {
framebuffer: backbuffer,
mvp
}
} else {
RenderTarget {
framebuffer: backbuffer,
mvp: DEFAULT_MVP
}
}
}
}
impl <'a> From<&Viewport<'a>> for RenderTarget<'a> {
fn from(value: &Viewport<'a>) -> Self {
RenderTarget::new(value.output, value.mvp)
}
}

View file

@ -26,6 +26,7 @@ pub struct Viewport<'a> {
pub x: i32, pub x: i32,
pub y: i32, pub y: i32,
pub output: &'a Framebuffer, pub output: &'a Framebuffer,
pub mvp: Option<&'a [f32]>
} }
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]