| Dan Stoza | cb1fcde | 2013-12-03 12:37:36 -0800 | [diff] [blame] | 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 |  | 
| Dan Stoza | f3730fb | 2013-11-26 15:10:10 -0800 | [diff] [blame] | 17 | #include "GLTest.h" | 
 | 18 |  | 
 | 19 | #include <gui/Surface.h> | 
 | 20 |  | 
 | 21 | #include <GLES2/gl2.h> | 
 | 22 |  | 
 | 23 | namespace android { | 
 | 24 |  | 
 | 25 | static int abs(int value) { | 
 | 26 |     return value > 0 ? value : -value; | 
 | 27 | } | 
 | 28 |  | 
 | 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 |  | 
 | 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 |  | 
 | 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 |  | 
 | 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 |  | 
 | 162 | EGLint GLTest::getSurfaceWidth() { | 
 | 163 |     return 512; | 
 | 164 | } | 
 | 165 |  | 
 | 166 | EGLint GLTest::getSurfaceHeight() { | 
 | 167 |     return 512; | 
 | 168 | } | 
 | 169 |  | 
 | 170 | EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config, | 
 | 171 |                                        sp<ANativeWindow>& window) const { | 
| Dan Stoza | f3730fb | 2013-11-26 15:10:10 -0800 | [diff] [blame] | 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 |  | 
 | 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 |  | 
 | 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 |