• 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/AidlStatusUtil.h>
19 #include <gui/SyncScreenCaptureListener.h>
20 #include <private/gui/ComposerServiceAIDL.h>
21 #include <ui/FenceResult.h>
22 #include <ui/Rect.h>
23 #include <utils/String8.h>
24 #include <functional>
25 #include "TransactionUtils.h"
26 
27 namespace android {
28 
29 using gui::aidl_utils::statusTFromBinderStatus;
30 
31 namespace {
32 
33 // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
34 // individual pixel values for testing purposes.
35 class ScreenCapture : public RefBase {
36 public:
captureDisplay(DisplayCaptureArgs & captureArgs,ScreenCaptureResults & captureResults)37     static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
38                                    ScreenCaptureResults& captureResults) {
39         const auto sf = ComposerServiceAIDL::getComposerService();
40         SurfaceComposerClient::Transaction().apply(true);
41 
42         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
43         const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
44         binder::Status status = sf->captureDisplay(captureArgs, captureListener);
45         status_t err = statusTFromBinderStatus(status);
46         if (err != NO_ERROR) {
47             return err;
48         }
49         captureResults = captureListener->waitForResults();
50         return fenceStatus(captureResults.fenceResult);
51     }
52 
captureScreen(std::unique_ptr<ScreenCapture> * sc)53     static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
54         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);
59     }
60 
captureScreen(std::unique_ptr<ScreenCapture> * sc,sp<IBinder> displayToken)61     static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
62         DisplayCaptureArgs args;
63         args.displayToken = displayToken;
64         captureDisplay(sc, args);
65     }
66 
captureDisplay(std::unique_ptr<ScreenCapture> * sc,DisplayCaptureArgs & captureArgs)67     static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
68                                DisplayCaptureArgs& captureArgs) {
69         ScreenCaptureResults captureResults;
70         ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
71         *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
72                                               captureResults.capturedHdrLayers);
73     }
74 
captureLayers(LayerCaptureArgs & captureArgs,ScreenCaptureResults & captureResults)75     static status_t captureLayers(LayerCaptureArgs& captureArgs,
76                                   ScreenCaptureResults& captureResults) {
77         const auto sf = ComposerServiceAIDL::getComposerService();
78         SurfaceComposerClient::Transaction().apply(true);
79 
80         captureArgs.dataspace = ui::Dataspace::V0_SRGB;
81         const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
82         binder::Status status = sf->captureLayers(captureArgs, captureListener);
83         status_t err = statusTFromBinderStatus(status);
84         if (err != NO_ERROR) {
85             return err;
86         }
87         captureResults = captureListener->waitForResults();
88         return fenceStatus(captureResults.fenceResult);
89     }
90 
captureLayers(std::unique_ptr<ScreenCapture> * sc,LayerCaptureArgs & captureArgs)91     static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
92         ScreenCaptureResults captureResults;
93         ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
94         *sc = std::make_unique<ScreenCapture>(captureResults.buffer,
95                                               captureResults.capturedHdrLayers);
96     }
97 
capturedHdrLayers()98     bool capturedHdrLayers() const { return mContainsHdr; }
99 
100     void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
101         ASSERT_NE(nullptr, mOutBuffer);
102         ASSERT_NE(nullptr, mPixels);
103         ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
104         TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
105     }
106 
107     void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
108         ASSERT_NE(nullptr, mOutBuffer);
109         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 
checkPixel(uint32_t x,uint32_t y,uint8_t r,uint8_t g,uint8_t b)165     void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
166         ASSERT_NE(nullptr, mOutBuffer);
167         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]));
173             EXPECT_EQ(String8(), err) << err.c_str();
174         }
175     }
176 
getPixelColor(uint32_t x,uint32_t y)177     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 
expectFGColor(uint32_t x,uint32_t y)186     void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
187 
expectBGColor(uint32_t x,uint32_t y)188     void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
189 
expectChildColor(uint32_t x,uint32_t y)190     void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
191 
expectSize(uint32_t width,uint32_t height)192     void expectSize(uint32_t width, uint32_t height) {
193         EXPECT_EQ(width, mOutBuffer->getWidth());
194         EXPECT_EQ(height, mOutBuffer->getHeight());
195     }
196 
ScreenCapture(const sp<GraphicBuffer> & outBuffer,bool containsHdr)197     explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer, bool containsHdr)
198           : mOutBuffer(outBuffer), mContainsHdr(containsHdr) {
199         if (mOutBuffer) {
200             mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
201         }
202     }
203 
~ScreenCapture()204     ~ScreenCapture() {
205         if (mOutBuffer) mOutBuffer->unlock();
206     }
207 
208 private:
209     sp<GraphicBuffer> mOutBuffer;
210     bool mContainsHdr = mContainsHdr;
211     uint8_t* mPixels = nullptr;
212 };
213 } // namespace
214 } // namespace android
215