Flutter Impeller
resource_manager_vk.cc
Go to the documentation of this file.
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 
6 
7 #include "flutter/fml/cpu_affinity.h"
8 #include "flutter/fml/thread.h"
9 #include "flutter/fml/trace_event.h"
10 #include "fml/logging.h"
11 
12 namespace impeller {
13 
14 std::shared_ptr<ResourceManagerVK> ResourceManagerVK::Create() {
15  // It will be tempting to refactor this to create the waiter thread in the
16  // static method instead of the constructor. However, that causes the
17  // destructor never to be called, and the thread never terminates!
18  //
19  // See https://github.com/flutter/flutter/issues/134482.
20  return std::shared_ptr<ResourceManagerVK>(new ResourceManagerVK());
21 }
22 
23 ResourceManagerVK::ResourceManagerVK() : waiter_([&]() { Start(); }) {}
24 
26  FML_DCHECK(waiter_.get_id() != std::this_thread::get_id())
27  << "The ResourceManager being destructed on its own spawned thread is a "
28  << "sign that ContextVK was not properly destroyed. A usual fix for this "
29  << "is to ensure that ContextVK is shutdown (i.e. context->Shutdown()) "
30  "before the ResourceManager is destroyed (i.e. at the end of a test).";
31  Terminate();
32  waiter_.join();
33 }
34 
35 void ResourceManagerVK::Start() {
36  // It's possible for Start() to be called when terminating:
37  // { ResourceManagerVK::Create(); }
38  //
39  // ... so no FML_DCHECK here.
40 
41  fml::Thread::SetCurrentThreadName(fml::Thread::ThreadConfig{"IplrVkResMgr"});
42  // While this code calls destructors it doesn't need to be particularly fast
43  // with them, as long as it doesn't interrupt raster thread.
44  fml::RequestAffinity(fml::CpuAffinity::kEfficiency);
45 
46  bool should_exit = false;
47  while (!should_exit) {
48  std::unique_lock lock(reclaimables_mutex_);
49 
50  // Wait until there are reclaimable resource or if the manager should be
51  // torn down.
52  reclaimables_cv_.wait(
53  lock, [&]() { return !reclaimables_.empty() || should_exit_; });
54 
55  // Don't reclaim resources when the lock is being held as this may gate
56  // further reclaimables from being registered.
57  Reclaimables resources_to_collect;
58  std::swap(resources_to_collect, reclaimables_);
59 
60  // We can't read the ivar outside the lock. Read it here instead.
61  should_exit = should_exit_;
62 
63  // We know what to collect. Unlock before doing anything else.
64  lock.unlock();
65 
66  // Claim all resources while tracing.
67  {
68  TRACE_EVENT0("Impeller", "ReclaimResources");
69  resources_to_collect.clear(); // Redundant because of scope but here so
70  // we can add a trace around it.
71  }
72  }
73 }
74 
75 void ResourceManagerVK::Reclaim(std::unique_ptr<ResourceVK> resource) {
76  if (!resource) {
77  return;
78  }
79  {
80  std::scoped_lock lock(reclaimables_mutex_);
81  reclaimables_.emplace_back(std::move(resource));
82  }
83  reclaimables_cv_.notify_one();
84 }
85 
86 void ResourceManagerVK::Terminate() {
87  // The thread should not be terminated more than once.
88  FML_DCHECK(!should_exit_);
89 
90  {
91  std::scoped_lock lock(reclaimables_mutex_);
92  should_exit_ = true;
93  }
94  reclaimables_cv_.notify_one();
95 }
96 
97 } // namespace impeller
A resource manager controls how resources are allocated and reclaimed.
static std::shared_ptr< ResourceManagerVK > Create()
Creates a shared resource manager (a dedicated thread).
void Reclaim(std::unique_ptr< ResourceVK > resource)
Mark a resource as being reclaimable.
~ResourceManagerVK()
Destroys the resource manager.