Skip to content

Commit

Permalink
Added new arguments for screenshot request
Browse files Browse the repository at this point in the history
Added frameScaleX and frameScaleY to replace frameScale to allow callers
to specify an X and Y scale separately.

Added grayscale flag to allow the caller to take the screenshot
in grayscale.

Test: ScreenCaptureTest.CaptureWithGrayscale
Bug: 155825630
Change-Id: Iea043b7074707df897d80bf057d7cc3870afad89
  • Loading branch information
chaviw committed Jan 29, 2021
1 parent 9959994 commit 17ac24b
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 39 deletions.
8 changes: 6 additions & 2 deletions libs/gui/LayerState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,11 +644,13 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunc
status_t CaptureArgs::write(Parcel& output) const {
SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(pixelFormat));
SAFE_PARCEL(output.write, sourceCrop);
SAFE_PARCEL(output.writeFloat, frameScale);
SAFE_PARCEL(output.writeFloat, frameScaleX);
SAFE_PARCEL(output.writeFloat, frameScaleY);
SAFE_PARCEL(output.writeBool, captureSecureLayers);
SAFE_PARCEL(output.writeInt32, uid);
SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace));
SAFE_PARCEL(output.writeBool, allowProtected);
SAFE_PARCEL(output.writeBool, grayscale);
return NO_ERROR;
}

Expand All @@ -657,12 +659,14 @@ status_t CaptureArgs::read(const Parcel& input) {
SAFE_PARCEL(input.readInt32, &value);
pixelFormat = static_cast<ui::PixelFormat>(value);
SAFE_PARCEL(input.read, sourceCrop);
SAFE_PARCEL(input.readFloat, &frameScale);
SAFE_PARCEL(input.readFloat, &frameScaleX);
SAFE_PARCEL(input.readFloat, &frameScaleY);
SAFE_PARCEL(input.readBool, &captureSecureLayers);
SAFE_PARCEL(input.readInt32, &uid);
SAFE_PARCEL(input.readInt32, &value);
dataspace = static_cast<ui::Dataspace>(value);
SAFE_PARCEL(input.readBool, &allowProtected);
SAFE_PARCEL(input.readBool, &grayscale);
return NO_ERROR;
}

Expand Down
5 changes: 4 additions & 1 deletion libs/gui/include/gui/LayerState.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,8 @@ struct CaptureArgs {

ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888};
Rect sourceCrop;
float frameScale{1};
float frameScaleX{1};
float frameScaleY{1};
bool captureSecureLayers{false};
int32_t uid{UNSET_UID};
// Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured
Expand All @@ -346,6 +347,8 @@ struct CaptureArgs {
// the contents being accessed/captured by screenshot or unsecure display.
bool allowProtected = false;

bool grayscale = false;

virtual status_t write(Parcel& output) const;
virtual status_t read(const Parcel& input);
};
Expand Down
2 changes: 1 addition & 1 deletion services/surfaceflinger/RegionSamplingThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ void RegionSamplingThread::captureSample() {

const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
true /* regionSampling */, captureListener);
true /* regionSampling */, false /* grayscale */, captureListener);
ScreenCaptureResults captureResults = captureListener->waitForResults();

std::vector<Descriptor> activeDescriptors;
Expand Down
59 changes: 33 additions & 26 deletions services/surfaceflinger/SurfaceFlinger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4900,23 +4900,24 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co
result.append("\n");
}

void SurfaceFlinger::updateColorMatrixLocked() {
mat4 colorMatrix;
if (mGlobalSaturationFactor != 1.0f) {
// Rec.709 luma coefficients
float3 luminance{0.213f, 0.715f, 0.072f};
luminance *= 1.0f - mGlobalSaturationFactor;
mat4 saturationMatrix = mat4(
vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f},
vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f},
vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f},
vec4{0.0f, 0.0f, 0.0f, 1.0f}
);
colorMatrix = mClientColorMatrix * saturationMatrix * mDaltonizer();
} else {
colorMatrix = mClientColorMatrix * mDaltonizer();
mat4 SurfaceFlinger::calculateColorMatrix(float saturation) {
if (saturation == 1) {
return mat4();
}

float3 luminance{0.213f, 0.715f, 0.072f};
luminance *= 1.0f - saturation;
mat4 saturationMatrix = mat4(vec4{luminance.r + saturation, luminance.r, luminance.r, 0.0f},
vec4{luminance.g, luminance.g + saturation, luminance.g, 0.0f},
vec4{luminance.b, luminance.b, luminance.b + saturation, 0.0f},
vec4{0.0f, 0.0f, 0.0f, 1.0f});
return saturationMatrix;
}

void SurfaceFlinger::updateColorMatrixLocked() {
mat4 colorMatrix =
mClientColorMatrix * calculateColorMatrix(mGlobalSaturationFactor) * mDaltonizer();

if (mCurrentState.colorMatrix != colorMatrix) {
mCurrentState.colorMatrix = colorMatrix;
mCurrentState.colorMatrixChanged = true;
Expand Down Expand Up @@ -5628,7 +5629,8 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
};

return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
args.pixelFormat, args.allowProtected, captureListener);
args.pixelFormat, args.allowProtected, args.grayscale,
captureListener);
}

status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
Expand Down Expand Up @@ -5664,7 +5666,7 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,

return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
ui::PixelFormat::RGBA_8888, false /* allowProtected */,
captureListener);
false /* grayscale */, captureListener);
}

status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
Expand Down Expand Up @@ -5710,12 +5712,12 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
crop.bottom = parentSourceBounds.getHeight();
}

if (crop.isEmpty() || args.frameScale <= 0.0f) {
if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) {
// Error out if the layer has no source bounds (i.e. they are boundless) and a source
// crop was not specified, or an invalid frame scale was provided.
return BAD_VALUE;
}
reqSize = ui::Size(crop.width() * args.frameScale, crop.height() * args.frameScale);
reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY);

for (const auto& handle : args.excludeHandles) {
sp<Layer> excludeLayer = fromHandleLocked(handle).promote();
Expand Down Expand Up @@ -5785,13 +5787,14 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
};

return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
args.pixelFormat, args.allowProtected, captureListener);
args.pixelFormat, args.allowProtected, args.grayscale,
captureListener);
}

status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
TraverseLayersFunction traverseLayers,
ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
const bool allowProtected,
bool allowProtected, bool grayscale,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();

Expand Down Expand Up @@ -5822,12 +5825,13 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
static_cast<android_pixel_format>(reqPixelFormat),
1 /* layerCount */, usage, "screenshot");
return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
false /* regionSampling */, captureListener);
false /* regionSampling */, grayscale, captureListener);
}

status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>& buffer, const bool regionSampling,
sp<GraphicBuffer>& buffer, bool regionSampling,
bool grayscale,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();

Expand All @@ -5843,7 +5847,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
if (mRefreshPending) {
ALOGW("Skipping screenshot for now");
captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling,
captureListener);
grayscale, captureListener);
return;
}
ScreenCaptureResults captureResults;
Expand All @@ -5858,7 +5862,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
status_t result = NO_ERROR;
renderArea->render([&] {
result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem,
regionSampling, captureResults);
regionSampling, grayscale, captureResults);
});

captureResults.result = result;
Expand All @@ -5871,7 +5875,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
const sp<GraphicBuffer>& buffer, bool forSystem,
bool regionSampling,
bool regionSampling, bool grayscale,
ScreenCaptureResults& captureResults) {
ATRACE_CALL();

Expand Down Expand Up @@ -5912,6 +5916,9 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace();
clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance;

const float colorSaturation = grayscale ? 0 : 1;
clientCompositionDisplay.colorTransform = calculateColorMatrix(colorSaturation);

const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());

compositionengine::LayerFE::LayerSettings fillLayer;
Expand Down
9 changes: 6 additions & 3 deletions services/surfaceflinger/SurfaceFlinger.h
Original file line number Diff line number Diff line change
Expand Up @@ -810,13 +810,14 @@ class SurfaceFlinger : public BnSurfaceComposer,
void startBootAnim();

status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
ui::PixelFormat, const bool allowProtected,
ui::PixelFormat, bool allowProtected, bool grayscale,
const sp<IScreenCaptureListener>&);
status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
bool regionSampling, const sp<IScreenCaptureListener>&);
bool regionSampling, bool grayscale,
const sp<IScreenCaptureListener>&);
status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
const sp<GraphicBuffer>&, bool forSystem, bool regionSampling,
ScreenCaptureResults&);
bool grayscale, ScreenCaptureResults&);

sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
Expand Down Expand Up @@ -1019,6 +1020,8 @@ class SurfaceFlinger : public BnSurfaceComposer,

void onFrameRateFlexibilityTokenReleased();

static mat4 calculateColorMatrix(float saturation);

void updateColorMatrixLocked();

// Verify that transaction is being called by an approved process:
Expand Down
16 changes: 12 additions & 4 deletions services/surfaceflinger/tests/LayerState_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) {
DisplayCaptureArgs args;
args.pixelFormat = ui::PixelFormat::RGB_565;
args.sourceCrop = Rect(0, 0, 500, 200);
args.frameScale = 2;
args.frameScaleX = 2;
args.frameScaleY = 4;
args.captureSecureLayers = true;
args.displayToken = new BBinder();
args.width = 10;
args.height = 20;
args.useIdentityTransform = true;
args.grayscale = true;

Parcel p;
args.write(p);
Expand All @@ -46,23 +48,27 @@ TEST(LayerStateTest, ParcellingDisplayCaptureArgs) {

ASSERT_EQ(args.pixelFormat, args2.pixelFormat);
ASSERT_EQ(args.sourceCrop, args2.sourceCrop);
ASSERT_EQ(args.frameScale, args2.frameScale);
ASSERT_EQ(args.frameScaleX, args2.frameScaleX);
ASSERT_EQ(args.frameScaleY, args2.frameScaleY);
ASSERT_EQ(args.captureSecureLayers, args2.captureSecureLayers);
ASSERT_EQ(args.displayToken, args2.displayToken);
ASSERT_EQ(args.width, args2.width);
ASSERT_EQ(args.height, args2.height);
ASSERT_EQ(args.useIdentityTransform, args2.useIdentityTransform);
ASSERT_EQ(args.grayscale, args2.grayscale);
}

TEST(LayerStateTest, ParcellingLayerCaptureArgs) {
LayerCaptureArgs args;
args.pixelFormat = ui::PixelFormat::RGB_565;
args.sourceCrop = Rect(0, 0, 500, 200);
args.frameScale = 2;
args.frameScaleX = 2;
args.frameScaleY = 4;
args.captureSecureLayers = true;
args.layerHandle = new BBinder();
args.excludeHandles = {new BBinder(), new BBinder()};
args.childrenOnly = false;
args.grayscale = true;

Parcel p;
args.write(p);
Expand All @@ -73,11 +79,13 @@ TEST(LayerStateTest, ParcellingLayerCaptureArgs) {

ASSERT_EQ(args.pixelFormat, args2.pixelFormat);
ASSERT_EQ(args.sourceCrop, args2.sourceCrop);
ASSERT_EQ(args.frameScale, args2.frameScale);
ASSERT_EQ(args.frameScaleX, args2.frameScaleX);
ASSERT_EQ(args.frameScaleY, args2.frameScaleY);
ASSERT_EQ(args.captureSecureLayers, args2.captureSecureLayers);
ASSERT_EQ(args.layerHandle, args2.layerHandle);
ASSERT_EQ(args.excludeHandles, args2.excludeHandles);
ASSERT_EQ(args.childrenOnly, args2.childrenOnly);
ASSERT_EQ(args.grayscale, args2.grayscale);
}

TEST(LayerStateTest, ParcellingScreenCaptureResults) {
Expand Down
39 changes: 38 additions & 1 deletion services/surfaceflinger/tests/ScreenCapture_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,9 @@ TEST_F(ScreenCaptureTest, CaptureSize) {
// red area to the right of the blue area
mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);

captureArgs.frameScale = 0.5f;
captureArgs.frameScaleX = 0.5f;
captureArgs.frameScaleY = 0.5f;

ScreenCapture::captureLayers(&mCapture, captureArgs);
// Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
Expand Down Expand Up @@ -768,6 +770,41 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithUid) {
mCapture->expectBorder(Rect(128, 128, 160, 160), {63, 63, 195, 255});
}

TEST_F(ScreenCaptureTest, CaptureWithGrayscale) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test layer", 32, 32,
ISurfaceComposerClient::eFXSurfaceBufferState,
mBGSurfaceControl.get()));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
Transaction().show(layer).setLayer(layer, INT32_MAX).apply();

LayerCaptureArgs captureArgs;
captureArgs.layerHandle = layer->getHandle();

ScreenCapture::captureLayers(&mCapture, captureArgs);
mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED);

captureArgs.grayscale = true;

const uint8_t tolerance = 1;

// Values based on SurfaceFlinger::calculateColorMatrix
float3 luminance{0.213f, 0.715f, 0.072f};

ScreenCapture::captureLayers(&mCapture, captureArgs);

uint8_t expectedColor = luminance.r * 255;
mCapture->expectColor(Rect(0, 0, 32, 32),
Color{expectedColor, expectedColor, expectedColor, 255}, tolerance);

ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
ScreenCapture::captureLayers(&mCapture, captureArgs);

expectedColor = luminance.b * 255;
mCapture->expectColor(Rect(0, 0, 32, 32),
Color{expectedColor, expectedColor, expectedColor, 255}, tolerance);
}

// In the following tests we verify successful skipping of a parent layer,
// so we use the same verification logic and only change how we mutate
// the parent layer to verify that various properties are ignored.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ class TestableSurfaceFlinger final : private ISchedulerCallback {
bool regionSampling) {
ScreenCaptureResults captureResults;
return mFlinger->renderScreenImplLocked(renderArea, traverseLayers, buffer, forSystem,
regionSampling, captureResults);
regionSampling, false /* grayscale */,
captureResults);
}

auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid,
Expand Down

0 comments on commit 17ac24b

Please sign in to comment.