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