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

Commit 723fe9c

Browse files
committed
[Impeller] started recycling vkRenderPass and vkFramebuffer
1 parent c3f57b7 commit 723fe9c

File tree

2 files changed

+100
-12
lines changed

2 files changed

+100
-12
lines changed

impeller/renderer/backend/vulkan/context_vk.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "impeller/renderer/backend/vulkan/queue_vk.h"
1818
#include "impeller/renderer/backend/vulkan/sampler_library_vk.h"
1919
#include "impeller/renderer/backend/vulkan/shader_library_vk.h"
20+
#include "impeller/renderer/backend/vulkan/shared_object_vk.h"
2021
#include "impeller/renderer/capabilities.h"
2122
#include "impeller/renderer/context.h"
2223

@@ -31,6 +32,71 @@ class FenceWaiterVK;
3132
class ResourceManagerVK;
3233
class SurfaceContextVK;
3334

35+
/// @brief Ring buffer for one writer thread and one reader thread.
36+
template <typename T>
37+
class RingBuffer {
38+
public:
39+
RingBuffer(int32_t size) : read_(0), write_(0), buffer_(size) {}
40+
41+
std::optional<T> Read() {
42+
int32_t current_read = read_.load();
43+
if (current_read == write_.load()) {
44+
return {};
45+
} else {
46+
int32_t next_read = (current_read + 1) % buffer_.size();
47+
read_.store(next_read);
48+
return buffer_[current_read];
49+
}
50+
}
51+
52+
bool Write(const T& value) {
53+
int32_t current_write = write_.load();
54+
int32_t next_write = (current_write + 1) % buffer_.size();
55+
if (next_write == read_.load()) { // Buffer full
56+
return false;
57+
}
58+
buffer_[current_write] = value;
59+
write_.store(next_write);
60+
return true;
61+
}
62+
63+
private:
64+
std::atomic<int32_t> read_;
65+
std::atomic<int32_t> write_;
66+
std::vector<T> buffer_;
67+
};
68+
69+
template <typename T>
70+
class RingBufferItem : public SharedObjectVK {
71+
public:
72+
RingBufferItem(std::weak_ptr<const ContextVK> context,
73+
RingBuffer<T>* ring_buffer,
74+
std::optional<T> value)
75+
: context_(context), ring_buffer_(ring_buffer), value_(value) {}
76+
77+
virtual ~RingBufferItem() {
78+
auto context = context_.lock();
79+
if (value_ && context) {
80+
bool did_write = ring_buffer_->Write(value_.value());
81+
FML_CHECK(did_write);
82+
}
83+
}
84+
85+
std::optional<T>& GetValue() { return value_; }
86+
87+
private:
88+
FML_DISALLOW_COPY_AND_ASSIGN(RingBufferItem<T>);
89+
90+
std::weak_ptr<const ContextVK> context_;
91+
RingBuffer<T>* ring_buffer_;
92+
std::optional<T> value_;
93+
};
94+
95+
struct RenderPassFrameBufferPair {
96+
SharedHandleVK<vk::RenderPass> render_pass;
97+
SharedHandleVK<vk::Framebuffer> framebuffer;
98+
};
99+
34100
class ContextVK final : public Context,
35101
public BackendCast<ContextVK, Context>,
36102
public std::enable_shared_from_this<ContextVK> {
@@ -135,6 +201,12 @@ class ContextVK final : public Context,
135201

136202
std::shared_ptr<ResourceManagerVK> GetResourceManager() const;
137203

204+
std::shared_ptr<RingBufferItem<RenderPassFrameBufferPair>>
205+
GetRenderPassFrameBufferPair() const {
206+
return std::make_shared<RingBufferItem<RenderPassFrameBufferPair>>(
207+
shared_from_this(), &render_pass_pool_, render_pass_pool_.Read());
208+
}
209+
138210
private:
139211
struct DeviceHolderImpl : public DeviceHolder {
140212
// |DeviceHolder|
@@ -162,6 +234,8 @@ class ContextVK final : public Context,
162234
std::string device_name_;
163235
std::shared_ptr<fml::ConcurrentMessageLoop> raster_message_loop_;
164236
const uint64_t hash_;
237+
mutable RingBuffer<RenderPassFrameBufferPair> render_pass_pool_ =
238+
RingBuffer<RenderPassFrameBufferPair>(10);
165239

166240
bool is_valid_ = false;
167241

impeller/renderer/backend/vulkan/render_pass_vk.cc

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -609,27 +609,41 @@ bool RenderPassVK::OnEncodeCommands(const Context& context) const {
609609

610610
const auto& target_size = render_target_.GetRenderTargetSize();
611611

612-
auto render_pass = CreateVKRenderPass(vk_context, command_buffer);
613-
if (!render_pass) {
614-
VALIDATION_LOG << "Could not create renderpass.";
615-
return false;
616-
}
612+
std::shared_ptr<RingBufferItem<RenderPassFrameBufferPair>>
613+
render_pass_frame_buffer_pair = vk_context.GetRenderPassFrameBufferPair();
617614

618-
auto framebuffer = CreateVKFramebuffer(vk_context, *render_pass);
619-
if (!framebuffer) {
620-
VALIDATION_LOG << "Could not create framebuffer.";
621-
return false;
615+
if (!render_pass_frame_buffer_pair->GetValue()) {
616+
auto render_pass = CreateVKRenderPass(vk_context, command_buffer);
617+
if (!render_pass) {
618+
VALIDATION_LOG << "Could not create renderpass.";
619+
return false;
620+
}
621+
622+
auto framebuffer = CreateVKFramebuffer(vk_context, *render_pass);
623+
if (!framebuffer) {
624+
VALIDATION_LOG << "Could not create framebuffer.";
625+
return false;
626+
}
627+
628+
RenderPassFrameBufferPair pair = RenderPassFrameBufferPair{
629+
.render_pass = render_pass,
630+
.framebuffer = framebuffer,
631+
};
632+
633+
render_pass_frame_buffer_pair->GetValue() = std::move(pair);
622634
}
623635

624-
if (!encoder->Track(framebuffer) || !encoder->Track(render_pass)) {
636+
if (!encoder->Track(render_pass_frame_buffer_pair)) {
625637
return false;
626638
}
627639

628640
auto clear_values = GetVKClearValues(render_target_);
629641

630642
vk::RenderPassBeginInfo pass_info;
631-
pass_info.renderPass = *render_pass;
632-
pass_info.framebuffer = *framebuffer;
643+
pass_info.renderPass =
644+
*render_pass_frame_buffer_pair->GetValue()->render_pass;
645+
pass_info.framebuffer =
646+
*render_pass_frame_buffer_pair->GetValue()->framebuffer;
633647
pass_info.renderArea.extent.width = static_cast<uint32_t>(target_size.width);
634648
pass_info.renderArea.extent.height =
635649
static_cast<uint32_t>(target_size.height);

0 commit comments

Comments
 (0)