diff --git a/librashader-runtime/src/binding.rs b/librashader-runtime/src/binding.rs index b566121..72c5de3 100644 --- a/librashader-runtime/src/binding.rs +++ b/librashader-runtime/src/binding.rs @@ -348,6 +348,11 @@ where } } +pub struct BindingRequirements { + pub(crate) required_history: usize, + pub(crate) uses_final_pass_as_feedback: bool, +} + /// Trait for objects that can be used to create a binding map. pub trait BindingUtil { /// Create the uniform binding map with the given reflection information. @@ -357,7 +362,7 @@ pub trait BindingUtil { ) -> FastHashMap; /// Calculate the number of required images for history. - fn calculate_required_history<'a>(pass_meta: impl Iterator) -> usize + fn calculate_requirements<'a>(pass_meta: impl Iterator) -> BindingRequirements where Self: 'a; } @@ -383,32 +388,65 @@ impl BindingUtil for BindingMeta { uniform_bindings } - fn calculate_required_history<'a>(pass_meta: impl Iterator) -> usize + fn calculate_requirements<'a>(pass_meta: impl Iterator) -> BindingRequirements where Self: 'a, { let mut required_images = 0; + let mut len: i64 = 0; + let mut latest_feedback_pass: i64 = -1; + for pass in pass_meta { + len += 1; + // If a shader uses history size, but not history, we still need to keep the texture. - let texture_max_index = pass + let history_texture_max_index = pass .texture_meta .iter() .filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory) .map(|(semantic, _)| semantic.index) .fold(0, std::cmp::max); - let texture_size_max_index = pass + let history_texture_size_max_index = pass .texture_size_meta .iter() .filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory) .map(|(semantic, _)| semantic.index) .fold(0, std::cmp::max); - required_images = std::cmp::max(required_images, texture_max_index); - required_images = std::cmp::max(required_images, texture_size_max_index); + let feedback_max_index = pass + .texture_meta + .iter() + .filter(|(semantics, _)| semantics.semantics == TextureSemantics::PassFeedback) + .map(|(semantic, _)| semantic.index as i64) + .fold(-1, std::cmp::max); + let feedback_max_size_index = pass + .texture_size_meta + .iter() + .filter(|(semantics, _)| semantics.semantics == TextureSemantics::PassFeedback) + .map(|(semantic, _)| semantic.index as i64) + .fold(-1, std::cmp::max); + + latest_feedback_pass = std::cmp::max(latest_feedback_pass, feedback_max_index); + latest_feedback_pass = std::cmp::max(latest_feedback_pass, feedback_max_size_index); + + required_images = std::cmp::max(required_images, history_texture_max_index); + required_images = std::cmp::max(required_images, history_texture_size_max_index); } - required_images + let uses_feedback = if latest_feedback_pass.is_negative() { + false + } else { + // Technically = but we can be permissive here + + // account for off by 1 + latest_feedback_pass + 1 >= len + }; + + BindingRequirements { + required_history: required_images, + uses_final_pass_as_feedback: uses_feedback, + } } } diff --git a/librashader-runtime/src/framebuffer.rs b/librashader-runtime/src/framebuffer.rs index 674e8ed..f908b5e 100644 --- a/librashader-runtime/src/framebuffer.rs +++ b/librashader-runtime/src/framebuffer.rs @@ -1,4 +1,4 @@ -use crate::binding::BindingUtil; +use crate::binding::{BindingRequirements, BindingUtil}; use librashader_reflect::reflect::semantics::BindingMeta; use std::collections::VecDeque; @@ -6,7 +6,7 @@ use std::collections::VecDeque; pub struct FramebufferInit<'a, F, I, E> { owned_generator: &'a dyn Fn() -> Result, input_generator: &'a dyn Fn() -> I, - required_history: usize, + requirements: BindingRequirements, filters_count: usize, } @@ -19,19 +19,20 @@ impl<'a, F, I, E> FramebufferInit<'a, F, I, E> { input_generator: &'a dyn Fn() -> I, ) -> Self { let filters_count = filters.len(); - let required_history = BindingMeta::calculate_required_history(filters); + let requirements = BindingMeta::calculate_requirements(filters); + Self { owned_generator, input_generator, filters_count, - required_history, + requirements, } } /// Initialize history framebuffers and views. pub fn init_history(&self) -> Result<(VecDeque, Box<[I]>), E> { init_history( - self.required_history, + self.requirements.required_history, self.owned_generator, self.input_generator, ) @@ -45,6 +46,11 @@ impl<'a, F, I, E> FramebufferInit<'a, F, I, E> { self.input_generator, ) } + + /// Get if the final pass is used as feedback. + pub const fn uses_final_pass_as_feedback(&self) -> bool { + self.requirements.uses_final_pass_as_feedback + } } fn init_history<'a, F, I, E>(