Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ final class SurfaceTextureRegistryEntry
textureWrapper.markDirty();
scheduleEngineFrame();
};
// The callback relies on being executed on the UI thread (unsynchronised read of
// The callback relies on being executed on the UI thread (un-synchronised read of
// mNativeView and also the engine code check for platform thread in
// Shell::OnPlatformViewMarkTextureFrameAvailable), so we explicitly pass a Handler for the
// current thread.
Expand Down Expand Up @@ -449,7 +449,7 @@ final class ImageReaderSurfaceProducer
// Will be true in tests and on Android API < 33.
private boolean ignoringFence = false;

private boolean trimOnMemoryPressure = CLEANUP_ON_MEMORY_PRESSURE;
private static final boolean trimOnMemoryPressure = CLEANUP_ON_MEMORY_PRESSURE;

// The requested width and height are updated by setSize.
private int requestedWidth = 1;
Expand All @@ -466,11 +466,10 @@ final class ImageReaderSurfaceProducer
private long lastScheduleTime = 0;
private int numTrims = 0;

private Object lock = new Object();
private final Object lock = new Object();
// REQUIRED: The following fields must only be accessed when lock is held.
private final ArrayDeque<PerImageReader> imageReaderQueue = new ArrayDeque<PerImageReader>();
private final HashMap<ImageReader, PerImageReader> perImageReaders =
new HashMap<ImageReader, PerImageReader>();
private final ArrayDeque<PerImageReader> imageReaderQueue = new ArrayDeque<>();
private final HashMap<ImageReader, PerImageReader> perImageReaders = new HashMap<>();
private PerImage lastDequeuedImage = null;
private PerImageReader lastReaderDequeuedFrom = null;
private Callback callback = null;
Expand All @@ -489,29 +488,28 @@ public PerImage(Image image, long queuedTime) {
/** Internal class: state held per ImageReader. */
private class PerImageReader {
public final ImageReader reader;
private final ArrayDeque<PerImage> imageQueue = new ArrayDeque<PerImage>();
private final ArrayDeque<PerImage> imageQueue = new ArrayDeque<>();
private boolean closed = false;

private final ImageReader.OnImageAvailableListener onImageAvailableListener =
reader -> {
Image image = null;
try {
image = reader.acquireLatestImage();
} catch (IllegalStateException e) {
Log.e(TAG, "onImageAvailable acquireLatestImage failed: " + e);
}
if (image == null) {
return;
}
if (released || closed) {
image.close();
return;
}
onImage(reader, image);
};

public PerImageReader(ImageReader reader) {
this.reader = reader;
ImageReader.OnImageAvailableListener onImageAvailableListener =
r -> {
Image image = null;
try {
image = r.acquireLatestImage();
} catch (IllegalStateException e) {
Log.e(TAG, "onImageAvailable acquireLatestImage failed: " + e);
}
if (image == null) {
return;
}
if (released || closed) {
image.close();
return;
}
onImage(r, image);
};
reader.setOnImageAvailableListener(
onImageAvailableListener, new Handler(Looper.getMainLooper()));
}
Expand All @@ -526,24 +524,23 @@ PerImage queueImage(Image image) {
while (imageQueue.size() > 2) {
PerImage r = imageQueue.removeFirst();
if (VERBOSE_LOGS) {
Log.i(TAG, "" + reader.hashCode() + " force closed image=" + r.image.hashCode());
Log.i(TAG, reader.hashCode() + " force closed image=" + r.image.hashCode());
}
r.image.close();
}
return perImage;
}

PerImage dequeueImage() {
if (imageQueue.size() == 0) {
if (imageQueue.isEmpty()) {
return null;
}
PerImage r = imageQueue.removeFirst();
return r;
return imageQueue.removeFirst();
}

/** returns true if we can prune this reader */
boolean canPrune() {
return imageQueue.size() == 0 && lastReaderDequeuedFrom != this;
return imageQueue.isEmpty() && lastReaderDequeuedFrom != this;
}

void close() {
Expand All @@ -557,8 +554,7 @@ void close() {
}

double deltaMillis(long deltaNanos) {
double ms = (double) deltaNanos / (double) 1000000.0;
return ms;
return (double) deltaNanos / 1000000.0;
}

PerImageReader getOrCreatePerImageReader(ImageReader reader) {
Expand All @@ -579,7 +575,7 @@ void pruneImageReaderQueue() {
// Prune nodes from the head of the ImageReader queue.
while (imageReaderQueue.size() > 1) {
PerImageReader r = imageReaderQueue.peekFirst();
if (!r.canPrune()) {
if (r == null || !r.canPrune()) {
// No more ImageReaders can be pruned this round.
break;
}
Expand All @@ -594,7 +590,7 @@ void pruneImageReaderQueue() {
}

void onImage(ImageReader reader, Image image) {
PerImage queuedImage = null;
PerImage queuedImage;
synchronized (lock) {
PerImageReader perReader = getOrCreatePerImageReader(reader);
queuedImage = perReader.queueImage(image);
Expand All @@ -609,8 +605,7 @@ void onImage(ImageReader reader, Image image) {
long queueDelta = now - lastQueueTime;
Log.i(
TAG,
""
+ reader.hashCode()
reader.hashCode()
+ " enqueued image="
+ queuedImage.image.hashCode()
+ " queueDelta="
Expand Down Expand Up @@ -640,8 +635,7 @@ PerImage dequeueImage() {
long scheduleDelay = now - lastScheduleTime;
Log.i(
TAG,
""
+ reader.reader.hashCode()
reader.reader.hashCode()
+ " dequeued image="
+ r.image.hashCode()
+ " queuedFor= "
Expand All @@ -659,16 +653,14 @@ PerImage dequeueImage() {
if (VERBOSE_LOGS) {
Log.i(
TAG,
""
+ lastReaderDequeuedFrom.reader.hashCode()
lastReaderDequeuedFrom.reader.hashCode()
+ " closing image="
+ lastDequeuedImage.image.hashCode());
}
// We must keep the last image dequeued open until we are done presenting
// it. We have just dequeued a new image (r). Close the previously dequeued
// image.
lastDequeuedImage.image.close();
lastDequeuedImage = null;
}
// Remember the last image and reader dequeued from. We do this because we must
// keep both of these alive until we are done presenting the image.
Expand Down Expand Up @@ -750,7 +742,7 @@ private void maybeWaitOnFence(Image image) {
}
// Log once per ImageTextureEntry.
ignoringFence = true;
Log.w(TAG, "ImageTextureEntry can't wait on the fence on Android < 33");
Log.d(TAG, "ImageTextureEntry can't wait on the fence on Android < 33");
}

ImageReaderSurfaceProducer(long id) {
Expand Down Expand Up @@ -805,7 +797,7 @@ public int getHeight() {
public Surface getSurface() {
PerImageReader pir = getActiveReader();
if (VERBOSE_LOGS) {
Log.i(TAG, "" + pir.reader.hashCode() + " returning surface to render a new frame.");
Log.i(TAG, pir.reader.hashCode() + " returning surface to render a new frame.");
}
return pir.reader.getSurface();
}
Expand Down Expand Up @@ -842,8 +834,7 @@ private PerImageReader getActiveReader() {
ImageReader reader = createImageReader();
if (VERBOSE_LOGS) {
Log.i(
TAG,
"" + reader.hashCode() + " created w=" + requestedWidth + " h=" + requestedHeight);
TAG, reader.hashCode() + " created w=" + requestedWidth + " h=" + requestedHeight);
}
return getOrCreatePerImageReader(reader);
}
Expand Down Expand Up @@ -878,20 +869,17 @@ private ImageReader createImageReader33() {
builder.setImageFormat(ImageFormat.PRIVATE);
// Hint that consumed images will only be read by GPU.
builder.setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
final ImageReader reader = builder.build();
return reader;
return builder.build();
}

@TargetApi(API_LEVELS.API_29)
private ImageReader createImageReader29() {
final ImageReader reader =
ImageReader.newInstance(
requestedWidth,
requestedHeight,
ImageFormat.PRIVATE,
MAX_IMAGES,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
return reader;
return ImageReader.newInstance(
requestedWidth,
requestedHeight,
ImageFormat.PRIVATE,
MAX_IMAGES,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
}

private ImageReader createImageReader() {
Expand Down Expand Up @@ -1012,7 +1000,7 @@ private void maybeWaitOnFence(Image image) {
}
// Log once per ImageTextureEntry.
ignoringFence = true;
Log.w(TAG, "ImageTextureEntry can't wait on the fence on Android < 33");
Log.d(TAG, "ImageTextureEntry can't wait on the fence on Android < 33");
}

@Override
Expand Down Expand Up @@ -1244,11 +1232,6 @@ private void scheduleEngineFrame() {
flutterJNI.scheduleFrame();
}

// TODO(mattcarroll): describe the native behavior that this invokes
private void markTextureFrameAvailable(long textureId) {
flutterJNI.markTextureFrameAvailable(textureId);
}

// TODO(mattcarroll): describe the native behavior that this invokes
private void unregisterTexture(long textureId) {
flutterJNI.unregisterTexture(textureId);
Expand Down