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:
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user