gl: abstract output to render target
This commit is contained in:
parent
19cd09d32b
commit
e911d40429
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
|
37
librashader-runtime-gl/src/render_target.rs
Normal file
37
librashader-runtime-gl/src/render_target.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in a new issue