Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
reactor_gles.h
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#ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_REACTOR_GLES_H_
6#define FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_REACTOR_GLES_H_
7
8#include <functional>
9#include <memory>
10#include <vector>
11
12#include "flutter/fml/macros.h"
16
17namespace impeller {
18
19//------------------------------------------------------------------------------
20/// @brief The reactor attempts to make thread-safe usage of OpenGL ES
21/// easier to reason about.
22///
23/// In the other Impeller backends (like Metal and Vulkan),
24/// resources can be created, used, and deleted on any thread with
25/// relatively few restrictions. However, OpenGL resources can only
26/// be created, used, and deleted on a thread on which an OpenGL
27/// context (or one in the same sharegroup) is current.
28///
29/// There aren't too many OpenGL contexts to go around and making
30/// the caller reason about the timing and threading requirement
31/// only when the OpenGL backend is in use is tedious. To work
32/// around this tedium, there is an abstraction between the
33/// resources and their handles in OpenGL. The reactor is this
34/// abstraction.
35///
36/// The reactor is thread-safe and can created, used, and collected
37/// on any thread.
38///
39/// Reactor handles `HandleGLES` can be created, used, and collected
40/// on any thread. These handles can be to textures, buffers, etc..
41///
42/// Operations added to the reactor are guaranteed to run on a
43/// worker within a finite amount of time unless the reactor itself
44/// is torn down or there are no workers. These operations may run
45/// on the calling thread immediately if a worker is active on the
46/// current thread and can perform reactions. The operations are
47/// guaranteed to run with an OpenGL context current and all reactor
48/// handles having live OpenGL handle counterparts.
49///
50/// Creating a handle in the reactor doesn't mean an OpenGL handle
51/// is created immediately. OpenGL handles become live before the
52/// next reaction. Similarly, dropping the last reference to a
53/// reactor handle means that the OpenGL handle will be deleted at
54/// some point in the near future.
55///
57 public:
59
60 //----------------------------------------------------------------------------
61 /// @brief A delegate implemented by a thread on which an OpenGL context
62 /// is current. There may be multiple workers for the reactor to
63 /// perform reactions on. In that case, it is the workers
64 /// responsibility to ensure that all of them use either the same
65 /// OpenGL context or multiple OpenGL contexts in the same
66 /// sharegroup.
67 ///
68 class Worker {
69 public:
70 virtual ~Worker() = default;
71
72 //--------------------------------------------------------------------------
73 /// @brief Determines the ability of the worker to service a reaction
74 /// on the current thread. The OpenGL context must be current on
75 /// the thread if the worker says it is able to service a
76 /// reaction.
77 ///
78 /// @param[in] reactor The reactor
79 ///
80 /// @return If the worker is able to service a reaction. The reactor
81 /// assumes the context is already current if true.
82 ///
84 const ReactorGLES& reactor) const = 0;
85 };
86
87 using Ref = std::shared_ptr<ReactorGLES>;
88
89 //----------------------------------------------------------------------------
90 /// @brief Create a new reactor. There are expensive and only one per
91 /// application instance is necessary.
92 ///
93 /// @param[in] gl The proc table for GL access. This is necessary for the
94 /// reactor to be able to create and collect OpenGL handles.
95 ///
96 explicit ReactorGLES(std::unique_ptr<ProcTableGLES> gl);
97
98 //----------------------------------------------------------------------------
99 /// @brief Destroy a reactor.
100 ///
102
103 //----------------------------------------------------------------------------
104 /// @brief If this is a valid reactor. Invalid reactors must be discarded
105 /// immediately.
106 ///
107 /// @return If this reactor is valid.
108 ///
109 bool IsValid() const;
110
111 //----------------------------------------------------------------------------
112 /// @brief Adds a worker to the reactor. Each new worker must ensure that
113 /// the context it manages is the same as the other workers in the
114 /// reactor or in the same sharegroup.
115 ///
116 /// @param[in] worker The worker
117 ///
118 /// @return The worker identifier. This identifier can be used to remove
119 /// the worker from the reactor later.
120 ///
121 WorkerID AddWorker(std::weak_ptr<Worker> worker);
122
123 //----------------------------------------------------------------------------
124 /// @brief Remove a previously added worker from the reactor. If the
125 /// reactor has no workers, pending added operations will never
126 /// run.
127 ///
128 /// @param[in] id The worker identifier previously returned by `AddWorker`.
129 ///
130 /// @return If a worker with the given identifer was successfully removed
131 /// from the reactor.
132 ///
133 bool RemoveWorker(WorkerID id);
134
135 //----------------------------------------------------------------------------
136 /// @brief Get the OpenGL proc. table the reactor uses to manage handles.
137 ///
138 /// @return The proc table.
139 ///
140 const ProcTableGLES& GetProcTable() const;
141
142 //----------------------------------------------------------------------------
143 /// @brief Returns the OpenGL handle for a reactor handle if one is
144 /// available. This is typically only safe to call within a
145 /// reaction. That is, within a `ReactorGLES::Operation`.
146 ///
147 /// Asking for the OpenGL handle before the reactor has a chance
148 /// to reactor will return `std::nullopt`.
149 ///
150 /// This can be called on any thread but is typically useless
151 /// outside of a reaction since the handle is useless outside of a
152 /// reactor operation.
153 ///
154 /// @param[in] handle The reactor handle.
155 ///
156 /// @return The OpenGL handle if the reactor has had a chance to react.
157 /// `std::nullopt` otherwise.
158 ///
159 std::optional<GLuint> GetGLHandle(const HandleGLES& handle) const;
160
161 //----------------------------------------------------------------------------
162 /// @brief Create a reactor handle.
163 ///
164 /// This can be called on any thread. Even one that doesn't have
165 /// an OpenGL context.
166 ///
167 /// @param[in] type The type of handle to create.
168 ///
169 /// @return The reactor handle.
170 ///
172
173 //----------------------------------------------------------------------------
174 /// @brief Collect a reactor handle.
175 ///
176 /// This can be called on any thread. Even one that doesn't have
177 /// an OpenGL context.
178 ///
179 /// @param[in] handle The reactor handle handle
180 ///
181 void CollectHandle(HandleGLES handle);
182
183 //----------------------------------------------------------------------------
184 /// @brief Set the debug label on a reactor handle.
185 ///
186 /// This call ensures that the OpenGL debug label is propagated to
187 /// even the OpenGL handle hasn't been created at the time the
188 /// caller sets the label.
189 ///
190 /// @param[in] handle The handle
191 /// @param[in] label The label
192 ///
193 void SetDebugLabel(const HandleGLES& handle, std::string label);
194
195 using Operation = std::function<void(const ReactorGLES& reactor)>;
196
197 //----------------------------------------------------------------------------
198 /// @brief Adds an operation that the reactor runs on a worker that
199 /// ensures that an OpenGL context is current.
200 ///
201 /// This operation is not guaranteed to run immediately. It will
202 /// complete in a finite amount of time on any thread as long as
203 /// there is a reactor worker and the reactor itself is not being
204 /// torn down.
205 ///
206 /// @param[in] operation The operation
207 ///
208 /// @return If the operation was successfully queued for completion.
209 ///
210 [[nodiscard]] bool AddOperation(Operation operation);
211
212 //----------------------------------------------------------------------------
213 /// @brief Perform a reaction on the current thread if able.
214 ///
215 /// It is safe to call this simultaneously from multiple threads
216 /// at the same time.
217 ///
218 /// @return If a reaction was performed on the calling thread.
219 ///
220 [[nodiscard]] bool React();
221
222 private:
223 struct LiveHandle {
224 std::optional<GLuint> name;
225 std::optional<std::string> pending_debug_label;
226 bool pending_collection = false;
227
228 LiveHandle() = default;
229
230 explicit LiveHandle(std::optional<GLuint> p_name) : name(p_name) {}
231
232 constexpr bool IsLive() const { return name.has_value(); }
233 };
234
235 std::unique_ptr<ProcTableGLES> proc_table_;
236
237 Mutex ops_execution_mutex_;
238 mutable Mutex ops_mutex_;
239 std::vector<Operation> ops_ IPLR_GUARDED_BY(ops_mutex_);
240
241 // Make sure the container is one where erasing items during iteration doesn't
242 // invalidate other iterators.
243 using LiveHandles = std::unordered_map<HandleGLES,
244 LiveHandle,
245 HandleGLES::Hash,
246 HandleGLES::Equal>;
247 mutable RWMutex handles_mutex_;
248 LiveHandles handles_ IPLR_GUARDED_BY(handles_mutex_);
249
250 mutable Mutex workers_mutex_;
251 mutable std::map<WorkerID, std::weak_ptr<Worker>> workers_ IPLR_GUARDED_BY(
252 workers_mutex_);
253
254 bool can_set_debug_labels_ = false;
255 bool is_valid_ = false;
256
257 bool ReactOnce() IPLR_REQUIRES(ops_execution_mutex_);
258
259 bool HasPendingOperations() const;
260
261 bool CanReactOnCurrentThread() const;
262
263 bool ConsolidateHandles();
264
265 bool FlushOps();
266
267 void SetupDebugGroups();
268
269 ReactorGLES(const ReactorGLES&) = delete;
270
271 ReactorGLES& operator=(const ReactorGLES&) = delete;
272};
273
274} // namespace impeller
275
276#endif // FLUTTER_IMPELLER_RENDERER_BACKEND_GLES_REACTOR_GLES_H_
static void operation(T operation, uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint8_t s, uint32_t t)
Definition SkMD5.cpp:144
A delegate implemented by a thread on which an OpenGL context is current. There may be multiple worke...
virtual bool CanReactorReactOnCurrentThreadNow(const ReactorGLES &reactor) const =0
Determines the ability of the worker to service a reaction on the current thread. The OpenGL context ...
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
std::optional< GLuint > GetGLHandle(const HandleGLES &handle) const
Returns the OpenGL handle for a reactor handle if one is available. This is typically only safe to ca...
void CollectHandle(HandleGLES handle)
Collect a reactor handle.
std::function< void(const ReactorGLES &reactor)> Operation
bool React()
Perform a reaction on the current thread if able.
~ReactorGLES()
Destroy a reactor.
const ProcTableGLES & GetProcTable() const
Get the OpenGL proc. table the reactor uses to manage handles.
std::shared_ptr< ReactorGLES > Ref
HandleGLES CreateHandle(HandleType type)
Create a reactor handle.
void SetDebugLabel(const HandleGLES &handle, std::string label)
Set the debug label on a reactor handle.
bool AddOperation(Operation operation)
Adds an operation that the reactor runs on a worker that ensures that an OpenGL context is current.
bool RemoveWorker(WorkerID id)
Remove a previously added worker from the reactor. If the reactor has no workers, pending added opera...
WorkerID AddWorker(std::weak_ptr< Worker > worker)
Adds a worker to the reactor. Each new worker must ensure that the context it manages is the same as ...
bool IsValid() const
If this is a valid reactor. Invalid reactors must be discarded immediately.
#define IPLR_REQUIRES(...)
#define IPLR_GUARDED_BY(x)