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::IResult;
use std::str::FromStr;
use nom::character::complete::multispace1;
#[derive(Debug)]
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_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, name) = take_while(|c| c != ' ')(input)?;
let (input, _) = tag(" ")(input)?;
let (input, name) = take_while(|c| c != ' ' && c != '\t')(input)?;
let (input, _) = multispace1(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, _) = tag(" ")(input)?;
let (input, _) = multispace1(input)?;
let (input, minimum) = float(input)?;
let (input, _) = tag(" ")(input)?;
let (input, _) = multispace1(input)?;
let (input, maximum) = float(input)?;
let (input, _) = tag(" ")(input)?;
let (input, _) = multispace1(input)?;
let (input, step) = float(input)?;
Ok((
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 {
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> {

View file

@ -10,3 +10,4 @@ thiserror = "1.0.37"
nom = "7.1.1"
nom_locate = "4.0.0"
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),
_ => None,
})
.unwrap_or(1),
.unwrap_or(0),
srgb_framebuffer: shader_values
.iter()
.find_map(|f| match f {

View file

@ -6,6 +6,8 @@ use nom::character::complete::digit1;
use nom::combinator::{eof, map_res};
use nom::IResult;
use num_traits::cast::ToPrimitive;
use crate::parse::token::do_lex;
use std::fs::File;
@ -66,14 +68,28 @@ impl Value {
fn from_int(input: Span) -> Result<i32, ParsePresetError> {
i32::from_str(input.trim()).map_err(|_| {
eprintln!("{input}");
ParsePresetError::ParserError {
offset: input.location_offset(),
row: input.location_line(),
col: input.get_column(),
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> {

View file

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

View file

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

View file

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

View file

@ -1,3 +1,4 @@
use std::collections::VecDeque;
use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
use crate::filter_pass::FilterPass;
use crate::framebuffer::Framebuffer;
@ -6,8 +7,8 @@ use crate::util;
use crate::util::{GlImage, InlineRingBuffer, Size, Texture, Viewport};
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
use librashader::image::Image;
use librashader::{FilterMode, ShaderSource};
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader::{FilterMode, ShaderSource, WrapMode};
use librashader_presets::{ScaleType, ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::cross::{GlVersion, GlslangGlslContext};
use librashader_reflect::back::targets::{CompilerBackend, FromCompilation, GLSL};
use librashader_reflect::back::CompileShader;
@ -19,11 +20,27 @@ use rustc_hash::FxHashMap;
use spirv_cross::spirv::Decoration;
use std::error::Error;
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 {
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> = (
&'a ShaderPassConfig,
ShaderSource,
@ -330,7 +329,6 @@ impl FilterChain {
.vertex
.get_decoration(res.id, Decoration::Location)?;
let loc_name = format!("LIBRA_ATTRIBUTE_{loc}\0");
eprintln!("{loc_name}");
gl::BindAttribLocation(program, loc, loc_name.as_str().as_ptr().cast())
}
gl::LinkProgram(program);
@ -443,7 +441,7 @@ impl FilterChain {
);
}
// eprintln!("{:#?}", semantics);
// eprintln!("{:#?}", reflection.meta.texture_meta);
// eprintln!("{:#?}", reflection.meta);
// eprintln!("{:#?}", locations);
// eprintln!("{:#?}", reflection.push_constant);
@ -469,7 +467,7 @@ impl FilterChain {
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;
for pass in filters {
@ -493,56 +491,27 @@ impl FilterChain {
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();
// not using frame history;
if required_images <= 1 {
println!("[history] not using frame history");
return (VecDeque::new(), Box::new([]))
}
// 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.into_boxed_slice()
}
pub fn init_feedback(filters: &[FilterPass]) -> Box<[Framebuffer]> {
let mut required_images = 0;
let mut history_textures = Vec::new();
history_textures.resize_with(required_images, || Texture {
image: Default::default(),
filter,
mip_filter: filter,
wrap_mode
});
for pass in filters {
// 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()
(framebuffers, history_textures.into_boxed_slice())
}
pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> {
@ -553,49 +522,50 @@ impl FilterChain {
// initialize passes
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
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1));
let mut output_textures = Vec::new();
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
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
let mut quad_vbo = 0;
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 draw_quad = DrawQuad::new();
let mut quad_vao = 0;
let mut filter_vao = 0;
unsafe {
gl::GenVertexArrays(1, &mut quad_vao);
gl::GenVertexArrays(1, &mut filter_vao);
}
Ok(FilterChain {
passes: filters,
output_framebuffers: output_framebuffers.into_boxed_slice(),
quad_vao,
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
history_framebuffers,
filter_vao,
common: FilterCommon {
semantics,
preset,
original_history,
history: vec![],
feedback: vec![],
luts,
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)
}
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() {
return;
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindVertexArray(self.quad_vao);
gl::BindVertexArray(self.filter_vao);
}
// todo: copy framebuffer
// shader_gl3: 2067
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();
let filter = self.passes[0].config.filter;
let wrap_mode = self.passes[0].config.wrap_mode;
// 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 {
image: input,
image: *input,
filter,
mip_filter: filter,
wrap_mode,
@ -650,7 +643,7 @@ impl FilterChain {
let _framebuffer_size = target.scale(
pass.config.scaling.clone(),
pass.get_format(),
vp,
viewport,
&original,
&source,
);
@ -660,9 +653,13 @@ impl FilterChain {
pass.draw(
index,
&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,
vp,
viewport,
&original,
&source,
RenderTarget::new(target, None),
@ -681,19 +678,29 @@ impl FilterChain {
pass.draw(
passes_len - 1,
&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,
vp,
viewport,
&original,
&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 {
gl::BindFramebuffer(gl::FRAMEBUFFER, 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)
}
fn bind_texture(binding: &TextureImage, texture: &Texture) {
fn bind_texture(binding: &TextureImage, texture: &Texture, semantic: TextureSemantics) {
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);
gl::ActiveTexture(gl::TEXTURE0 + binding.binding);
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
@ -220,7 +223,7 @@ impl FilterPass {
gl::EnableVertexAttribArray(0);
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,
/// and not a known provenance to the Rust abstract machine, therefore we give it invalid pointers.
@ -344,8 +347,7 @@ impl FilterPass {
.texture_meta
.get(&TextureSemantics::Original.semantics(0))
{
eprintln!("setting original binding to {}", binding.binding);
FilterPass::bind_texture(binding, original);
FilterPass::bind_texture(binding, original, TextureSemantics::Original);
}
// bind OriginalSize
@ -372,7 +374,7 @@ impl FilterPass {
.get(&TextureSemantics::Source.semantics(0))
{
// eprintln!("setting source binding to {}", binding.binding);
FilterPass::bind_texture(binding, source);
FilterPass::bind_texture(binding, source, TextureSemantics::Source);
}
// 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
.reflection
.meta
.texture_meta
.get(&TextureSemantics::PassOutput.semantics(index))
{
FilterPass::bind_texture(binding, output);
FilterPass::bind_texture(binding, output, TextureSemantics::PassOutput);
}
if let Some((location, offset)) = self
@ -417,20 +465,32 @@ impl FilterPass {
}
}
// // todo: history
//
// // if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
// // FilterPass::set_texture(binding, original);
// // }
// // if let Some(variable) = self.reflection.meta.texture_size_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
// // let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location();
// // let (buffer, offset) = match variable.offset {
// // MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset),
// // MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset)
// // };
// // FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size);
// // }
//
// PassFeedback
for (index, feedback) in parent.feedback_textures.iter().enumerate() {
if let Some(binding) = self
.reflection
.meta
.texture_meta
.get(&TextureSemantics::PassFeedback.semantics(index))
{
FilterPass::bind_texture(binding, feedback, TextureSemantics::PassFeedback);
}
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
for (id, (location, offset)) in
@ -475,7 +535,7 @@ impl FilterPass {
.texture_meta
.get(&TextureSemantics::User.semantics(*index))
{
FilterPass::bind_texture(binding, lut);
FilterPass::bind_texture(binding, lut, TextureSemantics::User);
}
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::{GlImage, Size, Texture, Viewport};
use gl::types::{GLenum, GLsizei, GLuint};
use gl::types::{GLenum, GLint, GLsizei, GLuint};
use librashader::{FilterMode, ShaderFormat, WrapMode};
use librashader_presets::{Scale2D, ScaleType, Scaling};
@ -131,7 +131,68 @@ impl Framebuffer {
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.size = size;

View file

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

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::util::Viewport;
use crate::util::{Texture, Viewport};
#[rustfmt::skip]
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 {
let shader = gl::CreateShader(stage);
gl::ShaderSource(