gl: implement PassOutput binding

This commit is contained in:
chyyran 2022-11-20 02:09:05 -05:00
parent 23b13ef047
commit 1e9d180bf0
3 changed files with 177 additions and 54 deletions

View file

@ -104,19 +104,20 @@ impl FilterChain {
} }
pub struct FilterChain { pub struct FilterChain {
passes: Vec<FilterPass>, passes: Box<[FilterPass]>,
common: FilterCommon, common: FilterCommon,
quad_vao: GLuint, quad_vao: GLuint,
output_framebuffers: Box<[Framebuffer]>,
} }
pub struct FilterCommon { pub struct FilterCommon {
semantics: ReflectSemantics, semantics: ReflectSemantics,
pub(crate) preset: ShaderPreset, pub(crate) preset: ShaderPreset,
original_history: Vec<Framebuffer>, pub original_history: Box<[Framebuffer]>,
history: Vec<Texture>, pub history: Vec<Texture>,
feedback: Vec<Texture>, pub feedback: Vec<Texture>,
pub(crate) luts: FxHashMap<usize, Texture>, pub(crate) luts: FxHashMap<usize, Texture>,
outputs: Vec<Framebuffer>, pub output_textures: Box<[Texture]>,
pub(crate) quad_vbo: GLuint, pub(crate) quad_vbo: GLuint,
} }
@ -125,18 +126,13 @@ type ShaderPassMeta<'a> = (
ShaderSource, ShaderSource,
CompilerBackend< CompilerBackend<
impl CompileShader<GLSL, Options = GlVersion, Context = GlslangGlslContext> impl CompileShader<GLSL, Options = GlVersion, Context = GlslangGlslContext>
+ ReflectShader + ReflectShader
+ Sized, + Sized,
>, >,
); );
impl FilterChain { impl FilterChain {
fn load_preset( fn load_preset(preset: &ShaderPreset) -> (Vec<ShaderPassMeta>, ReflectSemantics) {
preset: &ShaderPreset,
) -> (
Vec<ShaderPassMeta>,
ReflectSemantics,
) {
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default(); let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> = let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
Default::default(); Default::default();
@ -305,7 +301,10 @@ impl FilterChain {
Ok(luts) Ok(luts)
} }
pub fn init_passes(passes: Vec<ShaderPassMeta>, semantics: &ReflectSemantics) -> Result<Vec<FilterPass>, Box<dyn Error>> { pub fn init_passes(
passes: Vec<ShaderPassMeta>,
semantics: &ReflectSemantics,
) -> Result<Box<[FilterPass]>, Box<dyn Error>> {
let mut filters = Vec::new(); let mut filters = Vec::new();
// initialize passes // initialize passes
@ -401,7 +400,7 @@ impl FilterChain {
.map(|ubo| ubo.size as usize) .map(|ubo| ubo.size as usize)
.unwrap_or(0) .unwrap_or(0)
] ]
.into_boxed_slice(); .into_boxed_slice();
let push_buffer = vec![ let push_buffer = vec![
0; 0;
reflection reflection
@ -410,12 +409,12 @@ impl FilterChain {
.map(|push| push.size as usize) .map(|push| push.size as usize)
.unwrap_or(0) .unwrap_or(0)
] ]
.into_boxed_slice(); .into_boxed_slice();
// todo: reflect indexed parameters // todo: reflect indexed parameters
let mut locations = FxHashMap::default(); let mut variable_bindings = FxHashMap::default();
for param in reflection.meta.parameter_meta.values() { for param in reflection.meta.parameter_meta.values() {
locations.insert( variable_bindings.insert(
UniformBinding::Parameter(param.id.clone()), UniformBinding::Parameter(param.id.clone()),
( (
FilterChain::reflect_uniform_location(program, param), FilterChain::reflect_uniform_location(program, param),
@ -425,7 +424,7 @@ impl FilterChain {
} }
for (semantics, param) in &reflection.meta.variable_meta { for (semantics, param) in &reflection.meta.variable_meta {
locations.insert( variable_bindings.insert(
UniformBinding::SemanticVariable(*semantics), UniformBinding::SemanticVariable(*semantics),
( (
FilterChain::reflect_uniform_location(program, param), FilterChain::reflect_uniform_location(program, param),
@ -435,7 +434,7 @@ impl FilterChain {
} }
for (semantics, param) in &reflection.meta.texture_size_meta { for (semantics, param) in &reflection.meta.texture_size_meta {
locations.insert( variable_bindings.insert(
UniformBinding::TextureSize(*semantics), UniformBinding::TextureSize(*semantics),
( (
FilterChain::reflect_uniform_location(program, param), FilterChain::reflect_uniform_location(program, param),
@ -461,15 +460,90 @@ impl FilterChain {
ubo_ring, ubo_ring,
uniform_buffer, uniform_buffer,
push_buffer, push_buffer,
variable_bindings: locations, variable_bindings,
source, source,
config: config.clone(), 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<Path>) -> Result<FilterChain, Box<dyn Error>> { pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> {
// load passes from preset // load passes from preset
@ -482,10 +556,14 @@ impl FilterChain {
// 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();
output_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);
// create VBO objects // create VBO objects
let mut quad_vbo = 0; let mut quad_vbo = 0;
unsafe { unsafe {
@ -507,20 +585,26 @@ impl FilterChain {
Ok(FilterChain { Ok(FilterChain {
passes: filters, passes: filters,
output_framebuffers: output_framebuffers.into_boxed_slice(),
quad_vao, quad_vao,
common: FilterCommon { common: FilterCommon {
semantics, semantics,
preset, preset,
original_history: vec![], original_history,
history: vec![], history: vec![],
feedback: vec![], feedback: vec![],
luts, luts,
outputs: output_framebuffers, output_textures: output_textures.into_boxed_slice(),
quad_vbo, 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) { pub fn frame(&mut self, count: usize, vp: &Viewport, input: GlImage, _clear: bool) {
if self.passes.is_empty() { if self.passes.is_empty() {
return; return;
@ -562,7 +646,7 @@ impl FilterChain {
for (index, pass) in pass.iter_mut().enumerate() { 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( let _framebuffer_size = target.scale(
pass.config.scaling.clone(), pass.config.scaling.clone(),
pass.get_format(), pass.get_format(),
@ -571,8 +655,10 @@ impl FilterChain {
&source, &source,
); );
} }
let target = &self.common.outputs[index];
let target = &self.output_framebuffers[index];
pass.draw( pass.draw(
index,
&self.common, &self.common,
(count % pass.config.frame_count_mod as usize) as u32, (count % pass.config.frame_count_mod as usize) as u32,
1, 1,
@ -581,11 +667,11 @@ impl FilterChain {
&source, &source,
RenderTarget::new(target, None), 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; source = target;
// passes.build_semantics(&self, None, count, 1, vp, &original, &source);
} }
assert_eq!(last.len(), 1); assert_eq!(last.len(), 1);
@ -593,6 +679,7 @@ impl FilterChain {
source.filter = pass.config.filter; source.filter = pass.config.filter;
source.mip_filter = pass.config.filter; source.mip_filter = pass.config.filter;
pass.draw( pass.draw(
passes_len - 1,
&self.common, &self.common,
(count % pass.config.frame_count_mod as usize) as u32, (count % pass.config.frame_count_mod as usize) as u32,
1, 1,

View file

@ -135,6 +135,7 @@ impl FilterPass {
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
pub fn draw( pub fn draw(
&mut self, &mut self,
pass_index: usize,
parent: &FilterCommon, parent: &FilterCommon,
frame_count: u32, frame_count: u32,
frame_direction: i32, frame_direction: i32,
@ -151,6 +152,7 @@ impl FilterPass {
} }
self.build_semantics( self.build_semantics(
pass_index,
parent, parent,
output.mvp, output.mvp,
frame_count, frame_count,
@ -256,6 +258,7 @@ impl FilterPass {
// framecount should be pre-modded // framecount should be pre-modded
fn build_semantics( fn build_semantics(
&mut self, &mut self,
pass_index: usize,
parent: &FilterCommon, parent: &FilterCommon,
mvp: &[f32], mvp: &[f32],
frame_count: u32, frame_count: u32,
@ -265,6 +268,7 @@ impl FilterPass {
original: &Texture, original: &Texture,
source: &Texture, source: &Texture,
) { ) {
// Bind MVP
if let Some((_location, offset)) = if let Some((_location, offset)) =
self.variable_bindings.get(&VariableSemantics::MVP.into()) self.variable_bindings.get(&VariableSemantics::MVP.into())
{ {
@ -276,6 +280,7 @@ impl FilterPass {
FilterPass::build_mvp(&mut buffer[offset..][..mvp_size], mvp) FilterPass::build_mvp(&mut buffer[offset..][..mvp_size], mvp)
} }
// bind OutputSize
if let Some((location, offset)) = self if let Some((location, offset)) = self
.variable_bindings .variable_bindings
.get(&VariableSemantics::Output.into()) .get(&VariableSemantics::Output.into())
@ -288,6 +293,7 @@ impl FilterPass {
FilterPass::build_vec4(location.location(), &mut buffer[offset..][..4], fb_size) FilterPass::build_vec4(location.location(), &mut buffer[offset..][..4], fb_size)
} }
// bind FinalViewportSize
if let Some((location, offset)) = self if let Some((location, offset)) = self
.variable_bindings .variable_bindings
.get(&VariableSemantics::FinalViewport.into()) .get(&VariableSemantics::FinalViewport.into())
@ -303,6 +309,7 @@ impl FilterPass {
) )
} }
// bind FrameCount
if let Some((location, offset)) = self if let Some((location, offset)) = self
.variable_bindings .variable_bindings
.get(&VariableSemantics::FrameCount.into()) .get(&VariableSemantics::FrameCount.into())
@ -314,6 +321,7 @@ impl FilterPass {
FilterPass::build_uint(location.location(), &mut buffer[offset..][..4], frame_count) FilterPass::build_uint(location.location(), &mut buffer[offset..][..4], frame_count)
} }
// bind FrameDirection
if let Some((location, offset)) = self if let Some((location, offset)) = self
.variable_bindings .variable_bindings
.get(&VariableSemantics::FrameDirection.into()) .get(&VariableSemantics::FrameDirection.into())
@ -329,6 +337,7 @@ impl FilterPass {
) )
} }
// bind Original sampler
if let Some(binding) = self if let Some(binding) = self
.reflection .reflection
.meta .meta
@ -339,6 +348,7 @@ impl FilterPass {
FilterPass::bind_texture(binding, original); FilterPass::bind_texture(binding, original);
} }
// bind OriginalSize
if let Some((location, offset)) = self if let Some((location, offset)) = self
.variable_bindings .variable_bindings
.get(&TextureSemantics::Original.semantics(0).into()) .get(&TextureSemantics::Original.semantics(0).into())
@ -354,6 +364,7 @@ impl FilterPass {
); );
} }
// bind Source sampler
if let Some(binding) = self if let Some(binding) = self
.reflection .reflection
.meta .meta
@ -363,6 +374,8 @@ impl FilterPass {
// eprintln!("setting source binding to {}", binding.binding); // eprintln!("setting source binding to {}", binding.binding);
FilterPass::bind_texture(binding, source); FilterPass::bind_texture(binding, source);
} }
// bind SourceSize
if let Some((location, offset)) = self if let Some((location, offset)) = self
.variable_bindings .variable_bindings
.get(&TextureSemantics::Source.semantics(0).into()) .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 // // todo: history
// //
// // if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) { // // 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); // // FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size);
// // } // // }
// //
// bind float parameters
for (id, (location, offset)) in for (id, (location, offset)) in
self.variable_bindings self.variable_bindings
.iter() .iter()
@ -426,30 +467,25 @@ impl FilterPass {
FilterPass::build_float(location.location(), &mut buffer[offset..][..4], value) FilterPass::build_float(location.location(), &mut buffer[offset..][..4], value)
} }
for (id, (location, offset)) in // bind luts
self.variable_bindings for (index, lut) in &parent.luts {
.iter() if let Some(binding) = self
.filter_map(|(binding, value)| match binding { .reflection
UniformBinding::TextureSize(semantics) => { .meta
if semantics.semantics == TextureSemantics::User { .texture_meta
Some((semantics, value)) .get(&TextureSemantics::User.semantics(*index))
} else { {
None FilterPass::bind_texture(binding, lut);
} }
}
_ => 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);
}
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( FilterPass::build_vec4(
location.location(), location.location(),
&mut buffer[offset..][..4], &mut buffer[offset..][..4],

View file

@ -13,7 +13,7 @@ pub fn calc_miplevel(width: u32, height: u32) -> u32 {
levels levels
} }
#[derive(Debug, Copy, Clone)] #[derive(Default, Debug, Copy, Clone)]
pub struct Texture { pub struct Texture {
pub image: GlImage, pub image: GlImage,
pub filter: FilterMode, pub filter: FilterMode,
@ -35,7 +35,7 @@ pub struct Size {
pub height: u32, pub height: u32,
} }
#[derive(Debug, Copy, Clone)] #[derive(Default, Debug, Copy, Clone)]
pub struct GlImage { pub struct GlImage {
pub handle: GLuint, pub handle: GLuint,
pub format: GLenum, pub format: GLenum,