blob: 74bc8195d4d7afdfd10baa2568f686bdb4ece2bc [file] [log] [blame] [edit]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_IMPELLER_TOOLKIT_EGL_CONTEXT_H_
#define FLUTTER_IMPELLER_TOOLKIT_EGL_CONTEXT_H_
#include <functional>
#include "impeller/base/comparable.h"
#include "impeller/base/thread.h"
#include "impeller/toolkit/egl/egl.h"
namespace impeller {
namespace egl {
class Surface;
class Display;
//------------------------------------------------------------------------------
/// @brief An instance of an EGL context.
///
/// An EGL context can only be used on a single thread at a given
/// time. A thread can only have a single context current at any
/// given time.
///
/// Context cannot be created directly. Only a valid instance of an
/// egl::Display can create a context.
///
class Context {
public:
~Context();
//----------------------------------------------------------------------------
/// @brief Determines if a valid context could be created. The context
/// still needs to be made current on the thread for it to be
/// useful.
///
/// @return True if valid, False otherwise.
///
bool IsValid() const;
//----------------------------------------------------------------------------
/// @brief Get the underlying handle to the EGL context.
///
/// @return The handle.
///
const EGLContext& GetHandle() const;
//----------------------------------------------------------------------------
/// @brief Make the context current on the calling thread. It is the
/// caller responsibility to ensure that any context previously
/// current on the thread must be cleared via `ClearCurrent`.
///
/// @important The config used to create the surface must match the config
/// used to create this context instance.
///
/// @param[in] surface The surface to use to make the context current.
///
/// @return If the context could be made current on the callers thread.
///
bool MakeCurrent(const Surface& surface) const;
//----------------------------------------------------------------------------
/// @brief Clear the thread association of this context.
///
/// @return If the thread association could be cleared.
///
bool ClearCurrent() const;
enum class LifecycleEvent {
kDidMakeCurrent,
kWillClearCurrent,
};
using LifecycleListener = std::function<void(LifecycleEvent)>;
//----------------------------------------------------------------------------
/// @brief Add a listener that gets invoked when the context is made and
/// cleared current from the thread. Applications typically use
/// this to manage workers that schedule OpenGL API calls that
/// need to be careful about the context being current when
/// called.
///
/// @param[in] listener The listener
///
/// @return A unique ID for the listener that can used used in
/// `RemoveLifecycleListener` to remove a previously added
/// listener.
///
std::optional<UniqueID> AddLifecycleListener(
const LifecycleListener& listener);
//----------------------------------------------------------------------------
/// @brief Remove a previously added context listener.
///
/// @param[in] id The identifier obtained via a previous call to
/// `AddLifecycleListener`.
///
/// @return True if the listener could be removed.
///
bool RemoveLifecycleListener(UniqueID id);
//----------------------------------------------------------------------------
/// @return True if the context is current and attached to any surface,
/// False otherwise.
///
bool IsCurrent() const;
private:
friend class Display;
EGLDisplay display_ = EGL_NO_DISPLAY;
EGLContext context_ = EGL_NO_CONTEXT;
mutable RWMutex listeners_mutex_;
std::map<UniqueID, LifecycleListener> listeners_ IPLR_GUARDED_BY(
listeners_mutex_);
Context(EGLDisplay display, EGLContext context);
void DispatchLifecyleEvent(LifecycleEvent event) const;
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
};
} // namespace egl
} // namespace impeller
#endif // FLUTTER_IMPELLER_TOOLKIT_EGL_CONTEXT_H_