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