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