1 /*
2 * Copyright 2013 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 #include "GLTest.h"
18
19 #include <gui/Surface.h>
20
21 #include <GLES2/gl2.h>
22
23 namespace android {
24
25 using Transaction = SurfaceComposerClient::Transaction;
26
abs(int value)27 static int abs(int value) {
28 return value > 0 ? value : -value;
29 }
30
SetUp()31 void GLTest::SetUp() {
32 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
33 ASSERT_EQ(EGL_SUCCESS, eglGetError());
34 ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
35
36 EGLint majorVersion;
37 EGLint minorVersion;
38 EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
39 ASSERT_EQ(EGL_SUCCESS, eglGetError());
40 RecordProperty("EglVersionMajor", majorVersion);
41 RecordProperty("EglVersionMinor", minorVersion);
42
43 EGLint numConfigs = 0;
44 EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig, 1,
45 &numConfigs));
46 ASSERT_EQ(EGL_SUCCESS, eglGetError());
47
48 char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
49 if (displaySecsEnv != nullptr) {
50 mDisplaySecs = atoi(displaySecsEnv);
51 if (mDisplaySecs < 0) {
52 mDisplaySecs = 0;
53 }
54 } else {
55 mDisplaySecs = 0;
56 }
57
58 if (mDisplaySecs > 0) {
59 mComposerClient = new SurfaceComposerClient;
60 ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
61
62 mSurfaceControl = mComposerClient->createSurface(
63 String8("Test Surface"), getSurfaceWidth(), getSurfaceHeight(),
64 PIXEL_FORMAT_RGB_888, 0);
65
66 ASSERT_TRUE(mSurfaceControl != nullptr);
67 ASSERT_TRUE(mSurfaceControl->isValid());
68
69 Transaction t;
70 ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF)
71 .show(mSurfaceControl)
72 .apply());
73
74 sp<ANativeWindow> window = mSurfaceControl->getSurface();
75 mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window);
76 } else {
77 EGLint pbufferAttribs[] = {
78 EGL_WIDTH, getSurfaceWidth(),
79 EGL_HEIGHT, getSurfaceHeight(),
80 EGL_NONE };
81
82 mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
83 pbufferAttribs);
84 }
85 ASSERT_EQ(EGL_SUCCESS, eglGetError());
86 ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
87
88 mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT,
89 getContextAttribs());
90 ASSERT_EQ(EGL_SUCCESS, eglGetError());
91 ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
92
93 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
94 mEglContext));
95 ASSERT_EQ(EGL_SUCCESS, eglGetError());
96
97 EGLint w, h;
98 EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
99 ASSERT_EQ(EGL_SUCCESS, eglGetError());
100 EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
101 ASSERT_EQ(EGL_SUCCESS, eglGetError());
102 RecordProperty("EglSurfaceWidth", w);
103 RecordProperty("EglSurfaceHeight", h);
104
105 glViewport(0, 0, w, h);
106 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
107 }
108
TearDown()109 void GLTest::TearDown() {
110 // Display the result
111 if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) {
112 eglSwapBuffers(mEglDisplay, mEglSurface);
113 sleep(mDisplaySecs);
114 }
115
116 if (mComposerClient != nullptr) {
117 mComposerClient->dispose();
118 }
119 if (mEglContext != EGL_NO_CONTEXT) {
120 eglDestroyContext(mEglDisplay, mEglContext);
121 }
122 if (mEglSurface != EGL_NO_SURFACE) {
123 eglDestroySurface(mEglDisplay, mEglSurface);
124 }
125 if (mEglDisplay != EGL_NO_DISPLAY) {
126 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
127 EGL_NO_CONTEXT);
128 eglTerminate(mEglDisplay);
129 }
130 ASSERT_EQ(EGL_SUCCESS, eglGetError());
131 }
132
getConfigAttribs()133 EGLint const* GLTest::getConfigAttribs() {
134 static const EGLint sDefaultConfigAttribs[] = {
135 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
136 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
137 EGL_RED_SIZE, 8,
138 EGL_GREEN_SIZE, 8,
139 EGL_BLUE_SIZE, 8,
140 EGL_ALPHA_SIZE, 8,
141 EGL_DEPTH_SIZE, 16,
142 EGL_STENCIL_SIZE, 8,
143 EGL_NONE };
144
145 return sDefaultConfigAttribs;
146 }
147
getContextAttribs()148 EGLint const* GLTest::getContextAttribs() {
149 static const EGLint sDefaultContextAttribs[] = {
150 EGL_CONTEXT_CLIENT_VERSION, 2,
151 EGL_NONE };
152
153 return sDefaultContextAttribs;
154 }
155
getSurfaceWidth()156 EGLint GLTest::getSurfaceWidth() {
157 return 512;
158 }
159
getSurfaceHeight()160 EGLint GLTest::getSurfaceHeight() {
161 return 512;
162 }
163
createWindowSurface(EGLDisplay display,EGLConfig config,sp<ANativeWindow> & window) const164 EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config,
165 sp<ANativeWindow>& window) const {
166 return eglCreateWindowSurface(display, config, window.get(), nullptr);
167 }
168
checkPixel(int x,int y,int r,int g,int b,int a,int tolerance)169 ::testing::AssertionResult GLTest::checkPixel(int x, int y,
170 int r, int g, int b, int a, int tolerance) {
171 GLubyte pixel[4];
172 String8 msg;
173 glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
174 GLenum err = glGetError();
175 if (err != GL_NO_ERROR) {
176 msg += String8::format("error reading pixel: %#x", err);
177 while ((err = glGetError()) != GL_NO_ERROR) {
178 msg += String8::format(", %#x", err);
179 }
180 return ::testing::AssertionFailure(::testing::Message(msg.c_str()));
181 }
182 if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
183 msg += String8::format("r(%d isn't %d)", pixel[0], r);
184 }
185 if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
186 if (!msg.empty()) {
187 msg += " ";
188 }
189 msg += String8::format("g(%d isn't %d)", pixel[1], g);
190 }
191 if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
192 if (!msg.empty()) {
193 msg += " ";
194 }
195 msg += String8::format("b(%d isn't %d)", pixel[2], b);
196 }
197 if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
198 if (!msg.empty()) {
199 msg += " ";
200 }
201 msg += String8::format("a(%d isn't %d)", pixel[3], a);
202 }
203 if (!msg.empty()) {
204 return ::testing::AssertionFailure(::testing::Message(msg.c_str()));
205 } else {
206 return ::testing::AssertionSuccess();
207 }
208 }
209
assertRectEq(const Rect & r1,const Rect & r2,int tolerance)210 ::testing::AssertionResult GLTest::assertRectEq(const Rect &r1, const Rect &r2,
211 int tolerance) {
212 String8 msg;
213
214 if (abs(r1.left - r2.left) > tolerance) {
215 msg += String8::format("left(%d isn't %d)", r1.left, r2.left);
216 }
217 if (abs(r1.top - r2.top) > tolerance) {
218 if (!msg.empty()) {
219 msg += " ";
220 }
221 msg += String8::format("top(%d isn't %d)", r1.top, r2.top);
222 }
223 if (abs(r1.right - r2.right) > tolerance) {
224 if (!msg.empty()) {
225 msg += " ";
226 }
227 msg += String8::format("right(%d isn't %d)", r1.right, r2.right);
228 }
229 if (abs(r1.bottom - r2.bottom) > tolerance) {
230 if (!msg.empty()) {
231 msg += " ";
232 }
233 msg += String8::format("bottom(%d isn't %d)", r1.bottom, r2.bottom);
234 }
235 if (!msg.empty()) {
236 msg += String8::format(" R1: [%d %d %d %d] R2: [%d %d %d %d]",
237 r1.left, r1.top, r1.right, r1.bottom,
238 r2.left, r2.top, r2.right, r2.bottom);
239 fprintf(stderr, "assertRectEq: %s\n", msg.c_str());
240 return ::testing::AssertionFailure(::testing::Message(msg.c_str()));
241 } else {
242 return ::testing::AssertionSuccess();
243 }
244 }
245
loadShader(GLenum shaderType,const char * pSource,GLuint * outShader)246 void GLTest::loadShader(GLenum shaderType, const char* pSource,
247 GLuint* outShader) {
248 GLuint shader = glCreateShader(shaderType);
249 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
250 if (shader) {
251 glShaderSource(shader, 1, &pSource, nullptr);
252 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
253 glCompileShader(shader);
254 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
255 GLint compiled = 0;
256 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
257 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
258 if (!compiled) {
259 GLint infoLen = 0;
260 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
261 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
262 if (infoLen) {
263 char* buf = (char*) malloc(infoLen);
264 if (buf) {
265 glGetShaderInfoLog(shader, infoLen, nullptr, buf);
266 printf("Shader compile log:\n%s\n", buf);
267 free(buf);
268 FAIL();
269 }
270 } else {
271 char* buf = (char*) malloc(0x1000);
272 if (buf) {
273 glGetShaderInfoLog(shader, 0x1000, nullptr, buf);
274 printf("Shader compile log:\n%s\n", buf);
275 free(buf);
276 FAIL();
277 }
278 }
279 glDeleteShader(shader);
280 shader = 0;
281 }
282 }
283 ASSERT_TRUE(shader != 0);
284 *outShader = shader;
285 }
286
createProgram(const char * pVertexSource,const char * pFragmentSource,GLuint * outPgm)287 void GLTest::createProgram(const char* pVertexSource,
288 const char* pFragmentSource, GLuint* outPgm) {
289 GLuint vertexShader, fragmentShader;
290 {
291 SCOPED_TRACE("compiling vertex shader");
292 ASSERT_NO_FATAL_FAILURE(loadShader(GL_VERTEX_SHADER, pVertexSource,
293 &vertexShader));
294 }
295 {
296 SCOPED_TRACE("compiling fragment shader");
297 ASSERT_NO_FATAL_FAILURE(loadShader(GL_FRAGMENT_SHADER, pFragmentSource,
298 &fragmentShader));
299 }
300
301 GLuint program = glCreateProgram();
302 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
303 if (program) {
304 glAttachShader(program, vertexShader);
305 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
306 glAttachShader(program, fragmentShader);
307 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
308 glLinkProgram(program);
309 GLint linkStatus = GL_FALSE;
310 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
311 if (linkStatus != GL_TRUE) {
312 GLint bufLength = 0;
313 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
314 if (bufLength) {
315 char* buf = (char*) malloc(bufLength);
316 if (buf) {
317 glGetProgramInfoLog(program, bufLength, nullptr, buf);
318 printf("Program link log:\n%s\n", buf);
319 free(buf);
320 FAIL();
321 }
322 }
323 glDeleteProgram(program);
324 program = 0;
325 }
326 }
327 glDeleteShader(vertexShader);
328 glDeleteShader(fragmentShader);
329 ASSERT_TRUE(program != 0);
330 *outPgm = program;
331 }
332
333 } // namespace android
334