blob: 1675584f5a201d8e52e761aa682e089141031476 [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
Huihong Luo3bdef862022-03-03 11:57:19 -080018#include <gui/AidlStatusUtil.h>
chaviwe7b9f272020-08-18 16:08:59 -070019#include <gui/SyncScreenCaptureListener.h>
Huihong Luo9e84f332021-12-16 14:33:46 -080020#include <private/gui/ComposerServiceAIDL.h>
Patrick Williamsfdb57bb2022-08-09 22:48:18 +000021#include <ui/FenceResult.h>
Valerie Haue9137b72019-08-27 13:22:18 -070022#include <ui/Rect.h>
23#include <utils/String8.h>
chaviw8ffc7b82020-08-18 11:25:37 -070024#include <functional>
Valerie Haue9137b72019-08-27 13:22:18 -070025#include "TransactionUtils.h"
26
27namespace android {
28
Huihong Luo3bdef862022-03-03 11:57:19 -080029using gui::aidl_utils::statusTFromBinderStatus;
30
Valerie Haue9137b72019-08-27 13:22:18 -070031namespace {
32
33// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
34// individual pixel values for testing purposes.
35class ScreenCapture : public RefBase {
36public:
chaviw8ffc7b82020-08-18 11:25:37 -070037 static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
38 ScreenCaptureResults& captureResults) {
Huihong Luo9e84f332021-12-16 14:33:46 -080039 const auto sf = ComposerServiceAIDL::getComposerService();
Valerie Haue9137b72019-08-27 13:22:18 -070040 SurfaceComposerClient::Transaction().apply(true);
41
Peiyong Lincd261472020-10-06 18:05:25 -070042 captureArgs.dataspace = ui::Dataspace::V0_SRGB;
Ady Abrahamd11bade2022-08-01 16:18:03 -070043 const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
Huihong Luo9e84f332021-12-16 14:33:46 -080044 binder::Status status = sf->captureDisplay(captureArgs, captureListener);
Huihong Luo3bdef862022-03-03 11:57:19 -080045 status_t err = statusTFromBinderStatus(status);
46 if (err != NO_ERROR) {
47 return err;
chaviw8ffc7b82020-08-18 11:25:37 -070048 }
49 captureResults = captureListener->waitForResults();
Patrick Williamsfdb57bb2022-08-09 22:48:18 +000050 return fenceStatus(captureResults.fenceResult);
chaviw8ffc7b82020-08-18 11:25:37 -070051 }
52
53 static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
Huihong Luo31b5ac22022-08-15 20:38:10 -070054 const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
55 // TODO(b/248317436): extend to cover all displays for multi-display devices
56 const auto display =
57 ids.empty() ? nullptr : SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
58 captureScreen(sc, display);
chaviw4b9d5e12020-08-04 18:30:35 -070059 }
60
61 static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
chaviwd2432892020-07-24 17:42:39 -070062 DisplayCaptureArgs args;
63 args.displayToken = displayToken;
chaviw4b9d5e12020-08-04 18:30:35 -070064 captureDisplay(sc, args);
Valerie Haue9137b72019-08-27 13:22:18 -070065 }
66
chaviw8ffc7b82020-08-18 11:25:37 -070067 static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
68 DisplayCaptureArgs& captureArgs) {
69 ScreenCaptureResults captureResults;
70 ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
Alec Mouri14d5b862022-04-27 21:20:04 +000071 *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
72 captureResults.capturedHdrLayers);
chaviw8ffc7b82020-08-18 11:25:37 -070073 }
74
75 static status_t captureLayers(LayerCaptureArgs& captureArgs,
76 ScreenCaptureResults& captureResults) {
Huihong Luo9e84f332021-12-16 14:33:46 -080077 const auto sf = ComposerServiceAIDL::getComposerService();
Valerie Haue9137b72019-08-27 13:22:18 -070078 SurfaceComposerClient::Transaction().apply(true);
79
Peiyong Lincd261472020-10-06 18:05:25 -070080 captureArgs.dataspace = ui::Dataspace::V0_SRGB;
Ady Abrahamd11bade2022-08-01 16:18:03 -070081 const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
Huihong Luo9e84f332021-12-16 14:33:46 -080082 binder::Status status = sf->captureLayers(captureArgs, captureListener);
Huihong Luo3bdef862022-03-03 11:57:19 -080083 status_t err = statusTFromBinderStatus(status);
84 if (err != NO_ERROR) {
85 return err;
chaviw8ffc7b82020-08-18 11:25:37 -070086 }
87 captureResults = captureListener->waitForResults();
Patrick Williamsfdb57bb2022-08-09 22:48:18 +000088 return fenceStatus(captureResults.fenceResult);
chaviw8ffc7b82020-08-18 11:25:37 -070089 }
90
91 static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
chaviw3efadb12020-07-27 10:07:15 -070092 ScreenCaptureResults captureResults;
chaviw8ffc7b82020-08-18 11:25:37 -070093 ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
Alec Mouri14d5b862022-04-27 21:20:04 +000094 *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
95 captureResults.capturedHdrLayers);
Valerie Haue9137b72019-08-27 13:22:18 -070096 }
97
Alec Mouri14d5b862022-04-27 21:20:04 +000098 bool capturedHdrLayers() const { return mContainsHdr; }
99
Valerie Haue9137b72019-08-27 13:22:18 -0700100 void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
Arthur Hung58144272021-01-16 03:43:53 +0000101 ASSERT_NE(nullptr, mOutBuffer);
arthurhungf1b7c7b2021-03-03 17:42:23 +0800102 ASSERT_NE(nullptr, mPixels);
Valerie Haue9137b72019-08-27 13:22:18 -0700103 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
Valerie Haue271df92019-09-06 09:23:22 -0700104 TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
Valerie Haue9137b72019-08-27 13:22:18 -0700105 }
106
107 void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
Arthur Hung58144272021-01-16 03:43:53 +0000108 ASSERT_NE(nullptr, mOutBuffer);
Valerie Haue9137b72019-08-27 13:22:18 -0700109 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
110 const bool leftBorder = rect.left > 0;
111 const bool topBorder = rect.top > 0;
112 const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
113 const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
114
115 if (topBorder) {
116 Rect top(rect.left, rect.top - 1, rect.right, rect.top);
117 if (leftBorder) {
118 top.left -= 1;
119 }
120 if (rightBorder) {
121 top.right += 1;
122 }
123 expectColor(top, color, tolerance);
124 }
125 if (leftBorder) {
126 Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
127 expectColor(left, color, tolerance);
128 }
129 if (rightBorder) {
130 Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
131 expectColor(right, color, tolerance);
132 }
133 if (bottomBorder) {
134 Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
135 if (leftBorder) {
136 bottom.left -= 1;
137 }
138 if (rightBorder) {
139 bottom.right += 1;
140 }
141 expectColor(bottom, color, tolerance);
142 }
143 }
144
145 void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
146 const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
147 uint8_t tolerance = 0) {
148 ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
149
150 const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
151 const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
152 // avoid checking borders due to unspecified filtering behavior
153 const int32_t offsetX = filtered ? 2 : 0;
154 const int32_t offsetY = filtered ? 2 : 0;
155 expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
156 tolerance);
157 expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
158 tolerance);
159 expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
160 tolerance);
161 expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
162 bottomRight, tolerance);
163 }
164
165 void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
Arthur Hung58144272021-01-16 03:43:53 +0000166 ASSERT_NE(nullptr, mOutBuffer);
Valerie Haue9137b72019-08-27 13:22:18 -0700167 ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
168 const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
169 if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
170 String8 err(String8::format("pixel @ (%3d, %3d): "
171 "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
172 x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
Tomasz Wasilczyk0e1adf42023-08-11 00:06:51 +0000173 EXPECT_EQ(String8(), err) << err.c_str();
Valerie Haue9137b72019-08-27 13:22:18 -0700174 }
175 }
176
Galia Peycheva561d05c2021-03-08 15:14:05 +0100177 Color getPixelColor(uint32_t x, uint32_t y) {
178 if (!mOutBuffer || mOutBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_RGBA_8888) {
179 return {0, 0, 0, 0};
180 }
181
182 const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
183 return {pixel[0], pixel[1], pixel[2], pixel[3]};
184 }
185
Valerie Haue9137b72019-08-27 13:22:18 -0700186 void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
187
188 void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
189
190 void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
191
chaviw79468ab2021-10-27 11:11:24 -0500192 void expectSize(uint32_t width, uint32_t height) {
193 EXPECT_EQ(width, mOutBuffer->getWidth());
194 EXPECT_EQ(height, mOutBuffer->getHeight());
195 }
196
Alec Mouri14d5b862022-04-27 21:20:04 +0000197 explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer, bool containsHdr)
198 : mOutBuffer(outBuffer), mContainsHdr(containsHdr) {
Arthur Hung58144272021-01-16 03:43:53 +0000199 if (mOutBuffer) {
200 mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
201 }
Valerie Haue9137b72019-08-27 13:22:18 -0700202 }
203
Arthur Hung58144272021-01-16 03:43:53 +0000204 ~ScreenCapture() {
205 if (mOutBuffer) mOutBuffer->unlock();
206 }
Valerie Haue9137b72019-08-27 13:22:18 -0700207
208private:
209 sp<GraphicBuffer> mOutBuffer;
Alec Mouri14d5b862022-04-27 21:20:04 +0000210 bool mContainsHdr = mContainsHdr;
Valerie Haue9137b72019-08-27 13:22:18 -0700211 uint8_t* mPixels = nullptr;
212};
213} // namespace
214} // namespace android