blob: c7efa86de8168d07bbde57558df48ac980a56dab [file] [log] [blame]
// 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.
#include "flutter/shell/platform/embedder/embedder_surface_gl_impeller.h"
#include <utility>
#include "impeller/entity/gles/entity_shaders_gles.h"
#include "impeller/entity/gles/framebuffer_blend_shaders_gles.h"
#include "impeller/entity/gles/modern_shaders_gles.h"
#include "impeller/renderer/backend/gles/context_gles.h"
#include "impeller/renderer/backend/gles/proc_table_gles.h"
#if IMPELLER_ENABLE_3D
#include "impeller/scene/shaders/gles/scene_shaders_gles.h" // nogncheck
#endif // IMPELLER_ENABLE_3D
namespace flutter {
class ReactorWorker final : public impeller::ReactorGLES::Worker {
public:
ReactorWorker() = default;
// |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);
};
EmbedderSurfaceGLImpeller::EmbedderSurfaceGLImpeller(
EmbedderSurfaceGL::GLDispatchTable gl_dispatch_table,
bool fbo_reset_after_present,
std::shared_ptr<EmbedderExternalViewEmbedder> external_view_embedder)
: gl_dispatch_table_(std::move(gl_dispatch_table)),
fbo_reset_after_present_(fbo_reset_after_present),
external_view_embedder_(std::move(external_view_embedder)),
worker_(std::make_shared<ReactorWorker>()) {
// Make sure all required members of the dispatch table are checked.
if (!gl_dispatch_table_.gl_make_current_callback ||
!gl_dispatch_table_.gl_clear_current_callback ||
!gl_dispatch_table_.gl_present_callback ||
!gl_dispatch_table_.gl_fbo_callback ||
!gl_dispatch_table_.gl_populate_existing_damage ||
!gl_dispatch_table_.gl_proc_resolver) {
return;
}
// Certain GL backends need to made current before any GL
// state can be accessed.
gl_dispatch_table_.gl_make_current_callback();
std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
std::make_shared<fml::NonOwnedMapping>(
impeller_entity_shaders_gles_data,
impeller_entity_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_modern_shaders_gles_data,
impeller_modern_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_framebuffer_blend_shaders_gles_data,
impeller_framebuffer_blend_shaders_gles_length),
#if IMPELLER_ENABLE_3D
std::make_shared<fml::NonOwnedMapping>(
impeller_scene_shaders_gles_data, impeller_scene_shaders_gles_length),
#endif // IMPELLER_ENABLE_3D
};
auto gl = std::make_unique<impeller::ProcTableGLES>(
gl_dispatch_table_.gl_proc_resolver);
if (!gl->IsValid()) {
return;
}
impeller_context_ = impeller::ContextGLES::Create(
std::move(gl), shader_mappings, /*enable_gpu_tracing=*/false);
if (!impeller_context_) {
FML_LOG(ERROR) << "Could not create Impeller context.";
return;
}
auto worker_id = impeller_context_->AddReactorWorker(worker_);
if (!worker_id.has_value()) {
FML_LOG(ERROR) << "Could not add reactor worker.";
return;
}
gl_dispatch_table_.gl_clear_current_callback();
FML_LOG(IMPORTANT) << "Using the Impeller rendering backend (OpenGL).";
valid_ = true;
}
EmbedderSurfaceGLImpeller::~EmbedderSurfaceGLImpeller() = default;
// |EmbedderSurface|
bool EmbedderSurfaceGLImpeller::IsValid() const {
return valid_;
}
// |GPUSurfaceGLDelegate|
std::unique_ptr<GLContextResult>
EmbedderSurfaceGLImpeller::GLContextMakeCurrent() {
worker_->SetReactionsAllowedOnCurrentThread(true);
return std::make_unique<GLContextDefaultResult>(
gl_dispatch_table_.gl_make_current_callback());
}
// |GPUSurfaceGLDelegate|
bool EmbedderSurfaceGLImpeller::GLContextClearCurrent() {
worker_->SetReactionsAllowedOnCurrentThread(false);
return gl_dispatch_table_.gl_clear_current_callback();
}
// |GPUSurfaceGLDelegate|
bool EmbedderSurfaceGLImpeller::GLContextPresent(
const GLPresentInfo& present_info) {
// Pass the present information to the embedder present callback.
return gl_dispatch_table_.gl_present_callback(present_info);
}
// |GPUSurfaceGLDelegate|
GLFBOInfo EmbedderSurfaceGLImpeller::GLContextFBO(
GLFrameInfo frame_info) const {
// Get the FBO ID using the gl_fbo_callback and then get exiting damage by
// passing that ID to the gl_populate_existing_damage.
return gl_dispatch_table_.gl_populate_existing_damage(
gl_dispatch_table_.gl_fbo_callback(frame_info));
}
// |GPUSurfaceGLDelegate|
bool EmbedderSurfaceGLImpeller::GLContextFBOResetAfterPresent() const {
return fbo_reset_after_present_;
}
// |GPUSurfaceGLDelegate|
SkMatrix EmbedderSurfaceGLImpeller::GLContextSurfaceTransformation() const {
auto callback = gl_dispatch_table_.gl_surface_transformation_callback;
if (!callback) {
SkMatrix matrix;
matrix.setIdentity();
return matrix;
}
return callback();
}
// |GPUSurfaceGLDelegate|
EmbedderSurfaceGL::GLProcResolver EmbedderSurfaceGLImpeller::GetGLProcResolver()
const {
return gl_dispatch_table_.gl_proc_resolver;
}
// |GPUSurfaceGLDelegate|
SurfaceFrame::FramebufferInfo
EmbedderSurfaceGLImpeller::GLContextFramebufferInfo() const {
// Enable partial repaint by default on the embedders.
auto info = SurfaceFrame::FramebufferInfo{};
info.supports_readback = true;
info.supports_partial_repaint =
gl_dispatch_table_.gl_populate_existing_damage != nullptr;
return info;
}
// |EmbedderSurface|
std::unique_ptr<Surface> EmbedderSurfaceGLImpeller::CreateGPUSurface() {
// Ensure that the GL context is current before creating the GPU surface.
// GPUSurfaceGLImpeller initialization will set up shader pipelines, and the
// current thread needs to be able to execute reactor operations.
GLContextMakeCurrent();
return std::make_unique<GPUSurfaceGLImpeller>(
this, // GPU surface GL delegate
impeller_context_, // Impeller context
!external_view_embedder_ // render to surface
);
}
// |EmbedderSurface|
std::shared_ptr<impeller::Context>
EmbedderSurfaceGLImpeller::CreateImpellerContext() const {
return impeller_context_;
}
// |EmbedderSurface|
sk_sp<GrDirectContext> EmbedderSurfaceGLImpeller::CreateResourceContext()
const {
if (gl_dispatch_table_.gl_make_resource_current_callback()) {
worker_->SetReactionsAllowedOnCurrentThread(true);
} else {
FML_DLOG(ERROR) << "Could not make the resource context current.";
worker_->SetReactionsAllowedOnCurrentThread(false);
}
return nullptr;
}
} // namespace flutter