Skip to content

Commit bdeb534

Browse files
Fix high FPS screen flicker of Platform Views when using ImageReaderPlatformViewRenderTarget (flutter#46724)
The root bug (b/300627634) was that we were holding onto HardwareBuffers after the owning Image was closed. This CL refactors the C++ code to properly hold a reference to the Image until it is safe to dispose of. This CL also refactors the Impeller GL and Skia GL code paths to share more code.
1 parent c0fcf94 commit bdeb534

10 files changed

+273
-178
lines changed

shell/platform/android/hardware_buffer_external_texture.cc

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include <android/hardware_buffer_jni.h>
55
#include <android/sensor.h>
6+
7+
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
68
#include "flutter/shell/platform/android/ndk_helpers.h"
79

810
namespace flutter {
@@ -23,6 +25,7 @@ void HardwareBufferExternalTexture::Paint(PaintContext& context,
2325
if (state_ == AttachmentState::kDetached) {
2426
return;
2527
}
28+
Attach(context);
2629
const bool should_process_frame =
2730
(!freeze && new_frame_ready_) || dl_image_ == nullptr;
2831
if (should_process_frame) {
@@ -39,7 +42,7 @@ void HardwareBufferExternalTexture::Paint(PaintContext& context,
3942
flutter::DlCanvas::SrcRectConstraint::kStrict // enforce edges
4043
);
4144
} else {
42-
FML_LOG(WARNING)
45+
FML_LOG(ERROR)
4346
<< "No DlImage available for HardwareBufferExternalTexture to paint.";
4447
}
4548
}
@@ -57,53 +60,56 @@ void HardwareBufferExternalTexture::OnGrContextCreated() {
5760
state_ = AttachmentState::kUninitialized;
5861
}
5962

60-
AHardwareBuffer* HardwareBufferExternalTexture::GetLatestHardwareBuffer() {
63+
// Implementing flutter::ContextListener.
64+
void HardwareBufferExternalTexture::OnGrContextDestroyed() {
65+
if (state_ == AttachmentState::kAttached) {
66+
dl_image_.reset();
67+
Detach();
68+
}
69+
state_ = AttachmentState::kDetached;
70+
}
71+
72+
JavaLocalRef HardwareBufferExternalTexture::AcquireLatestImage() {
6173
JNIEnv* env = fml::jni::AttachCurrentThread();
6274
FML_CHECK(env != nullptr);
6375

6476
// ImageTextureEntry.acquireLatestImage.
6577
JavaLocalRef image_java = jni_facade_->ImageTextureEntryAcquireLatestImage(
6678
JavaLocalRef(image_texture_entry_));
67-
if (image_java.obj() == nullptr) {
68-
return nullptr;
69-
}
79+
return image_java;
80+
}
7081

71-
// Image.getHardwareBuffer.
72-
JavaLocalRef hardware_buffer_java =
73-
jni_facade_->ImageGetHardwareBuffer(image_java);
74-
if (hardware_buffer_java.obj() == nullptr) {
75-
jni_facade_->ImageClose(image_java);
76-
return nullptr;
82+
void HardwareBufferExternalTexture::CloseImage(
83+
const fml::jni::JavaRef<jobject>& image) {
84+
if (image.obj() == nullptr) {
85+
return;
7786
}
87+
jni_facade_->ImageClose(JavaLocalRef(image));
88+
}
7889

79-
// Convert into NDK HardwareBuffer.
80-
AHardwareBuffer* latest_hardware_buffer =
81-
NDKHelpers::AHardwareBuffer_fromHardwareBuffer(
82-
env, hardware_buffer_java.obj());
83-
if (latest_hardware_buffer == nullptr) {
84-
jni_facade_->HardwareBufferClose(hardware_buffer_java);
85-
jni_facade_->ImageClose(image_java);
86-
return nullptr;
90+
void HardwareBufferExternalTexture::CloseHardwareBuffer(
91+
const fml::jni::JavaRef<jobject>& hardware_buffer) {
92+
if (hardware_buffer.obj() == nullptr) {
93+
return;
8794
}
88-
89-
// Keep hardware buffer alive.
90-
NDKHelpers::AHardwareBuffer_acquire(latest_hardware_buffer);
91-
92-
// Now that we have referenced the native hardware buffer, close the Java
93-
// Image and HardwareBuffer objects.
94-
jni_facade_->HardwareBufferClose(hardware_buffer_java);
95-
jni_facade_->ImageClose(image_java);
96-
97-
return latest_hardware_buffer;
95+
jni_facade_->HardwareBufferClose(JavaLocalRef(hardware_buffer));
9896
}
9997

100-
// Implementing flutter::ContextListener.
101-
void HardwareBufferExternalTexture::OnGrContextDestroyed() {
102-
if (state_ == AttachmentState::kAttached) {
103-
dl_image_.reset();
104-
Detach();
98+
JavaLocalRef HardwareBufferExternalTexture::HardwareBufferFor(
99+
const fml::jni::JavaRef<jobject>& image) {
100+
if (image.obj() == nullptr) {
101+
return JavaLocalRef();
105102
}
106-
state_ = AttachmentState::kDetached;
103+
// Image.getHardwareBuffer.
104+
return jni_facade_->ImageGetHardwareBuffer(JavaLocalRef(image));
105+
}
106+
107+
AHardwareBuffer* HardwareBufferExternalTexture::AHardwareBufferFor(
108+
const fml::jni::JavaRef<jobject>& hardware_buffer) {
109+
JNIEnv* env = fml::jni::AttachCurrentThread();
110+
FML_CHECK(env != nullptr);
111+
return NDKHelpers::AHardwareBuffer_fromHardwareBuffer(env,
112+
hardware_buffer.obj());
107113
}
108114

109115
} // namespace flutter

shell/platform/android/hardware_buffer_external_texture.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "flutter/common/graphics/texture.h"
99
#include "flutter/fml/logging.h"
10+
#include "flutter/shell/platform/android/jni/platform_view_android_jni.h"
1011
#include "flutter/shell/platform/android/platform_view_android_jni_impl.h"
1112

1213
#include <android/hardware_buffer.h>
@@ -20,10 +21,11 @@ class HardwareBufferExternalTexture : public flutter::Texture {
2021
public:
2122
explicit HardwareBufferExternalTexture(
2223
int64_t id,
23-
const fml::jni::ScopedJavaGlobalRef<jobject>&
24-
hardware_buffer_texture_entry,
24+
const fml::jni::ScopedJavaGlobalRef<jobject>& image_texture_entry,
2525
const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade);
2626

27+
virtual ~HardwareBufferExternalTexture() = default;
28+
2729
// |flutter::Texture|.
2830
void Paint(PaintContext& context,
2931
const SkRect& bounds,
@@ -43,10 +45,16 @@ class HardwareBufferExternalTexture : public flutter::Texture {
4345
void OnGrContextDestroyed() override;
4446

4547
protected:
46-
virtual void ProcessFrame(PaintContext& context, const SkRect& bounds) = 0;
48+
virtual void Attach(PaintContext& context) = 0;
4749
virtual void Detach() = 0;
50+
virtual void ProcessFrame(PaintContext& context, const SkRect& bounds) = 0;
4851

49-
AHardwareBuffer* GetLatestHardwareBuffer();
52+
JavaLocalRef AcquireLatestImage();
53+
void CloseImage(const fml::jni::JavaRef<jobject>& image);
54+
JavaLocalRef HardwareBufferFor(const fml::jni::JavaRef<jobject>& image);
55+
void CloseHardwareBuffer(const fml::jni::JavaRef<jobject>& hardware_buffer);
56+
AHardwareBuffer* AHardwareBufferFor(
57+
const fml::jni::JavaRef<jobject>& hardware_buffer);
5058

5159
fml::jni::ScopedJavaGlobalRef<jobject> image_texture_entry_;
5260
std::shared_ptr<PlatformViewAndroidJNI> jni_facade_;

0 commit comments

Comments
 (0)