Merge "Support both HDR and display-native screenshots." into udc-dev

This commit is contained in:
Alec Mouri
2023-04-28 20:01:58 +00:00
committed by Android (Google) Code Review
5 changed files with 43 additions and 29 deletions

View File

@@ -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
@@ -448,6 +455,21 @@ public class ScreenCapture {
return getThis();
}
/**
* 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
*/
@@ -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) {

View File

@@ -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");

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -2999,11 +2999,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);
@@ -3014,8 +3017,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()