Flutter Engine
The Flutter Engine
Classes | Public Types | Public Member Functions | List of all members
impeller::ReactorGLES Class Reference

The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about. More...

#include <reactor_gles.h>

Classes

class  Worker
 A delegate implemented by a thread on which an OpenGL context is current. There may be multiple workers for the reactor to perform reactions on. In that case, it is the workers responsibility to ensure that all of them use either the same OpenGL context or multiple OpenGL contexts in the same sharegroup. More...
 

Public Types

using WorkerID = UniqueID
 
using Ref = std::shared_ptr< ReactorGLES >
 
using Operation = std::function< void(const ReactorGLES &reactor)>
 

Public Member Functions

 ReactorGLES (std::unique_ptr< ProcTableGLES > gl)
 Create a new reactor. There are expensive and only one per application instance is necessary. More...
 
 ~ReactorGLES ()
 Destroy a reactor. More...
 
bool IsValid () const
 If this is a valid reactor. Invalid reactors must be discarded immediately. More...
 
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 the other workers in the reactor or in the same sharegroup. More...
 
bool RemoveWorker (WorkerID id)
 Remove a previously added worker from the reactor. If the reactor has no workers, pending added operations will never run. More...
 
const ProcTableGLESGetProcTable () const
 Get the OpenGL proc. table the reactor uses to manage handles. More...
 
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 call within a reaction. That is, within a ReactorGLES::Operation. More...
 
HandleGLES CreateHandle (HandleType type)
 Create a reactor handle. More...
 
void CollectHandle (HandleGLES handle)
 Collect a reactor handle. More...
 
void SetDebugLabel (const HandleGLES &handle, std::string label)
 Set the debug label on a reactor handle. More...
 
bool AddOperation (Operation operation)
 Adds an operation that the reactor runs on a worker that ensures that an OpenGL context is current. More...
 
bool React ()
 Perform a reaction on the current thread if able. More...
 

Detailed Description

The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.

In the other Impeller backends (like Metal and Vulkan), resources can be created, used, and deleted on any thread with relatively few restrictions. However, OpenGL resources can only be created, used, and deleted on a thread on which an OpenGL context (or one in the same sharegroup) is current.

There aren't too many OpenGL contexts to go around and making the caller reason about the timing and threading requirement only when the OpenGL backend is in use is tedious. To work around this tedium, there is an abstraction between the resources and their handles in OpenGL. The reactor is this abstraction.

The reactor is thread-safe and can created, used, and collected on any thread.

Reactor handles HandleGLES can be created, used, and collected on any thread. These handles can be to textures, buffers, etc..

Operations added to the reactor are guaranteed to run on a worker within a finite amount of time unless the reactor itself is torn down or there are no workers. These operations may run on the calling thread immediately if a worker is active on the current thread and can perform reactions. The operations are guaranteed to run with an OpenGL context current and all reactor handles having live OpenGL handle counterparts.

Creating a handle in the reactor doesn't mean an OpenGL handle is created immediately. OpenGL handles become live before the next reaction. Similarly, dropping the last reference to a reactor handle means that the OpenGL handle will be deleted at some point in the near future.

Definition at line 55 of file reactor_gles.h.

Member Typedef Documentation

◆ Operation

Definition at line 194 of file reactor_gles.h.

◆ Ref

using impeller::ReactorGLES::Ref = std::shared_ptr<ReactorGLES>

Definition at line 86 of file reactor_gles.h.

◆ WorkerID

Definition at line 57 of file reactor_gles.h.

Constructor & Destructor Documentation

◆ ReactorGLES()

impeller::ReactorGLES::ReactorGLES ( std::unique_ptr< ProcTableGLES gl)
explicit

Create a new reactor. There are expensive and only one per application instance is necessary.

Parameters
[in]glThe proc table for GL access. This is necessary for the reactor to be able to create and collect OpenGL handles.

Definition at line 15 of file reactor_gles.cc.

16 : proc_table_(std::move(gl)) {
17 if (!proc_table_ || !proc_table_->IsValid()) {
18 VALIDATION_LOG << "Proc table was invalid.";
19 return;
20 }
21 can_set_debug_labels_ = proc_table_->GetDescription()->HasDebugExtension();
22 is_valid_ = true;
23}
gl
Definition: malisc.py:41
#define VALIDATION_LOG
Definition: validation.h:73

◆ ~ReactorGLES()

impeller::ReactorGLES::~ReactorGLES ( )
default

Destroy a reactor.

Member Function Documentation

◆ AddOperation()

bool impeller::ReactorGLES::AddOperation ( Operation  operation)

Adds an operation that the reactor runs on a worker that ensures that an OpenGL context is current.

This operation is not guaranteed to run immediately. It will complete in a finite amount of time on any thread as long as there is a reactor worker and the reactor itself is not being torn down.

Parameters
[in]operationThe operation
Returns
If the operation was successfully queued for completion.

Definition at line 71 of file reactor_gles.cc.

71 {
72 if (!operation) {
73 return false;
74 }
75 {
76 Lock ops_lock(ops_mutex_);
77 ops_.emplace_back(std::move(operation));
78 }
79 // Attempt a reaction if able but it is not an error if this isn't possible.
80 [[maybe_unused]] auto result = React();
81 return true;
82}
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
bool React()
Perform a reaction on the current thread if able.
GAsyncResult * result

◆ AddWorker()

ReactorGLES::WorkerID impeller::ReactorGLES::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 the other workers in the reactor or in the same sharegroup.

Parameters
[in]workerThe worker
Returns
The worker identifier. This identifier can be used to remove the worker from the reactor later.

Definition at line 31 of file reactor_gles.cc.

31 {
32 Lock lock(workers_mutex_);
33 auto id = WorkerID{};
34 workers_[id] = std::move(worker);
35 return id;
36}
const uintptr_t id

◆ CollectHandle()

void impeller::ReactorGLES::CollectHandle ( HandleGLES  handle)

Collect a reactor handle.

        This can be called on any thread. Even one that doesn't have
        an OpenGL context.
Parameters
[in]handleThe reactor handle handle

Definition at line 149 of file reactor_gles.cc.

149 {
150 WriterLock handles_lock(handles_mutex_);
151 if (auto found = handles_.find(handle); found != handles_.end()) {
152 found->second.pending_collection = true;
153 }
154}

◆ CreateHandle()

HandleGLES impeller::ReactorGLES::CreateHandle ( HandleType  type)

Create a reactor handle.

        This can be called on any thread. Even one that doesn't have
        an OpenGL context.
Parameters
[in]typeThe type of handle to create.
Returns
The reactor handle.

Definition at line 133 of file reactor_gles.cc.

133 {
134 if (type == HandleType::kUnknown) {
135 return HandleGLES::DeadHandle();
136 }
137 auto new_handle = HandleGLES::Create(type);
138 if (new_handle.IsDead()) {
139 return HandleGLES::DeadHandle();
140 }
141 WriterLock handles_lock(handles_mutex_);
142 auto gl_handle = CanReactOnCurrentThread()
144 : std::nullopt;
145 handles_[new_handle] = LiveHandle{gl_handle};
146 return new_handle;
147}
GLenum type
const ProcTableGLES & GetProcTable() const
Get the OpenGL proc. table the reactor uses to manage handles.
Definition: reactor_gles.cc:48
static std::optional< GLuint > CreateGLHandle(const ProcTableGLES &gl, HandleType type)
Definition: reactor_gles.cc:84
Definition: ref_ptr.h:256
static HandleGLES DeadHandle()
Definition: handle_gles.h:35

◆ GetGLHandle()

std::optional< GLuint > impeller::ReactorGLES::GetGLHandle ( const HandleGLES handle) const

Returns the OpenGL handle for a reactor handle if one is available. This is typically only safe to call within a reaction. That is, within a ReactorGLES::Operation.

Asking for the OpenGL handle before the reactor has a chance to reactor will return std::nullopt.

This can be called on any thread but is typically useless outside of a reaction since the handle is useless outside of a reactor operation.

Parameters
[in]handleThe reactor handle.
Returns
The OpenGL handle if the reactor has had a chance to react. std::nullopt otherwise.

Definition at line 53 of file reactor_gles.cc.

53 {
54 ReaderLock handles_lock(handles_mutex_);
55 if (auto found = handles_.find(handle); found != handles_.end()) {
56 if (found->second.pending_collection) {
58 << "Attempted to acquire a handle that was pending collection.";
59 return std::nullopt;
60 }
61 if (!found->second.name.has_value()) {
62 VALIDATION_LOG << "Attempt to acquire a handle outside of an operation.";
63 return std::nullopt;
64 }
65 return found->second.name;
66 }
67 VALIDATION_LOG << "Attempted to acquire an invalid GL handle.";
68 return std::nullopt;
69}

◆ GetProcTable()

const ProcTableGLES & impeller::ReactorGLES::GetProcTable ( ) const

Get the OpenGL proc. table the reactor uses to manage handles.

Returns
The proc table.

Definition at line 48 of file reactor_gles.cc.

48 {
50 return *proc_table_;
51}
bool IsValid() const
If this is a valid reactor. Invalid reactors must be discarded immediately.
Definition: reactor_gles.cc:27
#define FML_DCHECK(condition)
Definition: logging.h:103

◆ IsValid()

bool impeller::ReactorGLES::IsValid ( ) const

If this is a valid reactor. Invalid reactors must be discarded immediately.

Returns
If this reactor is valid.

Definition at line 27 of file reactor_gles.cc.

27 {
28 return is_valid_;
29}

◆ React()

bool impeller::ReactorGLES::React ( )

Perform a reaction on the current thread if able.

        It is safe to call this simultaneously from multiple threads
        at the same time.
Returns
If a reaction was performed on the calling thread.

Definition at line 156 of file reactor_gles.cc.

156 {
157 if (!CanReactOnCurrentThread()) {
158 return false;
159 }
160 TRACE_EVENT0("impeller", "ReactorGLES::React");
161 while (HasPendingOperations()) {
162 // Both the raster thread and the IO thread can flush queued operations.
163 // Ensure that execution of the ops is serialized.
164 Lock execution_lock(ops_execution_mutex_);
165
166 if (!ReactOnce()) {
167 return false;
168 }
169 }
170 return true;
171}
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131

◆ RemoveWorker()

bool impeller::ReactorGLES::RemoveWorker ( WorkerID  id)

Remove a previously added worker from the reactor. If the reactor has no workers, pending added operations will never run.

Parameters
[in]idThe worker identifier previously returned by AddWorker.
Returns
If a worker with the given identifer was successfully removed from the reactor.

Definition at line 38 of file reactor_gles.cc.

38 {
39 Lock lock(workers_mutex_);
40 return workers_.erase(worker) == 1;
41}

◆ SetDebugLabel()

void impeller::ReactorGLES::SetDebugLabel ( const HandleGLES handle,
std::string  label 
)

Set the debug label on a reactor handle.

        This call ensures that the OpenGL debug label is propagated to
        even the OpenGL handle hasn't been created at the time the
        caller sets the label.
Parameters
[in]handleThe handle
[in]labelThe label

Definition at line 274 of file reactor_gles.cc.

274 {
275 if (!can_set_debug_labels_) {
276 return;
277 }
278 if (handle.IsDead()) {
279 return;
280 }
281 WriterLock handles_lock(handles_mutex_);
282 if (auto found = handles_.find(handle); found != handles_.end()) {
283 found->second.pending_debug_label = std::move(label);
284 }
285}

The documentation for this class was generated from the following files: