Reenable HardwareBuffer backed Android Platform Views on SDK >= 29 (flutter/engine#44790)

- Fix a bug in the SDK < 33 ImageReader construction code path.
- Fix a bug that resulted in references to Images produced by a closed
ImageReader.
- Fix an order of operations bug in ImageReaderPlatformViewRenderTarget
release/finalizer code path.
- Enable HardwareBuffer backed Android Platform Views on SDK >= 29

Manually tested on device rotating and shutting down the app.
This commit is contained in:
John McCutchan
2023-08-17 13:15:25 -07:00
committed by GitHub
parent 177a6128c1
commit 5c518f77f3
5 changed files with 34 additions and 33 deletions

View File

@@ -39,7 +39,8 @@ void HardwareBufferExternalTexture::Paint(PaintContext& context,
flutter::DlCanvas::SrcRectConstraint::kStrict // enforce edges
);
} else {
FML_LOG(WARNING) << "No DlImage available.";
FML_LOG(WARNING)
<< "No DlImage available for HardwareBufferExternalTexture to paint.";
}
}

View File

@@ -322,6 +322,7 @@ public class FlutterRenderer implements TextureRegistry {
@Keep
final class ImageTextureRegistryEntry implements TextureRegistry.ImageTextureEntry {
private static final String TAG = "ImageTextureRegistryEntry";
private final long id;
private boolean released;
private Image image;
@@ -356,8 +357,10 @@ public class FlutterRenderer implements TextureRegistry {
if (toClose != null) {
toClose.close();
}
// Mark that we have a new frame available.
markTextureFrameAvailable(id);
if (image != null) {
// Mark that we have a new frame available.
markTextureFrameAvailable(id);
}
}
@Override

View File

@@ -11,10 +11,9 @@ import android.os.Handler;
import android.view.Surface;
import io.flutter.view.TextureRegistry.ImageTextureEntry;
@TargetApi(26)
@TargetApi(29)
public class ImageReaderPlatformViewRenderTarget implements PlatformViewRenderTarget {
private ImageTextureEntry textureEntry;
private boolean mustRecreateImageReader = false;
private ImageReader reader;
private int bufferWidth = 0;
private int bufferHeight = 0;
@@ -22,20 +21,14 @@ public class ImageReaderPlatformViewRenderTarget implements PlatformViewRenderTa
private void closeReader() {
if (this.reader != null) {
// Push a null image, forcing the texture entry to close any cached images.
textureEntry.pushImage(null);
// Close the reader, which also closes any produced images.
this.reader.close();
this.reader = null;
}
}
private void recreateImageReaderIfNeeded() {
if (!mustRecreateImageReader) {
return;
}
mustRecreateImageReader = false;
closeReader();
this.reader = createImageReader();
}
private final Handler onImageAvailableHandler = new Handler();
private final ImageReader.OnImageAvailableListener onImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
@@ -55,9 +48,12 @@ public class ImageReaderPlatformViewRenderTarget implements PlatformViewRenderTa
// Allow for double buffering.
builder.setMaxImages(3);
// Use PRIVATE image format so that we can support video decoding.
// TODO(johnmccutchan): Should we always use PRIVATE here? It may impact our ability
// to read back texture data. If we don't always want to use it, how do we decide when
// to use it or not? Perhaps PlatformViews can indicate if they may contain DRM'd content.
// TODO(johnmccutchan): Should we always use PRIVATE here? It may impact our
// ability to read back texture data. If we don't always want to use it, how do we
// decide when to use it or not? Perhaps PlatformViews can indicate if they may contain
// DRM'd content.
// I need to investigate how PRIVATE impacts our ability to take screenshots or capture
// the output of Flutter application.
builder.setImageFormat(ImageFormat.PRIVATE);
// Hint that consumed images will only be read by GPU.
builder.setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
@@ -68,13 +64,15 @@ public class ImageReaderPlatformViewRenderTarget implements PlatformViewRenderTa
@TargetApi(29)
protected ImageReader createImageReader29() {
return ImageReader.newInstance(
bufferWidth, bufferHeight, ImageFormat.PRIVATE, 2, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
}
@TargetApi(26)
protected ImageReader createImageReader26() {
return ImageReader.newInstance(bufferWidth, bufferHeight, ImageFormat.PRIVATE, 2);
final ImageReader reader =
ImageReader.newInstance(
bufferWidth,
bufferHeight,
ImageFormat.PRIVATE,
2,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
reader.setOnImageAvailableListener(this.onImageAvailableListener, onImageAvailableHandler);
return reader;
}
protected ImageReader createImageReader() {
@@ -82,15 +80,15 @@ public class ImageReaderPlatformViewRenderTarget implements PlatformViewRenderTa
return createImageReader33();
} else if (Build.VERSION.SDK_INT >= 29) {
return createImageReader29();
} else {
return createImageReader26();
}
throw new UnsupportedOperationException(
"ImageReaderPlatformViewRenderTarget requires API version 29+");
}
public ImageReaderPlatformViewRenderTarget(ImageTextureEntry textureEntry) {
if (Build.VERSION.SDK_INT < 26) {
if (Build.VERSION.SDK_INT < 29) {
throw new UnsupportedOperationException(
"ImageReaderPlatformViewRenderTarget requires API version 26+");
"ImageReaderPlatformViewRenderTarget requires API version 29+");
}
this.textureEntry = textureEntry;
}
@@ -127,9 +125,9 @@ public class ImageReaderPlatformViewRenderTarget implements PlatformViewRenderTa
}
public void release() {
closeReader();
// textureEntry has a finalizer attached.
textureEntry = null;
closeReader();
}
public boolean isReleased() {
@@ -137,7 +135,6 @@ public class ImageReaderPlatformViewRenderTarget implements PlatformViewRenderTa
}
public Surface getSurface() {
recreateImageReaderIfNeeded();
return this.reader.getSurface();
}
}

View File

@@ -968,8 +968,7 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
private static PlatformViewRenderTarget makePlatformViewRenderTarget(
TextureRegistry textureRegistry) {
// TODO(johnmccutchan): Enable ImageReaderPlatformViewRenderTarget for public use.
if (false) {
if (Build.VERSION.SDK_INT >= 29) {
final TextureRegistry.ImageTextureEntry textureEntry = textureRegistry.createImageTexture();
return new ImageReaderPlatformViewRenderTarget(textureEntry);
}

View File

@@ -65,7 +65,8 @@ void SurfaceTextureExternalTexture::Paint(PaintContext& context,
flutter::DlCanvas::SrcRectConstraint::kStrict // enforce edges
);
} else {
FML_LOG(WARNING) << "No DlImage available.";
FML_LOG(WARNING)
<< "No DlImage available for SurfaceTextureExternalTexture to paint.";
}
}