Skip to content

Commit d1ae9d7

Browse files
committed
rt(vk): sparse framebuffers
1 parent 886d4d9 commit d1ae9d7

1 file changed

Lines changed: 126 additions & 128 deletions

File tree

librashader-runtime-vk/src/filter_chain.rs

Lines changed: 126 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtif
2727
use librashader_reflect::reflect::semantics::ShaderSemantics;
2828
use librashader_reflect::reflect::ReflectShader;
2929
use librashader_runtime::binding::BindingUtil;
30-
use librashader_runtime::framebuffer::FramebufferInit;
30+
use librashader_runtime::framebuffer::{FramebufferInit, FramebufferPool};
3131
use librashader_runtime::image::{ImageError, LoadedTexture, UVDirection, BGRA8};
3232
use librashader_runtime::quad::QuadType;
3333
use librashader_runtime::render_target::RenderTarget;
@@ -172,8 +172,8 @@ pub struct FilterChainVulkan {
172172
pub(crate) common: FilterCommon,
173173
passes: Box<[FilterPass]>,
174174
vulkan: VulkanObjects,
175-
output_framebuffers: Box<[OwnedImage]>,
176-
feedback_framebuffers: Box<[OwnedImage]>,
175+
output: FramebufferPool<OwnedImage>,
176+
feedback: FramebufferPool<OwnedImage>,
177177
history_framebuffers: VecDeque<OwnedImage>,
178178
disable_mipmaps: bool,
179179
residuals: Box<[FrameResiduals]>,
@@ -468,11 +468,10 @@ impl FilterChainVulkan {
468468
);
469469

470470
// initialize output framebuffers
471-
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
471+
let (output, output_textures) = framebuffer_init.init_output_framebuffers()?;
472472

473473
// initialize feedback framebuffers
474-
let (feedback_framebuffers, feedback_textures) =
475-
framebuffer_init.init_output_framebuffers()?;
474+
let (feedback, feedback_textures) = framebuffer_init.init_feedback_framebuffers()?;
476475

477476
// initialize history
478477
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
@@ -497,8 +496,8 @@ impl FilterChainVulkan {
497496
},
498497
passes: filters,
499498
vulkan: device,
500-
output_framebuffers,
501-
feedback_framebuffers,
499+
output,
500+
feedback,
502501
history_framebuffers,
503502
residuals: intermediates.into_boxed_slice(),
504503
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
@@ -733,159 +732,158 @@ impl FilterChainVulkan {
733732

734733
let mut source = original.clone();
735734

735+
let passes_len = passes.len();
736+
let options = options.unwrap_or(&self.default_options);
737+
736738
// swap output and feedback **before** recording command buffers
737-
std::mem::swap(
738-
&mut self.output_framebuffers,
739-
&mut self.feedback_framebuffers,
740-
);
739+
for index in 0..passes_len {
740+
if self.feedback.contains(index) {
741+
std::mem::swap(&mut self.output[index], &mut self.feedback[index]);
742+
}
743+
}
744+
745+
let scale_context = Some(OwnedImageLayout {
746+
dst_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
747+
dst_access: vk::AccessFlags::SHADER_READ,
748+
src_stage: vk::PipelineStageFlags::TOP_OF_PIPE,
749+
dst_stage: vk::PipelineStageFlags::FRAGMENT_SHADER,
750+
cmd,
751+
});
741752

742-
// rescale render buffers to ensure all bindings are valid.
743-
OwnedImage::scale_framebuffers_with_context(
753+
// rescale feedback buffers and refresh their bound textures.
754+
OwnedImage::scale_feedback_framebuffers_with_context(
744755
source.image.size,
745756
viewport.output.size,
746757
original.image.size,
747-
&mut self.output_framebuffers,
748-
&mut self.feedback_framebuffers,
758+
&mut self.feedback,
749759
passes,
750-
&Some(OwnedImageLayout {
751-
dst_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
752-
dst_access: vk::AccessFlags::SHADER_READ,
753-
src_stage: vk::PipelineStageFlags::TOP_OF_PIPE,
754-
dst_stage: vk::PipelineStageFlags::FRAGMENT_SHADER,
755-
cmd,
756-
}),
757-
Some(&mut |index: usize,
758-
pass: &FilterPass,
759-
output: &OwnedImage,
760-
feedback: &OwnedImage| {
761-
// refresh inputs
760+
&scale_context,
761+
|index, pass, feedback| {
762762
self.common.feedback_textures[index] =
763763
Some(feedback.as_input(pass.meta.filter, pass.meta.wrap_mode));
764-
self.common.output_textures[index] =
765-
Some(output.as_input(pass.meta.filter, pass.meta.wrap_mode));
766764
Ok(())
767-
}),
765+
},
768766
)?;
769767

770-
let passes_len = passes.len();
771-
let (pass, last) = passes.split_at_mut(passes_len - 1);
772-
773-
let options = options.unwrap_or(&self.default_options);
774-
775768
self.common
776769
.draw_quad
777770
.bind_vbo_for_frame(&self.vulkan.device, cmd);
778-
for (index, pass) in pass.iter_mut().enumerate() {
779-
let target = &self.output_framebuffers[index];
780-
source.filter_mode = pass.meta.filter;
781-
source.wrap_mode = pass.meta.wrap_mode;
782-
source.mip_filter = pass.meta.filter;
783-
784-
let output_image = OutputImage::new(&self.vulkan.device, target.image.clone())?;
785-
let out = RenderTarget::identity(&output_image)?;
786-
787-
let residual_fb = pass.draw(
788-
cmd,
789-
target.image.format,
790-
index,
791-
&self.common,
792-
pass.meta.get_frame_count(frame_count),
793-
options,
794-
viewport,
795-
&original,
796-
&source,
797-
&out,
798-
None,
799-
QuadType::Offscreen,
800-
false,
801-
)?;
802-
803-
if target.max_miplevels > 1 && !self.disable_mipmaps {
804-
target.generate_mipmaps_and_end_pass(cmd);
805-
} else {
806-
out.output.end_pass(&self.vulkan.device, cmd);
807-
}
808-
809-
source = self.common.output_textures[index].clone().unwrap();
810-
intermediates.dispose_outputs(output_image);
811-
intermediates.dispose_framebuffers(residual_fb);
812-
}
813771

814-
// try to hint the optimizer
815-
assert_eq!(last.len(), 1);
816-
if let Some(pass) = last.iter_mut().next() {
817-
let index = passes_len - 1;
818-
if pass
819-
.graphics_pipeline
820-
.render_passes
821-
.get(&viewport.output.format)
822-
.is_none()
823-
{
824-
// need to recompile
825-
pass.graphics_pipeline.recompile(viewport.output.format)?;
826-
}
772+
OwnedImage::scale_output_framebuffers_with_context(
773+
source.image.size,
774+
viewport.output.size,
775+
original.image.size,
776+
&mut self.output,
777+
passes,
778+
&scale_context,
779+
|index, pass, target, _size| {
780+
source.filter_mode = pass.meta.filter;
781+
source.wrap_mode = pass.meta.wrap_mode;
782+
source.mip_filter = pass.meta.filter;
783+
let frame_count_pass = pass.meta.get_frame_count(frame_count);
784+
785+
if index != passes_len - 1 {
786+
let output_image = OutputImage::new(&self.vulkan.device, target.image.clone())?;
787+
let out = RenderTarget::identity(&output_image)?;
788+
789+
let residual_fb = pass.draw(
790+
cmd,
791+
target.image.format,
792+
index,
793+
&self.common,
794+
frame_count_pass,
795+
options,
796+
viewport,
797+
&original,
798+
&source,
799+
&out,
800+
None,
801+
QuadType::Offscreen,
802+
false,
803+
)?;
804+
805+
if target.max_miplevels > 1 && !self.disable_mipmaps {
806+
target.generate_mipmaps_and_end_pass(cmd);
807+
} else {
808+
out.output.end_pass(&self.vulkan.device, cmd);
809+
}
810+
811+
self.common.output_textures[index] =
812+
Some(target.as_input(pass.meta.filter, pass.meta.wrap_mode));
813+
source = self.common.output_textures[index].clone().unwrap();
814+
intermediates.dispose_outputs(output_image);
815+
intermediates.dispose_framebuffers(residual_fb);
816+
return Ok(());
817+
}
827818

828-
source.filter_mode = pass.meta.filter;
829-
source.wrap_mode = pass.meta.wrap_mode;
830-
source.mip_filter = pass.meta.filter;
819+
if pass
820+
.graphics_pipeline
821+
.render_passes
822+
.get(&viewport.output.format)
823+
.is_none()
824+
{
825+
// need to recompile
826+
pass.graphics_pipeline.recompile(viewport.output.format)?;
827+
}
831828

832-
// When feedback is enabled, render the last pass to the intermediate
833-
// framebuffer first then render to the viewport with the OutputSize semantic
834-
// overridden to the FB scale.
835-
//
836-
// Shaders need to see the pass's declared scale rather than the viewport size,
837-
// or they won't render correctly for feedback.
838-
let output_size_override = if self.draw_last_pass_feedback {
839-
let target = &self.output_framebuffers[index];
829+
// When feedback is enabled, render the last pass to the intermediate
830+
// framebuffer first then render to the viewport with the OutputSize semantic
831+
// overridden to the FB scale.
832+
//
833+
// Shaders need to see the pass's declared scale rather than the viewport size,
834+
// or they won't render correctly for feedback.
835+
let output_size_override = if self.draw_last_pass_feedback {
836+
let output_image = OutputImage::new(&self.vulkan.device, target.image.clone())?;
837+
let out = RenderTarget::viewport_with_output(&output_image, viewport);
838+
839+
let residual_fb = pass.draw(
840+
cmd,
841+
target.image.format,
842+
index,
843+
&self.common,
844+
frame_count_pass,
845+
options,
846+
viewport,
847+
&original,
848+
&source,
849+
&out,
850+
None,
851+
QuadType::Final,
852+
true,
853+
)?;
854+
out.output.end_pass(&self.vulkan.device, cmd);
855+
intermediates.dispose_outputs(output_image);
856+
intermediates.dispose_framebuffers(residual_fb);
857+
Some(target.image.size)
858+
} else {
859+
None
860+
};
840861

841-
let output_image = OutputImage::new(&self.vulkan.device, target.image.clone())?;
862+
let output_image =
863+
OutputImage::new(&self.vulkan.device, viewport.output.clone())?;
842864
let out = RenderTarget::viewport_with_output(&output_image, viewport);
843865

844866
let residual_fb = pass.draw(
845867
cmd,
846-
target.image.format,
868+
viewport.output.format,
847869
index,
848870
&self.common,
849-
pass.meta.get_frame_count(frame_count),
871+
frame_count_pass,
850872
options,
851873
viewport,
852874
&original,
853875
&source,
854876
&out,
855-
None,
877+
output_size_override,
856878
QuadType::Final,
857-
true,
879+
false,
858880
)?;
859-
out.output.end_pass(&self.vulkan.device, cmd);
881+
860882
intermediates.dispose_outputs(output_image);
861883
intermediates.dispose_framebuffers(residual_fb);
862-
Some(target.image.size)
863-
} else {
864-
None
865-
};
866-
867-
let output_image = OutputImage::new(&self.vulkan.device, viewport.output.clone())?;
868-
let out = RenderTarget::viewport_with_output(&output_image, viewport);
869-
870-
let residual_fb = pass.draw(
871-
cmd,
872-
viewport.output.format,
873-
index,
874-
&self.common,
875-
pass.meta.get_frame_count(frame_count),
876-
options,
877-
viewport,
878-
&original,
879-
&source,
880-
&out,
881-
output_size_override,
882-
QuadType::Final,
883-
false,
884-
)?;
885-
886-
intermediates.dispose_outputs(output_image);
887-
intermediates.dispose_framebuffers(residual_fb);
888-
}
884+
Ok(())
885+
},
886+
)?;
889887

890888
intermediates.dispose_image_view(original_image_view);
891889

0 commit comments

Comments
 (0)