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::filter_pass::FilterPass;
use crate::framebuffer::Framebuffer;
use crate::render_target::RenderTarget;
use crate::util;
use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport};
@ -97,23 +98,23 @@ impl FilterChain {
pub struct FilterChain {
passes: Vec<FilterPass>,
common: FilterCommon,
pub quad_vao: GLuint,
quad_vao: GLuint,
}
pub struct FilterCommon {
semantics: ReflectSemantics,
preset: ShaderPreset,
pub(crate) preset: ShaderPreset,
original_history: Vec<Framebuffer>,
history: Vec<Texture>,
feedback: Vec<Texture>,
luts: FxHashMap<usize, Texture>,
pub(crate) luts: FxHashMap<usize, Texture>,
outputs: Vec<Framebuffer>,
pub quad_vbo: GLuint,
pub(crate) quad_vbo: GLuint,
}
impl FilterChain {
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 texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> = Default::default();
@ -274,9 +275,6 @@ impl FilterChain {
push_buffer,
variable_bindings: locations,
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()
});
}
@ -382,7 +380,10 @@ impl FilterChain {
}
pub fn frame(&mut self, count: u32, vp: &Viewport, input: GlImage, clear: bool) {
//
if self.passes.is_empty() {
return;
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
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 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);
// todo: update-pass-outputs
@ -423,7 +424,7 @@ impl FilterChain {
for pass in last {
source.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 {

View file

@ -13,6 +13,7 @@ use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, Texture
use crate::framebuffer::Framebuffer;
use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
use crate::filter_chain::{FilterChain, FilterCommon};
use crate::render_target::RenderTarget;
use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport};
pub struct FilterPass {
@ -24,7 +25,6 @@ pub struct FilterPass {
pub uniform_buffer: Box<[u8]>,
pub push_buffer: Box<[u8]>,
pub variable_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
pub feedback_framebuffer: Framebuffer,
pub source: ShaderSource,
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)
pub fn draw(&mut self, parent: &FilterCommon, mvp: Option<&[f32]>, frame_count: u32,
frame_direction: i32, viewport: &Viewport, original: &Texture, source: &Texture, output: &Framebuffer) {
pub fn draw(&mut self, parent: &FilterCommon, frame_count: u32,
frame_direction: i32, viewport: &Viewport, original: &Texture, source: &Texture, output: RenderTarget) {
let framebuffer = output.framebuffer;
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, output.framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
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
if self.ubo_location.vertex != gl::INVALID_INDEX && self.ubo_location.fragment != gl::INVALID_INDEX {
@ -142,14 +145,14 @@ impl FilterPass {
// todo: final pass?
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, output.framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32);
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);
} else {
gl::Disable(gl::FRAMEBUFFER_SRGB);
@ -161,6 +164,7 @@ impl FilterPass {
gl::EnableVertexAttribArray(0);
gl::EnableVertexAttribArray(1);
gl::BindBuffer(gl::ARRAY_BUFFER, parent.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
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()) {
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 (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),

View file

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

View file

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

View file

@ -6,33 +6,7 @@ mod util;
mod framebuffer;
mod binding;
mod filter_chain;
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;
mod render_target;
#[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 y: i32,
pub output: &'a Framebuffer,
pub mvp: Option<&'a [f32]>
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]