gl: implement passfeedback and original history
This commit is contained in:
parent
0b336ca8c5
commit
10eb2c3106
|
@ -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> {
|
||||||
|
|
|
@ -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"
|
|
@ -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 {
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()..];
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
let viewport = Viewport {
|
||||||
filter.frame(
|
|
||||||
framecount,
|
|
||||||
&Viewport {
|
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
output: &fb,
|
output: &output,
|
||||||
mvp: None,
|
mvp: None,
|
||||||
},
|
};
|
||||||
GlImage {
|
|
||||||
|
let rendered = GlImage {
|
||||||
handle: rendered_texture,
|
handle: rendered_texture,
|
||||||
format: gl::RGBA8,
|
format: gl::RGBA8,
|
||||||
size: Size {
|
size: Size {
|
||||||
width: WIDTH,
|
width: fb_width as u32,
|
||||||
height: HEIGHT,
|
height: fb_height as u32,
|
||||||
},
|
},
|
||||||
padded_size: Default::default(),
|
padded_size: Default::default(),
|
||||||
},
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
filter.frame(
|
||||||
|
framecount,
|
||||||
|
&viewport,
|
||||||
|
&rendered,
|
||||||
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)
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
35
librashader-runtime-gl/src/quad_render.rs
Normal file
35
librashader-runtime-gl/src/quad_render.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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] = &[
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in a new issue