-
Notifications
You must be signed in to change notification settings - Fork 6k
Reenable HardwareBuffer backed Android Platform Views on SDK >= 29 #44790
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,31 +11,24 @@ | |
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; | ||
private static final String TAG = "ImageReaderPlatformViewRenderTarget"; | ||
|
||
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 @@ protected ImageReader createImageReader33() { | |
// 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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: formatting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed added more context to the TODO. |
||
// 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,29 +64,31 @@ protected ImageReader createImageReader33() { | |
|
||
@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() { | ||
if (Build.VERSION.SDK_INT >= 33) { | ||
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,17 +125,16 @@ public long getId() { | |
} | ||
|
||
public void release() { | ||
closeReader(); | ||
// textureEntry has a finalizer attached. | ||
textureEntry = null; | ||
closeReader(); | ||
} | ||
|
||
public boolean isReleased() { | ||
return this.textureEntry == null; | ||
} | ||
|
||
public Surface getSurface() { | ||
recreateImageReaderIfNeeded(); | ||
return this.reader.getSurface(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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."; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto on log message. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the developer action to take here?
If there is none, maybe this should be a DLOG/DCHECK?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is useful information for debugging the engine and I'd like to keep it in place for now until this code is more solid.