summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alec Mouri <alecmouri@google.com> 2023-04-07 17:29:19 +0000
committer Alec Mouri <alecmouri@google.com> 2023-04-25 03:27:16 +0000
commit164df0b0fd64ca2838b4301051e2e1359a801698 (patch)
treed74fc5b66b8b0fcb5704475ad4755c0a7c5a6d00
parenta6a6b061f6d7ac8582e4ff1f73cfdce078db7e78 (diff)
Support both HDR and display-native screenshots.
Screen rotation should be display-native to round trip properly during the animation, but other use-cases like recents will perform an intermediate composite into SDR before being displayed, in which case an HDR screenshot will tonemap better. Bug: 242324609 Bug: 276812775 Test: Rotation animation Test: Switch apps with recents Change-Id: Idd25acea9ceffa19d7bf16b871132e87d16791d7
-rw-r--r--core/java/android/window/ScreenCapture.java35
-rw-r--r--core/jni/android_window_ScreenCapture.cpp29
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java1
-rw-r--r--services/core/java/com/android/server/wm/ScreenRotationAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/Transition.java5
5 files changed, 43 insertions, 29 deletions
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index 95451a966055..fa7f577dadb8 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -198,17 +198,21 @@ public class ScreenCapture {
* Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
*
* @param hardwareBuffer The existing HardwareBuffer object
- * @param namedColorSpace Integer value of a named color space {@link ColorSpace.Named}
+ * @param dataspace Dataspace describing the content.
+ * {@see android.hardware.DataSpace}
* @param containsSecureLayers Indicates whether this graphic buffer contains captured
* contents of secure layers, in which case the screenshot
* should not be persisted.
* @param containsHdrLayers Indicates whether this graphic buffer contains HDR content.
*/
private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
- int namedColorSpace, boolean containsSecureLayers, boolean containsHdrLayers) {
- ColorSpace colorSpace = ColorSpace.get(ColorSpace.Named.values()[namedColorSpace]);
+ int dataspace, boolean containsSecureLayers, boolean containsHdrLayers) {
+ ColorSpace colorSpace = ColorSpace.getFromDataSpace(dataspace);
return new ScreenshotHardwareBuffer(
- hardwareBuffer, colorSpace, containsSecureLayers, containsHdrLayers);
+ hardwareBuffer,
+ colorSpace != null ? colorSpace : ColorSpace.get(ColorSpace.Named.SRGB),
+ containsSecureLayers,
+ containsHdrLayers);
}
public ColorSpace getColorSpace() {
@@ -271,8 +275,8 @@ public class ScreenCapture {
public final boolean mAllowProtected;
public final long mUid;
public final boolean mGrayscale;
-
final SurfaceControl[] mExcludeLayers;
+ public final boolean mHintForSeamlessTransition;
private CaptureArgs(CaptureArgs.Builder<? extends CaptureArgs.Builder<?>> builder) {
mPixelFormat = builder.mPixelFormat;
@@ -284,6 +288,7 @@ public class ScreenCapture {
mUid = builder.mUid;
mGrayscale = builder.mGrayscale;
mExcludeLayers = builder.mExcludeLayers;
+ mHintForSeamlessTransition = builder.mHintForSeamlessTransition;
}
private CaptureArgs(Parcel in) {
@@ -305,6 +310,7 @@ public class ScreenCapture {
} else {
mExcludeLayers = null;
}
+ mHintForSeamlessTransition = in.readBoolean();
}
/** Release any layers if set using {@link Builder#setExcludeLayers(SurfaceControl[])}. */
@@ -352,6 +358,7 @@ public class ScreenCapture {
private long mUid = -1;
private boolean mGrayscale;
private SurfaceControl[] mExcludeLayers;
+ private boolean mHintForSeamlessTransition;
/**
* Construct a new {@link CaptureArgs} with the set parameters. The builder remains
@@ -449,6 +456,21 @@ public class ScreenCapture {
}
/**
+ * Set whether the screenshot will be used in a system animation.
+ * This hint is used for picking the "best" colorspace for the screenshot, in particular
+ * for mixing HDR and SDR content.
+ * E.g., hintForSeamlessTransition is false, then a colorspace suitable for file
+ * encoding, such as BT2100, may be chosen. Otherwise, then the display's color space
+ * would be chosen, with the possibility of having an extended brightness range. This
+ * is important for screenshots that are directly re-routed to a SurfaceControl in
+ * order to preserve accurate colors.
+ */
+ public T setHintForSeamlessTransition(boolean hintForSeamlessTransition) {
+ mHintForSeamlessTransition = hintForSeamlessTransition;
+ return getThis();
+ }
+
+ /**
* Each sub class should return itself to allow the builder to chain properly
*/
T getThis() {
@@ -471,7 +493,6 @@ public class ScreenCapture {
dest.writeBoolean(mAllowProtected);
dest.writeLong(mUid);
dest.writeBoolean(mGrayscale);
-
if (mExcludeLayers != null) {
dest.writeInt(mExcludeLayers.length);
for (SurfaceControl excludeLayer : mExcludeLayers) {
@@ -480,6 +501,7 @@ public class ScreenCapture {
} else {
dest.writeInt(0);
}
+ dest.writeBoolean(mHintForSeamlessTransition);
}
public static final Parcelable.Creator<CaptureArgs> CREATOR =
@@ -627,6 +649,7 @@ public class ScreenCapture {
setUid(args.mUid);
setGrayscale(args.mGrayscale);
setExcludeLayers(args.mExcludeLayers);
+ setHintForSeamlessTransition(args.mHintForSeamlessTransition);
}
public Builder(SurfaceControl layer) {
diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp
index 1b67a0da57e1..986dbe9a204c 100644
--- a/core/jni/android_window_ScreenCapture.cpp
+++ b/core/jni/android_window_ScreenCapture.cpp
@@ -46,6 +46,7 @@ static struct {
jfieldID uid;
jfieldID grayscale;
jmethodID getNativeExcludeLayers;
+ jfieldID hintForSeamlessTransition;
} gCaptureArgsClassInfo;
static struct {
@@ -69,23 +70,6 @@ static struct {
jmethodID builder;
} gScreenshotHardwareBufferClassInfo;
-enum JNamedColorSpace : jint {
- // ColorSpace.Named.SRGB.ordinal() = 0;
- SRGB = 0,
-
- // ColorSpace.Named.DISPLAY_P3.ordinal() = 7;
- DISPLAY_P3 = 7,
-};
-
-constexpr jint fromDataspaceToNamedColorSpaceValue(const ui::Dataspace dataspace) {
- switch (dataspace) {
- case ui::Dataspace::DISPLAY_P3:
- return JNamedColorSpace::DISPLAY_P3;
- default:
- return JNamedColorSpace::SRGB;
- }
-}
-
static void checkAndClearException(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
ALOGE("An exception was thrown by callback '%s'.", methodName);
@@ -119,12 +103,11 @@ public:
captureResults.fenceResult.value()->waitForever(LOG_TAG);
jobject jhardwareBuffer = android_hardware_HardwareBuffer_createFromAHardwareBuffer(
env, captureResults.buffer->toAHardwareBuffer());
- const jint namedColorSpace =
- fromDataspaceToNamedColorSpaceValue(captureResults.capturedDataspace);
jobject screenshotHardwareBuffer =
env->CallStaticObjectMethod(gScreenshotHardwareBufferClassInfo.clazz,
gScreenshotHardwareBufferClassInfo.builder,
- jhardwareBuffer, namedColorSpace,
+ jhardwareBuffer,
+ static_cast<jint>(captureResults.capturedDataspace),
captureResults.capturedSecureLayers,
captureResults.capturedHdrLayers);
checkAndClearException(env, "builder");
@@ -185,6 +168,9 @@ static void getCaptureArgs(JNIEnv* env, jobject captureArgsObject, CaptureArgs&
captureArgs.excludeHandles.emplace(excludeObject->getHandle());
}
}
+ captureArgs.hintForSeamlessTransition =
+ env->GetBooleanField(captureArgsObject,
+ gCaptureArgsClassInfo.hintForSeamlessTransition);
}
static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env,
@@ -318,9 +304,10 @@ int register_android_window_ScreenCapture(JNIEnv* env) {
GetFieldIDOrDie(env, captureArgsClazz, "mAllowProtected", "Z");
gCaptureArgsClassInfo.uid = GetFieldIDOrDie(env, captureArgsClazz, "mUid", "J");
gCaptureArgsClassInfo.grayscale = GetFieldIDOrDie(env, captureArgsClazz, "mGrayscale", "Z");
-
gCaptureArgsClassInfo.getNativeExcludeLayers =
GetMethodIDOrDie(env, captureArgsClazz, "getNativeExcludeLayers", "()[J");
+ gCaptureArgsClassInfo.hintForSeamlessTransition =
+ GetFieldIDOrDie(env, captureArgsClazz, "mHintForSeamlessTransition", "Z");
jclass displayCaptureArgsClazz =
FindClassOrDie(env, "android/window/ScreenCapture$DisplayCaptureArgs");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index d25318df6b6a..9ce22094d56b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -144,6 +144,7 @@ class ScreenRotationAnimation {
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
+ .setHintForSeamlessTransition(true)
.build();
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
ScreenCapture.captureLayers(args);
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index b5df3e0937ec..bbb85636f1ee 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -193,6 +193,7 @@ class ScreenRotationAnimation {
.setSourceCrop(new Rect(0, 0, width, height))
.setAllowProtected(true)
.setCaptureSecureLayers(true)
+ .setHintForSeamlessTransition(true)
.build();
screenshotBuffer = ScreenCapture.captureDisplay(captureArgs);
} else {
@@ -202,6 +203,7 @@ class ScreenRotationAnimation {
.setCaptureSecureLayers(true)
.setAllowProtected(true)
.setSourceCrop(new Rect(0, 0, width, height))
+ .setHintForSeamlessTransition(true)
.build();
screenshotBuffer = ScreenCapture.captureLayers(captureArgs);
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 54dfdd93b26c..2d4b772e654f 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2924,11 +2924,14 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
Rect cropBounds = new Rect(bounds);
cropBounds.offsetTo(0, 0);
+ final boolean isDisplayRotation = wc.asDisplayContent() != null
+ && wc.asDisplayContent().isRotationChanging();
ScreenCapture.LayerCaptureArgs captureArgs =
new ScreenCapture.LayerCaptureArgs.Builder(wc.getSurfaceControl())
.setSourceCrop(cropBounds)
.setCaptureSecureLayers(true)
.setAllowProtected(true)
+ .setHintForSeamlessTransition(isDisplayRotation)
.build();
ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
ScreenCapture.captureLayers(captureArgs);
@@ -2939,8 +2942,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
Slog.w(TAG, "Failed to capture screenshot for " + wc);
return false;
}
- final boolean isDisplayRotation = wc.asDisplayContent() != null
- && wc.asDisplayContent().isRotationChanging();
// Some tests may check the name "RotationLayer" to detect display rotation.
final String name = isDisplayRotation ? "RotationLayer" : "transition snapshot: " + wc;
SurfaceControl snapshotSurface = wc.makeAnimationLeash()