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 {
passes: Vec<FilterPass>,
passes: Box<[FilterPass]>,
common: FilterCommon,
quad_vao: GLuint,
output_framebuffers: Box<[Framebuffer]>,
}
pub struct FilterCommon {
semantics: ReflectSemantics,
pub(crate) preset: ShaderPreset,
original_history: Vec<Framebuffer>,
history: Vec<Texture>,
feedback: Vec<Texture>,
pub original_history: Box<[Framebuffer]>,
pub history: Vec<Texture>,
pub feedback: Vec<Texture>,
pub(crate) luts: FxHashMap<usize, Texture>,
outputs: Vec<Framebuffer>,
pub output_textures: Box<[Texture]>,
pub(crate) quad_vbo: GLuint,
}
@ -125,18 +126,13 @@ type ShaderPassMeta<'a> = (
ShaderSource,
CompilerBackend<
impl CompileShader<GLSL, Options = GlVersion, Context = GlslangGlslContext>
+ ReflectShader
+ Sized,
+ ReflectShader
+ Sized,
>,
);
impl FilterChain {
fn load_preset(
preset: &ShaderPreset,
) -> (
Vec<ShaderPassMeta>,
ReflectSemantics,
) {
fn load_preset(preset: &ShaderPreset) -> (Vec<ShaderPassMeta>, ReflectSemantics) {
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
Default::default();
@ -305,7 +301,10 @@ impl FilterChain {
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();
// 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<Path>) -> Result<FilterChain, Box<dyn Error>> {
// 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,

View file

@ -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],

View file

@ -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,