blob: 3cbfed98f53b9cead1c99eb16da6fc772b55a68e [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
17#pragma once
18
Marin Shalamanov30b0b3c2020-10-13 19:15:06 +020019#pragma clang diagnostic push
20#pragma clang diagnostic ignored "-Wconversion"
Marin Shalamanovbed7fd32020-12-21 20:02:20 +010021#pragma clang diagnostic ignored "-Wextra"
Marin Shalamanov30b0b3c2020-10-13 19:15:06 +020022
Valerie Haue9137b72019-08-27 13:22:18 -070023#include <chrono>
Valerie Haue9137b72019-08-27 13:22:18 -070024
25#include <android/native_window.h>
Valerie Haue9137b72019-08-27 13:22:18 -070026#include <binder/IPCThreadState.h>
Peiyong Line9d809e2020-04-14 13:10:48 -070027#include <gtest/gtest.h>
Valerie Haue9137b72019-08-27 13:22:18 -070028#include <gui/Surface.h>
29#include <gui/SurfaceComposerClient.h>
Valerie Haue9137b72019-08-27 13:22:18 -070030#include <private/gui/ComposerService.h>
Valerie Haue9137b72019-08-27 13:22:18 -070031#include <ui/GraphicBuffer.h>
32#include <ui/Rect.h>
33
34#include "ColorUtils.h"
Valerie Haue9137b72019-08-27 13:22:18 -070035
36namespace android {
37
38namespace {
39
40using namespace std::chrono_literals;
Valerie Haue271df92019-09-06 09:23:22 -070041using Transaction = SurfaceComposerClient::Transaction;
Valerie Haue9137b72019-08-27 13:22:18 -070042
43std::ostream& operator<<(std::ostream& os, const Color& color) {
44 os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
45 return os;
46}
47
Valerie Haue271df92019-09-06 09:23:22 -070048class TransactionUtils {
49public:
50 // Fill a region with the specified color.
51 static void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
52 const Color& color) {
53 Rect r(0, 0, buffer.width, buffer.height);
54 if (!r.intersect(rect, &r)) {
55 return;
56 }
Valerie Haue9137b72019-08-27 13:22:18 -070057
Valerie Haue271df92019-09-06 09:23:22 -070058 int32_t width = r.right - r.left;
59 int32_t height = r.bottom - r.top;
Valerie Haue9137b72019-08-27 13:22:18 -070060
Valerie Haue271df92019-09-06 09:23:22 -070061 for (int32_t row = 0; row < height; row++) {
62 uint8_t* dst = static_cast<uint8_t*>(buffer.bits) +
63 (buffer.stride * (r.top + row) + r.left) * 4;
64 for (int32_t column = 0; column < width; column++) {
65 dst[0] = color.r;
66 dst[1] = color.g;
67 dst[2] = color.b;
68 dst[3] = color.a;
69 dst += 4;
70 }
Valerie Haue9137b72019-08-27 13:22:18 -070071 }
72 }
Valerie Haue9137b72019-08-27 13:22:18 -070073
Valerie Haue271df92019-09-06 09:23:22 -070074 // Fill a region with the specified color.
75 static void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect,
76 const Color& color) {
77 Rect r(0, 0, buffer->width, buffer->height);
78 if (!r.intersect(rect, &r)) {
79 return;
80 }
81
82 int32_t width = r.right - r.left;
83 int32_t height = r.bottom - r.top;
84
85 uint8_t* pixels;
86 buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
87 reinterpret_cast<void**>(&pixels));
88
89 for (int32_t row = 0; row < height; row++) {
90 uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
91 for (int32_t column = 0; column < width; column++) {
92 dst[0] = color.r;
93 dst[1] = color.g;
94 dst[2] = color.b;
95 dst[3] = color.a;
96 dst += 4;
97 }
98 }
99 buffer->unlock();
Valerie Haue9137b72019-08-27 13:22:18 -0700100 }
101
Valerie Haue271df92019-09-06 09:23:22 -0700102 // Check if a region has the specified color.
103 static void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels,
104 const Rect& rect, const Color& color, uint8_t tolerance) {
105 int32_t x = rect.left;
106 int32_t y = rect.top;
107 int32_t width = rect.right - rect.left;
108 int32_t height = rect.bottom - rect.top;
Valerie Haue9137b72019-08-27 13:22:18 -0700109
Valerie Haue271df92019-09-06 09:23:22 -0700110 int32_t bufferWidth = int32_t(outBuffer->getWidth());
111 int32_t bufferHeight = int32_t(outBuffer->getHeight());
112 if (x + width > bufferWidth) {
113 x = std::min(x, bufferWidth);
114 width = bufferWidth - x;
115 }
116 if (y + height > bufferHeight) {
117 y = std::min(y, bufferHeight);
118 height = bufferHeight - y;
119 }
Valerie Haue9137b72019-08-27 13:22:18 -0700120
Valerie Haue271df92019-09-06 09:23:22 -0700121 auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
122 uint8_t tmp = a >= b ? a - b : b - a;
123 return tmp <= tolerance;
124 };
125 for (int32_t j = 0; j < height; j++) {
126 const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
127 for (int32_t i = 0; i < width; i++) {
128 const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
129 EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
130 << "pixel @ (" << x + i << ", " << y + j << "): "
131 << "expected (" << color << "), "
132 << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
133 src += 4;
134 }
Valerie Haue9137b72019-08-27 13:22:18 -0700135 }
136 }
Valerie Haue9137b72019-08-27 13:22:18 -0700137
Vishnu Nairefc42e22019-12-03 17:36:12 -0800138 static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const Color& color,
139 bool unlock = true) {
140 fillSurfaceRGBA8(sc, color.r, color.g, color.b, unlock);
141 }
142
Valerie Haue271df92019-09-06 09:23:22 -0700143 // Fill an RGBA_8888 formatted surface with a single color.
144 static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
145 bool unlock = true) {
146 ANativeWindow_Buffer outBuffer;
147 sp<Surface> s = sc->getSurface();
148 ASSERT_TRUE(s != nullptr);
149 ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
150 uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
151 for (int y = 0; y < outBuffer.height; y++) {
152 for (int x = 0; x < outBuffer.width; x++) {
153 uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
154 pixel[0] = r;
155 pixel[1] = g;
156 pixel[2] = b;
157 pixel[3] = 255;
158 }
159 }
160 if (unlock) {
161 ASSERT_EQ(NO_ERROR, s->unlockAndPost());
Valerie Haue9137b72019-08-27 13:22:18 -0700162 }
163 }
Valerie Haue271df92019-09-06 09:23:22 -0700164};
Valerie Haue9137b72019-08-27 13:22:18 -0700165
166enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
167
168// Environment for starting up binder threads. This is required for testing
169// virtual displays, as BufferQueue parameters may be queried over binder.
170class BinderEnvironment : public ::testing::Environment {
171public:
172 void SetUp() override { ProcessState::self()->startThreadPool(); }
173};
174
175/** RAII Wrapper around get/seteuid */
176class UIDFaker {
177 uid_t oldId;
178
179public:
180 UIDFaker(uid_t uid) {
181 oldId = geteuid();
182 seteuid(uid);
183 }
184 ~UIDFaker() { seteuid(oldId); }
185};
186} // namespace
187} // namespace android
Marin Shalamanov30b0b3c2020-10-13 19:15:06 +0200188
189// TODO(b/129481165): remove the #pragma below and fix conversion issues
Marin Shalamanovbed7fd32020-12-21 20:02:20 +0100190#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"