blob: f6b33a9bc3b68c58589880abdc3eabdf696ff5a8 [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
19//#include <algorithm>
20#include <chrono>
21//#include <cinttypes>
22//#include <functional>
23//#include <limits>
24//#include <ostream>
25//#include <thread>
26#include <gtest/gtest.h>
27
28#include <android/native_window.h>
29#include <hardware/hwcomposer_defs.h>
30
31#include <binder/IPCThreadState.h>
32
33#include <gui/Surface.h>
34#include <gui/SurfaceComposerClient.h>
35
36#include <private/gui/ComposerService.h>
37
38#include <ui/GraphicBuffer.h>
39#include <ui/Rect.h>
40
41#include "ColorUtils.h"
42//#include <sys/types.h>
43//#include <unistd.h>
44
45namespace android {
46
47namespace {
48
49using namespace std::chrono_literals;
50
51std::ostream& operator<<(std::ostream& os, const Color& color) {
52 os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
53 return os;
54}
55
56// Fill a region with the specified color.
57void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
58 const Color& color) {
59 Rect r(0, 0, buffer.width, buffer.height);
60 if (!r.intersect(rect, &r)) {
61 return;
62 }
63
64 int32_t width = r.right - r.left;
65 int32_t height = r.bottom - r.top;
66
67 for (int32_t row = 0; row < height; row++) {
68 uint8_t* dst =
69 static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4;
70 for (int32_t column = 0; column < width; column++) {
71 dst[0] = color.r;
72 dst[1] = color.g;
73 dst[2] = color.b;
74 dst[3] = color.a;
75 dst += 4;
76 }
77 }
78}
79
80// Fill a region with the specified color.
81void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect, const Color& color) {
82 Rect r(0, 0, buffer->width, buffer->height);
83 if (!r.intersect(rect, &r)) {
84 return;
85 }
86
87 int32_t width = r.right - r.left;
88 int32_t height = r.bottom - r.top;
89
90 uint8_t* pixels;
91 buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
92 reinterpret_cast<void**>(&pixels));
93
94 for (int32_t row = 0; row < height; row++) {
95 uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
96 for (int32_t column = 0; column < width; column++) {
97 dst[0] = color.r;
98 dst[1] = color.g;
99 dst[2] = color.b;
100 dst[3] = color.a;
101 dst += 4;
102 }
103 }
104 buffer->unlock();
105}
106
107// Check if a region has the specified color.
108void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels, const Rect& rect,
109 const Color& color, uint8_t tolerance) {
110 int32_t x = rect.left;
111 int32_t y = rect.top;
112 int32_t width = rect.right - rect.left;
113 int32_t height = rect.bottom - rect.top;
114
115 int32_t bufferWidth = int32_t(outBuffer->getWidth());
116 int32_t bufferHeight = int32_t(outBuffer->getHeight());
117 if (x + width > bufferWidth) {
118 x = std::min(x, bufferWidth);
119 width = bufferWidth - x;
120 }
121 if (y + height > bufferHeight) {
122 y = std::min(y, bufferHeight);
123 height = bufferHeight - y;
124 }
125
126 auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
127 uint8_t tmp = a >= b ? a - b : b - a;
128 return tmp <= tolerance;
129 };
130 for (int32_t j = 0; j < height; j++) {
131 const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
132 for (int32_t i = 0; i < width; i++) {
133 const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
134 EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
135 << "pixel @ (" << x + i << ", " << y + j << "): "
136 << "expected (" << color << "), "
137 << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
138 src += 4;
139 }
140 }
141}
142
143using Transaction = SurfaceComposerClient::Transaction;
144
145// Fill an RGBA_8888 formatted surface with a single color.
146static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
147 bool unlock = true) {
148 ANativeWindow_Buffer outBuffer;
149 sp<Surface> s = sc->getSurface();
150 ASSERT_TRUE(s != nullptr);
151 ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
152 uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
153 for (int y = 0; y < outBuffer.height; y++) {
154 for (int x = 0; x < outBuffer.width; x++) {
155 uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
156 pixel[0] = r;
157 pixel[1] = g;
158 pixel[2] = b;
159 pixel[3] = 255;
160 }
161 }
162 if (unlock) {
163 ASSERT_EQ(NO_ERROR, s->unlockAndPost());
164 }
165}
166
167enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
168
169// Environment for starting up binder threads. This is required for testing
170// virtual displays, as BufferQueue parameters may be queried over binder.
171class BinderEnvironment : public ::testing::Environment {
172public:
173 void SetUp() override { ProcessState::self()->startThreadPool(); }
174};
175
176/** RAII Wrapper around get/seteuid */
177class UIDFaker {
178 uid_t oldId;
179
180public:
181 UIDFaker(uid_t uid) {
182 oldId = geteuid();
183 seteuid(uid);
184 }
185 ~UIDFaker() { seteuid(oldId); }
186};
187} // namespace
188} // namespace android