Add support for HardwareBuffer backed Android Platform Views under Impeller/GLES (flutter/engine#44617)

- Implement Impeller/GLES code paths.
- A couple of fixes for EXTERNAL_OES textures via bdero@
This commit is contained in:
John McCutchan
2023-08-11 00:41:53 -07:00
committed by GitHub
parent e2129a4e3a
commit bcd2be5d8a
6 changed files with 143 additions and 8 deletions

View File

@@ -269,6 +269,8 @@ ContentContext::ContentContext(std::shared_ptr<Context> context)
CreateDefaultPipeline<BlendPipeline>(*context_);
texture_pipelines_[default_options_] =
CreateDefaultPipeline<TexturePipeline>(*context_);
texture_external_pipelines_[default_options_] =
CreateDefaultPipeline<TextureExternalPipeline>(*context_);
position_uv_pipelines_[default_options_] =
CreateDefaultPipeline<PositionUVPipeline>(*context_);
tiled_texture_pipelines_[default_options_] =

View File

@@ -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;

View File

@@ -6,6 +6,10 @@
#include <android/hardware_buffer_jni.h>
#include <android/sensor.h>
#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<impeller::ContextGLES>& context,
int64_t id,
const fml::jni::ScopedJavaGlobalRef<jobject>&
hardware_buffer_texture_entry,
const std::shared_ptr<PlatformViewAndroidJNI>& 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<int>(bounds.width()),
static_cast<int>(bounds.height())};
desc.mip_count = 1;
auto texture = std::make_shared<impeller::TextureGLES>(
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

View File

@@ -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<impeller::ContextGLES>& context,
int64_t id,
const fml::jni::ScopedJavaGlobalRef<jobject>&
hardware_buffer_texture_entry,
const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade);
~HardwareBufferExternalTextureImpellerGL() override;
private:
void ProcessFrame(PaintContext& context, const SkRect& bounds) override;
void Detach() override;
const std::shared_ptr<impeller::ContextGLES> 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_

View File

@@ -54,6 +54,9 @@ void HardwareBufferExternalTextureVK::ProcessFrame(PaintContext& context,
std::make_shared<impeller::TextureVK>(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() {}

View File

@@ -312,9 +312,18 @@ void PlatformViewAndroid::RegisterImageTexture(
int64_t texture_id,
const fml::jni::ScopedJavaGlobalRef<jobject>& image_texture_entry) {
if (android_context_->RenderingApi() == AndroidRenderingAPI::kOpenGLES) {
RegisterTexture(std::make_shared<HardwareBufferExternalTextureGL>(
std::static_pointer_cast<AndroidContextGLSkia>(android_context_),
texture_id, image_texture_entry, jni_facade_));
if (android_context_->GetImpellerContext() != nullptr) {
// Impeller GLES.
RegisterTexture(std::make_shared<HardwareBufferExternalTextureImpellerGL>(
std::static_pointer_cast<impeller::ContextGLES>(
android_context_->GetImpellerContext()),
texture_id, image_texture_entry, jni_facade_));
} else {
// Legacy GL.
RegisterTexture(std::make_shared<HardwareBufferExternalTextureGL>(
std::static_pointer_cast<AndroidContextGLSkia>(android_context_),
texture_id, image_texture_entry, jni_facade_));
}
} else if (android_context_->RenderingApi() == AndroidRenderingAPI::kVulkan) {
RegisterTexture(std::make_shared<HardwareBufferExternalTextureVK>(
std::static_pointer_cast<impeller::ContextVK>(