Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Impeller] Started using a pool for HostBuffers. #44081

Merged
merged 9 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/licenses_golden/excluded_files
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
../../../flutter/impeller/renderer/device_buffer_unittests.cc
../../../flutter/impeller/renderer/host_buffer_unittests.cc
../../../flutter/impeller/renderer/pipeline_descriptor_unittests.cc
../../../flutter/impeller/renderer/pool_unittests.cc
../../../flutter/impeller/renderer/renderer_dart_unittests.cc
../../../flutter/impeller/renderer/renderer_unittests.cc
../../../flutter/impeller/renderer/testing
Expand Down
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1600,6 +1600,7 @@ ORIGIN: ../../../flutter/impeller/renderer/pipeline_descriptor.cc + ../../../flu
ORIGIN: ../../../flutter/impeller/renderer/pipeline_descriptor.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/pipeline_library.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/pipeline_library.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/pool.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/prefix_sum_test.comp + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/render_pass.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/render_pass.h + ../../../flutter/LICENSE
Expand Down Expand Up @@ -4294,6 +4295,7 @@ FILE: ../../../flutter/impeller/renderer/pipeline_descriptor.cc
FILE: ../../../flutter/impeller/renderer/pipeline_descriptor.h
FILE: ../../../flutter/impeller/renderer/pipeline_library.cc
FILE: ../../../flutter/impeller/renderer/pipeline_library.h
FILE: ../../../flutter/impeller/renderer/pool.h
FILE: ../../../flutter/impeller/renderer/prefix_sum_test.comp
FILE: ../../../flutter/impeller/renderer/render_pass.cc
FILE: ../../../flutter/impeller/renderer/render_pass.h
Expand Down
2 changes: 1 addition & 1 deletion impeller/base/allocation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ bool Allocation::ReserveNPOT(size_t reserved) {
}

bool Allocation::Reserve(size_t reserved) {
if (reserved == reserved_) {
if (reserved <= reserved_) {
return true;
}

Expand Down
11 changes: 11 additions & 0 deletions impeller/core/host_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,15 @@ std::shared_ptr<const DeviceBuffer> HostBuffer::GetDeviceBuffer(
return device_buffer_;
}

void HostBuffer::Reset() {
generation_ += 1;
device_buffer_ = nullptr;
bool did_truncate = Truncate(0);
FML_CHECK(did_truncate);
}

size_t HostBuffer::GetSize() const {
return GetReservedLength();
}

} // namespace impeller
9 changes: 9 additions & 0 deletions impeller/core/host_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ class HostBuffer final : public std::enable_shared_from_this<HostBuffer>,
///
BufferView Emplace(size_t length, size_t align, const EmplaceProc& cb);

//----------------------------------------------------------------------------
/// @brief Resets the contents of the HostBuffer to nothing so it can be
/// reused.
void Reset();

//----------------------------------------------------------------------------
/// @brief Returns the size of the HostBuffer in memory in bytes.
size_t GetSize() const;

private:
mutable std::shared_ptr<DeviceBuffer> device_buffer_;
mutable size_t device_buffer_generation_ = 0u;
Expand Down
2 changes: 2 additions & 0 deletions impeller/renderer/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ impeller_component("renderer") {
"pipeline_descriptor.h",
"pipeline_library.cc",
"pipeline_library.h",
"pool.h",
"render_pass.cc",
"render_pass.h",
"render_target.cc",
Expand Down Expand Up @@ -125,6 +126,7 @@ impeller_component("renderer_unittests") {
"device_buffer_unittests.cc",
"host_buffer_unittests.cc",
"pipeline_descriptor_unittests.cc",
"pool_unittests.cc",
"renderer_unittests.cc",
]

Expand Down
8 changes: 8 additions & 0 deletions impeller/renderer/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

#include "flutter/fml/macros.h"
#include "impeller/core/formats.h"
#include "impeller/core/host_buffer.h"
#include "impeller/renderer/capabilities.h"
#include "impeller/renderer/pool.h"

namespace impeller {

Expand Down Expand Up @@ -158,10 +160,16 @@ class Context {
///
virtual void Shutdown() = 0;

//----------------------------------------------------------------------------
/// @brief Accessor for a pool of HostBuffers.
Pool<HostBuffer>& GetHostBufferPool() const { return host_buffer_pool_; }

protected:
Context();

private:
mutable Pool<HostBuffer> host_buffer_pool_ = Pool<HostBuffer>(1'000'000);

FML_DISALLOW_COPY_AND_ASSIGN(Context);
};

Expand Down
54 changes: 54 additions & 0 deletions impeller/renderer/pool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#include <memory>
#include <mutex>

namespace impeller {

/// @brief A thread-safe pool with a limited byte size.
/// @tparam T The type that the pool will contain.
template <typename T>
class Pool {
public:
Pool(uint32_t limit_bytes) : limit_bytes_(limit_bytes), size_(0) {}

std::shared_ptr<T> Grab() {
std::scoped_lock lock(mutex_);
if (pool_.empty()) {
return T::Create();
}
std::shared_ptr<T> result = std::move(pool_.back());
pool_.pop_back();
size_ -= result->GetSize();
return result;
}

void Recycle(std::shared_ptr<T> object) {
gaaclarke marked this conversation as resolved.
Show resolved Hide resolved
std::scoped_lock lock(mutex_);
size_t object_size = object->GetSize();
if (size_ + object_size <= limit_bytes_ &&
object_size < (limit_bytes_ / 2)) {
object->Reset();
size_ += object_size;
pool_.emplace_back(std::move(object));
}
}

uint32_t GetSize() const {
std::scoped_lock lock(mutex_);
return size_;
}

private:
std::vector<std::shared_ptr<T>> pool_;
const uint32_t limit_bytes_;
uint32_t size_;
// Note: This would perform better as a lockless ring buffer.
mutable std::mutex mutex_;
};

} // namespace impeller
63 changes: 63 additions & 0 deletions impeller/renderer/pool_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gtest/gtest.h"

#include "impeller/renderer/pool.h"

namespace impeller {
namespace testing {

namespace {
class Foobar {
public:
static std::shared_ptr<Foobar> Create() { return std::make_shared<Foobar>(); }

size_t GetSize() const { return size_; }

void SetSize(size_t size) { size_ = size; }

void Reset() { is_reset_ = true; }

bool GetIsReset() const { return is_reset_; }

void SetIsReset(bool is_reset) { is_reset_ = is_reset; }

private:
size_t size_;
bool is_reset_ = false;
};
} // namespace

TEST(PoolTest, Simple) {
Pool<Foobar> pool(1'000);
{
auto grabbed = pool.Grab();
grabbed->SetSize(123);
pool.Recycle(grabbed);
EXPECT_EQ(pool.GetSize(), 123u);
}
auto grabbed = pool.Grab();
EXPECT_EQ(grabbed->GetSize(), 123u);
EXPECT_TRUE(grabbed->GetIsReset());
EXPECT_EQ(pool.GetSize(), 0u);
}

TEST(PoolTest, Overload) {
Pool<Foobar> pool(1'000);
{
std::vector<std::shared_ptr<Foobar>> values;
for (int i = 0; i < 20; i++) {
values.push_back(pool.Grab());
}
for (auto value : values) {
value->SetSize(100);
pool.Recycle(value);
}
}
EXPECT_EQ(pool.GetSize(), 1'000u);
}

} // namespace testing
} // namespace impeller
13 changes: 11 additions & 2 deletions impeller/renderer/render_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,18 @@ RenderPass::RenderPass(std::weak_ptr<const Context> context,
const RenderTarget& target)
: context_(std::move(context)),
render_target_(target),
transients_buffer_(HostBuffer::Create()) {}
transients_buffer_() {
auto strong_context = context_.lock();
FML_DCHECK(strong_context);
transients_buffer_ = strong_context->GetHostBufferPool().Grab();
}

RenderPass::~RenderPass() = default;
RenderPass::~RenderPass() {
gaaclarke marked this conversation as resolved.
Show resolved Hide resolved
auto strong_context = context_.lock();
if (strong_context) {
strong_context->GetHostBufferPool().Recycle(transients_buffer_);
}
}

const RenderTarget& RenderPass::GetRenderTarget() const {
return render_target_;
Expand Down