• 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 <ui/Rect.h>
19 #include <utils/String8.h>
20 #include "TransactionUtils.h"
21 
22 namespace android {
23 
24 namespace {
25 
26 // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
27 // individual pixel values for testing purposes.
28 class ScreenCapture : public RefBase {
29 public:
captureScreen(std::unique_ptr<ScreenCapture> * sc)30     static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
31         captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
32     }
33 
captureScreen(std::unique_ptr<ScreenCapture> * sc,sp<IBinder> displayToken)34     static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
35         const auto sf = ComposerService::getComposerService();
36         SurfaceComposerClient::Transaction().apply(true);
37 
38         sp<GraphicBuffer> outBuffer;
39         ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
40         *sc = std::make_unique<ScreenCapture>(outBuffer);
41     }
42 
43     static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
44                               Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
45         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
46         SurfaceComposerClient::Transaction().apply(true);
47 
48         sp<GraphicBuffer> outBuffer;
49         ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale));
50         *sc = std::make_unique<ScreenCapture>(outBuffer);
51     }
52 
53     static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
54                                    Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
55         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
56         SurfaceComposerClient::Transaction().apply(true);
57 
58         sp<GraphicBuffer> outBuffer;
59         ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
60         *sc = std::make_unique<ScreenCapture>(outBuffer);
61     }
62 
captureChildLayersExcluding(std::unique_ptr<ScreenCapture> * sc,sp<IBinder> & parentHandle,std::unordered_set<sp<IBinder>,ISurfaceComposer::SpHash<IBinder>> excludeLayers)63     static void captureChildLayersExcluding(
64             std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
65             std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
66         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
67         SurfaceComposerClient::Transaction().apply(true);
68 
69         sp<GraphicBuffer> outBuffer;
70         ASSERT_EQ(NO_ERROR,
71                   sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB,
72                                     ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers,
73                                     1.0f, true));
74         *sc = std::make_unique<ScreenCapture>(outBuffer);
75     }
76 
77     void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
78         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
79         TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
80     }
81 
82     void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
83         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
84         const bool leftBorder = rect.left > 0;
85         const bool topBorder = rect.top > 0;
86         const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
87         const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
88 
89         if (topBorder) {
90             Rect top(rect.left, rect.top - 1, rect.right, rect.top);
91             if (leftBorder) {
92                 top.left -= 1;
93             }
94             if (rightBorder) {
95                 top.right += 1;
96             }
97             expectColor(top, color, tolerance);
98         }
99         if (leftBorder) {
100             Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
101             expectColor(left, color, tolerance);
102         }
103         if (rightBorder) {
104             Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
105             expectColor(right, color, tolerance);
106         }
107         if (bottomBorder) {
108             Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
109             if (leftBorder) {
110                 bottom.left -= 1;
111             }
112             if (rightBorder) {
113                 bottom.right += 1;
114             }
115             expectColor(bottom, color, tolerance);
116         }
117     }
118 
119     void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
120                         const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
121                         uint8_t tolerance = 0) {
122         ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
123 
124         const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
125         const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
126         // avoid checking borders due to unspecified filtering behavior
127         const int32_t offsetX = filtered ? 2 : 0;
128         const int32_t offsetY = filtered ? 2 : 0;
129         expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
130                     tolerance);
131         expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
132                     tolerance);
133         expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
134                     tolerance);
135         expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
136                     bottomRight, tolerance);
137     }
138 
checkPixel(uint32_t x,uint32_t y,uint8_t r,uint8_t g,uint8_t b)139     void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
140         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
141         const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
142         if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
143             String8 err(String8::format("pixel @ (%3d, %3d): "
144                                         "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
145                                         x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
146             EXPECT_EQ(String8(), err) << err.string();
147         }
148     }
149 
expectFGColor(uint32_t x,uint32_t y)150     void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
151 
expectBGColor(uint32_t x,uint32_t y)152     void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
153 
expectChildColor(uint32_t x,uint32_t y)154     void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
155 
ScreenCapture(const sp<GraphicBuffer> & outBuffer)156     explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
157         mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
158     }
159 
~ScreenCapture()160     ~ScreenCapture() { mOutBuffer->unlock(); }
161 
162 private:
163     sp<GraphicBuffer> mOutBuffer;
164     uint8_t* mPixels = nullptr;
165 };
166 } // namespace
167 } // namespace android
168