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 | 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 ProcTableGLES & | GetProcTable () 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... | |
std::optional< GLsync > | GetGLFence (const HandleGLES &handle) const |
HandleGLES | CreateHandle (HandleType type, GLuint external_handle=GL_NONE) |
Create a reactor handle. More... | |
HandleGLES | CreateUntrackedHandle (HandleType type) const |
Create a handle that is not managed by ReactorGLES . More... | |
void | CollectHandle (HandleGLES handle) |
Collect a reactor handle. More... | |
void | SetDebugLabel (const HandleGLES &handle, std::string_view label) |
Set the debug label on a reactor handle. More... | |
bool | CanSetDebugLabels () const |
Whether the device is capable of writing debug labels. More... | |
bool | AddOperation (Operation operation, bool defer=false) |
Adds an operation that the reactor runs on a worker that ensures that an OpenGL context is current. More... | |
bool | RegisterCleanupCallback (const HandleGLES &handle, const fml::closure &callback) |
Register a cleanup callback that will be invokved with the provided user data when the handle is destroyed. More... | |
bool | React () |
Perform a reaction on the current thread if able. More... | |
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 57 of file reactor_gles.h.
using impeller::ReactorGLES::Operation = std::function<void(const ReactorGLES& reactor)> |
Definition at line 214 of file reactor_gles.h.
Definition at line 59 of file reactor_gles.h.
|
explicit |
Create a new reactor. There are expensive and only one per application instance is necessary.
[in] | gl | The proc table for GL access. This is necessary for the reactor to be able to create and collect OpenGL handles. |
Definition at line 73 of file reactor_gles.cc.
References VALIDATION_LOG.
impeller::ReactorGLES::~ReactorGLES | ( | ) |
Destroy a reactor.
Definition at line 83 of file reactor_gles.cc.
bool impeller::ReactorGLES::AddOperation | ( | Operation | operation, |
bool | defer = false |
||
) |
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.
[in] | operation | The operation |
[in] | defer | If false, the reactor attempts to React after adding this operation. |
Definition at line 173 of file reactor_gles.cc.
References React().
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.
[in] | worker | The worker |
Definition at line 103 of file reactor_gles.cc.
bool impeller::ReactorGLES::CanSetDebugLabels | ( | ) | const |
Whether the device is capable of writing debug labels.
This function is useful for short circuiting expensive debug labeling.
Definition at line 99 of file reactor_gles.cc.
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.
[in] | handle | The reactor handle handle |
Definition at line 235 of file reactor_gles.cc.
References impeller::HandleGLES::IsDead().
HandleGLES impeller::ReactorGLES::CreateHandle | ( | HandleType | type, |
GLuint | external_handle = GL_NONE |
||
) |
Create a reactor handle.
This can be called on any thread. Even one that doesn't have an OpenGL context.
[in] | type | The type of handle to create. |
[in] | external_handle | An already created GL handle if one exists. |
Definition at line 214 of file reactor_gles.cc.
References impeller::HandleGLES::DeadHandle(), GetProcTable(), impeller::kUnknown, and type.
HandleGLES impeller::ReactorGLES::CreateUntrackedHandle | ( | HandleType | type | ) | const |
Create a handle that is not managed by ReactorGLES
.
This behaves just like CreateHandle
but it doesn't add the handle to ReactorGLES::handles_ and the creation is executed synchronously, so it must be called from a proper thread. The benefit of this is that it avoid synchronization and hash table lookups when creating/accessing the handle.
type | The type of handle to create. |
Definition at line 203 of file reactor_gles.cc.
References GetProcTable(), and type.
Referenced by impeller::EncodeCommandsInReactor().
std::optional< GLsync > impeller::ReactorGLES::GetGLFence | ( | const HandleGLES & | handle | ) | const |
Definition at line 162 of file reactor_gles.cc.
References impeller::HandleGLES::GetType(), and impeller::kFence.
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.
[in] | handle | The reactor handle. |
std::nullopt
otherwise. Definition at line 151 of file reactor_gles.cc.
References impeller::HandleGLES::GetType(), and impeller::kFence.
Referenced by impeller::EncodeCommandsInReactor(), and impeller::LinkProgram().
const ProcTableGLES & impeller::ReactorGLES::GetProcTable | ( | ) | const |
Get the OpenGL proc. table the reactor uses to manage handles.
Definition at line 122 of file reactor_gles.cc.
References IsValid().
Referenced by CreateHandle(), CreateUntrackedHandle(), impeller::BlitCopyBufferToTextureCommandGLES::Encode(), impeller::BlitCopyTextureToTextureCommandGLES::Encode(), impeller::BlitCopyTextureToBufferCommandGLES::Encode(), impeller::BlitResizeTextureCommandGLES::Encode(), impeller::EncodeCommandsInReactor(), impeller::LinkProgram(), and SetDebugLabel().
bool impeller::ReactorGLES::IsValid | ( | ) | const |
If this is a valid reactor. Invalid reactors must be discarded immediately.
Definition at line 95 of file reactor_gles.cc.
Referenced by GetProcTable().
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.
Definition at line 255 of file reactor_gles.cc.
Referenced by AddOperation().
bool impeller::ReactorGLES::RegisterCleanupCallback | ( | const HandleGLES & | handle, |
const fml::closure & | callback | ||
) |
Register a cleanup callback that will be invokved with the provided user data when the handle is destroyed.
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.
[in] | handle | The handle to attach the cleanup to. |
[in] | callback | The cleanup callback to execute. |
Definition at line 189 of file reactor_gles.cc.
References impeller::HandleGLES::IsDead().
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.
[in] | id | The worker identifier previously returned by AddWorker . |
Definition at line 110 of file reactor_gles.cc.
void impeller::ReactorGLES::SetDebugLabel | ( | const HandleGLES & | handle, |
std::string_view | 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.
[in] | handle | The handle |
[in] | label | The label |
Definition at line 390 of file reactor_gles.cc.
References GetProcTable(), impeller::HandleGLES::GetType(), impeller::HandleGLES::IsDead(), impeller::kFence, and impeller::ToDebugResourceType().