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::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> {
|
||||
|
|
|
@ -10,3 +10,4 @@ thiserror = "1.0.37"
|
|||
nom = "7.1.1"
|
||||
nom_locate = "4.0.0"
|
||||
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),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(1),
|
||||
.unwrap_or(0),
|
||||
srgb_framebuffer: shader_values
|
||||
.iter()
|
||||
.find_map(|f| match f {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()..];
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
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 {
|
||||
filter.frame(
|
||||
framecount,
|
||||
&Viewport {
|
||||
x: 0,
|
||||
y: 0,
|
||||
output: &fb,
|
||||
mvp: None,
|
||||
},
|
||||
GlImage {
|
||||
handle: rendered_texture,
|
||||
format: gl::RGBA8,
|
||||
size: Size {
|
||||
width: WIDTH,
|
||||
height: HEIGHT,
|
||||
},
|
||||
padded_size: Default::default(),
|
||||
},
|
||||
&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)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
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::util::Viewport;
|
||||
use crate::util::{Texture, Viewport};
|
||||
|
||||
#[rustfmt::skip]
|
||||
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 {
|
||||
let shader = gl::CreateShader(stage);
|
||||
gl::ShaderSource(
|
||||
|
|
Loading…
Reference in a new issue