gl: implement passfeedback and original history

This commit is contained in:
chyyran 2022-11-21 02:13:10 -05:00
parent 0b336ca8c5
commit 10eb2c3106
15 changed files with 404 additions and 229 deletions

View file

@ -6,6 +6,7 @@ use nom::number::complete::float;
use nom::sequence::delimited; use nom::sequence::delimited;
use nom::IResult; use nom::IResult;
use std::str::FromStr; use std::str::FromStr;
use nom::character::complete::multispace1;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct ShaderMeta { pub(crate) struct ShaderMeta {
@ -15,18 +16,25 @@ pub(crate) struct ShaderMeta {
} }
fn parse_parameter_string(input: &str) -> Result<ShaderParameter, PreprocessError> { fn parse_parameter_string(input: &str) -> Result<ShaderParameter, PreprocessError> {
fn parse_parameter_string_inner(input: &str) -> IResult<&str, ShaderParameter> { fn parse_parameter_string_name(input: &str) -> IResult<&str, (&str, &str)> {
let (input, _) = tag("#pragma parameter ")(input)?; let (input, _) = tag("#pragma parameter ")(input)?;
let (input, name) = take_while(|c| c != ' ')(input)?; let (input, name) = take_while(|c| c != ' ' && c != '\t')(input)?;
let (input, _) = tag(" ")(input)?; let (input, _) = multispace1(input)?;
let (input, description) = delimited(tag("\""), is_not("\""), tag("\""))(input)?; let (input, description) = delimited(tag("\""), is_not("\""), tag("\""))(input)?;
let (input, _) = tag(" ")(input)?; let (input, _) = multispace1(input)?;
Ok((
input,
(name, description)
))
}
fn parse_parameter_string_inner<'a, 'b>(name: &'a str, description: &'a str, input: &'b str) -> IResult<&'b str, ShaderParameter> {
let (input, initial) = float(input)?; let (input, initial) = float(input)?;
let (input, _) = tag(" ")(input)?; let (input, _) = multispace1(input)?;
let (input, minimum) = float(input)?; let (input, minimum) = float(input)?;
let (input, _) = tag(" ")(input)?; let (input, _) = multispace1(input)?;
let (input, maximum) = float(input)?; let (input, maximum) = float(input)?;
let (input, _) = tag(" ")(input)?; let (input, _) = multispace1(input)?;
let (input, step) = float(input)?; let (input, step) = float(input)?;
Ok(( Ok((
input, input,
@ -41,11 +49,26 @@ fn parse_parameter_string(input: &str) -> Result<ShaderParameter, PreprocessErro
)) ))
} }
if let Ok((_, parameter)) = parse_parameter_string_inner(input) {
Ok(parameter) let Ok((params, (name, description))) = parse_parameter_string_name(input) else {
return Err(PreprocessError::PragmaParseError(input.to_string()));
};
// some shaders do some really funky things with their pragmas so we need to be lenient and ignore
// that it can be set at all.
if let Ok((_, param)) = parse_parameter_string_inner(name, description, params) {
Ok(param)
} else { } else {
Err(PreprocessError::PragmaParseError(input.to_string())) Ok(ShaderParameter {
id: name.to_string(),
description: description.to_string(),
initial: 0f32,
minimum: 0f32,
maximum: 0f32,
step: 0f32,
})
} }
} }
pub(crate) fn parse_pragma_meta(source: impl AsRef<str>) -> Result<ShaderMeta, PreprocessError> { pub(crate) fn parse_pragma_meta(source: impl AsRef<str>) -> Result<ShaderMeta, PreprocessError> {

View file

@ -10,3 +10,4 @@ thiserror = "1.0.37"
nom = "7.1.1" nom = "7.1.1"
nom_locate = "4.0.0" nom_locate = "4.0.0"
librashader = { path = "../librashader" } librashader = { path = "../librashader" }
num-traits = "0.2"

View file

@ -139,7 +139,7 @@ pub fn resolve_values(mut values: Vec<Value>) -> ShaderPreset {
Value::FrameCountMod(_, value) => Some(*value), Value::FrameCountMod(_, value) => Some(*value),
_ => None, _ => None,
}) })
.unwrap_or(1), .unwrap_or(0),
srgb_framebuffer: shader_values srgb_framebuffer: shader_values
.iter() .iter()
.find_map(|f| match f { .find_map(|f| match f {

View file

@ -6,6 +6,8 @@ use nom::character::complete::digit1;
use nom::combinator::{eof, map_res}; use nom::combinator::{eof, map_res};
use nom::IResult; use nom::IResult;
use num_traits::cast::ToPrimitive;
use crate::parse::token::do_lex; use crate::parse::token::do_lex;
use std::fs::File; use std::fs::File;
@ -66,14 +68,28 @@ impl Value {
fn from_int(input: Span) -> Result<i32, ParsePresetError> { fn from_int(input: Span) -> Result<i32, ParsePresetError> {
i32::from_str(input.trim()).map_err(|_| { i32::from_str(input.trim()).map_err(|_| {
eprintln!("{input}");
ParsePresetError::ParserError { ParsePresetError::ParserError {
offset: input.location_offset(), offset: input.location_offset(),
row: input.location_line(), row: input.location_line(),
col: input.get_column(), col: input.get_column(),
kind: ParseErrorKind::Int, kind: ParseErrorKind::Int,
} }
}).or_else(|e| {
let result = f32::from_str(input.trim())
.map_err(|_| e)?;
let result = result.trunc().to_i32()
.ok_or(ParsePresetError::ParserError {
offset: input.location_offset(),
row: input.location_line(),
col: input.get_column(),
kind: ParseErrorKind::Int,
})?;
eprintln!("falling back to float trunc {result}");
Ok(result)
}) })
} }
fn from_ul(input: Span) -> Result<u32, ParsePresetError> { fn from_ul(input: Span) -> Result<u32, ParsePresetError> {

View file

@ -260,6 +260,7 @@ where
if descriptor_set != 0 { if descriptor_set != 0 {
return Err(blame.error(SemanticsErrorKind::InvalidDescriptorSet(descriptor_set))); return Err(blame.error(SemanticsErrorKind::InvalidDescriptorSet(descriptor_set)));
} }
let size = ast.get_declared_struct_size(ubo.base_type_id)?; let size = ast.get_declared_struct_size(ubo.base_type_id)?;
Ok(UboData { Ok(UboData {
descriptor_set, descriptor_set,

View file

@ -1,3 +1,4 @@
use std::ops::Index;
use crate::error::ShaderReflectError; use crate::error::ShaderReflectError;
use crate::reflect::semantics::{ use crate::reflect::semantics::{
SemanticMap, TextureImage, TextureSemantics, TextureSizeMeta, VariableMeta, VariableSemantics, SemanticMap, TextureImage, TextureSemantics, TextureSizeMeta, VariableMeta, VariableSemantics,
@ -97,7 +98,9 @@ impl TextureSemanticMap<UniformSemantic> for FxHashMap<String, SemanticMap<Textu
None => { None => {
if let Some(semantics) = TextureSemantics::TEXTURE_SEMANTICS if let Some(semantics) = TextureSemantics::TEXTURE_SEMANTICS
.iter() .iter()
.find(|f| name.starts_with(f.texture_name())) .find(|f| {
name.starts_with(f.texture_name())
})
{ {
if semantics.is_array() { if semantics.is_array() {
let index = &name[semantics.texture_name().len()..]; let index = &name[semantics.texture_name().len()..];

View file

@ -63,10 +63,13 @@ pub enum TextureSemantics {
} }
impl TextureSemantics { impl TextureSemantics {
pub const TEXTURE_SEMANTICS: [TextureSemantics; 6] = [ pub(crate) const TEXTURE_SEMANTICS: [TextureSemantics; 6] = [
TextureSemantics::Original,
TextureSemantics::Source, TextureSemantics::Source,
// originalhistory needs to come first, otherwise
// the name lookup implementation will prioritize Original
// when reflecting semantics.
TextureSemantics::OriginalHistory, TextureSemantics::OriginalHistory,
TextureSemantics::Original,
TextureSemantics::PassOutput, TextureSemantics::PassOutput,
TextureSemantics::PassFeedback, TextureSemantics::PassFeedback,
TextureSemantics::User, TextureSemantics::User,

View file

@ -1,3 +1,4 @@
use std::collections::VecDeque;
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;
@ -6,8 +7,8 @@ use crate::util;
use crate::util::{GlImage, InlineRingBuffer, Size, Texture, Viewport}; use crate::util::{GlImage, InlineRingBuffer, Size, Texture, Viewport};
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint}; use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
use librashader::image::Image; use librashader::image::Image;
use librashader::{FilterMode, ShaderSource}; use librashader::{FilterMode, ShaderSource, WrapMode};
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; use librashader_presets::{ScaleType, ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::cross::{GlVersion, GlslangGlslContext}; use librashader_reflect::back::cross::{GlVersion, GlslangGlslContext};
use librashader_reflect::back::targets::{CompilerBackend, FromCompilation, GLSL}; use librashader_reflect::back::targets::{CompilerBackend, FromCompilation, GLSL};
use librashader_reflect::back::CompileShader; use librashader_reflect::back::CompileShader;
@ -19,11 +20,27 @@ use rustc_hash::FxHashMap;
use spirv_cross::spirv::Decoration; use spirv_cross::spirv::Decoration;
use std::error::Error; use std::error::Error;
use std::path::Path; use std::path::Path;
use crate::quad_render::DrawQuad;
pub struct FilterChain {
passes: Box<[FilterPass]>,
common: FilterCommon,
filter_vao: GLuint,
output_framebuffers: Box<[Framebuffer]>,
feedback_framebuffers: Box<[Framebuffer]>,
history_framebuffers: VecDeque<Framebuffer>,
}
pub struct FilterCommon {
semantics: ReflectSemantics,
pub(crate) preset: ShaderPreset,
pub(crate) luts: FxHashMap<usize, Texture>,
pub output_textures: Box<[Texture]>,
pub feedback_textures: Box<[Texture]>,
pub history_textures: Box<[Texture]>,
pub(crate) draw_quad: DrawQuad,
}
static QUAD_VBO_DATA: &[f32; 16] = &[
0.0f32, 0.0f32, 0.0f32, 0.0f32, 1.0f32, 0.0f32, 1.0f32, 0.0f32, 0.0f32, 1.0f32, 0.0f32, 1.0f32,
1.0f32, 1.0f32, 1.0f32, 1.0f32,
];
impl FilterChain { impl FilterChain {
fn load_pass_semantics( fn load_pass_semantics(
@ -103,24 +120,6 @@ impl FilterChain {
} }
} }
pub struct FilterChain {
passes: Box<[FilterPass]>,
common: FilterCommon,
quad_vao: GLuint,
output_framebuffers: Box<[Framebuffer]>,
}
pub struct FilterCommon {
semantics: ReflectSemantics,
pub(crate) preset: ShaderPreset,
pub original_history: Box<[Framebuffer]>,
pub history: Vec<Texture>,
pub feedback: Vec<Texture>,
pub(crate) luts: FxHashMap<usize, Texture>,
pub output_textures: Box<[Texture]>,
pub(crate) quad_vbo: GLuint,
}
type ShaderPassMeta<'a> = ( type ShaderPassMeta<'a> = (
&'a ShaderPassConfig, &'a ShaderPassConfig,
ShaderSource, ShaderSource,
@ -330,7 +329,6 @@ impl FilterChain {
.vertex .vertex
.get_decoration(res.id, Decoration::Location)?; .get_decoration(res.id, Decoration::Location)?;
let loc_name = format!("LIBRA_ATTRIBUTE_{loc}\0"); let loc_name = format!("LIBRA_ATTRIBUTE_{loc}\0");
eprintln!("{loc_name}");
gl::BindAttribLocation(program, loc, loc_name.as_str().as_ptr().cast()) gl::BindAttribLocation(program, loc, loc_name.as_str().as_ptr().cast())
} }
gl::LinkProgram(program); gl::LinkProgram(program);
@ -443,7 +441,7 @@ impl FilterChain {
); );
} }
// eprintln!("{:#?}", semantics); // eprintln!("{:#?}", reflection.meta.texture_meta);
// eprintln!("{:#?}", reflection.meta); // eprintln!("{:#?}", reflection.meta);
// eprintln!("{:#?}", locations); // eprintln!("{:#?}", locations);
// eprintln!("{:#?}", reflection.push_constant); // eprintln!("{:#?}", reflection.push_constant);
@ -469,7 +467,7 @@ impl FilterChain {
Ok(filters.into_boxed_slice()) Ok(filters.into_boxed_slice())
} }
pub fn init_history(filters: &[FilterPass]) -> Box<[Framebuffer]> { pub fn init_history(filters: &[FilterPass], filter: FilterMode, wrap_mode: WrapMode) -> (VecDeque<Framebuffer>, Box<[Texture]>) {
let mut required_images = 0; let mut required_images = 0;
for pass in filters { for pass in filters {
@ -493,56 +491,27 @@ impl FilterChain {
required_images = std::cmp::max(required_images, texture_size_count); required_images = std::cmp::max(required_images, texture_size_count);
} }
// not ussing frame history; // not using frame history;
if required_images < 2 { if required_images <= 1 {
eprintln!("not using frame history"); println!("[history] not using frame history");
return Vec::new().into_boxed_slice(); return (VecDeque::new(), Box::new([]))
} }
// history0 is aliased with the original // history0 is aliased with the original
required_images -= 1;
let mut framebuffers = Vec::new(); eprintln!("[history] using frame history with {required_images} images");
let mut framebuffers = VecDeque::with_capacity(required_images);
framebuffers.resize_with(required_images, || Framebuffer::new(1)); framebuffers.resize_with(required_images, || Framebuffer::new(1));
framebuffers.into_boxed_slice()
}
pub fn init_feedback(filters: &[FilterPass]) -> Box<[Framebuffer]> { let mut history_textures = Vec::new();
let mut required_images = 0; history_textures.resize_with(required_images, || Texture {
image: Default::default(),
filter,
mip_filter: filter,
wrap_mode
});
for pass in filters { (framebuffers, history_textures.into_boxed_slice())
// If a shader uses history size, but not history, we still need to keep the texture.
let texture_count = pass
.reflection
.meta
.texture_meta
.iter()
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
.count();
let texture_size_count = pass
.reflection
.meta
.texture_size_meta
.iter()
.filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
.count();
required_images = std::cmp::max(required_images, texture_count);
required_images = std::cmp::max(required_images, texture_size_count);
}
// not ussing frame history;
if required_images < 2 {
eprintln!("not using frame history");
return Vec::new().into_boxed_slice();
}
// history0 is aliased with the original
required_images -= 1;
let mut framebuffers = Vec::new();
framebuffers.resize_with(required_images, || Framebuffer::new(1));
framebuffers.into_boxed_slice()
} }
pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> { pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> {
@ -553,49 +522,50 @@ impl FilterChain {
// initialize passes // initialize passes
let filters = FilterChain::init_passes(passes, &semantics)?; let filters = FilterChain::init_passes(passes, &semantics)?;
let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default();
let default_wrap = filters.first().map(|f| f.config.wrap_mode).unwrap_or_default();
// initialize output framebuffers // initialize output framebuffers
let mut output_framebuffers = Vec::new(); let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1)); output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1));
let mut output_textures = Vec::new(); let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), Texture::default); output_textures.resize_with(filters.len(), Texture::default);
// initialize feedback framebuffers
let mut feedback_framebuffers = Vec::new();
feedback_framebuffers.resize_with(filters.len(), || Framebuffer::new(1));
let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), Texture::default);
// load luts // load luts
let luts = FilterChain::load_luts(&preset.textures)?; let luts = FilterChain::load_luts(&preset.textures)?;
let original_history = FilterChain::init_history(&filters); let (history_framebuffers, history_textures) =
FilterChain::init_history(&filters, default_filter, default_wrap);
// create VBO objects // create VBO objects
let mut quad_vbo = 0; let draw_quad = DrawQuad::new();
unsafe {
gl::GenBuffers(1, &mut quad_vbo);
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbo);
gl::BufferData(
gl::ARRAY_BUFFER,
std::mem::size_of_val(QUAD_VBO_DATA) as GLsizeiptr,
QUAD_VBO_DATA.as_ptr().cast(),
gl::STATIC_DRAW,
);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
}
let mut quad_vao = 0; let mut filter_vao = 0;
unsafe { unsafe {
gl::GenVertexArrays(1, &mut quad_vao); gl::GenVertexArrays(1, &mut filter_vao);
} }
Ok(FilterChain { Ok(FilterChain {
passes: filters, passes: filters,
output_framebuffers: output_framebuffers.into_boxed_slice(), output_framebuffers: output_framebuffers.into_boxed_slice(),
quad_vao, feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
history_framebuffers,
filter_vao,
common: FilterCommon { common: FilterCommon {
semantics, semantics,
preset, preset,
original_history,
history: vec![],
feedback: vec![],
luts, luts,
output_textures: output_textures.into_boxed_slice(), output_textures: output_textures.into_boxed_slice(),
quad_vbo, feedback_textures: feedback_textures.into_boxed_slice(),
history_textures,
draw_quad,
}, },
}) })
} }
@ -605,35 +575,58 @@ impl FilterChain {
self.output_framebuffers[index].as_texture(config.filter, config.wrap_mode) self.output_framebuffers[index].as_texture(config.filter, config.wrap_mode)
} }
pub fn frame(&mut self, count: usize, vp: &Viewport, input: GlImage, _clear: bool) { pub fn push_history(&mut self, input: &GlImage) {
if let Some(mut back) = self.history_framebuffers.pop_back() {
if back.size != input.size
|| (input.format != 0 && input.format != back.format) {
eprintln!("[history] resizing");
back.init(input.size, input.format);
}
if back.is_initialized() {
back.copy_from(&input);
}
self.history_framebuffers.push_front(back)
}
}
pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GlImage, clear: bool) {
if clear {
for framebuffer in &self.history_framebuffers {
framebuffer.clear()
}
}
if self.passes.is_empty() { if self.passes.is_empty() {
return; return;
} }
unsafe { unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindVertexArray(self.quad_vao); gl::BindVertexArray(self.filter_vao);
} }
// todo: copy framebuffer let filter = self.passes[0].config.filter;
// shader_gl3: 2067 let wrap_mode = self.passes[0].config.wrap_mode;
let filter = self
.common
.preset
.shaders
.first()
.map(|f| f.filter)
.unwrap_or_default();
let wrap_mode = self
.common
.preset
.shaders
.first()
.map(|f| f.wrap_mode)
.unwrap_or_default();
// update history
for (texture, fbo) in self.common.history_textures.iter_mut().zip(self.history_framebuffers.iter()) {
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(self.passes.iter())
{
texture.image = fbo.as_texture(pass.config.filter, pass.config.wrap_mode).image;
}
// shader_gl3: 2067
let original = Texture { let original = Texture {
image: input, image: *input,
filter, filter,
mip_filter: filter, mip_filter: filter,
wrap_mode, wrap_mode,
@ -650,7 +643,7 @@ impl FilterChain {
let _framebuffer_size = target.scale( let _framebuffer_size = target.scale(
pass.config.scaling.clone(), pass.config.scaling.clone(),
pass.get_format(), pass.get_format(),
vp, viewport,
&original, &original,
&source, &source,
); );
@ -660,9 +653,13 @@ impl FilterChain {
pass.draw( pass.draw(
index, index,
&self.common, &self.common,
(count % pass.config.frame_count_mod as usize) as u32, if pass.config.frame_count_mod > 0 {
count % pass.config.frame_count_mod as usize
} else {
count
} as u32,
1, 1,
vp, viewport,
&original, &original,
&source, &source,
RenderTarget::new(target, None), RenderTarget::new(target, None),
@ -681,19 +678,29 @@ impl FilterChain {
pass.draw( pass.draw(
passes_len - 1, passes_len - 1,
&self.common, &self.common,
(count % pass.config.frame_count_mod as usize) as u32, if pass.config.frame_count_mod > 0 {
count % pass.config.frame_count_mod as usize
} else {
count
} as u32,
1, 1,
vp, viewport,
&original, &original,
&source, &source,
RenderTarget::new(vp.output, vp.mvp), RenderTarget::new(viewport.output, viewport.mvp),
); );
} }
// swap feedback framebuffers with output
for (output, feedback) in self.output_framebuffers.iter_mut().zip(self.feedback_framebuffers.iter_mut()) {
std::mem::swap(output, feedback);
}
self.push_history(&input);
unsafe { unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindVertexArray(0); gl::BindVertexArray(0);
} }
// todo: deal with the mess that is frame history
} }
} }

View file

@ -93,8 +93,11 @@ impl FilterPass {
Self::build_uniform(location, buffer, value, gl::Uniform1f) Self::build_uniform(location, buffer, value, gl::Uniform1f)
} }
fn bind_texture(binding: &TextureImage, texture: &Texture) { fn bind_texture(binding: &TextureImage, texture: &Texture, semantic: TextureSemantics) {
unsafe { unsafe {
if texture.image.handle == 0 {
eprintln!("[WARNING] trying to bind {semantic:?} texture 0 to slot {} ", binding.binding)
}
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::ActiveTexture(gl::TEXTURE0 + binding.binding); gl::ActiveTexture(gl::TEXTURE0 + binding.binding);
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
@ -220,7 +223,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.draw_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,
/// and not a known provenance to the Rust abstract machine, therefore we give it invalid pointers. /// and not a known provenance to the Rust abstract machine, therefore we give it invalid pointers.
@ -344,8 +347,7 @@ impl FilterPass {
.texture_meta .texture_meta
.get(&TextureSemantics::Original.semantics(0)) .get(&TextureSemantics::Original.semantics(0))
{ {
eprintln!("setting original binding to {}", binding.binding); FilterPass::bind_texture(binding, original, TextureSemantics::Original);
FilterPass::bind_texture(binding, original);
} }
// bind OriginalSize // bind OriginalSize
@ -372,7 +374,7 @@ impl FilterPass {
.get(&TextureSemantics::Source.semantics(0)) .get(&TextureSemantics::Source.semantics(0))
{ {
// eprintln!("setting source binding to {}", binding.binding); // eprintln!("setting source binding to {}", binding.binding);
FilterPass::bind_texture(binding, source); FilterPass::bind_texture(binding, source, TextureSemantics::Source);
} }
// bind SourceSize // bind SourceSize
@ -391,14 +393,60 @@ impl FilterPass {
); );
} }
for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() {
if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
FilterPass::bind_texture(binding, original, TextureSemantics::OriginalHistory);
}
if let Some((location, offset)) = self
.variable_bindings
.get(&TextureSemantics::OriginalHistory.semantics(0).into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset),
};
FilterPass::build_vec4(
location.location(),
&mut buffer[offset..][..16],
original.image.size,
);
}
for (index, output) in parent.history_textures.iter().enumerate() {
if let Some(binding) = self
.reflection
.meta
.texture_meta
.get(&TextureSemantics::OriginalHistory.semantics(index + 1))
{
FilterPass::bind_texture(binding, output, TextureSemantics::OriginalHistory);
}
if let Some((location, offset)) = self
.variable_bindings
.get(&TextureSemantics::OriginalHistory.semantics(index + 1).into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset),
};
FilterPass::build_vec4(
location.location(),
&mut buffer[offset..][..16],
output.image.size,
);
}
}
// PassOutput
for (index, output) in parent.output_textures.iter().enumerate() {
if let Some(binding) = self if let Some(binding) = self
.reflection .reflection
.meta .meta
.texture_meta .texture_meta
.get(&TextureSemantics::PassOutput.semantics(index)) .get(&TextureSemantics::PassOutput.semantics(index))
{ {
FilterPass::bind_texture(binding, output); FilterPass::bind_texture(binding, output, TextureSemantics::PassOutput);
} }
if let Some((location, offset)) = self if let Some((location, offset)) = self
@ -417,20 +465,32 @@ impl FilterPass {
} }
} }
// // todo: history // PassFeedback
// for (index, feedback) in parent.feedback_textures.iter().enumerate() {
// // if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) { if let Some(binding) = self
// // FilterPass::set_texture(binding, original); .reflection
// // } .meta
// // if let Some(variable) = self.reflection.meta.texture_size_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) { .texture_meta
// // let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location(); .get(&TextureSemantics::PassFeedback.semantics(index))
// // let (buffer, offset) = match variable.offset { {
// // MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset), FilterPass::bind_texture(binding, feedback, TextureSemantics::PassFeedback);
// // MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) }
// // };
// // FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size); if let Some((location, offset)) = self
// // } .variable_bindings
// .get(&TextureSemantics::PassFeedback.semantics(index).into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset),
};
FilterPass::build_vec4(
location.location(),
&mut buffer[offset..][..16],
feedback.image.size,
);
}
}
// bind float parameters // bind float parameters
for (id, (location, offset)) in for (id, (location, offset)) in
@ -475,7 +535,7 @@ impl FilterPass {
.texture_meta .texture_meta
.get(&TextureSemantics::User.semantics(*index)) .get(&TextureSemantics::User.semantics(*index))
{ {
FilterPass::bind_texture(binding, lut); FilterPass::bind_texture(binding, lut, TextureSemantics::User);
} }
if let Some((location, offset)) = self if let Some((location, offset)) = self
@ -493,7 +553,5 @@ impl FilterPass {
); );
} }
} }
// // todo history
} }
} }

View file

@ -1,6 +1,6 @@
use crate::util; use crate::util;
use crate::util::{GlImage, Size, Texture, Viewport}; use crate::util::{GlImage, Size, Texture, Viewport};
use gl::types::{GLenum, GLsizei, GLuint}; use gl::types::{GLenum, GLint, GLsizei, GLuint};
use librashader::{FilterMode, ShaderFormat, WrapMode}; use librashader::{FilterMode, ShaderFormat, WrapMode};
use librashader_presets::{Scale2D, ScaleType, Scaling}; use librashader_presets::{Scale2D, ScaleType, Scaling};
@ -131,7 +131,68 @@ impl Framebuffer {
size size
} }
fn init(&mut self, mut size: Size, format: impl Into<GLenum>) { pub(crate) fn is_initialized(&self) -> bool {
self.init
}
pub fn clear(&self) {
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0, 0.0, 0.0, 0.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
}
pub fn copy_from(&mut self, image: &GlImage) {
if image.size != self.size || image.format != self.format {
self.init(image.size, image.format);
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
gl::FramebufferTexture2D(gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
image.handle, 0);
gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
self.image, 0);
gl::DrawBuffer(gl::COLOR_ATTACHMENT1);
gl::BlitFramebuffer(0, 0, self.size.width as GLint, self.size.height as GLint,
0, 0, self.size.width as GLint, self.size.height as GLint,
gl::COLOR_BUFFER_BIT, gl::NEAREST);
// cleanup after ourselves.
gl::FramebufferTexture2D(gl::READ_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0, 0);
gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT1,
gl::TEXTURE_2D,
0, 0);
// set this back to color_attachment 0
gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
self.image,
0,
);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
}
// todo: fix panic
pub(crate) fn init(&mut self, mut size: Size, format: impl Into<GLenum>) {
self.init = false;
self.format = format.into(); self.format = format.into();
self.size = size; self.size = size;

View file

@ -10,8 +10,8 @@ use crate::filter_chain::FilterChain;
use crate::framebuffer::Framebuffer; use crate::framebuffer::Framebuffer;
use crate::util::{GlImage, Size, Viewport}; use crate::util::{GlImage, Size, Viewport};
const WIDTH: u32 = 900; const WIDTH: u32 = 1920;
const HEIGHT: u32 = 700; const HEIGHT: u32 = 1080;
const TITLE: &str = "Hello From OpenGL World!"; const TITLE: &str = "Hello From OpenGL World!";
pub fn compile_program(vertex: &str, fragment: &str) -> GLuint { pub fn compile_program(vertex: &str, fragment: &str) -> GLuint {
@ -102,7 +102,7 @@ extern "system" fn debug_callback(
) { ) {
unsafe { unsafe {
let message = CStr::from_ptr(message); let message = CStr::from_ptr(message);
eprintln!("{message:?}"); println!("[gl] {message:?}");
} }
} }
@ -414,7 +414,9 @@ pub fn do_loop(
} }
let fullscreen_fbo = [ let fullscreen_fbo = [
-1.0f32, -1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0f32, -1.0, 0.0, 1.0,
-1.0, 0.0, -1.0, 1.0, 0.0,
-1.0, 1.0, 0.0, 1.0, -1.0, 0.0,
1.0, 1.0, 0.0, 1.0, 1.0, 0.0,
]; ];
@ -459,17 +461,21 @@ void main()
gl::GenVertexArrays(1, &mut quad_vao); gl::GenVertexArrays(1, &mut quad_vao);
} }
let fb = Framebuffer::new_from_raw( let (fb_width, fb_height) = window.get_framebuffer_size();
let (vp_width, vp_height) = window.get_size();
let output = Framebuffer::new_from_raw(
output_texture, output_texture,
output_framebuffer_handle, output_framebuffer_handle,
gl::RGBA8, gl::RGBA8,
Size { Size {
width: WIDTH, width: vp_width as u32,
height: HEIGHT, height: vp_height as u32,
}, },
1, 1,
); );
while !window.should_close() { while !window.should_close() {
glfw.poll_events(); glfw.poll_events();
for (_, event) in glfw::flush_messages(&events) { for (_, event) in glfw::flush_messages(&events) {
@ -479,7 +485,7 @@ void main()
unsafe { unsafe {
// render to fb // render to fb
gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer); gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer);
gl::Viewport(0, 0, WIDTH as GLsizei, HEIGHT as GLsizei); gl::Viewport(0, 0, vp_width, vp_height);
// clear color // clear color
clear_color(Color(0.3, 0.4, 0.6, 1.0)); clear_color(Color(0.3, 0.4, 0.6, 1.0));
@ -500,24 +506,28 @@ void main()
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
} }
let viewport = Viewport {
x: 0,
y: 0,
output: &output,
mvp: None,
};
let rendered = GlImage {
handle: rendered_texture,
format: gl::RGBA8,
size: Size {
width: fb_width as u32,
height: fb_height as u32,
},
padded_size: Default::default(),
};
unsafe { unsafe {
filter.frame( filter.frame(
framecount, framecount,
&Viewport { &viewport,
x: 0, &rendered,
y: 0,
output: &fb,
mvp: None,
},
GlImage {
handle: rendered_texture,
format: gl::RGBA8,
size: Size {
width: WIDTH,
height: HEIGHT,
},
padded_size: Default::default(),
},
false, false,
) )
} }
@ -561,6 +571,9 @@ fn glfw_handle_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
Event::Key(Key::Escape, _, Action::Press, _) => { Event::Key(Key::Escape, _, Action::Press, _) => {
window.set_should_close(true); window.set_should_close(true);
} }
Event::Size(width, height) => {
window.set_size(width, height)
}
_ => {} _ => {}
} }
} }

View file

@ -8,6 +8,7 @@ mod framebuffer;
mod hello_triangle; mod hello_triangle;
mod render_target; mod render_target;
mod util; mod util;
mod quad_render;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -17,7 +18,7 @@ mod tests {
#[test] #[test]
fn triangle() { fn triangle() {
let (glfw, window, events, shader, vao) = hello_triangle::setup(); let (glfw, window, events, shader, vao) = hello_triangle::setup();
let mut filter = FilterChain::load("../test/slang-shaders/crt/crt-geom.slangp").unwrap(); let mut filter = FilterChain::load("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV-GLASS.slangp").unwrap();
// FilterChain::load("../test/slang-shaders/crt/crt-royale.slangp").unwrap(); // FilterChain::load("../test/slang-shaders/crt/crt-royale.slangp").unwrap();

View file

@ -0,0 +1,35 @@
use gl::types::{GLsizeiptr, GLuint};
#[rustfmt::skip]
static QUAD_VBO_DATA: &[f32; 16] = &[
0.0f32, 0.0f32, 0.0f32, 0.0f32,
1.0f32, 0.0f32, 1.0f32, 0.0f32,
0.0f32, 1.0f32, 0.0f32, 1.0f32,
1.0f32, 1.0f32, 1.0f32, 1.0f32,
];
pub struct DrawQuad {
pub vbo: GLuint
}
impl DrawQuad {
pub fn new() -> DrawQuad {
let mut vbo = 0;
unsafe {
gl::GenBuffers(1, &mut vbo);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
gl::BufferData(
gl::ARRAY_BUFFER,
std::mem::size_of_val(QUAD_VBO_DATA) as GLsizeiptr,
QUAD_VBO_DATA.as_ptr().cast(),
gl::STATIC_DRAW,
);
gl::BindBuffer(gl::ARRAY_BUFFER, 0);
}
DrawQuad {
vbo
}
}
}

View file

@ -1,5 +1,5 @@
use crate::framebuffer::Framebuffer; use crate::framebuffer::Framebuffer;
use crate::util::Viewport; use crate::util::{Texture, Viewport};
#[rustfmt::skip] #[rustfmt::skip]
static DEFAULT_MVP: &[f32] = &[ static DEFAULT_MVP: &[f32] = &[

View file

@ -92,53 +92,6 @@ where
} }
} }
pub struct AllocRingBuffer<T> {
items: Box<[T]>,
index: usize
}
impl<T> AllocRingBuffer<T>
where
T: Default,
{
pub fn new(len: usize) -> Self {
let mut items = Vec::new();
items.resize_with(len, T::default);
Self {
items: items.into_boxed_slice(),
index: 0,
}
}
pub fn items(&self) -> &[T] {
&self.items
}
pub fn items_mut(&mut self) -> &mut [T] {
&mut self.items
}
}
impl <T> RingBuffer<T> for AllocRingBuffer<T> {
fn current(&self) -> &T {
&self.items[self.index]
}
fn current_mut(&mut self) -> &mut T {
&mut self.items[self.index]
}
fn next(&mut self) {
self.index += 1;
if self.index >= self.items.len() {
self.index = 0
}
}
}
pub unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint { pub unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint {
let shader = gl::CreateShader(stage); let shader = gl::CreateShader(stage);
gl::ShaderSource( gl::ShaderSource(