Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 319ff6c

Browse files
author
Jonah Williams
authored
[Impeller] Cache RenderPass/Framebuffer objects on the resolve texture sources. (#50142)
Cache vk::RenderPass and vk::Framebuffer objects on the resolve texture of any render target attachments. Use these on the next frame unconditionally. Fixes flutter/flutter#141750
1 parent 7c2f6c8 commit 319ff6c

9 files changed

Lines changed: 137 additions & 6 deletions

File tree

ci/licenses_golden/excluded_files

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@
176176
../../../flutter/impeller/renderer/backend/vulkan/context_vk_unittests.cc
177177
../../../flutter/impeller/renderer/backend/vulkan/descriptor_pool_vk_unittests.cc
178178
../../../flutter/impeller/renderer/backend/vulkan/fence_waiter_vk_unittests.cc
179+
../../../flutter/impeller/renderer/backend/vulkan/render_pass_cache_unittests.cc
179180
../../../flutter/impeller/renderer/backend/vulkan/resource_manager_vk_unittests.cc
180181
../../../flutter/impeller/renderer/backend/vulkan/test
181182
../../../flutter/impeller/renderer/blit_pass_unittests.cc

impeller/renderer/backend/vulkan/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ impeller_component("vulkan_unittests") {
1414
"context_vk_unittests.cc",
1515
"descriptor_pool_vk_unittests.cc",
1616
"fence_waiter_vk_unittests.cc",
17+
"render_pass_cache_unittests.cc",
1718
"resource_manager_vk_unittests.cc",
1819
"test/gpu_tracer_unittests.cc",
1920
"test/mock_vulkan.cc",
@@ -23,6 +24,7 @@ impeller_component("vulkan_unittests") {
2324
]
2425
deps = [
2526
":vulkan",
27+
"../../../playground:playground_test",
2628
"//flutter/testing:testing_lib",
2729
]
2830
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/testing/testing.h"
6+
#include "gtest/gtest.h"
7+
#include "impeller/playground/playground_test.h"
8+
#include "impeller/renderer/backend/vulkan/texture_vk.h"
9+
#include "impeller/renderer/render_target.h"
10+
11+
namespace impeller {
12+
namespace testing {
13+
14+
using RendererTest = PlaygroundTest;
15+
16+
TEST_P(RendererTest, CachesRenderPassAndFramebuffer) {
17+
if (GetBackend() != PlaygroundBackend::kVulkan) {
18+
GTEST_SKIP() << "Test only applies to Vulkan";
19+
}
20+
21+
auto allocator = std::make_shared<RenderTargetAllocator>(
22+
GetContext()->GetResourceAllocator());
23+
24+
auto render_target = RenderTarget::CreateOffscreenMSAA(
25+
*GetContext(), *allocator, {100, 100}, 1);
26+
auto resolve_texture =
27+
render_target.GetColorAttachments().find(0u)->second.resolve_texture;
28+
auto& texture_vk = TextureVK::Cast(*resolve_texture);
29+
30+
EXPECT_EQ(texture_vk.GetFramebuffer(), nullptr);
31+
EXPECT_EQ(texture_vk.GetRenderPass(), nullptr);
32+
33+
auto buffer = GetContext()->CreateCommandBuffer();
34+
auto render_pass = buffer->CreateRenderPass(render_target);
35+
36+
EXPECT_NE(texture_vk.GetFramebuffer(), nullptr);
37+
EXPECT_NE(texture_vk.GetRenderPass(), nullptr);
38+
39+
render_pass->EncodeCommands();
40+
GetContext()->GetCommandQueue()->Submit({buffer});
41+
42+
// Can be reused without error.
43+
auto buffer_2 = GetContext()->CreateCommandBuffer();
44+
auto render_pass_2 = buffer_2->CreateRenderPass(render_target);
45+
46+
EXPECT_TRUE(render_pass_2->EncodeCommands());
47+
EXPECT_TRUE(GetContext()->GetCommandQueue()->Submit({buffer_2}).ok());
48+
}
49+
50+
} // namespace testing
51+
} // namespace impeller

impeller/renderer/backend/vulkan/render_pass_vk.cc

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
2626
#include "impeller/renderer/backend/vulkan/texture_vk.h"
2727
#include "impeller/renderer/backend/vulkan/vk.h"
28+
#include "vulkan/vulkan_handles.hpp"
2829

2930
namespace impeller {
3031

@@ -79,6 +80,7 @@ static std::vector<vk::ClearValue> GetVKClearValues(
7980

8081
SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
8182
const ContextVK& context,
83+
const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
8284
const std::shared_ptr<CommandBufferVK>& command_buffer) const {
8385
BarrierVK barrier;
8486
barrier.new_layout = vk::ImageLayout::eGeneral;
@@ -127,6 +129,15 @@ SharedHandleVK<vk::RenderPass> RenderPassVK::CreateVKRenderPass(
127129
TextureVK::Cast(*stencil->texture).SetLayout(barrier);
128130
}
129131

132+
// There may exist a previous recycled render pass that we can continue using.
133+
// This is probably compatible with the render pass we are about to construct,
134+
// but I have not conclusively proven this. If there are scenarios that
135+
// produce validation warnings, we could use them to determine if we need
136+
// additional checks at this point to determine reusability.
137+
if (recycled_renderpass != nullptr) {
138+
return recycled_renderpass;
139+
}
140+
130141
auto pass = builder.Build(context.GetDevice());
131142

132143
if (!pass) {
@@ -143,6 +154,11 @@ RenderPassVK::RenderPassVK(const std::shared_ptr<const Context>& context,
143154
const RenderTarget& target,
144155
std::shared_ptr<CommandBufferVK> command_buffer)
145156
: RenderPass(context, target), command_buffer_(std::move(command_buffer)) {
157+
color_image_vk_ =
158+
render_target_.GetColorAttachments().find(0u)->second.texture;
159+
resolve_image_vk_ =
160+
render_target_.GetColorAttachments().find(0u)->second.resolve_texture;
161+
146162
const auto& vk_context = ContextVK::Cast(*context);
147163
const std::shared_ptr<CommandEncoderVK>& encoder =
148164
command_buffer_->GetEncoder();
@@ -154,16 +170,26 @@ RenderPassVK::RenderPassVK(const std::shared_ptr<const Context>& context,
154170
return true;
155171
});
156172

173+
SharedHandleVK<vk::RenderPass> recycled_render_pass;
174+
SharedHandleVK<vk::Framebuffer> recycled_framebuffer;
175+
if (resolve_image_vk_) {
176+
recycled_render_pass = TextureVK::Cast(*resolve_image_vk_).GetRenderPass();
177+
recycled_framebuffer = TextureVK::Cast(*resolve_image_vk_).GetFramebuffer();
178+
}
179+
157180
const auto& target_size = render_target_.GetRenderTargetSize();
158181

159-
render_pass_ = CreateVKRenderPass(vk_context, command_buffer_);
182+
render_pass_ =
183+
CreateVKRenderPass(vk_context, recycled_render_pass, command_buffer_);
160184
if (!render_pass_) {
161185
VALIDATION_LOG << "Could not create renderpass.";
162186
is_valid_ = false;
163187
return;
164188
}
165189

166-
auto framebuffer = CreateVKFramebuffer(vk_context, *render_pass_);
190+
auto framebuffer = (recycled_framebuffer == nullptr)
191+
? CreateVKFramebuffer(vk_context, *render_pass_)
192+
: recycled_framebuffer;
167193
if (!framebuffer) {
168194
VALIDATION_LOG << "Could not create framebuffer.";
169195
is_valid_ = false;
@@ -174,6 +200,10 @@ RenderPassVK::RenderPassVK(const std::shared_ptr<const Context>& context,
174200
is_valid_ = false;
175201
return;
176202
}
203+
if (resolve_image_vk_) {
204+
TextureVK::Cast(*resolve_image_vk_).SetFramebuffer(framebuffer);
205+
TextureVK::Cast(*resolve_image_vk_).SetRenderPass(render_pass_);
206+
}
177207

178208
auto clear_values = GetVKClearValues(render_target_);
179209

@@ -205,10 +235,6 @@ RenderPassVK::RenderPassVK(const std::shared_ptr<const Context>& context,
205235
.setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight()));
206236
command_buffer_vk_.setScissor(0, 1, &scissor);
207237

208-
color_image_vk_ =
209-
render_target_.GetColorAttachments().find(0u)->second.texture;
210-
resolve_image_vk_ =
211-
render_target_.GetColorAttachments().find(0u)->second.resolve_texture;
212238
is_valid_ = true;
213239
}
214240

impeller/renderer/backend/vulkan/render_pass_vk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
1212
#include "impeller/renderer/render_pass.h"
1313
#include "impeller/renderer/render_target.h"
14+
#include "vulkan/vulkan_handles.hpp"
1415

1516
namespace impeller {
1617

@@ -123,6 +124,7 @@ class RenderPassVK final : public RenderPass {
123124

124125
SharedHandleVK<vk::RenderPass> CreateVKRenderPass(
125126
const ContextVK& context,
127+
const SharedHandleVK<vk::RenderPass>& recycled_renderpass,
126128
const std::shared_ptr<CommandBufferVK>& command_buffer) const;
127129

128130
SharedHandleVK<vk::Framebuffer> CreateVKFramebuffer(

impeller/renderer/backend/vulkan/swapchain_image_vk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "impeller/renderer/backend/vulkan/formats_vk.h"
1010
#include "impeller/renderer/backend/vulkan/texture_source_vk.h"
1111
#include "impeller/renderer/backend/vulkan/vk.h"
12+
#include "vulkan/vulkan_handles.hpp"
1213

1314
namespace impeller {
1415

impeller/renderer/backend/vulkan/texture_source_vk.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#include "impeller/core/texture_descriptor.h"
1111
#include "impeller/renderer/backend/vulkan/barrier_vk.h"
1212
#include "impeller/renderer/backend/vulkan/formats_vk.h"
13+
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
1314
#include "impeller/renderer/backend/vulkan/vk.h"
15+
#include "vulkan/vulkan_handles.hpp"
1416

1517
namespace impeller {
1618

impeller/renderer/backend/vulkan/texture_vk.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,22 @@ vk::ImageView TextureVK::GetRenderTargetView() const {
173173
return source_->GetRenderTargetView();
174174
}
175175

176+
void TextureVK::SetFramebuffer(
177+
const SharedHandleVK<vk::Framebuffer>& framebuffer) {
178+
framebuffer_ = framebuffer;
179+
}
180+
181+
void TextureVK::SetRenderPass(
182+
const SharedHandleVK<vk::RenderPass>& render_pass) {
183+
render_pass_ = render_pass;
184+
}
185+
186+
SharedHandleVK<vk::Framebuffer> TextureVK::GetFramebuffer() const {
187+
return framebuffer_;
188+
}
189+
190+
SharedHandleVK<vk::RenderPass> TextureVK::GetRenderPass() const {
191+
return render_pass_;
192+
}
193+
176194
} // namespace impeller

impeller/renderer/backend/vulkan/texture_vk.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,37 @@ class TextureVK final : public Texture, public BackendCast<TextureVK, Texture> {
4444

4545
bool IsSwapchainImage() const { return source_->IsSwapchainImage(); }
4646

47+
// These methods should only be used by render_pass_vk.h
48+
49+
/// Store the last framebuffer object used with this texture.
50+
///
51+
/// This field is only set if this texture is used as the resolve texture
52+
/// of a render pass. By construction, this framebuffer should be compatible
53+
/// with any future render passes.
54+
void SetFramebuffer(const SharedHandleVK<vk::Framebuffer>& framebuffer);
55+
56+
/// Store the last render pass object used with this texture.
57+
///
58+
/// This field is only set if this texture is used as the resolve texture
59+
/// of a render pass. By construction, this framebuffer should be compatible
60+
/// with any future render passes.
61+
void SetRenderPass(const SharedHandleVK<vk::RenderPass>& render_pass);
62+
63+
/// Retrieve the last framebuffer object used with this texture.
64+
///
65+
/// May be nullptr if no previous framebuffer existed.
66+
SharedHandleVK<vk::Framebuffer> GetFramebuffer() const;
67+
68+
/// Retrieve the last render pass object used with this texture.
69+
///
70+
/// May be nullptr if no previous render pass existed.
71+
SharedHandleVK<vk::RenderPass> GetRenderPass() const;
72+
4773
private:
4874
std::weak_ptr<Context> context_;
4975
std::shared_ptr<TextureSourceVK> source_;
76+
SharedHandleVK<vk::Framebuffer> framebuffer_ = nullptr;
77+
SharedHandleVK<vk::RenderPass> render_pass_ = nullptr;
5078

5179
// |Texture|
5280
void SetLabel(std::string_view label) override;

0 commit comments

Comments
 (0)