diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 6139500e68656..9c5a5c473d94c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -555,6 +555,8 @@ FILE: ../../../flutter/shell/platform/embedder/embedder.cc FILE: ../../../flutter/shell/platform/embedder/embedder.h FILE: ../../../flutter/shell/platform/embedder/embedder_engine.cc FILE: ../../../flutter/shell/platform/embedder/embedder_engine.h +FILE: ../../../flutter/shell/platform/embedder/embedder_external_texture_gl.cc +FILE: ../../../flutter/shell/platform/embedder/embedder_external_texture_gl.h FILE: ../../../flutter/shell/platform/embedder/embedder_include.c FILE: ../../../flutter/shell/platform/embedder/embedder_surface.cc FILE: ../../../flutter/shell/platform/embedder/embedder_surface.h diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index 1e4142bab59af..633449795cade 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -18,6 +18,8 @@ source_set("embedder") { "embedder.h", "embedder_engine.cc", "embedder_engine.h", + "embedder_external_texture_gl.cc", + "embedder_external_texture_gl.h", "embedder_include.c", "embedder_surface.cc", "embedder_surface.h", @@ -33,6 +35,7 @@ source_set("embedder") { ":embedder_gpu_configuration", "$flutter_root/assets", "$flutter_root/common", + "$flutter_root/flow", "$flutter_root/fml", "$flutter_root/lib/snapshot", "$flutter_root/shell/common", diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 516f5919d500d..c8c965fdd680b 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -356,13 +356,65 @@ FlutterResult FlutterEngineRun(size_t version, return std::make_unique(shell.GetTaskRunners()); }; + // TODO(chinmaygarde): This is the wrong spot for this. It belongs in the + // platform view jump table. + shell::EmbedderExternalTextureGL::ExternalTextureCallback + external_texture_callback; + if (config->type == kOpenGL) { + const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl; + if (SAFE_ACCESS(open_gl_config, gl_external_texture_frame_callback, + nullptr) != nullptr) { + external_texture_callback = + [ptr = open_gl_config->gl_external_texture_frame_callback, user_data]( + int64_t texture_identifier, GrContext* context, + const SkISize& size) -> sk_sp { + FlutterOpenGLTexture texture = {}; + + if (!ptr(user_data, texture_identifier, size.width(), size.height(), + &texture)) { + return nullptr; + } + + GrGLTextureInfo gr_texture_info = {texture.target, texture.name, + texture.format}; + + GrBackendTexture gr_backend_texture(size.width(), size.height(), + GrMipMapped::kNo, gr_texture_info); + SkImage::TextureReleaseProc release_proc = texture.destruction_callback; + auto image = SkImage::MakeFromTexture( + context, // context + gr_backend_texture, // texture handle + kTopLeft_GrSurfaceOrigin, // origin + kRGBA_8888_SkColorType, // color type + kPremul_SkAlphaType, // alpha type + nullptr, // colorspace + release_proc, // texture release proc + texture.user_data // texture release context + ); + + if (!image) { + // In case Skia rejects the image, call the release proc so that + // embedders can perform collection of intermediates. + if (release_proc) { + release_proc(texture.user_data); + } + FML_LOG(ERROR) << "Could not create external texture."; + return nullptr; + } + + return image; + }; + } + } + // Step 1: Create the engine. auto embedder_engine = - std::make_unique(std::move(thread_host), // - std::move(task_runners), // - settings, // - on_create_platform_view, // - on_create_rasterizer // + std::make_unique(std::move(thread_host), // + std::move(task_runners), // + settings, // + on_create_platform_view, // + on_create_rasterizer, // + external_texture_callback // ); if (!embedder_engine->IsValid()) { @@ -524,3 +576,43 @@ FlutterResult __FlutterEngineFlushPendingTasksNow() { fml::MessageLoop::GetCurrent().RunExpiredTasksNow(); return kSuccess; } + +FlutterResult FlutterEngineRegisterExternalTexture(FlutterEngine engine, + int64_t texture_identifier) { + if (engine == nullptr || texture_identifier == 0) { + return kInvalidArguments; + } + if (!reinterpret_cast(engine)->RegisterTexture( + texture_identifier)) { + return kInternalInconsistency; + } + return kSuccess; +} + +FlutterResult FlutterEngineUnregisterExternalTexture( + FlutterEngine engine, + int64_t texture_identifier) { + if (engine == nullptr || texture_identifier == 0) { + return kInvalidArguments; + } + + if (!reinterpret_cast(engine)->UnregisterTexture( + texture_identifier)) { + return kInternalInconsistency; + } + + return kSuccess; +} + +FlutterResult FlutterEngineMarkExternalTextureFrameAvailable( + FlutterEngine engine, + int64_t texture_identifier) { + if (engine == nullptr || texture_identifier == 0) { + return kInvalidArguments; + } + if (!reinterpret_cast(engine) + ->MarkTextureFrameAvailable(texture_identifier)) { + return kInternalInconsistency; + } + return kSuccess; +} diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index dd1ba06ddcc20..535fb702dc577 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -23,6 +23,7 @@ typedef enum { kSuccess = 0, kInvalidLibraryVersion, kInvalidArguments, + kInternalInconsistency, } FlutterResult; typedef enum { @@ -53,6 +54,22 @@ typedef struct { double pers2; } FlutterTransformation; +typedef void (*VoidCallback)(void* /* user data */); + +typedef struct { + // Target texture of the active texture unit (example GL_TEXTURE_2D). + uint32_t target; + // The name of the texture. + uint32_t name; + // The texture format (example GL_RGBA8). + uint32_t format; + // User data to be returned on the invocation of the destruction callback. + void* user_data; + // Callback invoked (on an engine managed thread) that asks the embedder to + // collect the texture. + VoidCallback destruction_callback; +} FlutterOpenGLTexture; + typedef bool (*BoolCallback)(void* /* user data */); typedef FlutterTransformation (*TransformationCallback)(void* /* user data */); typedef uint32_t (*UIntCallback)(void* /* user data */); @@ -61,6 +78,11 @@ typedef bool (*SoftwareSurfacePresentCallback)(void* /* user data */, size_t /* row bytes */, size_t /* height */); typedef void* (*ProcResolver)(void* /* user data */, const char* /* name */); +typedef bool (*TextureFrameCallback)(void* /* user data */, + int64_t /* texture identifier */, + size_t /* width */, + size_t /* height */, + FlutterOpenGLTexture* /* texture out */); typedef struct { // The size of this struct. Must be sizeof(FlutterOpenGLRendererConfig). @@ -79,6 +101,11 @@ typedef struct { // operations. This callback is optional. TransformationCallback surface_transformation; ProcResolver gl_proc_resolver; + // When the embedder specifies that a texture has a frame available, the + // engine will call this method (on an internal engine managed thread) so that + // external texture details can be suppplied to the engine for subsequent + // composition. + TextureFrameCallback gl_external_texture_frame_callback; } FlutterOpenGLRendererConfig; typedef struct { @@ -220,6 +247,27 @@ FlutterResult FlutterEngineSendPlatformMessageResponse( FLUTTER_EXPORT FlutterResult __FlutterEngineFlushPendingTasksNow(); +// Register an external texture with a unique (per engine) identifier. Only +// rendering backends that support external textures accept external texture +// registrations. After the external texture is registered, the application can +// mark that a frame is available by calling +// |FlutterEngineMarkExternalTextureFrameAvailable|. +FLUTTER_EXPORT +FlutterResult FlutterEngineRegisterExternalTexture(FlutterEngine engine, + int64_t texture_identifier); + +// Unregister a previous texture registration. +FLUTTER_EXPORT +FlutterResult FlutterEngineUnregisterExternalTexture( + FlutterEngine engine, + int64_t texture_identifier); + +// Mark that a new texture frame is available for a given texture identifier. +FLUTTER_EXPORT +FlutterResult FlutterEngineMarkExternalTextureFrameAvailable( + FlutterEngine engine, + int64_t texture_identifier); + #if defined(__cplusplus) } // extern "C" #endif diff --git a/shell/platform/embedder/embedder_engine.cc b/shell/platform/embedder/embedder_engine.cc index ef4078cade8f9..9061bd3e8ae1d 100644 --- a/shell/platform/embedder/embedder_engine.cc +++ b/shell/platform/embedder/embedder_engine.cc @@ -13,12 +13,15 @@ EmbedderEngine::EmbedderEngine( blink::TaskRunners task_runners, blink::Settings settings, Shell::CreateCallback on_create_platform_view, - Shell::CreateCallback on_create_rasterizer) + Shell::CreateCallback on_create_rasterizer, + EmbedderExternalTextureGL::ExternalTextureCallback + external_texture_callback) : thread_host_(std::move(thread_host)), shell_(Shell::Create(std::move(task_runners), std::move(settings), on_create_platform_view, - on_create_rasterizer)) { + on_create_rasterizer)), + external_texture_callback_(external_texture_callback) { is_valid_ = shell_ != nullptr; } @@ -112,4 +115,30 @@ bool EmbedderEngine::SendPlatformMessage( return true; } +bool EmbedderEngine::RegisterTexture(int64_t texture) { + if (!IsValid() || !external_texture_callback_) { + return false; + } + shell_->GetPlatformView()->RegisterTexture( + std::make_unique(texture, + external_texture_callback_)); + return true; +} + +bool EmbedderEngine::UnregisterTexture(int64_t texture) { + if (!IsValid() || !external_texture_callback_) { + return false; + } + shell_->GetPlatformView()->UnregisterTexture(texture); + return true; +} + +bool EmbedderEngine::MarkTextureFrameAvailable(int64_t texture) { + if (!IsValid() || !external_texture_callback_) { + return false; + } + shell_->GetPlatformView()->MarkTextureFrameAvailable(texture); + return true; +} + } // namespace shell diff --git a/shell/platform/embedder/embedder_engine.h b/shell/platform/embedder/embedder_engine.h index 8ccac002754e0..b8110f02a7fef 100644 --- a/shell/platform/embedder/embedder_engine.h +++ b/shell/platform/embedder/embedder_engine.h @@ -11,6 +11,7 @@ #include "flutter/shell/common/shell.h" #include "flutter/shell/common/thread_host.h" #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/embedder/embedder_external_texture_gl.h" namespace shell { @@ -22,7 +23,9 @@ class EmbedderEngine { blink::TaskRunners task_runners, blink::Settings settings, Shell::CreateCallback on_create_platform_view, - Shell::CreateCallback on_create_rasterizer); + Shell::CreateCallback on_create_rasterizer, + EmbedderExternalTextureGL::ExternalTextureCallback + external_texture_callback); ~EmbedderEngine(); @@ -41,9 +44,17 @@ class EmbedderEngine { bool SendPlatformMessage(fml::RefPtr message); + bool RegisterTexture(int64_t texture); + + bool UnregisterTexture(int64_t texture); + + bool MarkTextureFrameAvailable(int64_t texture); + private: const ThreadHost thread_host_; std::unique_ptr shell_; + const EmbedderExternalTextureGL::ExternalTextureCallback + external_texture_callback_; bool is_valid_ = false; FML_DISALLOW_COPY_AND_ASSIGN(EmbedderEngine); diff --git a/shell/platform/embedder/embedder_external_texture_gl.cc b/shell/platform/embedder/embedder_external_texture_gl.cc new file mode 100644 index 0000000000000..d4c863c3766ca --- /dev/null +++ b/shell/platform/embedder/embedder_external_texture_gl.cc @@ -0,0 +1,46 @@ +// 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_external_texture_gl.h" + +#include "flutter/fml/logging.h" + +namespace shell { + +EmbedderExternalTextureGL::EmbedderExternalTextureGL( + int64_t texture_identifier, + ExternalTextureCallback callback) + : Texture(texture_identifier), external_texture_callback_(callback) { + FML_DCHECK(external_texture_callback_); +} + +EmbedderExternalTextureGL::~EmbedderExternalTextureGL() = default; + +// |flow::Texture| +void EmbedderExternalTextureGL::Paint(SkCanvas& canvas, + const SkRect& bounds, + bool freeze) { + if (auto image = external_texture_callback_( + Id(), // + canvas.getGrContext(), // + SkISize::Make(bounds.width(), bounds.height()) // + )) { + last_image_ = image; + } + + if (last_image_) { + canvas.drawImage(last_image_, bounds.x(), bounds.y()); + } +} + +// |flow::Texture| +void EmbedderExternalTextureGL::OnGrContextCreated() {} + +// |flow::Texture| +void EmbedderExternalTextureGL::OnGrContextDestroyed() {} + +// |flow::Texture| +void EmbedderExternalTextureGL::MarkNewFrameAvailable() {} + +} // namespace shell diff --git a/shell/platform/embedder/embedder_external_texture_gl.h b/shell/platform/embedder/embedder_external_texture_gl.h new file mode 100644 index 0000000000000..73017daf195ff --- /dev/null +++ b/shell/platform/embedder/embedder_external_texture_gl.h @@ -0,0 +1,46 @@ +// 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_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_GL_H_ +#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_GL_H_ + +#include "flutter/flow/texture.h" +#include "flutter/fml/macros.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkSize.h" + +namespace shell { + +class EmbedderExternalTextureGL : public flow::Texture { + public: + using ExternalTextureCallback = std::function< + sk_sp(int64_t texture_identifier, GrContext*, const SkISize&)>; + + EmbedderExternalTextureGL(int64_t texture_identifier, + ExternalTextureCallback callback); + + ~EmbedderExternalTextureGL(); + + private: + ExternalTextureCallback external_texture_callback_; + sk_sp last_image_; + + // |flow::Texture| + void Paint(SkCanvas& canvas, const SkRect& bounds, bool freeze) override; + + // |flow::Texture| + void OnGrContextCreated() override; + + // |flow::Texture| + void OnGrContextDestroyed() override; + + // |flow::Texture| + void MarkNewFrameAvailable() override; + + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalTextureGL); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_GL_H_