[impeller] OpenGL: Add support for threads and contexts. (flutter/engine#33575)
This commit is contained in:
@@ -103,4 +103,12 @@ struct hash<impeller::UniqueID> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct less<impeller::UniqueID> {
|
||||
constexpr bool operator()(const impeller::UniqueID& lhs,
|
||||
const impeller::UniqueID& rhs) const {
|
||||
return lhs.id < rhs.id;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
@@ -16,6 +16,33 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
class PlaygroundImplGLES::ReactorWorker final : public ReactorGLES::Worker {
|
||||
public:
|
||||
ReactorWorker() = default;
|
||||
|
||||
// |ReactorGLES::Worker|
|
||||
bool CanReactorReactOnCurrentThreadNow(
|
||||
const ReactorGLES& reactor) const override {
|
||||
ReaderLock lock(mutex_);
|
||||
auto found = reactions_allowed_.find(std::this_thread::get_id());
|
||||
if (found == reactions_allowed_.end()) {
|
||||
return false;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
void SetReactionsAllowedOnCurrentThread(bool allowed) {
|
||||
WriterLock lock(mutex_);
|
||||
reactions_allowed_[std::this_thread::get_id()] = allowed;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable RWMutex mutex_;
|
||||
std::map<std::thread::id, bool> reactions_allowed_ IPLR_GUARDED_BY(mutex_);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ReactorWorker);
|
||||
};
|
||||
|
||||
void PlaygroundImplGLES::DestroyWindowHandle(WindowHandle handle) {
|
||||
if (!handle) {
|
||||
return;
|
||||
@@ -24,7 +51,8 @@ void PlaygroundImplGLES::DestroyWindowHandle(WindowHandle handle) {
|
||||
}
|
||||
|
||||
PlaygroundImplGLES::PlaygroundImplGLES()
|
||||
: handle_(nullptr, &DestroyWindowHandle) {
|
||||
: handle_(nullptr, &DestroyWindowHandle),
|
||||
worker_(std::shared_ptr<ReactorWorker>(new ReactorWorker())) {
|
||||
::glfwDefaultWindowHints();
|
||||
|
||||
#if FML_OS_MACOSX
|
||||
@@ -48,6 +76,7 @@ PlaygroundImplGLES::PlaygroundImplGLES()
|
||||
auto window = ::glfwCreateWindow(1, 1, "Test", nullptr, nullptr);
|
||||
|
||||
::glfwMakeContextCurrent(window);
|
||||
worker_->SetReactionsAllowedOnCurrentThread(true);
|
||||
|
||||
handle_.reset(window);
|
||||
}
|
||||
@@ -79,8 +108,19 @@ std::shared_ptr<Context> PlaygroundImplGLES::GetContext() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ContextGLES::Create(std::move(gl),
|
||||
ShaderLibraryMappingsForPlayground());
|
||||
auto context =
|
||||
ContextGLES::Create(std::move(gl), ShaderLibraryMappingsForPlayground());
|
||||
if (!context) {
|
||||
FML_LOG(ERROR) << "Could not create context.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto worker_id = context->AddReactorWorker(worker_);
|
||||
if (!worker_id.has_value()) {
|
||||
FML_LOG(ERROR) << "Could not add reactor worker.";
|
||||
return nullptr;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
// |PlaygroundImpl|
|
||||
|
||||
@@ -16,9 +16,12 @@ class PlaygroundImplGLES final : public PlaygroundImpl {
|
||||
~PlaygroundImplGLES();
|
||||
|
||||
private:
|
||||
class ReactorWorker;
|
||||
|
||||
static void DestroyWindowHandle(WindowHandle handle);
|
||||
using UniqueHandle = std::unique_ptr<void, decltype(&DestroyWindowHandle)>;
|
||||
UniqueHandle handle_;
|
||||
std::shared_ptr<ReactorWorker> worker_;
|
||||
|
||||
// |PlaygroundImpl|
|
||||
std::shared_ptr<Context> GetContext() const override;
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
std::shared_ptr<Context> ContextGLES::Create(
|
||||
std::shared_ptr<ContextGLES> ContextGLES::Create(
|
||||
std::unique_ptr<ProcTableGLES> gl,
|
||||
std::vector<std::shared_ptr<fml::Mapping>> shader_libraries) {
|
||||
return std::shared_ptr<Context>(
|
||||
return std::shared_ptr<ContextGLES>(
|
||||
new ContextGLES(std::move(gl), std::move(shader_libraries)));
|
||||
}
|
||||
|
||||
@@ -70,10 +70,25 @@ ContextGLES::ContextGLES(
|
||||
|
||||
ContextGLES::~ContextGLES() = default;
|
||||
|
||||
const ReactorGLES::Ref ContextGLES::GetReactor() const {
|
||||
const ReactorGLES::Ref& ContextGLES::GetReactor() const {
|
||||
return reactor_;
|
||||
}
|
||||
|
||||
std::optional<ReactorGLES::WorkerID> ContextGLES::AddReactorWorker(
|
||||
std::shared_ptr<ReactorGLES::Worker> worker) {
|
||||
if (!IsValid()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return reactor_->AddWorker(std::move(worker));
|
||||
}
|
||||
|
||||
bool ContextGLES::RemoveReactorWorker(ReactorGLES::WorkerID id) {
|
||||
if (!IsValid()) {
|
||||
return false;
|
||||
}
|
||||
return reactor_->RemoveWorker(id);
|
||||
}
|
||||
|
||||
bool ContextGLES::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
@@ -19,14 +19,19 @@ namespace impeller {
|
||||
class ContextGLES final : public Context,
|
||||
public BackendCast<ContextGLES, Context> {
|
||||
public:
|
||||
static std::shared_ptr<Context> Create(
|
||||
static std::shared_ptr<ContextGLES> Create(
|
||||
std::unique_ptr<ProcTableGLES> gl,
|
||||
std::vector<std::shared_ptr<fml::Mapping>> shader_libraries);
|
||||
|
||||
// |Context|
|
||||
~ContextGLES() override;
|
||||
|
||||
const ReactorGLES::Ref GetReactor() const;
|
||||
const ReactorGLES::Ref& GetReactor() const;
|
||||
|
||||
std::optional<ReactorGLES::WorkerID> AddReactorWorker(
|
||||
std::shared_ptr<ReactorGLES::Worker> worker);
|
||||
|
||||
bool RemoveReactorWorker(ReactorGLES::WorkerID id);
|
||||
|
||||
private:
|
||||
ReactorGLES::Ref reactor_;
|
||||
|
||||
@@ -27,9 +27,11 @@ struct AutoErrorCheck {
|
||||
~AutoErrorCheck() {
|
||||
if (error_fn) {
|
||||
auto error = error_fn();
|
||||
FML_CHECK(error == GL_NO_ERROR)
|
||||
<< "GL Error " << GLErrorToString(error) << "(" << error << ")"
|
||||
<< " encountered on call to " << name;
|
||||
if (error != GL_NO_ERROR) {
|
||||
FML_LOG(ERROR) << "GL Error " << GLErrorToString(error) << "(" << error
|
||||
<< ")"
|
||||
<< " encountered on call to " << name;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,7 +27,20 @@ bool ReactorGLES::IsValid() const {
|
||||
return is_valid_;
|
||||
}
|
||||
|
||||
ReactorGLES::WorkerID ReactorGLES::AddWorker(std::weak_ptr<Worker> worker) {
|
||||
Lock lock(workers_mutex_);
|
||||
auto id = WorkerID{};
|
||||
workers_[id] = std::move(worker);
|
||||
return id;
|
||||
}
|
||||
|
||||
bool ReactorGLES::RemoveWorker(WorkerID worker) {
|
||||
Lock lock(workers_mutex_);
|
||||
return workers_.erase(worker) == 1;
|
||||
}
|
||||
|
||||
bool ReactorGLES::HasPendingOperations() const {
|
||||
Lock ops_lock(ops_mutex_);
|
||||
return !pending_operations_.empty() || !gl_handles_to_collect_.empty();
|
||||
}
|
||||
|
||||
@@ -37,6 +50,7 @@ const ProcTableGLES& ReactorGLES::GetProcTable() const {
|
||||
}
|
||||
|
||||
std::optional<GLuint> ReactorGLES::GetGLHandle(const HandleGLES& handle) const {
|
||||
ReaderLock handles_lock(handles_mutex_);
|
||||
auto found = live_gl_handles_.find(handle);
|
||||
if (found != live_gl_handles_.end()) {
|
||||
return found->second;
|
||||
@@ -48,8 +62,13 @@ bool ReactorGLES::AddOperation(Operation operation) {
|
||||
if (!operation) {
|
||||
return false;
|
||||
}
|
||||
pending_operations_.emplace_back(std::move(operation));
|
||||
return React();
|
||||
{
|
||||
Lock ops_lock(ops_mutex_);
|
||||
pending_operations_.emplace_back(std::move(operation));
|
||||
}
|
||||
// Attempt a reaction if able but it is not an error if this isn't possible.
|
||||
[[maybe_unused]] auto result = React();
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::optional<GLuint> CreateGLHandle(const ProcTableGLES& gl,
|
||||
@@ -109,17 +128,20 @@ HandleGLES ReactorGLES::CreateHandle(HandleType type) {
|
||||
if (new_handle.IsDead()) {
|
||||
return HandleGLES::DeadHandle();
|
||||
}
|
||||
WriterLock handles_lock(handles_mutex_);
|
||||
live_gl_handles_[new_handle] =
|
||||
in_reaction_ ? CreateGLHandle(GetProcTable(), type) : std::nullopt;
|
||||
return new_handle;
|
||||
}
|
||||
|
||||
void ReactorGLES::CollectHandle(HandleGLES handle) {
|
||||
WriterLock handles_lock(handles_mutex_);
|
||||
auto live_handle = live_gl_handles_.find(handle);
|
||||
if (live_handle == live_gl_handles_.end()) {
|
||||
return;
|
||||
}
|
||||
if (live_handle->second.has_value()) {
|
||||
Lock ops_lock(ops_mutex_);
|
||||
gl_handles_to_collect_[live_handle->first] = live_handle->second.value();
|
||||
}
|
||||
live_gl_handles_.erase(live_handle);
|
||||
@@ -127,6 +149,9 @@ void ReactorGLES::CollectHandle(HandleGLES handle) {
|
||||
|
||||
bool ReactorGLES::React() {
|
||||
TRACE_EVENT0("impeller", "ReactorGLES::React");
|
||||
if (!CanReactOnCurrentThread()) {
|
||||
return false;
|
||||
}
|
||||
in_reaction_ = true;
|
||||
fml::ScopedCleanupClosure reset_in_reaction([&]() { in_reaction_ = false; });
|
||||
while (HasPendingOperations()) {
|
||||
@@ -165,7 +190,13 @@ bool ReactorGLES::ReactOnce() {
|
||||
//----------------------------------------------------------------------------
|
||||
/// Collect all the handles for whom there is a GL handle sibling.
|
||||
///
|
||||
for (const auto& handle_to_collect : gl_handles_to_collect_) {
|
||||
decltype(gl_handles_to_collect_) gl_handles_to_collect;
|
||||
{
|
||||
Lock ops_lock(ops_mutex_);
|
||||
std::swap(gl_handles_to_collect_, gl_handles_to_collect);
|
||||
FML_DCHECK(gl_handles_to_collect_.empty());
|
||||
}
|
||||
for (const auto& handle_to_collect : gl_handles_to_collect) {
|
||||
if (!CollectGLHandle(gl, // proc table
|
||||
handle_to_collect.first.type, // handle type
|
||||
handle_to_collect.second // GL handle name
|
||||
@@ -174,26 +205,52 @@ bool ReactorGLES::ReactOnce() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
gl_handles_to_collect_.clear();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Make sure all pending handles have a GL handle sibling.
|
||||
///
|
||||
for (auto& live_handle : live_gl_handles_) {
|
||||
if (live_handle.second.has_value()) {
|
||||
// Already a realized GL handle.
|
||||
continue;
|
||||
{
|
||||
WriterLock handles_lock(handles_mutex_);
|
||||
for (auto& live_handle : live_gl_handles_) {
|
||||
if (live_handle.second.has_value()) {
|
||||
// Already a realized GL handle.
|
||||
continue;
|
||||
}
|
||||
auto gl_handle = CreateGLHandle(gl, live_handle.first.type);
|
||||
if (!gl_handle.has_value()) {
|
||||
VALIDATION_LOG << "Could not create GL handle.";
|
||||
return false;
|
||||
}
|
||||
live_handle.second = gl_handle;
|
||||
}
|
||||
auto gl_handle = CreateGLHandle(gl, live_handle.first.type);
|
||||
if (!gl_handle.has_value()) {
|
||||
VALIDATION_LOG << "Could not create GL handle.";
|
||||
return false;
|
||||
}
|
||||
live_handle.second = gl_handle;
|
||||
}
|
||||
|
||||
if (can_set_debug_labels_) {
|
||||
for (const auto& label : pending_debug_labels_) {
|
||||
//----------------------------------------------------------------------------
|
||||
/// Flush all pending operations in order.
|
||||
///
|
||||
decltype(pending_operations_) pending_operations;
|
||||
{
|
||||
Lock ops_lock(ops_mutex_);
|
||||
std::swap(pending_operations_, pending_operations);
|
||||
FML_DCHECK(pending_operations_.empty());
|
||||
}
|
||||
for (const auto& operation : pending_operations) {
|
||||
TRACE_EVENT0("impeller", "ReactorGLES::Operation");
|
||||
operation(*this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Make sure all pending debug labels have been flushed.
|
||||
///
|
||||
decltype(pending_debug_labels_) pending_debug_labels;
|
||||
{
|
||||
WriterLock handles_lock(handles_mutex_);
|
||||
std::swap(pending_debug_labels_, pending_debug_labels);
|
||||
FML_DCHECK(pending_debug_labels_.empty());
|
||||
}
|
||||
if (!pending_debug_labels.empty()) {
|
||||
ReaderLock handles_lock(handles_mutex_);
|
||||
for (const auto& label : pending_debug_labels) {
|
||||
auto live_handle = live_gl_handles_.find(label.first);
|
||||
if (live_handle == live_gl_handles_.end() ||
|
||||
!live_handle->second.has_value()) {
|
||||
@@ -205,16 +262,6 @@ bool ReactorGLES::ReactOnce() {
|
||||
);
|
||||
}
|
||||
}
|
||||
pending_debug_labels_.clear();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Flush all pending operations in order.
|
||||
///
|
||||
auto operations = std::move(pending_operations_);
|
||||
for (const auto& operation : operations) {
|
||||
operation(*this);
|
||||
}
|
||||
pending_operations_.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -229,18 +276,27 @@ void ReactorGLES::SetDebugLabel(const HandleGLES& handle, std::string label) {
|
||||
if (handle.IsDead()) {
|
||||
return;
|
||||
}
|
||||
if (in_reaction_) {
|
||||
if (auto found = live_gl_handles_.find(handle);
|
||||
found != live_gl_handles_.end() && found->second.has_value()) {
|
||||
GetProcTable().SetDebugLabel(
|
||||
ToDebugResourceType(found->first.type), // type
|
||||
found->second.value(), // name
|
||||
label // label
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
WriterLock handles_lock(handles_mutex_);
|
||||
pending_debug_labels_[handle] = std::move(label);
|
||||
}
|
||||
|
||||
bool ReactorGLES::CanReactOnCurrentThread() const {
|
||||
std::vector<WorkerID> dead_workers;
|
||||
Lock lock(workers_mutex_);
|
||||
for (const auto& worker : workers_) {
|
||||
auto worker_ptr = worker.second.lock();
|
||||
if (!worker_ptr) {
|
||||
dead_workers.push_back(worker.first);
|
||||
continue;
|
||||
}
|
||||
if (worker_ptr->CanReactorReactOnCurrentThreadNow(*this)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto& worker_id : dead_workers) {
|
||||
workers_.erase(worker_id);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace impeller
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "flutter/fml/closure.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/base/thread.h"
|
||||
#include "impeller/renderer/backend/gles/handle_gles.h"
|
||||
#include "impeller/renderer/backend/gles/proc_table_gles.h"
|
||||
|
||||
@@ -17,6 +18,16 @@ namespace impeller {
|
||||
|
||||
class ReactorGLES {
|
||||
public:
|
||||
using WorkerID = UniqueID;
|
||||
|
||||
class Worker {
|
||||
public:
|
||||
virtual ~Worker() = default;
|
||||
|
||||
virtual bool CanReactorReactOnCurrentThreadNow(
|
||||
const ReactorGLES& reactor) const = 0;
|
||||
};
|
||||
|
||||
using Ref = std::shared_ptr<ReactorGLES>;
|
||||
|
||||
ReactorGLES(std::unique_ptr<ProcTableGLES> gl);
|
||||
@@ -25,7 +36,9 @@ class ReactorGLES {
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
bool HasPendingOperations() const;
|
||||
WorkerID AddWorker(std::weak_ptr<Worker> worker);
|
||||
|
||||
bool RemoveWorker(WorkerID);
|
||||
|
||||
const ProcTableGLES& GetProcTable() const;
|
||||
|
||||
@@ -44,10 +57,22 @@ class ReactorGLES {
|
||||
|
||||
private:
|
||||
std::unique_ptr<ProcTableGLES> proc_table_;
|
||||
std::vector<Operation> pending_operations_;
|
||||
GLESHandleMap<std::optional<GLuint>> live_gl_handles_;
|
||||
GLESHandleMap<GLuint> gl_handles_to_collect_;
|
||||
GLESHandleMap<std::string> pending_debug_labels_;
|
||||
|
||||
mutable Mutex ops_mutex_;
|
||||
std::vector<Operation> pending_operations_ IPLR_GUARDED_BY(ops_mutex_);
|
||||
GLESHandleMap<GLuint> gl_handles_to_collect_ IPLR_GUARDED_BY(ops_mutex_);
|
||||
|
||||
mutable RWMutex handles_mutex_;
|
||||
GLESHandleMap<std::optional<GLuint>> live_gl_handles_
|
||||
IPLR_GUARDED_BY(handles_mutex_);
|
||||
GLESHandleMap<std::string> pending_debug_labels_
|
||||
IPLR_GUARDED_BY(handles_mutex_);
|
||||
|
||||
mutable Mutex workers_mutex_;
|
||||
mutable std::map<WorkerID, std::weak_ptr<Worker>> workers_
|
||||
IPLR_GUARDED_BY(workers_mutex_);
|
||||
|
||||
// TODO(csg): Make this thread safe.
|
||||
bool in_reaction_ = false;
|
||||
bool can_set_debug_labels_ = false;
|
||||
|
||||
@@ -55,6 +80,10 @@ class ReactorGLES {
|
||||
|
||||
bool ReactOnce();
|
||||
|
||||
bool HasPendingOperations() const;
|
||||
|
||||
bool CanReactOnCurrentThread() const;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ReactorGLES);
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@ impeller_component("egl") {
|
||||
"surface.h",
|
||||
]
|
||||
|
||||
deps = [ "//flutter/fml" ]
|
||||
deps = [
|
||||
"../../base",
|
||||
"//flutter/fml",
|
||||
]
|
||||
|
||||
libs = []
|
||||
if (is_android) {
|
||||
|
||||
@@ -54,10 +54,12 @@ bool Context::MakeCurrent(const Surface& surface) const {
|
||||
if (!result) {
|
||||
IMPELLER_LOG_EGL_ERROR;
|
||||
}
|
||||
DispatchLifecyleEvent(LifecycleEvent::kDidMakeCurrent);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Context::ClearCurrent() const {
|
||||
DispatchLifecyleEvent(LifecycleEvent::kWillClearCurrent);
|
||||
const auto result = EGLMakeCurrentIfNecessary(display_, //
|
||||
EGL_NO_SURFACE, //
|
||||
EGL_NO_SURFACE, //
|
||||
@@ -69,5 +71,33 @@ bool Context::ClearCurrent() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<UniqueID> Context::AddLifecycleListener(
|
||||
LifecycleListener listener) {
|
||||
if (!listener) {
|
||||
return std::nullopt;
|
||||
}
|
||||
WriterLock lock(listeners_mutex_);
|
||||
UniqueID id;
|
||||
listeners_[id] = listener;
|
||||
return id;
|
||||
}
|
||||
|
||||
bool Context::RemoveLifecycleListener(UniqueID id) {
|
||||
WriterLock lock(listeners_mutex_);
|
||||
auto found = listeners_.find(id);
|
||||
if (found == listeners_.end()) {
|
||||
return false;
|
||||
}
|
||||
listeners_.erase(found);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Context::DispatchLifecyleEvent(LifecycleEvent event) const {
|
||||
ReaderLock lock(listeners_mutex_);
|
||||
for (const auto& listener : listeners_) {
|
||||
listener.second(event);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace egl
|
||||
} // namespace impeller
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/base/comparable.h"
|
||||
#include "impeller/base/thread.h"
|
||||
#include "impeller/toolkit/egl/egl.h"
|
||||
|
||||
namespace impeller {
|
||||
@@ -26,9 +30,23 @@ class Context {
|
||||
|
||||
bool ClearCurrent() const;
|
||||
|
||||
enum class LifecycleEvent {
|
||||
kDidMakeCurrent,
|
||||
kWillClearCurrent,
|
||||
};
|
||||
using LifecycleListener = std::function<void(LifecycleEvent)>;
|
||||
std::optional<UniqueID> AddLifecycleListener(LifecycleListener listener);
|
||||
|
||||
bool RemoveLifecycleListener(UniqueID id);
|
||||
|
||||
private:
|
||||
EGLDisplay display_ = EGL_NO_DISPLAY;
|
||||
EGLContext context_ = EGL_NO_CONTEXT;
|
||||
mutable RWMutex listeners_mutex_;
|
||||
std::map<UniqueID, LifecycleListener> listeners_
|
||||
IPLR_GUARDED_BY(listeners_mutex_);
|
||||
|
||||
void DispatchLifecyleEvent(LifecycleEvent event) const;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Context);
|
||||
};
|
||||
|
||||
@@ -61,6 +61,7 @@ static sk_sp<DlImage> DecompressAndUploadTexture(
|
||||
TRACE_EVENT0("flutter", __FUNCTION__);
|
||||
|
||||
if (!context || !descriptor) {
|
||||
FML_DLOG(ERROR) << "Invalid context or descriptor.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,39 @@
|
||||
|
||||
namespace flutter {
|
||||
|
||||
static std::shared_ptr<impeller::Context> CreateImpellerContext() {
|
||||
class AndroidSurfaceGLImpeller::ReactorWorker final
|
||||
: public impeller::ReactorGLES::Worker {
|
||||
public:
|
||||
ReactorWorker() = default;
|
||||
|
||||
// |impeller::ReactorGLES::Worker|
|
||||
~ReactorWorker() override = default;
|
||||
|
||||
// |impeller::ReactorGLES::Worker|
|
||||
bool CanReactorReactOnCurrentThreadNow(
|
||||
const impeller::ReactorGLES& reactor) const override {
|
||||
impeller::ReaderLock lock(mutex_);
|
||||
auto found = reactions_allowed_.find(std::this_thread::get_id());
|
||||
if (found == reactions_allowed_.end()) {
|
||||
return false;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
void SetReactionsAllowedOnCurrentThread(bool allowed) {
|
||||
impeller::WriterLock lock(mutex_);
|
||||
reactions_allowed_[std::this_thread::get_id()] = allowed;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable impeller::RWMutex mutex_;
|
||||
std::map<std::thread::id, bool> reactions_allowed_ IPLR_GUARDED_BY(mutex_);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ReactorWorker);
|
||||
};
|
||||
|
||||
static std::shared_ptr<impeller::Context> CreateImpellerContext(
|
||||
std::shared_ptr<impeller::ReactorGLES::Worker> worker) {
|
||||
auto proc_table = std::make_unique<impeller::ProcTableGLES>(
|
||||
impeller::egl::CreateProcAddressResolver());
|
||||
|
||||
@@ -35,13 +67,20 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext() {
|
||||
FML_LOG(ERROR) << "Could not create OpenGLES Impeller Context.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!context->AddReactorWorker(std::move(worker)).has_value()) {
|
||||
FML_LOG(ERROR) << "Could not add reactor worker.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
AndroidSurfaceGLImpeller::AndroidSurfaceGLImpeller(
|
||||
const std::shared_ptr<AndroidContext>& android_context,
|
||||
std::shared_ptr<PlatformViewAndroidJNI> jni_facade)
|
||||
: AndroidSurface(android_context) {
|
||||
: AndroidSurface(android_context),
|
||||
reactor_worker_(std::shared_ptr<ReactorWorker>(new ReactorWorker())) {
|
||||
auto display = std::make_unique<impeller::egl::Display>();
|
||||
if (!display->IsValid()) {
|
||||
FML_DLOG(ERROR) << "Could not create EGL display.";
|
||||
@@ -94,7 +133,7 @@ AndroidSurfaceGLImpeller::AndroidSurfaceGLImpeller(
|
||||
return;
|
||||
}
|
||||
|
||||
auto impeller_context = CreateImpellerContext();
|
||||
auto impeller_context = CreateImpellerContext(reactor_worker_);
|
||||
|
||||
if (!impeller_context) {
|
||||
FML_DLOG(ERROR) << "Could not create Impeller context.";
|
||||
@@ -106,6 +145,24 @@ AndroidSurfaceGLImpeller::AndroidSurfaceGLImpeller(
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup context listeners.
|
||||
impeller::egl::Context::LifecycleListener listener =
|
||||
[worker =
|
||||
reactor_worker_](impeller::egl ::Context::LifecycleEvent event) {
|
||||
switch (event) {
|
||||
case impeller::egl::Context::LifecycleEvent::kDidMakeCurrent:
|
||||
worker->SetReactionsAllowedOnCurrentThread(true);
|
||||
break;
|
||||
case impeller::egl::Context::LifecycleEvent::kWillClearCurrent:
|
||||
worker->SetReactionsAllowedOnCurrentThread(false);
|
||||
break;
|
||||
}
|
||||
};
|
||||
if (!onscreen_context->AddLifecycleListener(listener).has_value() ||
|
||||
!offscreen_context->AddLifecycleListener(listener).has_value()) {
|
||||
FML_DLOG(ERROR) << "Could not add lifecycle listeners";
|
||||
}
|
||||
|
||||
display_ = std::move(display);
|
||||
onscreen_config_ = std::move(onscreen_config);
|
||||
offscreen_config_ = std::move(offscreen_config);
|
||||
@@ -182,6 +239,12 @@ std::unique_ptr<Surface> AndroidSurfaceGLImpeller::CreateSnapshotSurface() {
|
||||
FML_UNREACHABLE();
|
||||
}
|
||||
|
||||
// |AndroidSurface|
|
||||
std::shared_ptr<impeller::Context>
|
||||
AndroidSurfaceGLImpeller::GetImpellerContext() {
|
||||
return impeller_context_;
|
||||
}
|
||||
|
||||
// |GPUSurfaceGLDelegate|
|
||||
std::unique_ptr<GLContextResult>
|
||||
AndroidSurfaceGLImpeller::GLContextMakeCurrent() {
|
||||
|
||||
@@ -49,6 +49,9 @@ class AndroidSurfaceGLImpeller final : public GPUSurfaceGLDelegate,
|
||||
// |AndroidSurface|
|
||||
std::unique_ptr<Surface> CreateSnapshotSurface() override;
|
||||
|
||||
// |AndroidSurface|
|
||||
std::shared_ptr<impeller::Context> GetImpellerContext() override;
|
||||
|
||||
// |GPUSurfaceGLDelegate|
|
||||
std::unique_ptr<GLContextResult> GLContextMakeCurrent() override;
|
||||
|
||||
@@ -72,6 +75,9 @@ class AndroidSurfaceGLImpeller final : public GPUSurfaceGLDelegate,
|
||||
sk_sp<const GrGLInterface> GetGLInterface() const override;
|
||||
|
||||
private:
|
||||
class ReactorWorker;
|
||||
|
||||
std::shared_ptr<ReactorWorker> reactor_worker_;
|
||||
std::unique_ptr<impeller::egl::Display> display_;
|
||||
std::unique_ptr<impeller::egl::Config> onscreen_config_;
|
||||
std::unique_ptr<impeller::egl::Config> offscreen_config_;
|
||||
|
||||
@@ -332,6 +332,15 @@ void PlatformViewAndroid::ReleaseResourceContext() const {
|
||||
}
|
||||
}
|
||||
|
||||
// |PlatformView|
|
||||
std::shared_ptr<impeller::Context> PlatformViewAndroid::GetImpellerContext()
|
||||
const {
|
||||
if (android_surface_) {
|
||||
return android_surface_->GetImpellerContext();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// |PlatformView|
|
||||
std::unique_ptr<std::vector<std::string>>
|
||||
PlatformViewAndroid::ComputePlatformResolvedLocales(
|
||||
|
||||
@@ -158,6 +158,9 @@ class PlatformViewAndroid final : public PlatformView {
|
||||
// |PlatformView|
|
||||
void ReleaseResourceContext() const override;
|
||||
|
||||
// |PlatformView|
|
||||
std::shared_ptr<impeller::Context> GetImpellerContext() const override;
|
||||
|
||||
// |PlatformView|
|
||||
std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocales(
|
||||
const std::vector<std::string>& supported_locale_data) override;
|
||||
|
||||
@@ -19,4 +19,8 @@ std::unique_ptr<Surface> AndroidSurface::CreateSnapshotSurface() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<impeller::Context> AndroidSurface::GetImpellerContext() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#include "flutter/shell/platform/android/surface/android_native_window.h"
|
||||
#include "third_party/skia/include/core/SkSize.h"
|
||||
|
||||
namespace impeller {
|
||||
class Context;
|
||||
} // namespace impeller
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class AndroidExternalViewEmbedder;
|
||||
@@ -39,6 +43,8 @@ class AndroidSurface {
|
||||
|
||||
virtual std::unique_ptr<Surface> CreateSnapshotSurface();
|
||||
|
||||
virtual std::shared_ptr<impeller::Context> GetImpellerContext();
|
||||
|
||||
protected:
|
||||
explicit AndroidSurface(
|
||||
const std::shared_ptr<AndroidContext>& android_context);
|
||||
|
||||
Reference in New Issue
Block a user