blob: ee7e92cbf6da667f107fc89f219f6bbf3ea324e9 [file] [log] [blame]
Valerie Haue9137b72019-08-27 13:22:18 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
chaviwe7b9f272020-08-18 16:08:59 -070018#include <gui/SyncScreenCaptureListener.h>
Huihong Luof5029222021-12-16 14:33:46 -080019#include <private/gui/ComposerServiceAIDL.h>
Valerie Haue9137b72019-08-27 13:22:18 -070020#include <ui/Rect.h>
21#include <utils/String8.h>
chaviw8ffc7b82020-08-18 11:25:37 -070022#include <functional>
Valerie Haue9137b72019-08-27 13:22:18 -070023#include "TransactionUtils.h"
24
25namespace android {
26
27namespace {
28
29// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
30// individual pixel values for testing purposes.
31class ScreenCapture : public RefBase {
32public:
chaviw8ffc7b82020-08-18 11:25:37 -070033 static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
34 ScreenCaptureResults& captureResults) {
Huihong Luof5029222021-12-16 14:33:46 -080035 const auto sf = ComposerServiceAIDL::getComposerService();
Valerie Haue9137b72019-08-27 13:22:18 -070036 SurfaceComposerClient::Transaction().apply(true);
37
Peiyong Lincd261472020-10-06 18:05:25 -070038 captureArgs.dataspace = ui::Dataspace::V0_SRGB;
chaviw8ffc7b82020-08-18 11:25:37 -070039 const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
Huihong Luof5029222021-12-16 14:33:46 -080040 binder::Status status = sf->captureDisplay(captureArgs, captureListener);
arthurhung79e81aa2020-08-28 00:09:19 +080041
Huihong Luof5029222021-12-16 14:33:46 -080042 if (status.transactionError() != NO_ERROR) {
43 return status.transactionError();
chaviw8ffc7b82020-08-18 11:25:37 -070044 }
45 captureResults = captureListener->waitForResults();
46 return captureResults.result;
47 }
48
49 static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
50 captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
chaviw4b9d5e12020-08-04 18:30:35 -070051 }
52
53 static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
chaviwd2432892020-07-24 17:42:39 -070054 DisplayCaptureArgs args;
55 args.displayToken = displayToken;
chaviw4b9d5e12020-08-04 18:30:35 -070056 captureDisplay(sc, args);
Valerie Haue9137b72019-08-27 13:22:18 -070057 }
58
chaviw8ffc7b82020-08-18 11:25:37 -070059 static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
60 DisplayCaptureArgs& captureArgs) {
61 ScreenCaptureResults captureResults;
62 ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
63 *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
64 }
65
66 static status_t captureLayers(LayerCaptureArgs& captureArgs,
67 ScreenCaptureResults& captureResults) {
Huihong Luof5029222021-12-16 14:33:46 -080068 const auto sf = ComposerServiceAIDL::getComposerService();
Valerie Haue9137b72019-08-27 13:22:18 -070069 SurfaceComposerClient::Transaction().apply(true);
70
Peiyong Lincd261472020-10-06 18:05:25 -070071 captureArgs.dataspace = ui::Dataspace::V0_SRGB;
chaviw8ffc7b82020-08-18 11:25:37 -070072 const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
Huihong Luof5029222021-12-16 14:33:46 -080073 binder::Status status = sf->captureLayers(captureArgs, captureListener);
74 if (status.transactionError() != NO_ERROR) {
75 return status.transactionError();
chaviw8ffc7b82020-08-18 11:25:37 -070076 }
77 captureResults = captureListener->waitForResults();
78 return captureResults.result;
79 }
80
81 static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
chaviw3efadb12020-07-27 10:07:15 -070082 ScreenCaptureResults captureResults;
chaviw8ffc7b82020-08-18 11:25:37 -070083 ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
chaviw3efadb12020-07-27 10:07:15 -070084 *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
Valerie Haue9137b72019-08-27 13:22:18 -070085 }
86
87 void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
Arthur Hung58144272021-01-16 03:43:53 +000088 ASSERT_NE(nullptr, mOutBuffer);
arthurhungf1b7c7b2021-03-03 17:42:23 +080089 ASSERT_NE(nullptr, mPixels);
Valerie Haue9137b72019-08-27 13:22:18 -070090 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
Valerie Haue271df92019-09-06 09:23:22 -070091 TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
Valerie Haue9137b72019-08-27 13:22:18 -070092 }
93
94 void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
Arthur Hung58144272021-01-16 03:43:53 +000095 ASSERT_NE(nullptr, mOutBuffer);
Valerie Haue9137b72019-08-27 13:22:18 -070096 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
97 const bool leftBorder = rect.left > 0;
98 const bool topBorder = rect.top > 0;
99 const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
100 const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
101
102 if (topBorder) {
103 Rect top(rect.left, rect.top - 1, rect.right, rect.top);
104 if (leftBorder) {
105 top.left -= 1;
106 }
107 if (rightBorder) {
108 top.right += 1;
109 }
110 expectColor(top, color, tolerance);
111 }
112 if (leftBorder) {
113 Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
114 expectColor(left, color, tolerance);
115 }
116 if (rightBorder) {
117 Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
118 expectColor(right, color, tolerance);
119 }
120 if (bottomBorder) {
121 Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
122 if (leftBorder) {
123 bottom.left -= 1;
124 }
125 if (rightBorder) {
126 bottom.right += 1;
127 }
128 expectColor(bottom, color, tolerance);
129 }
130 }
131
132 void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
133 const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
134 uint8_t tolerance = 0) {
135 ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
136
137 const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
138 const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
139 // avoid checking borders due to unspecified filtering behavior
140 const int32_t offsetX = filtered ? 2 : 0;
141 const int32_t offsetY = filtered ? 2 : 0;
142 expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
143 tolerance);
144 expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
145 tolerance);
146 expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
147 tolerance);
148 expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
149 bottomRight, tolerance);
150 }
151
152 void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
Arthur Hung58144272021-01-16 03:43:53 +0000153 ASSERT_NE(nullptr, mOutBuffer);
Valerie Haue9137b72019-08-27 13:22:18 -0700154 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
155 const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
156 if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
157 String8 err(String8::format("pixel @ (%3d, %3d): "
158 "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
159 x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
160 EXPECT_EQ(String8(), err) << err.string();
161 }
162 }
163
Galia Peycheva561d05c2021-03-08 15:14:05 +0100164 Color getPixelColor(uint32_t x, uint32_t y) {
165 if (!mOutBuffer || mOutBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_RGBA_8888) {
166 return {0, 0, 0, 0};
167 }
168
169 const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
170 return {pixel[0], pixel[1], pixel[2], pixel[3]};
171 }
172
Valerie Haue9137b72019-08-27 13:22:18 -0700173 void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
174
175 void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
176
177 void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
178
chaviw79468ab2021-10-27 11:11:24 -0500179 void expectSize(uint32_t width, uint32_t height) {
180 EXPECT_EQ(width, mOutBuffer->getWidth());
181 EXPECT_EQ(height, mOutBuffer->getHeight());
182 }
183
Valerie Haue9137b72019-08-27 13:22:18 -0700184 explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
Arthur Hung58144272021-01-16 03:43:53 +0000185 if (mOutBuffer) {
186 mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
187 }
Valerie Haue9137b72019-08-27 13:22:18 -0700188 }
189
Arthur Hung58144272021-01-16 03:43:53 +0000190 ~ScreenCapture() {
191 if (mOutBuffer) mOutBuffer->unlock();
192 }
Valerie Haue9137b72019-08-27 13:22:18 -0700193
194private:
195 sp<GraphicBuffer> mOutBuffer;
196 uint8_t* mPixels = nullptr;
197};
198} // namespace
199} // namespace android