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