diff --git a/engine/src/flutter/impeller/entity/contents/content_context.cc b/engine/src/flutter/impeller/entity/contents/content_context.cc index ac398a11c5..a727bf186e 100644 --- a/engine/src/flutter/impeller/entity/contents/content_context.cc +++ b/engine/src/flutter/impeller/entity/contents/content_context.cc @@ -269,6 +269,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); texture_pipelines_[default_options_] = CreateDefaultPipeline(*context_); + texture_external_pipelines_[default_options_] = + CreateDefaultPipeline(*context_); position_uv_pipelines_[default_options_] = CreateDefaultPipeline(*context_); tiled_texture_pipelines_[default_options_] = diff --git a/engine/src/flutter/impeller/entity/contents/texture_contents.cc b/engine/src/flutter/impeller/entity/contents/texture_contents.cc index b8ec205517..2d3dd29cc5 100644 --- a/engine/src/flutter/impeller/entity/contents/texture_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/texture_contents.cc @@ -13,6 +13,7 @@ #include "impeller/entity/entity.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" +#include "impeller/entity/texture_fill_external.frag.h" #include "impeller/geometry/constants.h" #include "impeller/geometry/path_builder.h" #include "impeller/renderer/render_pass.h" @@ -109,12 +110,16 @@ bool TextureContents::Render(const ContentContext& renderer, RenderPass& pass) const { using VS = TextureFillVertexShader; using FS = TextureFillFragmentShader; + using FSExternal = TextureFillExternalFragmentShader; if (destination_rect_.size.IsEmpty() || source_rect_.IsEmpty() || texture_ == nullptr || texture_->GetSize().IsEmpty()) { return true; // Nothing to render. } + bool is_external_texture = + texture_->GetTextureDescriptor().type == TextureType::kTextureExternalOES; + // Expand the source rect by half a texel, which aligns sampled texels to the // pixel grid if the source rect is the same size as the destination rect. auto texture_coords = @@ -149,8 +154,7 @@ bool TextureContents::Render(const ContentContext& renderer, } pipeline_options.primitive_type = PrimitiveType::kTriangleStrip; - if (texture_->GetTextureDescriptor().type == - TextureType::kTextureExternalOES) { + if (is_external_texture) { cmd.pipeline = renderer.GetTextureExternalPipeline(pipeline_options); } else { cmd.pipeline = renderer.GetTexturePipeline(pipeline_options); @@ -158,9 +162,17 @@ bool TextureContents::Render(const ContentContext& renderer, cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer)); VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - FS::BindTextureSampler(cmd, texture_, - renderer.GetContext()->GetSamplerLibrary()->GetSampler( - sampler_descriptor_)); + if (is_external_texture) { + FSExternal::BindSAMPLEREXTERNALOESTextureSampler( + cmd, texture_, + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + sampler_descriptor_)); + } else { + FS::BindTextureSampler( + cmd, texture_, + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + sampler_descriptor_)); + } pass.AddCommand(std::move(cmd)); return true; diff --git a/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_gl.cc b/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_gl.cc index 3f3f6f220f..ffdfbe947b 100644 --- a/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_gl.cc +++ b/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_gl.cc @@ -6,6 +6,10 @@ #include #include +#include "flutter/common/graphics/texture.h" +#include "impeller/core/formats.h" +#include "impeller/display_list/dl_image_impeller.h" +#include "impeller/renderer/backend/gles/texture_gles.h" #include "impeller/toolkit/egl/image.h" #include "impeller/toolkit/gles/texture.h" #include "shell/platform/android/ndk_helpers.h" @@ -53,6 +57,7 @@ void HardwareBufferExternalTextureGL::ProcessFrame(PaintContext& context, NDKHelpers::eglGetNativeClientBufferANDROID(latest_hardware_buffer); if (client_buffer == nullptr) { FML_LOG(WARNING) << "eglGetNativeClientBufferAndroid returned null."; + NDKHelpers::AHardwareBuffer_release(latest_hardware_buffer); return; } FML_CHECK(client_buffer != nullptr); @@ -86,4 +91,82 @@ HardwareBufferExternalTextureGL::HardwareBufferExternalTextureGL( HardwareBufferExternalTextureGL::~HardwareBufferExternalTextureGL() {} +HardwareBufferExternalTextureImpellerGL:: + HardwareBufferExternalTextureImpellerGL( + const std::shared_ptr& context, + int64_t id, + const fml::jni::ScopedJavaGlobalRef& + hardware_buffer_texture_entry, + const std::shared_ptr& jni_facade) + : HardwareBufferExternalTexture(id, + hardware_buffer_texture_entry, + jni_facade), + impeller_context_(context) {} + +HardwareBufferExternalTextureImpellerGL:: + ~HardwareBufferExternalTextureImpellerGL() {} + +void HardwareBufferExternalTextureImpellerGL::Detach() { + egl_image_.reset(); +} + +void HardwareBufferExternalTextureImpellerGL::ProcessFrame( + PaintContext& context, + const SkRect& bounds) { + EGLDisplay display = eglGetCurrentDisplay(); + FML_CHECK(display != EGL_NO_DISPLAY); + + if (state_ == AttachmentState::kUninitialized) { + // First processed frame we are attached. + state_ = AttachmentState::kAttached; + } + + AHardwareBuffer* latest_hardware_buffer = GetLatestHardwareBuffer(); + if (latest_hardware_buffer == nullptr) { + FML_LOG(ERROR) << "GetLatestHardwareBuffer returned null."; + return; + } + + EGLClientBuffer client_buffer = + NDKHelpers::eglGetNativeClientBufferANDROID(latest_hardware_buffer); + if (client_buffer == nullptr) { + FML_LOG(ERROR) << "eglGetNativeClientBufferAndroid returned null."; + NDKHelpers::AHardwareBuffer_release(latest_hardware_buffer); + return; + } + + FML_CHECK(client_buffer != nullptr); + egl_image_.reset(impeller::EGLImageKHRWithDisplay{ + eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, + client_buffer, 0), + display}); + FML_CHECK(egl_image_.get().image != EGL_NO_IMAGE_KHR); + + // Create the texture. + impeller::TextureDescriptor desc; + desc.type = impeller::TextureType::kTextureExternalOES; + desc.storage_mode = impeller::StorageMode::kDevicePrivate; + desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt; + desc.size = {static_cast(bounds.width()), + static_cast(bounds.height())}; + desc.mip_count = 1; + auto texture = std::make_shared( + impeller_context_->GetReactor(), desc, + impeller::TextureGLES::IsWrapped::kWrapped); + texture->SetIntent(impeller::TextureIntent::kUploadFromHost); + if (!texture->Bind()) { + FML_LOG(ERROR) << "Could not bind texture."; + NDKHelpers::AHardwareBuffer_release(latest_hardware_buffer); + return; + } + // Associate the hardware buffer image with the texture. + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, + (GLeglImageOES)egl_image_.get().image); + + dl_image_ = impeller::DlImageImpeller::Make(texture); + + // Release the reference acquired by GetLatestHardwareBuffer. + NDKHelpers::AHardwareBuffer_release(latest_hardware_buffer); +} + } // namespace flutter diff --git a/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_gl.h b/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_gl.h index b266c4d6ec..c8e05e0c75 100644 --- a/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_gl.h +++ b/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_gl.h @@ -7,6 +7,9 @@ #include "flutter/shell/platform/android/hardware_buffer_external_texture.h" +#include "flutter/impeller/renderer/backend/gles/context_gles.h" +#include "flutter/impeller/renderer/backend/gles/gles.h" +#include "flutter/impeller/renderer/backend/gles/texture_gles.h" #include "flutter/impeller/toolkit/egl/egl.h" #include "flutter/impeller/toolkit/egl/image.h" #include "flutter/impeller/toolkit/gles/texture.h" @@ -36,6 +39,29 @@ class HardwareBufferExternalTextureGL : public HardwareBufferExternalTexture { FML_DISALLOW_COPY_AND_ASSIGN(HardwareBufferExternalTextureGL); }; +class HardwareBufferExternalTextureImpellerGL + : public HardwareBufferExternalTexture { + public: + HardwareBufferExternalTextureImpellerGL( + const std::shared_ptr& context, + int64_t id, + const fml::jni::ScopedJavaGlobalRef& + hardware_buffer_texture_entry, + const std::shared_ptr& jni_facade); + + ~HardwareBufferExternalTextureImpellerGL() override; + + private: + void ProcessFrame(PaintContext& context, const SkRect& bounds) override; + void Detach() override; + + const std::shared_ptr impeller_context_; + + impeller::UniqueEGLImageKHR egl_image_; + + FML_DISALLOW_COPY_AND_ASSIGN(HardwareBufferExternalTextureImpellerGL); +}; + } // namespace flutter #endif // FLUTTER_SHELL_PLATFORM_ANDROID_HARDWARE_BUFFER_EXTERNAL_TEXTURE_GL_H_ diff --git a/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_vk.cc b/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_vk.cc index c99441b37b..9ba52e43e7 100644 --- a/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_vk.cc +++ b/engine/src/flutter/shell/platform/android/hardware_buffer_external_texture_vk.cc @@ -54,6 +54,9 @@ void HardwareBufferExternalTextureVK::ProcessFrame(PaintContext& context, std::make_shared(impeller_context_, texture_source); dl_image_ = impeller::DlImageImpeller::Make(texture); + + // GetLatestHardwareBuffer keeps a reference on the hardware buffer, drop it. + NDKHelpers::AHardwareBuffer_release(latest_hardware_buffer); } void HardwareBufferExternalTextureVK::Detach() {} diff --git a/engine/src/flutter/shell/platform/android/platform_view_android.cc b/engine/src/flutter/shell/platform/android/platform_view_android.cc index 936761b334..6a1f96dead 100644 --- a/engine/src/flutter/shell/platform/android/platform_view_android.cc +++ b/engine/src/flutter/shell/platform/android/platform_view_android.cc @@ -312,9 +312,18 @@ void PlatformViewAndroid::RegisterImageTexture( int64_t texture_id, const fml::jni::ScopedJavaGlobalRef& image_texture_entry) { if (android_context_->RenderingApi() == AndroidRenderingAPI::kOpenGLES) { - RegisterTexture(std::make_shared( - std::static_pointer_cast(android_context_), - texture_id, image_texture_entry, jni_facade_)); + if (android_context_->GetImpellerContext() != nullptr) { + // Impeller GLES. + RegisterTexture(std::make_shared( + std::static_pointer_cast( + android_context_->GetImpellerContext()), + texture_id, image_texture_entry, jni_facade_)); + } else { + // Legacy GL. + RegisterTexture(std::make_shared( + std::static_pointer_cast(android_context_), + texture_id, image_texture_entry, jni_facade_)); + } } else if (android_context_->RenderingApi() == AndroidRenderingAPI::kVulkan) { RegisterTexture(std::make_shared( std::static_pointer_cast(