• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
18 #include <gui/SyncScreenCaptureListener.h>
19 #include <private/gui/ComposerServiceAIDL.h>
20 #include <ui/Rect.h>
21 #include <utils/String8.h>
22 #include <functional>
23 #include "TransactionUtils.h"
24 
25 namespace android {
26 
27 namespace {
28 
29 // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
30 // individual pixel values for testing purposes.
31 class ScreenCapture : public RefBase {
32 public:
captureDisplay(DisplayCaptureArgs & captureArgs,ScreenCaptureResults & captureResults)33     static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
34                                    ScreenCaptureResults& captureResults) {
35         const auto sf = ComposerServiceAIDL::getComposerService();
36         SurfaceComposerClient::Transaction().apply(true);
37 
38         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
39         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
40         binder::Status status = sf->captureDisplay(captureArgs, captureListener);
41 
42         if (status.transactionError() != NO_ERROR) {
43             return status.transactionError();
44         }
45         captureResults = captureListener->waitForResults();
46         return captureResults.result;
47     }
48 
captureScreen(std::unique_ptr<ScreenCapture> * sc)49     static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
50         captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
51     }
52 
captureScreen(std::unique_ptr<ScreenCapture> * sc,sp<IBinder> displayToken)53     static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
54         DisplayCaptureArgs args;
55         args.displayToken = displayToken;
56         captureDisplay(sc, args);
57     }
58 
captureDisplay(std::unique_ptr<ScreenCapture> * sc,DisplayCaptureArgs & captureArgs)59     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                                               captureResults.capturedHdrLayers);
65     }
66 
captureLayers(LayerCaptureArgs & captureArgs,ScreenCaptureResults & captureResults)67     static status_t captureLayers(LayerCaptureArgs& captureArgs,
68                                   ScreenCaptureResults& captureResults) {
69         const auto sf = ComposerServiceAIDL::getComposerService();
70         SurfaceComposerClient::Transaction().apply(true);
71 
72         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
73         const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
74         binder::Status status = sf->captureLayers(captureArgs, captureListener);
75         if (status.transactionError() != NO_ERROR) {
76             return status.transactionError();
77         }
78         captureResults = captureListener->waitForResults();
79         return captureResults.result;
80     }
81 
captureLayers(std::unique_ptr<ScreenCapture> * sc,LayerCaptureArgs & captureArgs)82     static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
83         ScreenCaptureResults captureResults;
84         ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
85         *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
86                                               captureResults.capturedHdrLayers);
87     }
88 
capturedHdrLayers()89     bool capturedHdrLayers() const { return mContainsHdr; }
90 
91     void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
92         ASSERT_NE(nullptr, mOutBuffer);
93         ASSERT_NE(nullptr, mPixels);
94         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
95         TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
96     }
97 
98     void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
99         ASSERT_NE(nullptr, mOutBuffer);
100         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
101         const bool leftBorder = rect.left > 0;
102         const bool topBorder = rect.top > 0;
103         const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
104         const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
105 
106         if (topBorder) {
107             Rect top(rect.left, rect.top - 1, rect.right, rect.top);
108             if (leftBorder) {
109                 top.left -= 1;
110             }
111             if (rightBorder) {
112                 top.right += 1;
113             }
114             expectColor(top, color, tolerance);
115         }
116         if (leftBorder) {
117             Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
118             expectColor(left, color, tolerance);
119         }
120         if (rightBorder) {
121             Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
122             expectColor(right, color, tolerance);
123         }
124         if (bottomBorder) {
125             Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
126             if (leftBorder) {
127                 bottom.left -= 1;
128             }
129             if (rightBorder) {
130                 bottom.right += 1;
131             }
132             expectColor(bottom, color, tolerance);
133         }
134     }
135 
136     void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
137                         const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
138                         uint8_t tolerance = 0) {
139         ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
140 
141         const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
142         const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
143         // avoid checking borders due to unspecified filtering behavior
144         const int32_t offsetX = filtered ? 2 : 0;
145         const int32_t offsetY = filtered ? 2 : 0;
146         expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
147                     tolerance);
148         expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
149                     tolerance);
150         expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
151                     tolerance);
152         expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
153                     bottomRight, tolerance);
154     }
155 
checkPixel(uint32_t x,uint32_t y,uint8_t r,uint8_t g,uint8_t b)156     void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
157         ASSERT_NE(nullptr, mOutBuffer);
158         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
159         const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
160         if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
161             String8 err(String8::format("pixel @ (%3d, %3d): "
162                                         "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
163                                         x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
164             EXPECT_EQ(String8(), err) << err.string();
165         }
166     }
167 
getPixelColor(uint32_t x,uint32_t y)168     Color getPixelColor(uint32_t x, uint32_t y) {
169         if (!mOutBuffer || mOutBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_RGBA_8888) {
170             return {0, 0, 0, 0};
171         }
172 
173         const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
174         return {pixel[0], pixel[1], pixel[2], pixel[3]};
175     }
176 
expectFGColor(uint32_t x,uint32_t y)177     void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
178 
expectBGColor(uint32_t x,uint32_t y)179     void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
180 
expectChildColor(uint32_t x,uint32_t y)181     void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
182 
expectSize(uint32_t width,uint32_t height)183     void expectSize(uint32_t width, uint32_t height) {
184         EXPECT_EQ(width, mOutBuffer->getWidth());
185         EXPECT_EQ(height, mOutBuffer->getHeight());
186     }
187 
ScreenCapture(const sp<GraphicBuffer> & outBuffer,bool containsHdr)188     explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer, bool containsHdr)
189           : mOutBuffer(outBuffer), mContainsHdr(containsHdr) {
190         if (mOutBuffer) {
191             mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
192         }
193     }
194 
~ScreenCapture()195     ~ScreenCapture() {
196         if (mOutBuffer) mOutBuffer->unlock();
197     }
198 
199 private:
200     sp<GraphicBuffer> mOutBuffer;
201     bool mContainsHdr = mContainsHdr;
202     uint8_t* mPixels = nullptr;
203 };
204 } // namespace
205 } // namespace android
206