Merge "Improve performance of edge extension animation" into tm-dev am: 47aa2ca8aa

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18029144

Change-Id: I06cde9a0f72878c49bce5d114016e7babb5a0bf5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Pablo Gamito
2022-05-04 13:13:49 +00:00
committed by Automerger Merge Worker

View File

@@ -16,6 +16,7 @@
package com.android.server.wm; package com.android.server.wm;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.util.TimeUtils.NANOS_PER_MS; import static android.util.TimeUtils.NANOS_PER_MS;
import static android.view.Choreographer.CALLBACK_TRAVERSAL; import static android.view.Choreographer.CALLBACK_TRAVERSAL;
import static android.view.Choreographer.getSfInstance; import static android.view.Choreographer.getSfInstance;
@@ -26,14 +27,13 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.graphics.Canvas;
import android.graphics.Insets; import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Rect; import android.graphics.Rect;
import android.hardware.power.Boost; import android.hardware.power.Boost;
import android.os.Handler; import android.os.Handler;
import android.os.PowerManagerInternal; import android.os.PowerManagerInternal;
import android.os.Trace;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.view.Choreographer; import android.view.Choreographer;
@@ -50,6 +50,8 @@ import com.android.server.AnimationThread;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
@@ -83,6 +85,12 @@ class SurfaceAnimationRunner {
private final PowerManagerInternal mPowerManagerInternal; private final PowerManagerInternal mPowerManagerInternal;
private boolean mApplyScheduled; private boolean mApplyScheduled;
// Executor to perform the edge extension.
// With two threads because in practice we will want to extend two surfaces in one animation,
// in which case we want to be able to parallelize those two extensions to cut down latency in
// starting the animation.
private final ExecutorService mEdgeExtensionExecutor = Executors.newFixedThreadPool(2);
@GuardedBy("mLock") @GuardedBy("mLock")
@VisibleForTesting @VisibleForTesting
final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>(); final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>();
@@ -173,7 +181,7 @@ class SurfaceAnimationRunner {
// We must wait for t to be committed since otherwise the leash doesn't have the // We must wait for t to be committed since otherwise the leash doesn't have the
// windows we want to screenshot and extend as children. // windows we want to screenshot and extend as children.
t.addTransactionCommittedListener(Runnable::run, () -> { t.addTransactionCommittedListener(mEdgeExtensionExecutor, () -> {
final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec(); final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();
final Transaction edgeExtensionCreationTransaction = new Transaction(); final Transaction edgeExtensionCreationTransaction = new Transaction();
@@ -403,30 +411,17 @@ class SurfaceAnimationRunner {
private void createExtensionSurface(SurfaceControl leash, Rect edgeBounds, private void createExtensionSurface(SurfaceControl leash, Rect edgeBounds,
Rect extensionRect, int xPos, int yPos, String layerName, Rect extensionRect, int xPos, int yPos, String layerName,
Transaction startTransaction) { Transaction startTransaction) {
synchronized (mEdgeExtensionLock) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createExtensionSurface");
if (!mEdgeExtensions.containsKey(leash)) { doCreateExtensionSurface(leash, edgeBounds, extensionRect, xPos, yPos, layerName,
// Animation leash has already been removed so we shouldn't perform any extension startTransaction);
return; Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
createExtensionSurfaceLocked(leash, edgeBounds, extensionRect, xPos, yPos, layerName,
startTransaction);
}
} }
private void createExtensionSurfaceLocked(SurfaceControl surfaceToExtend, Rect edgeBounds, private void doCreateExtensionSurface(SurfaceControl leash, Rect edgeBounds,
Rect extensionRect, int xPos, int yPos, String layerName, Rect extensionRect, int xPos, int yPos, String layerName,
Transaction startTransaction) { Transaction startTransaction) {
final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
.setName(layerName)
.setParent(surfaceToExtend)
.setHidden(true)
.setCallsite("DefaultTransitionHandler#startAnimation")
.setOpaque(true)
.setBufferSize(extensionRect.width(), extensionRect.height())
.build();
SurfaceControl.LayerCaptureArgs captureArgs = SurfaceControl.LayerCaptureArgs captureArgs =
new SurfaceControl.LayerCaptureArgs.Builder(surfaceToExtend) new SurfaceControl.LayerCaptureArgs.Builder(leash /* surfaceToExtend */)
.setSourceCrop(edgeBounds) .setSourceCrop(edgeBounds)
.setFrameScale(1) .setFrameScale(1)
.setPixelFormat(PixelFormat.RGBA_8888) .setPixelFormat(PixelFormat.RGBA_8888)
@@ -437,31 +432,76 @@ class SurfaceAnimationRunner {
SurfaceControl.captureLayers(captureArgs); SurfaceControl.captureLayers(captureArgs);
if (edgeBuffer == null) { if (edgeBuffer == null) {
// The leash we are trying to screenshot may have been removed by this point, which is
// likely the reason for ending up with a null edgeBuffer, in which case we just want to
// return and do nothing.
Log.e("SurfaceAnimationRunner", "Failed to create edge extension - " Log.e("SurfaceAnimationRunner", "Failed to create edge extension - "
+ "edge buffer is null"); + "edge buffer is null");
return; return;
} }
android.graphics.BitmapShader shader = final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
new android.graphics.BitmapShader(edgeBuffer.asBitmap(), .setName(layerName)
android.graphics.Shader.TileMode.CLAMP, .setHidden(true)
android.graphics.Shader.TileMode.CLAMP); .setCallsite("DefaultTransitionHandler#startAnimation")
final Paint paint = new Paint(); .setOpaque(true)
paint.setShader(shader); .setBufferSize(edgeBounds.width(), edgeBounds.height())
.build();
final Surface surface = new Surface(edgeExtensionLayer); final Surface surface = new Surface(edgeExtensionLayer);
Canvas c = surface.lockHardwareCanvas(); surface.attachAndQueueBufferWithColorSpace(edgeBuffer.getHardwareBuffer(),
c.drawRect(extensionRect, paint); edgeBuffer.getColorSpace());
surface.unlockCanvasAndPost(c);
surface.release(); surface.release();
startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE); final float scaleX = getScaleXForExtensionSurface(edgeBounds, extensionRect);
startTransaction.setPosition(edgeExtensionLayer, xPos, yPos); final float scaleY = getScaleYForExtensionSurface(edgeBounds, extensionRect);
startTransaction.setVisibility(edgeExtensionLayer, true);
mEdgeExtensions.get(surfaceToExtend).add(edgeExtensionLayer); synchronized (mEdgeExtensionLock) {
if (!mEdgeExtensions.containsKey(leash)) {
// The animation leash has already been removed, so we don't want to attach the
// edgeExtension layer and should immediately remove it instead.
startTransaction.remove(edgeExtensionLayer);
return;
}
startTransaction.setScale(edgeExtensionLayer, scaleX, scaleY);
startTransaction.reparent(edgeExtensionLayer, leash);
startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
startTransaction.setVisibility(edgeExtensionLayer, true);
mEdgeExtensions.get(leash).add(edgeExtensionLayer);
}
} }
private float getScaleXForExtensionSurface(Rect edgeBounds, Rect extensionRect) {
if (edgeBounds.width() == extensionRect.width()) {
// Top or bottom edge extension, no need to scale the X axis of the extension surface.
return 1;
}
if (edgeBounds.width() == 1) {
// Left or right edge extension, scale the surface to be the extensionRect's width.
return extensionRect.width();
}
throw new RuntimeException("Unexpected edgeBounds and extensionRect widths");
}
private float getScaleYForExtensionSurface(Rect edgeBounds, Rect extensionRect) {
if (edgeBounds.height() == extensionRect.height()) {
// Left or right edge extension, no need to scale the Y axis of the extension surface.
return 1;
}
if (edgeBounds.height() == 1) {
// Top or bottom edge extension, scale the surface to be the extensionRect's height.
return extensionRect.height();
}
throw new RuntimeException("Unexpected edgeBounds and extensionRect heights");
}
private static final class RunningAnimation { private static final class RunningAnimation {
final AnimationSpec mAnimSpec; final AnimationSpec mAnimSpec;
final SurfaceControl mLeash; final SurfaceControl mLeash;