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::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 {
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
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 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)]
|
||||||
|
|
Loading…
Reference in a new issue