Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 7 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 @@ -153,6 +153,7 @@
../../../flutter/impeller/renderer/backend/vulkan/blit_command_vk_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/context_vk_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/pass_bindings_cache_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/resource_manager_vk_unittests.cc
../../../flutter/impeller/renderer/backend/vulkan/test
../../../flutter/impeller/renderer/capabilities_unittests.cc
../../../flutter/impeller/renderer/compute_subgroup_unittests.cc
Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/vulkan/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impeller_component("vulkan_unittests") {
"blit_command_vk_unittests.cc",
"context_vk_unittests.cc",
"pass_bindings_cache_unittests.cc",
"resource_manager_vk_unittests.cc",
"test/mock_vulkan.cc",
"test/mock_vulkan.h",
]
Expand Down
4 changes: 2 additions & 2 deletions impeller/renderer/backend/vulkan/allocator_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,8 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
<< vk::to_string(result);
return;
}
resource_.Reset(ImageResource(ImageVMA{allocator, allocation, image},
std::move(image_view)));
resource_.Swap(ImageResource(ImageVMA{allocator, allocation, image},
std::move(image_view)));
is_valid_ = true;
}

Expand Down
16 changes: 13 additions & 3 deletions impeller/renderer/backend/vulkan/resource_manager_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,28 @@

#include "flutter/fml/thread.h"
#include "flutter/fml/trace_event.h"
#include "fml/logging.h"

namespace impeller {

std::shared_ptr<ResourceManagerVK> ResourceManagerVK::Create() {
return std::shared_ptr<ResourceManagerVK>(new ResourceManagerVK());
auto manager = std::shared_ptr<ResourceManagerVK>(new ResourceManagerVK());
manager->waiter_ = std::thread([manager]() { manager->Start(); });
manager->waiter_.detach();
return manager;
}

ResourceManagerVK::ResourceManagerVK() : waiter_([&]() { Main(); }) {}
ResourceManagerVK::ResourceManagerVK() {}

ResourceManagerVK::~ResourceManagerVK() {
Terminate();
waiter_.join();
}

void ResourceManagerVK::Main() {
void ResourceManagerVK::Start() {
// This thread should not be started more than once.
FML_DCHECK(!should_exit_);

fml::Thread::SetCurrentThreadName(
fml::Thread::ThreadConfig{"io.flutter.impeller.resource_manager"});

Expand Down Expand Up @@ -65,6 +72,9 @@ void ResourceManagerVK::Reclaim(std::unique_ptr<ResourceVK> resource) {
}

void ResourceManagerVK::Terminate() {
// The thread should not be terminated more than once.
FML_DCHECK(!should_exit_);

{
std::scoped_lock lock(reclaimables_mutex_);
should_exit_ = true;
Expand Down
106 changes: 80 additions & 26 deletions impeller/renderer/backend/vulkan/resource_manager_vk.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@
#include <memory>
#include <mutex>
#include <thread>
#include <type_traits>
#include <vector>

#include "flutter/fml/macros.h"

namespace impeller {

//------------------------------------------------------------------------------
/// @brief A resource that will be reclaimed by the resource manager. Do
/// not subclass this yourself. Instead, use the `UniqueResourceVKT`
/// template
/// @brief A resource that may be reclaimed by a |ResourceManagerVK|.
///
/// To create a resource, use `UniqueResourceVKT` to create a unique handle:
///
/// auto resource = UniqueResourceVKT<SomeResource>(resource_manager);
///
/// @see |ResourceManagerVK::Reclaim|.
class ResourceVK {
public:
virtual ~ResourceVK() = default;
Expand All @@ -33,66 +35,95 @@ class ResourceVK {
/// thread. In the future, the resource manager may allow resource
/// pooling/reuse, delaying reclamation past frame workloads, etc...
///
class ResourceManagerVK
class ResourceManagerVK final
: public std::enable_shared_from_this<ResourceManagerVK> {
public:
//----------------------------------------------------------------------------
/// @brief Create a shared resource manager. This creates a dedicated
/// thread for resource management. Only one is created per Vulkan
/// context.
/// @brief Creates a shared resource manager (a dedicated thread).
///
/// Upon creation, a thread is spawned which will collect resources as they
/// are reclaimed (passed to `Reclaim`). The thread will exit when the
/// resource manager is destroyed.
///
/// @note Only one |ResourceManagerVK| should be created per Vulkan
/// context, but that contract is not enforced by this method.
///
/// @return A resource manager if one could be created.
///
static std::shared_ptr<ResourceManagerVK> Create();

//----------------------------------------------------------------------------
/// @brief Destroy the resource manager and join all thread. An
/// unreclaimed resources will be destroyed now.
/// @brief Mark a resource as being reclaimable.
///
~ResourceManagerVK();

//----------------------------------------------------------------------------
/// @brief Mark a resource as being reclaimable by giving ownership of
/// the resource to the resource manager.
/// The resource will be reset at some point in the future.
///
/// @param[in] resource The resource to reclaim.
///
/// @note Despite being a public API, this method cannot be invoked
/// directly. Instead, use `UniqueResourceVKT` to create a unique
/// handle to a resource, which will call this method.
void Reclaim(std::unique_ptr<ResourceVK> resource);

//----------------------------------------------------------------------------
/// @brief Terminate the resource manager. Any resources given to the
/// resource manager post termination will be collected when the
/// resource manager is collected.
/// @brief Destroys the resource manager.
///
void Terminate();
/// The resource manager will stop collecting resources and will be destroyed
/// when all references to it are dropped.
~ResourceManagerVK();

private:
ResourceManagerVK();

using Reclaimables = std::vector<std::unique_ptr<ResourceVK>>;

ResourceManagerVK();

std::thread waiter_;
std::mutex reclaimables_mutex_;
std::condition_variable reclaimables_cv_;
Reclaimables reclaimables_;
bool should_exit_ = false;

void Main();
//----------------------------------------------------------------------------
/// @brief Starts the resource manager thread.
///
/// This method is called implicitly by `Create`.
void Start();

//----------------------------------------------------------------------------
/// @brief Terminates the resource manager thread.
///
/// Any resources given to the resource manager post termination will be
/// collected when the resource manager is collected.
void Terminate();

FML_DISALLOW_COPY_AND_ASSIGN(ResourceManagerVK);
};

//------------------------------------------------------------------------------
/// @brief An internal type that is used to move a resource reference.
///
/// Do not use directly, use `UniqueResourceVKT` instead.
///
/// @tparam ResourceType_ The type of the resource.
///
/// @see |UniqueResourceVKT|.
template <class ResourceType_>
class ResourceVKT : public ResourceVK {
public:
using ResourceType = ResourceType_;

/// @brief Construct a resource from a move-constructible resource.
///
/// @param[in] resource The resource to move.
explicit ResourceVKT(ResourceType&& resource)
: resource_(std::move(resource)) {}

/// @brief Returns a pointer to the resource.
const ResourceType* Get() const { return &resource_; }

private:
// Prevents subclassing, use `UniqueResourceVKT`.
ResourceVKT() = default;

ResourceType resource_;

FML_DISALLOW_COPY_AND_ASSIGN(ResourceVKT);
Expand All @@ -105,13 +136,25 @@ class ResourceVKT : public ResourceVK {
/// @tparam ResourceType_ A move-constructible resource type.
///
template <class ResourceType_>
class UniqueResourceVKT {
class UniqueResourceVKT final {
public:
using ResourceType = ResourceType_;

/// @brief Construct a unique resource handle belonging to a manager.
///
/// Initially the handle is empty, and can be populated by calling `Swap`.
///
/// @param[in] resource_manager The resource manager.
explicit UniqueResourceVKT(std::weak_ptr<ResourceManagerVK> resource_manager)
: resource_manager_(std::move(resource_manager)) {}

/// @brief Construct a unique resource handle belonging to a manager.
///
/// Initially the handle is populated with the specified resource, but can
/// be replaced (reclaiming the old resource) by calling `Swap`.
///
/// @param[in] resource_manager The resource manager.
/// @param[in] resource The resource to move.
explicit UniqueResourceVKT(std::weak_ptr<ResourceManagerVK> resource_manager,
ResourceType&& resource)
: resource_manager_(std::move(resource_manager)),
Expand All @@ -120,19 +163,30 @@ class UniqueResourceVKT {

~UniqueResourceVKT() { Reset(); }

const ResourceType* operator->() const { return resource_.get()->Get(); }
/// @brief Returns a pointer to the resource.
const ResourceType* operator->() const {
// If this would segfault, fail with a nicer error message.
FML_CHECK(resource_) << "UniqueResourceVKT was reclaimed.";

return resource_.get()->Get();
}

void Reset(ResourceType&& other) {
/// @brief Reclaims the existing resource, if any, and replaces it.
///
/// @param[in] other The (new) resource to move.
void Swap(ResourceType&& other) {
Reset();
resource_ = std::make_unique<ResourceVKT<ResourceType>>(std::move(other));
}

/// @brief Reclaims the existing resource, if any.
void Reset() {
if (!resource_) {
return;
}
// If there is a manager, ask it to reclaim the resource. If there isn't a
// manager, just drop it on the floor here.
// manager (because the manager has been destroyed), just drop it on the
// floor here.
if (auto manager = resource_manager_.lock()) {
manager->Reclaim(std::move(resource_));
}
Expand Down
23 changes: 23 additions & 0 deletions impeller/renderer/backend/vulkan/resource_manager_vk_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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 <sys/types.h>
#include <memory>
#include "flutter/testing/testing.h"
#include "impeller/renderer/backend/vulkan/resource_manager_vk.h"

namespace impeller {
namespace testing {

// While expected to be a singleton per context, the class does not enforce it.
TEST(ResourceManagerVKTest, CreatesANewInstance) {
auto const a = ResourceManagerVK::Create();
auto const b = ResourceManagerVK::Create();
EXPECT_NE(a, b);
}

// TODO: See what Aaron and Chinmay think can be tested here, and how.

} // namespace testing
} // namespace impeller