Skip to content

Commit 87e040d

Browse files
committed
rt(vk): sparse framebuffers
1 parent 4df95fd commit 87e040d

2 files changed

Lines changed: 132 additions & 134 deletions

File tree

librashader-runtime-vk/src/filter_chain.rs

Lines changed: 122 additions & 124 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_framebuffers: FramebufferPool<OwnedImage>,
176+
feedback_framebuffers: FramebufferPool<OwnedImage>,
177177
history_framebuffers: VecDeque<OwnedImage>,
178178
disable_mipmaps: bool,
179179
residuals: Box<[FrameResiduals]>,
@@ -471,8 +471,7 @@ impl FilterChainVulkan {
471471
let (output_framebuffers, 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_framebuffers, feedback_textures) = framebuffer_init.init_feedback_framebuffers()?;
476475

477476
// initialize history
478477
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
@@ -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_framebuffers.contains(index) {
741+
std::mem::swap(&mut self.output_framebuffers[index], &mut self.feedback_framebuffers[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,
748758
&mut self.feedback_framebuffers,
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-
}
808771

809-
source = self.common.output_textures[index].clone().unwrap();
810-
intermediates.dispose_outputs(output_image);
811-
intermediates.dispose_framebuffers(residual_fb);
812-
}
813-
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_framebuffers,
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

librashader-runtime-wgpu/src/filter_chain.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ use librashader_runtime::parameters::RuntimeParameters;
105105
pub struct FilterChainWgpu {
106106
pub(crate) common: FilterCommon,
107107
passes: Box<[FilterPass]>,
108-
output: FramebufferPool<OwnedImage>,
109-
feedback: FramebufferPool<OwnedImage>,
108+
output_framebuffers: FramebufferPool<OwnedImage>,
109+
feedback_framebuffers: FramebufferPool<OwnedImage>,
110110
history_framebuffers: VecDeque<OwnedImage>,
111111
disable_mipmaps: bool,
112112
mipmapper: MipmapGen,
@@ -256,10 +256,10 @@ impl FilterChainWgpu {
256256

257257
//
258258
// // initialize output framebuffers
259-
let (output, output_textures) = framebuffer_init.init_output_framebuffers()?;
259+
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
260260
//
261261
// initialize feedback framebuffers
262-
let (feedback, feedback_textures) = framebuffer_init.init_feedback_framebuffers()?;
262+
let (feedback_framebuffers, feedback_textures) = framebuffer_init.init_feedback_framebuffers()?;
263263
//
264264
// initialize history
265265
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
@@ -280,8 +280,8 @@ impl FilterChainWgpu {
280280
history_textures,
281281
},
282282
passes: filters,
283-
output,
284-
feedback,
283+
output_framebuffers,
284+
feedback_framebuffers,
285285
history_framebuffers,
286286
disable_mipmaps: options.map(|f| f.force_no_mipmaps).unwrap_or(false),
287287
mipmapper,
@@ -485,8 +485,8 @@ impl FilterChainWgpu {
485485

486486
// swap output and feedback **before** recording command buffers
487487
for index in 0..passes_len {
488-
if self.feedback.contains(index) {
489-
std::mem::swap(&mut self.output[index], &mut self.feedback[index]);
488+
if self.feedback_framebuffers.contains(index) {
489+
std::mem::swap(&mut self.output_framebuffers[index], &mut self.feedback_framebuffers[index]);
490490
}
491491
}
492492

@@ -497,7 +497,7 @@ impl FilterChainWgpu {
497497
source.image.size().into(),
498498
viewport.output.size,
499499
original.image.size().into(),
500-
&mut self.feedback,
500+
&mut self.feedback_framebuffers,
501501
passes,
502502
&scale_context,
503503
|index, pass, feedback| {
@@ -511,7 +511,7 @@ impl FilterChainWgpu {
511511
source.image.size().into(),
512512
viewport.output.size,
513513
original.image.size().into(),
514-
&mut self.output,
514+
&mut self.output_framebuffers,
515515
passes,
516516
&scale_context,
517517
|index, pass, target, size| {

0 commit comments

Comments
 (0)