| Flutter Impeller |

reactor_gles.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
5 #include "impeller/renderer/backend/gles/reactor_gles.h"
6
7 #include <algorithm>
8
9 #include "flutter/fml/trace_event.h"
10 #include "impeller/base/validation.h"
11
12 namespace impeller {
13
14 ReactorGLES::ReactorGLES(std::unique_ptr<ProcTableGLES> gl)
15 : proc_table_(std::move(gl)) {
16 if (!proc_table_ || !proc_table_->IsValid()) {
17 VALIDATION_LOG << "Proc table was invalid.";
18 return;
19 }
20 can_set_debug_labels_ = proc_table_->GetDescription()->HasDebugExtension();
21 is_valid_ = true;
22 }
23
24 ReactorGLES::~ReactorGLES() = default;
25
26 bool ReactorGLES::IsValid() const {
27 return is_valid_;
28 }
29
30 ReactorGLES::WorkerID ReactorGLES::AddWorker(std::weak_ptr<Worker> worker) {
31 Lock lock(workers_mutex_);
32 auto id = WorkerID{};
33 workers_[id] = std::move(worker);
34 return id;
35 }
36
37 bool ReactorGLES::RemoveWorker(WorkerID worker) {
38 Lock lock(workers_mutex_);
39 return workers_.erase(worker) == 1;
40 }
41
42 bool ReactorGLES::HasPendingOperations() const {
43 Lock ops_lock(ops_mutex_);
44 return !ops_.empty();
45 }
46
47 const ProcTableGLES& ReactorGLES::GetProcTable() const {
48 FML_DCHECK(IsValid());
49 return *proc_table_;
50 }
51
52 std::optional<GLuint> ReactorGLES::GetGLHandle(const HandleGLES& handle) const {
53 ReaderLock handles_lock(handles_mutex_);
54 if (auto found = handles_.find(handle); found != handles_.end()) {
55 if (found->second.pending_collection) {
56 VALIDATION_LOG
57 << "Attempted to acquire a handle that was pending collection.";
58 return std::nullopt;
59 }
60 if (!found->second.name.has_value()) {
61 VALIDATION_LOG << "Attempt to acquire a handle outside of an operation.";
62 return std::nullopt;
63 }
64 return found->second.name;
65 }
66 VALIDATION_LOG << "Attempted to acquire an invalid GL handle.";
67 return std::nullopt;
68 }
69
70 bool ReactorGLES::AddOperation(Operation operation) {
71 if (!operation) {
72 return false;
73 }
74 {
75 Lock ops_lock(ops_mutex_);
76 ops_.emplace_back(std::move(operation));
77 }
78 // Attempt a reaction if able but it is not an error if this isn't possible.
79 [[maybe_unused]] auto result = React();
80 return true;
81 }
82
83 static std::optional<GLuint> CreateGLHandle(const ProcTableGLES& gl,
84 HandleType type) {
85 GLuint handle = GL_NONE;
86 switch (type) {
87 case HandleType::kUnknown:
88 return std::nullopt;
89 case HandleType::kTexture:
90 gl.GenTextures(1u, &handle);
91 return handle;
92 case HandleType::kBuffer:
93 gl.GenBuffers(1u, &handle);
94 return handle;
95 case HandleType::kProgram:
96 return gl.CreateProgram();
97 case HandleType::kRenderBuffer:
98 gl.GenRenderbuffers(1u, &handle);
99 return handle;
100 case HandleType::kFrameBuffer:
101 gl.GenFramebuffers(1u, &handle);
102 return handle;
103 }
104 return std::nullopt;
105 }
106
107 static bool CollectGLHandle(const ProcTableGLES& gl,
108 HandleType type,
109 GLuint handle) {
110 switch (type) {
111 case HandleType::kUnknown:
112 return false;
113 case HandleType::kTexture:
114 gl.DeleteTextures(1u, &handle);
115 return true;
116 case HandleType::kBuffer:
117 gl.DeleteBuffers(1u, &handle);
118 return true;
119 case HandleType::kProgram:
120 gl.DeleteProgram(handle);
121 return true;
122 case HandleType::kRenderBuffer:
123 gl.DeleteRenderbuffers(1u, &handle);
124 return true;
125 case HandleType::kFrameBuffer:
126 gl.DeleteFramebuffers(1u, &handle);
127 return true;
128 }
129 return false;
130 }
131
132 HandleGLES ReactorGLES::CreateHandle(HandleType type) {
133 if (type == HandleType::kUnknown) {
134 return HandleGLES::DeadHandle();
135 }
136 auto new_handle = HandleGLES::Create(type);
137 if (new_handle.IsDead()) {
138 return HandleGLES::DeadHandle();
139 }
140 WriterLock handles_lock(handles_mutex_);
141 auto gl_handle = CanReactOnCurrentThread()
142 ? CreateGLHandle(GetProcTable(), type)
143 : std::nullopt;
144 handles_[new_handle] = LiveHandle{gl_handle};
145 return new_handle;
146 }
147
148 void ReactorGLES::CollectHandle(HandleGLES handle) {
149 WriterLock handles_lock(handles_mutex_);
150 if (auto found = handles_.find(handle); found != handles_.end()) {
151 found->second.pending_collection = true;
152 }
153 }
154
155 bool ReactorGLES::React() {
156 if (!CanReactOnCurrentThread()) {
157 return false;
158 }
159 TRACE_EVENT0("impeller", "ReactorGLES::React");
160 while (HasPendingOperations()) {
161 if (!ReactOnce()) {
162 return false;
163 }
164 }
165 return true;
166 }
167
168 static DebugResourceType ToDebugResourceType(HandleType type) {
169 switch (type) {
170 case HandleType::kUnknown:
171 FML_UNREACHABLE();
172 case HandleType::kTexture:
173 return DebugResourceType::kTexture;
174 case HandleType::kBuffer:
175 return DebugResourceType::kBuffer;
176 case HandleType::kProgram:
177 return DebugResourceType::kProgram;
178 case HandleType::kRenderBuffer:
179 return DebugResourceType::kRenderBuffer;
180 case HandleType::kFrameBuffer:
181 return DebugResourceType::kFrameBuffer;
182 }
183 FML_UNREACHABLE();
184 }
185
186 bool ReactorGLES::ReactOnce() {
187 if (!IsValid()) {
188 return false;
189 }
190 TRACE_EVENT0("impeller", __FUNCTION__);
191 return ConsolidateHandles() && FlushOps();
192 }
193
194 bool ReactorGLES::ConsolidateHandles() {
195 TRACE_EVENT0("impeller", __FUNCTION__);
196 const auto& gl = GetProcTable();
197 WriterLock handles_lock(handles_mutex_);
198 std::vector<HandleGLES> handles_to_delete;
199 for (auto& handle : handles_) {
200 // Collect dead handles.
201 if (handle.second.pending_collection) {
202 // This could be false if the handle was created and collected without
203 // use. We still need to get rid of map entry.
204 if (handle.second.name.has_value()) {
205 CollectGLHandle(gl, handle.first.type, handle.second.name.value());
206 }
207 handles_to_delete.push_back(handle.first);
208 continue;
209 }
210 // Create live handles.
211 if (!handle.second.name.has_value()) {
212 auto gl_handle = CreateGLHandle(gl, handle.first.type);
213 if (!gl_handle) {
214 VALIDATION_LOG << "Could not create GL handle.";
215 return false;
216 }
217 handle.second.name = gl_handle;
218 }
219 // Set pending debug labels.
220 if (handle.second.pending_debug_label.has_value()) {
221 if (gl.SetDebugLabel(ToDebugResourceType(handle.first.type),
222 handle.second.name.value(),
223 handle.second.pending_debug_label.value())) {
224 handle.second.pending_debug_label = std::nullopt;
225 }
226 }
227 }
228 for (const auto& handle_to_delete : handles_to_delete) {
229 handles_.erase(handle_to_delete);
230 }
231 return true;
232 }
233
234 bool ReactorGLES::FlushOps() {
235 TRACE_EVENT0("impeller", __FUNCTION__);
236 // Do NOT hold the ops or handles locks while performing operations in case
237 // the ops enqueue more ops.
238 decltype(ops_) ops;
239 {
240 Lock ops_lock(ops_mutex_);
241 std::swap(ops_, ops);
242 }
243 for (const auto& op : ops) {
244 TRACE_EVENT0("impeller", "ReactorGLES::Operation");
245 op(*this);
246 }
247 return true;
248 }
249
250 void ReactorGLES::SetDebugLabel(const HandleGLES& handle, std::string label) {
251 if (!can_set_debug_labels_) {
252 return;
253 }
254 if (handle.IsDead()) {
255 return;
256 }
257 WriterLock handles_lock(handles_mutex_);
258 if (auto found = handles_.find(handle); found != handles_.end()) {
259 found->second.pending_debug_label = std::move(label);
260 }
261 }
262
263 bool ReactorGLES::CanReactOnCurrentThread() const {
264 std::vector<WorkerID> dead_workers;
265 Lock lock(workers_mutex_);
266 for (const auto& worker : workers_) {
267 auto worker_ptr = worker.second.lock();
268 if (!worker_ptr) {
269 dead_workers.push_back(worker.first);
270 continue;
271 }
272 if (worker_ptr->CanReactorReactOnCurrentThreadNow(*this)) {
273 return true;
274 }
275 }
276 for (const auto& worker_id : dead_workers) {
277 workers_.erase(worker_id);
278 }
279 return false;
280 }
281
282 } // namespace impeller
impeller::ReactorGLES::Operation
std::function< void(const ReactorGLES &reactor)> Operation
Definition: reactor_gles.h:53
impeller::ReactorGLES::GetProcTable
const ProcTableGLES & GetProcTable() const
Definition: reactor_gles.cc:47
impeller::HandleGLES::DeadHandle
static HandleGLES DeadHandle()
Definition: handle_gles.h:38
impeller::ReactorGLES::ReactorGLES
ReactorGLES(std::unique_ptr< ProcTableGLES > gl)
Definition: reactor_gles.cc:14
impeller::ReactorGLES::SetDebugLabel
void SetDebugLabel(const HandleGLES &handle, std::string label)
Definition: reactor_gles.cc:250
impeller::HandleType::kRenderBuffer
@ kRenderBuffer
impeller::WriterLock
Definition: thread.h:83
impeller::ReactorGLES::CreateHandle
HandleGLES CreateHandle(HandleType type)
Definition: reactor_gles.cc:132
impeller::HandleType
HandleType
Definition: handle_gles.h:21
impeller::HandleType::kTexture
@ kTexture
impeller::Lock
Definition: thread.h:54
impeller::ToDebugResourceType
static DebugResourceType ToDebugResourceType(HandleType type)
Definition: reactor_gles.cc:168
impeller::DebugResourceType::kBuffer
@ kBuffer
impeller::HandleType::kUnknown
@ kUnknown
impeller::DebugResourceType::kProgram
@ kProgram
impeller::HandleGLES::IsDead
constexpr bool IsDead() const
Definition: handle_gles.h:42
validation.h
impeller::ReactorGLES::React
bool React()
Definition: reactor_gles.cc:155
impeller::DebugResourceType::kTexture
@ kTexture
impeller::ReaderLock
Definition: thread.h:68
impeller::ReactorGLES::~ReactorGLES
~ReactorGLES()
impeller::HandleGLES
Definition: handle_gles.h:34
impeller::ProcTableGLES
Definition: proc_table_gles.h:188
impeller::ReactorGLES::RemoveWorker
bool RemoveWorker(WorkerID)
Definition: reactor_gles.cc:37
impeller::ReactorGLES::IsValid
bool IsValid() const
Definition: reactor_gles.cc:26
impeller::DebugResourceType::kRenderBuffer
@ kRenderBuffer
impeller::HandleType::kProgram
@ kProgram
impeller::CreateGLHandle
static std::optional< GLuint > CreateGLHandle(const ProcTableGLES &gl, HandleType type)
Definition: reactor_gles.cc:83
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::ReactorGLES::CollectHandle
void CollectHandle(HandleGLES handle)
Definition: reactor_gles.cc:148
reactor_gles.h
impeller::DebugResourceType
DebugResourceType
Definition: proc_table_gles.h:179
impeller::ReactorGLES::AddOperation
bool AddOperation(Operation operation)
Definition: reactor_gles.cc:70
impeller::ReactorGLES::AddWorker
WorkerID AddWorker(std::weak_ptr< Worker > worker)
Definition: reactor_gles.cc:30
std
Definition: comparable.h:98
impeller::CollectGLHandle
static bool CollectGLHandle(const ProcTableGLES &gl, HandleType type, GLuint handle)
Definition: reactor_gles.cc:107
impeller::HandleType::kFrameBuffer
@ kFrameBuffer
impeller::DebugResourceType::kFrameBuffer
@ kFrameBuffer
impeller::UniqueID
Definition: comparable.h:19
impeller::HandleType::kBuffer
@ kBuffer
impeller
Definition: aiks_context.cc:10
impeller::ReactorGLES::GetGLHandle
std::optional< GLuint > GetGLHandle(const HandleGLES &handle) const
Definition: reactor_gles.cc:52