[Impeller] Add keep alive for 4 frames in render target cache. (flutter/engine#57020)
Improve cache usage by keeping textures alive for 4 frames after the last usage. This improves cache usage in scenarios such as repeatidly dragging the android overscroll functionality. THis isn't expected to have a negative impact on memory, because a texture cannot be _immediately_ deleted anyway.
This commit is contained in:
parent
13c0f5ad58
commit
d58cd98b8c
@ -8,8 +8,10 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
RenderTargetCache::RenderTargetCache(std::shared_ptr<Allocator> allocator)
|
||||
: RenderTargetAllocator(std::move(allocator)) {}
|
||||
RenderTargetCache::RenderTargetCache(std::shared_ptr<Allocator> allocator,
|
||||
uint32_t keep_alive_frame_count)
|
||||
: RenderTargetAllocator(std::move(allocator)),
|
||||
keep_alive_frame_count_(keep_alive_frame_count) {}
|
||||
|
||||
void RenderTargetCache::Start() {
|
||||
for (auto& td : render_target_data_) {
|
||||
@ -20,9 +22,12 @@ void RenderTargetCache::Start() {
|
||||
void RenderTargetCache::End() {
|
||||
std::vector<RenderTargetData> retain;
|
||||
|
||||
for (const auto& td : render_target_data_) {
|
||||
for (RenderTargetData& td : render_target_data_) {
|
||||
if (td.used_this_frame) {
|
||||
retain.push_back(td);
|
||||
} else if (td.keep_alive_frame_count > 0) {
|
||||
td.keep_alive_frame_count--;
|
||||
retain.push_back(td);
|
||||
}
|
||||
}
|
||||
render_target_data_.swap(retain);
|
||||
@ -49,10 +54,11 @@ RenderTarget RenderTargetCache::CreateOffscreen(
|
||||
.has_msaa = false,
|
||||
.has_depth_stencil = stencil_attachment_config.has_value(),
|
||||
};
|
||||
for (auto& render_target_data : render_target_data_) {
|
||||
const auto other_config = render_target_data.config;
|
||||
for (RenderTargetData& render_target_data : render_target_data_) {
|
||||
const RenderTargetConfig other_config = render_target_data.config;
|
||||
if (!render_target_data.used_this_frame && other_config == config) {
|
||||
render_target_data.used_this_frame = true;
|
||||
render_target_data.keep_alive_frame_count = keep_alive_frame_count_;
|
||||
ColorAttachment color0 =
|
||||
render_target_data.render_target.GetColorAttachment(0);
|
||||
std::optional<DepthAttachment> depth =
|
||||
@ -69,10 +75,12 @@ RenderTarget RenderTargetCache::CreateOffscreen(
|
||||
if (!created_target.IsValid()) {
|
||||
return created_target;
|
||||
}
|
||||
render_target_data_.push_back(
|
||||
RenderTargetData{.used_this_frame = true,
|
||||
.config = config,
|
||||
.render_target = created_target});
|
||||
render_target_data_.push_back(RenderTargetData{
|
||||
.used_this_frame = true, //
|
||||
.keep_alive_frame_count = keep_alive_frame_count_, //
|
||||
.config = config, //
|
||||
.render_target = created_target //
|
||||
});
|
||||
return created_target;
|
||||
}
|
||||
|
||||
@ -99,10 +107,11 @@ RenderTarget RenderTargetCache::CreateOffscreenMSAA(
|
||||
.has_msaa = true,
|
||||
.has_depth_stencil = stencil_attachment_config.has_value(),
|
||||
};
|
||||
for (auto& render_target_data : render_target_data_) {
|
||||
const auto other_config = render_target_data.config;
|
||||
for (RenderTargetData& render_target_data : render_target_data_) {
|
||||
const RenderTargetConfig other_config = render_target_data.config;
|
||||
if (!render_target_data.used_this_frame && other_config == config) {
|
||||
render_target_data.used_this_frame = true;
|
||||
render_target_data.keep_alive_frame_count = keep_alive_frame_count_;
|
||||
ColorAttachment color0 =
|
||||
render_target_data.render_target.GetColorAttachment(0);
|
||||
std::optional<DepthAttachment> depth =
|
||||
@ -120,10 +129,12 @@ RenderTarget RenderTargetCache::CreateOffscreenMSAA(
|
||||
if (!created_target.IsValid()) {
|
||||
return created_target;
|
||||
}
|
||||
render_target_data_.push_back(
|
||||
RenderTargetData{.used_this_frame = true,
|
||||
.config = config,
|
||||
.render_target = created_target});
|
||||
render_target_data_.push_back(RenderTargetData{
|
||||
.used_this_frame = true, //
|
||||
.keep_alive_frame_count = keep_alive_frame_count_, //
|
||||
.config = config, //
|
||||
.render_target = created_target //
|
||||
});
|
||||
return created_target;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,8 @@ namespace impeller {
|
||||
/// Any textures unused after a frame are immediately discarded.
|
||||
class RenderTargetCache : public RenderTargetAllocator {
|
||||
public:
|
||||
explicit RenderTargetCache(std::shared_ptr<Allocator> allocator);
|
||||
explicit RenderTargetCache(std::shared_ptr<Allocator> allocator,
|
||||
uint32_t keep_alive_frame_count = 4);
|
||||
|
||||
~RenderTargetCache() = default;
|
||||
|
||||
@ -59,11 +60,13 @@ class RenderTargetCache : public RenderTargetAllocator {
|
||||
private:
|
||||
struct RenderTargetData {
|
||||
bool used_this_frame;
|
||||
uint32_t keep_alive_frame_count;
|
||||
RenderTargetConfig config;
|
||||
RenderTarget render_target;
|
||||
};
|
||||
|
||||
std::vector<RenderTargetData> render_target_data_;
|
||||
uint32_t keep_alive_frame_count_;
|
||||
|
||||
RenderTargetCache(const RenderTargetCache&) = delete;
|
||||
|
||||
|
@ -50,8 +50,8 @@ class TestAllocator : public Allocator {
|
||||
};
|
||||
|
||||
TEST_P(RenderTargetCacheTest, CachesUsedTexturesAcrossFrames) {
|
||||
auto render_target_cache =
|
||||
RenderTargetCache(GetContext()->GetResourceAllocator());
|
||||
auto render_target_cache = RenderTargetCache(
|
||||
GetContext()->GetResourceAllocator(), /*keep_alive_frame_count=*/0);
|
||||
|
||||
render_target_cache.Start();
|
||||
// Create two render targets of the same exact size/shape. Both should be
|
||||
@ -73,10 +73,41 @@ TEST_P(RenderTargetCacheTest, CachesUsedTexturesAcrossFrames) {
|
||||
EXPECT_EQ(render_target_cache.CachedTextureCount(), 1u);
|
||||
}
|
||||
|
||||
TEST_P(RenderTargetCacheTest, CachesUsedTexturesAcrossFramesWithKeepAlive) {
|
||||
auto render_target_cache = RenderTargetCache(
|
||||
GetContext()->GetResourceAllocator(), /*keep_alive_frame_count=*/3);
|
||||
|
||||
render_target_cache.Start();
|
||||
// Create two render targets of the same exact size/shape. Both should be
|
||||
// marked as used this frame, so the cached data set will contain two.
|
||||
render_target_cache.CreateOffscreen(*GetContext(), {100, 100}, 1);
|
||||
render_target_cache.CreateOffscreen(*GetContext(), {100, 100}, 1);
|
||||
|
||||
EXPECT_EQ(render_target_cache.CachedTextureCount(), 2u);
|
||||
|
||||
render_target_cache.End();
|
||||
render_target_cache.Start();
|
||||
|
||||
// The unused texture is kept alive until the keep alive countdown
|
||||
// reaches 0.
|
||||
EXPECT_EQ(render_target_cache.CachedTextureCount(), 2u);
|
||||
|
||||
for (auto i = 0; i < 3; i++) {
|
||||
render_target_cache.Start();
|
||||
render_target_cache.End();
|
||||
EXPECT_EQ(render_target_cache.CachedTextureCount(), 2u);
|
||||
}
|
||||
// After the countdown has elapsed the texture is removed.
|
||||
render_target_cache.Start();
|
||||
render_target_cache.End();
|
||||
EXPECT_EQ(render_target_cache.CachedTextureCount(), 0u);
|
||||
}
|
||||
|
||||
TEST_P(RenderTargetCacheTest, DoesNotPersistFailedAllocations) {
|
||||
ScopedValidationDisable disable;
|
||||
auto allocator = std::make_shared<TestAllocator>();
|
||||
auto render_target_cache = RenderTargetCache(allocator);
|
||||
auto render_target_cache =
|
||||
RenderTargetCache(allocator, /*keep_alive_frame_count=*/0);
|
||||
|
||||
render_target_cache.Start();
|
||||
allocator->should_fail = true;
|
||||
@ -89,8 +120,8 @@ TEST_P(RenderTargetCacheTest, DoesNotPersistFailedAllocations) {
|
||||
}
|
||||
|
||||
TEST_P(RenderTargetCacheTest, CachedTextureGetsNewAttachmentConfig) {
|
||||
auto render_target_cache =
|
||||
RenderTargetCache(GetContext()->GetResourceAllocator());
|
||||
auto render_target_cache = RenderTargetCache(
|
||||
GetContext()->GetResourceAllocator(), /*keep_alive_frame_count=*/0);
|
||||
|
||||
render_target_cache.Start();
|
||||
RenderTarget::AttachmentConfig color_attachment_config =
|
||||
@ -114,8 +145,8 @@ TEST_P(RenderTargetCacheTest, CachedTextureGetsNewAttachmentConfig) {
|
||||
}
|
||||
|
||||
TEST_P(RenderTargetCacheTest, CreateWithEmptySize) {
|
||||
auto render_target_cache =
|
||||
RenderTargetCache(GetContext()->GetResourceAllocator());
|
||||
auto render_target_cache = RenderTargetCache(
|
||||
GetContext()->GetResourceAllocator(), /*keep_alive_frame_count=*/0);
|
||||
|
||||
render_target_cache.Start();
|
||||
RenderTarget empty_target =
|
||||
|
Loading…
x
Reference in New Issue
Block a user