From 1e9d180bf073bc0540198cbba5cd7e2604ea3702 Mon Sep 17 00:00:00 2001 From: chyyran Date: Sun, 20 Nov 2022 02:09:05 -0500 Subject: [PATCH] gl: implement PassOutput binding --- librashader-runtime-gl/src/filter_chain.rs | 145 ++++++++++++++++----- librashader-runtime-gl/src/filter_pass.rs | 82 ++++++++---- librashader-runtime-gl/src/util.rs | 4 +- 3 files changed, 177 insertions(+), 54 deletions(-) diff --git a/librashader-runtime-gl/src/filter_chain.rs b/librashader-runtime-gl/src/filter_chain.rs index 95c7952..2fa2730 100644 --- a/librashader-runtime-gl/src/filter_chain.rs +++ b/librashader-runtime-gl/src/filter_chain.rs @@ -104,19 +104,20 @@ impl FilterChain { } pub struct FilterChain { - passes: Vec, + passes: Box<[FilterPass]>, common: FilterCommon, quad_vao: GLuint, + output_framebuffers: Box<[Framebuffer]>, } pub struct FilterCommon { semantics: ReflectSemantics, pub(crate) preset: ShaderPreset, - original_history: Vec, - history: Vec, - feedback: Vec, + pub original_history: Box<[Framebuffer]>, + pub history: Vec, + pub feedback: Vec, pub(crate) luts: FxHashMap, - outputs: Vec, + pub output_textures: Box<[Texture]>, pub(crate) quad_vbo: GLuint, } @@ -125,18 +126,13 @@ type ShaderPassMeta<'a> = ( ShaderSource, CompilerBackend< impl CompileShader - + ReflectShader - + Sized, + + ReflectShader + + Sized, >, ); impl FilterChain { - fn load_preset( - preset: &ShaderPreset, - ) -> ( - Vec, - ReflectSemantics, - ) { + fn load_preset(preset: &ShaderPreset) -> (Vec, ReflectSemantics) { let mut uniform_semantics: FxHashMap = Default::default(); let mut texture_semantics: FxHashMap> = Default::default(); @@ -305,7 +301,10 @@ impl FilterChain { Ok(luts) } - pub fn init_passes(passes: Vec, semantics: &ReflectSemantics) -> Result, Box> { + pub fn init_passes( + passes: Vec, + semantics: &ReflectSemantics, + ) -> Result, Box> { let mut filters = Vec::new(); // initialize passes @@ -401,7 +400,7 @@ impl FilterChain { .map(|ubo| ubo.size as usize) .unwrap_or(0) ] - .into_boxed_slice(); + .into_boxed_slice(); let push_buffer = vec![ 0; reflection @@ -410,12 +409,12 @@ impl FilterChain { .map(|push| push.size as usize) .unwrap_or(0) ] - .into_boxed_slice(); + .into_boxed_slice(); // todo: reflect indexed parameters - let mut locations = FxHashMap::default(); + let mut variable_bindings = FxHashMap::default(); for param in reflection.meta.parameter_meta.values() { - locations.insert( + variable_bindings.insert( UniformBinding::Parameter(param.id.clone()), ( FilterChain::reflect_uniform_location(program, param), @@ -425,7 +424,7 @@ impl FilterChain { } for (semantics, param) in &reflection.meta.variable_meta { - locations.insert( + variable_bindings.insert( UniformBinding::SemanticVariable(*semantics), ( FilterChain::reflect_uniform_location(program, param), @@ -435,7 +434,7 @@ impl FilterChain { } for (semantics, param) in &reflection.meta.texture_size_meta { - locations.insert( + variable_bindings.insert( UniformBinding::TextureSize(*semantics), ( FilterChain::reflect_uniform_location(program, param), @@ -461,15 +460,90 @@ impl FilterChain { ubo_ring, uniform_buffer, push_buffer, - variable_bindings: locations, + variable_bindings, source, config: config.clone(), }); } - Ok(filters) + Ok(filters.into_boxed_slice()) } + pub fn init_history(filters: &[FilterPass]) -> Box<[Framebuffer]> { + let mut required_images = 0; + + 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() + } + + pub fn init_feedback(filters: &[FilterPass]) -> Box<[Framebuffer]> { + let mut required_images = 0; + + 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() + } pub fn load(path: impl AsRef) -> Result> { // load passes from preset @@ -482,10 +556,14 @@ impl FilterChain { // 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); // load luts let luts = FilterChain::load_luts(&preset.textures)?; + let original_history = FilterChain::init_history(&filters); + // create VBO objects let mut quad_vbo = 0; unsafe { @@ -507,20 +585,26 @@ impl FilterChain { Ok(FilterChain { passes: filters, + output_framebuffers: output_framebuffers.into_boxed_slice(), quad_vao, common: FilterCommon { semantics, preset, - original_history: vec![], + original_history, history: vec![], feedback: vec![], luts, - outputs: output_framebuffers, + output_textures: output_textures.into_boxed_slice(), quad_vbo, }, }) } + pub(crate) fn get_output_texture(&self, index: usize) -> Texture { + let config = &self.passes[index].config; + self.output_framebuffers[index].as_texture(config.filter, config.wrap_mode) + } + pub fn frame(&mut self, count: usize, vp: &Viewport, input: GlImage, _clear: bool) { if self.passes.is_empty() { return; @@ -562,7 +646,7 @@ impl FilterChain { for (index, pass) in pass.iter_mut().enumerate() { { - let target = &mut self.common.outputs[index]; + let target = &mut self.output_framebuffers[index]; let _framebuffer_size = target.scale( pass.config.scaling.clone(), pass.get_format(), @@ -571,8 +655,10 @@ impl FilterChain { &source, ); } - let target = &self.common.outputs[index]; + + let target = &self.output_framebuffers[index]; pass.draw( + index, &self.common, (count % pass.config.frame_count_mod as usize) as u32, 1, @@ -581,11 +667,11 @@ impl FilterChain { &source, RenderTarget::new(target, None), ); - let target = target.as_texture(pass.config.filter, pass.config.wrap_mode); - // todo: update-pass-outputs + let target = target.as_texture(pass.config.filter, pass.config.wrap_mode); + self.common.output_textures[index] = target; source = target; - // passes.build_semantics(&self, None, count, 1, vp, &original, &source); + } assert_eq!(last.len(), 1); @@ -593,6 +679,7 @@ impl FilterChain { source.filter = pass.config.filter; source.mip_filter = pass.config.filter; pass.draw( + passes_len - 1, &self.common, (count % pass.config.frame_count_mod as usize) as u32, 1, diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 3b86467..f440249 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -135,6 +135,7 @@ impl FilterPass { // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) pub fn draw( &mut self, + pass_index: usize, parent: &FilterCommon, frame_count: u32, frame_direction: i32, @@ -151,6 +152,7 @@ impl FilterPass { } self.build_semantics( + pass_index, parent, output.mvp, frame_count, @@ -256,6 +258,7 @@ impl FilterPass { // framecount should be pre-modded fn build_semantics( &mut self, + pass_index: usize, parent: &FilterCommon, mvp: &[f32], frame_count: u32, @@ -265,6 +268,7 @@ impl FilterPass { original: &Texture, source: &Texture, ) { + // Bind MVP if let Some((_location, offset)) = self.variable_bindings.get(&VariableSemantics::MVP.into()) { @@ -276,6 +280,7 @@ impl FilterPass { FilterPass::build_mvp(&mut buffer[offset..][..mvp_size], mvp) } + // bind OutputSize if let Some((location, offset)) = self .variable_bindings .get(&VariableSemantics::Output.into()) @@ -288,6 +293,7 @@ impl FilterPass { FilterPass::build_vec4(location.location(), &mut buffer[offset..][..4], fb_size) } + // bind FinalViewportSize if let Some((location, offset)) = self .variable_bindings .get(&VariableSemantics::FinalViewport.into()) @@ -303,6 +309,7 @@ impl FilterPass { ) } + // bind FrameCount if let Some((location, offset)) = self .variable_bindings .get(&VariableSemantics::FrameCount.into()) @@ -314,6 +321,7 @@ impl FilterPass { FilterPass::build_uint(location.location(), &mut buffer[offset..][..4], frame_count) } + // bind FrameDirection if let Some((location, offset)) = self .variable_bindings .get(&VariableSemantics::FrameDirection.into()) @@ -329,6 +337,7 @@ impl FilterPass { ) } + // bind Original sampler if let Some(binding) = self .reflection .meta @@ -339,6 +348,7 @@ impl FilterPass { FilterPass::bind_texture(binding, original); } + // bind OriginalSize if let Some((location, offset)) = self .variable_bindings .get(&TextureSemantics::Original.semantics(0).into()) @@ -354,6 +364,7 @@ impl FilterPass { ); } + // bind Source sampler if let Some(binding) = self .reflection .meta @@ -363,6 +374,8 @@ impl FilterPass { // eprintln!("setting source binding to {}", binding.binding); FilterPass::bind_texture(binding, source); } + + // bind SourceSize if let Some((location, offset)) = self .variable_bindings .get(&TextureSemantics::Source.semantics(0).into()) @@ -378,6 +391,32 @@ 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::PassOutput.semantics(index)) + { + FilterPass::bind_texture(binding, output); + } + + if let Some((location, offset)) = self + .variable_bindings + .get(&TextureSemantics::PassOutput.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..][..4], + output.image.size, + ); + } + } + // // todo: history // // // if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) { @@ -392,6 +431,8 @@ impl FilterPass { // // FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size); // // } // + + // bind float parameters for (id, (location, offset)) in self.variable_bindings .iter() @@ -426,30 +467,25 @@ impl FilterPass { FilterPass::build_float(location.location(), &mut buffer[offset..][..4], value) } - for (id, (location, offset)) in - self.variable_bindings - .iter() - .filter_map(|(binding, value)| match binding { - UniformBinding::TextureSize(semantics) => { - if semantics.semantics == TextureSemantics::User { - Some((semantics, value)) - } else { - None - } - } - _ => None, - }) - { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - - if let Some(lut) = parent.luts.get(&id.index) { - if let Some(binding) = self.reflection.meta.texture_meta.get(id) { - FilterPass::bind_texture(binding, lut); - } + // bind luts + for (index, lut) in &parent.luts { + if let Some(binding) = self + .reflection + .meta + .texture_meta + .get(&TextureSemantics::User.semantics(*index)) + { + FilterPass::bind_texture(binding, lut); + } + if let Some((location, offset)) = self + .variable_bindings + .get(&TextureSemantics::User.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..][..4], diff --git a/librashader-runtime-gl/src/util.rs b/librashader-runtime-gl/src/util.rs index eab2ed6..75400fb 100644 --- a/librashader-runtime-gl/src/util.rs +++ b/librashader-runtime-gl/src/util.rs @@ -13,7 +13,7 @@ pub fn calc_miplevel(width: u32, height: u32) -> u32 { levels } -#[derive(Debug, Copy, Clone)] +#[derive(Default, Debug, Copy, Clone)] pub struct Texture { pub image: GlImage, pub filter: FilterMode, @@ -35,7 +35,7 @@ pub struct Size { pub height: u32, } -#[derive(Debug, Copy, Clone)] +#[derive(Default, Debug, Copy, Clone)] pub struct GlImage { pub handle: GLuint, pub format: GLenum,