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
23namespace android {
24
25static int abs(int value) {
26    return value > 0 ? value : -value;
27}
28
29void 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
111void 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
139EGLint 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
154EGLint const* GLTest::getContextAttribs() {
155    static const EGLint sDefaultContextAttribs[] = {
156        EGL_CONTEXT_CLIENT_VERSION, 2,
157        EGL_NONE };
158
159    return sDefaultContextAttribs;
160}
161
162EGLint GLTest::getSurfaceWidth() {
163    return 512;
164}
165
166EGLint GLTest::getSurfaceHeight() {
167    return 512;
168}
169
170EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config,
171                                       sp<ANativeWindow>& window) const {
172    return eglCreateWindowSurface(display, config, window.get(), NULL);
173}
174
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
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
252void 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
293void 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