mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Impeller] Document ReactorGLES. (flutter/engine#47070)
This commit is contained in:
parent
688a695f2b
commit
34497469a9
@ -15,43 +15,207 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief 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.
|
||||
///
|
||||
class ReactorGLES {
|
||||
public:
|
||||
using WorkerID = UniqueID;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief 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.
|
||||
///
|
||||
class Worker {
|
||||
public:
|
||||
virtual ~Worker() = default;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// @brief Determines the ability of the worker to service a reaction
|
||||
/// on the current thread. The OpenGL context must be current on
|
||||
/// the thread if the worker says it is able to service a
|
||||
/// reaction.
|
||||
///
|
||||
/// @param[in] reactor The reactor
|
||||
///
|
||||
/// @return If the worker is able to service a reaction. The reactor
|
||||
/// assumes the context is already current if true.
|
||||
///
|
||||
virtual bool CanReactorReactOnCurrentThreadNow(
|
||||
const ReactorGLES& reactor) const = 0;
|
||||
};
|
||||
|
||||
using Ref = std::shared_ptr<ReactorGLES>;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Create a new reactor. There are expensive and only one per
|
||||
/// application instance is necessary.
|
||||
///
|
||||
/// @param[in] gl The proc table for GL access. This is necessary for the
|
||||
/// reactor to be able to create and collect OpenGL handles.
|
||||
///
|
||||
explicit ReactorGLES(std::unique_ptr<ProcTableGLES> gl);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Destroy a reactor.
|
||||
///
|
||||
~ReactorGLES();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief If this is a valid reactor. Invalid reactors must be discarded
|
||||
/// immediately.
|
||||
///
|
||||
/// @return If this reactor is valid.
|
||||
///
|
||||
bool IsValid() const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief 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.
|
||||
///
|
||||
/// @param[in] worker The worker
|
||||
///
|
||||
/// @return The worker identifier. This identifier can be used to remove
|
||||
/// the worker from the reactor later.
|
||||
///
|
||||
WorkerID AddWorker(std::weak_ptr<Worker> worker);
|
||||
|
||||
bool RemoveWorker(WorkerID);
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Remove a previously added worker from the reactor. If the
|
||||
/// reactor has no workers, pending added operations will never
|
||||
/// run.
|
||||
///
|
||||
/// @param[in] id The worker identifier previously returned by `AddWorker`.
|
||||
///
|
||||
/// @return If a worker with the given identifer was successfully removed
|
||||
/// from the reactor.
|
||||
///
|
||||
bool RemoveWorker(WorkerID id);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Get the OpenGL proc. table the reactor uses to manage handles.
|
||||
///
|
||||
/// @return The proc table.
|
||||
///
|
||||
const ProcTableGLES& GetProcTable() const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief 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.
|
||||
///
|
||||
/// @param[in] handle The reactor handle.
|
||||
///
|
||||
/// @return The OpenGL handle if the reactor has had a chance to react.
|
||||
/// `std::nullopt` otherwise.
|
||||
///
|
||||
std::optional<GLuint> GetGLHandle(const HandleGLES& handle) const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Create a reactor handle.
|
||||
///
|
||||
/// This can be called on any thread. Even one that doesn't have
|
||||
/// an OpenGL context.
|
||||
///
|
||||
/// @param[in] type The type of handle to create.
|
||||
///
|
||||
/// @return The reactor handle.
|
||||
///
|
||||
HandleGLES CreateHandle(HandleType type);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Collect a reactor handle.
|
||||
///
|
||||
/// This can be called on any thread. Even one that doesn't have
|
||||
/// an OpenGL context.
|
||||
///
|
||||
/// @param[in] handle The reactor handle handle
|
||||
///
|
||||
void CollectHandle(HandleGLES handle);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief 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.
|
||||
///
|
||||
/// @param[in] handle The handle
|
||||
/// @param[in] label The label
|
||||
///
|
||||
void SetDebugLabel(const HandleGLES& handle, std::string label);
|
||||
|
||||
using Operation = std::function<void(const ReactorGLES& reactor)>;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief 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.
|
||||
///
|
||||
/// @param[in] operation The operation
|
||||
///
|
||||
/// @return If the operation was successfully queued for completion.
|
||||
///
|
||||
[[nodiscard]] bool AddOperation(Operation operation);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Perform a reaction on the current thread if able.
|
||||
///
|
||||
/// It is safe to call this simultaneously from multiple threads
|
||||
/// at the same time.
|
||||
///
|
||||
/// @return If a reaction was performed on the calling thread.
|
||||
///
|
||||
[[nodiscard]] bool React();
|
||||
|
||||
private:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user