1 /* 2 * Copyright (C) 2012 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 <GLES2/gl2.h> 18 #include <GLES2/gl2ext.h> 19 20 #include <ui/DisplayInfo.h> 21 #include <gui/SurfaceComposerClient.h> 22 23 #include "GLHelper.h" 24 25 namespace android { 26 27 GLHelper::GLHelper() : 28 mDisplay(EGL_NO_DISPLAY), 29 mContext(EGL_NO_CONTEXT), 30 mDummySurface(EGL_NO_SURFACE), 31 mConfig(0), 32 mShaderPrograms(NULL), 33 mDitherTexture(0) { 34 } 35 36 GLHelper::~GLHelper() { 37 } 38 39 bool GLHelper::setUp(const ShaderDesc* shaderDescs, size_t numShaders) { 40 bool result; 41 42 mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 43 if (mDisplay == EGL_NO_DISPLAY) { 44 fprintf(stderr, "eglGetDisplay error: %#x\n", eglGetError()); 45 return false; 46 } 47 48 EGLint majorVersion; 49 EGLint minorVersion; 50 result = eglInitialize(mDisplay, &majorVersion, &minorVersion); 51 if (result != EGL_TRUE) { 52 fprintf(stderr, "eglInitialize error: %#x\n", eglGetError()); 53 return false; 54 } 55 56 EGLint numConfigs = 0; 57 EGLint configAttribs[] = { 58 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 59 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 60 EGL_RED_SIZE, 8, 61 EGL_GREEN_SIZE, 8, 62 EGL_BLUE_SIZE, 8, 63 EGL_ALPHA_SIZE, 8, 64 EGL_NONE 65 }; 66 result = eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, 67 &numConfigs); 68 if (result != EGL_TRUE) { 69 fprintf(stderr, "eglChooseConfig error: %#x\n", eglGetError()); 70 return false; 71 } 72 73 EGLint contextAttribs[] = { 74 EGL_CONTEXT_CLIENT_VERSION, 2, 75 EGL_NONE 76 }; 77 mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, 78 contextAttribs); 79 if (mContext == EGL_NO_CONTEXT) { 80 fprintf(stderr, "eglCreateContext error: %#x\n", eglGetError()); 81 return false; 82 } 83 84 bool resultb = createNamedSurfaceTexture(0, 1, 1, &mDummyGLConsumer, 85 &mDummySurface); 86 if (!resultb) { 87 return false; 88 } 89 90 resultb = makeCurrent(mDummySurface); 91 if (!resultb) { 92 return false; 93 } 94 95 resultb = setUpShaders(shaderDescs, numShaders); 96 if (!resultb) { 97 return false; 98 } 99 100 return true; 101 } 102 103 void GLHelper::tearDown() { 104 if (mShaderPrograms != NULL) { 105 delete[] mShaderPrograms; 106 mShaderPrograms = NULL; 107 } 108 109 if (mSurfaceComposerClient != NULL) { 110 mSurfaceComposerClient->dispose(); 111 mSurfaceComposerClient.clear(); 112 } 113 114 if (mDisplay != EGL_NO_DISPLAY) { 115 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 116 EGL_NO_CONTEXT); 117 } 118 119 if (mContext != EGL_NO_CONTEXT) { 120 eglDestroyContext(mDisplay, mContext); 121 } 122 123 if (mDummySurface != EGL_NO_SURFACE) { 124 eglDestroySurface(mDisplay, mDummySurface); 125 } 126 127 mDisplay = EGL_NO_DISPLAY; 128 mContext = EGL_NO_CONTEXT; 129 mDummySurface = EGL_NO_SURFACE; 130 mDummyGLConsumer.clear(); 131 mConfig = 0; 132 } 133 134 bool GLHelper::makeCurrent(EGLSurface surface) { 135 EGLint result; 136 137 result = eglMakeCurrent(mDisplay, surface, surface, mContext); 138 if (result != EGL_TRUE) { 139 fprintf(stderr, "eglMakeCurrent error: %#x\n", eglGetError()); 140 return false; 141 } 142 143 EGLint w, h; 144 eglQuerySurface(mDisplay, surface, EGL_WIDTH, &w); 145 eglQuerySurface(mDisplay, surface, EGL_HEIGHT, &h); 146 glViewport(0, 0, w, h); 147 148 return true; 149 } 150 151 bool GLHelper::createSurfaceTexture(uint32_t w, uint32_t h, 152 sp<GLConsumer>* glConsumer, EGLSurface* surface, 153 GLuint* name) { 154 if (!makeCurrent(mDummySurface)) { 155 return false; 156 } 157 158 *name = 0; 159 glGenTextures(1, name); 160 if (*name == 0) { 161 fprintf(stderr, "glGenTextures error: %#x\n", glGetError()); 162 return false; 163 } 164 165 return createNamedSurfaceTexture(*name, w, h, glConsumer, surface); 166 } 167 168 void GLHelper::destroySurface(EGLSurface* surface) { 169 if (eglGetCurrentSurface(EGL_READ) == *surface || 170 eglGetCurrentSurface(EGL_DRAW) == *surface) { 171 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 172 EGL_NO_CONTEXT); 173 } 174 eglDestroySurface(mDisplay, *surface); 175 *surface = EGL_NO_SURFACE; 176 } 177 178 bool GLHelper::swapBuffers(EGLSurface surface) { 179 EGLint result; 180 result = eglSwapBuffers(mDisplay, surface); 181 if (result != EGL_TRUE) { 182 fprintf(stderr, "eglSwapBuffers error: %#x\n", eglGetError()); 183 return false; 184 } 185 return true; 186 } 187 188 bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) { 189 for (size_t i = 0; i < mNumShaders; i++) { 190 if (strcmp(mShaderDescs[i].name, name) == 0) { 191 *outPgm = mShaderPrograms[i]; 192 return true; 193 } 194 } 195 196 fprintf(stderr, "unknown shader name: \"%s\"\n", name); 197 198 return false; 199 } 200 201 bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, 202 sp<GLConsumer>* glConsumer, EGLSurface* surface) { 203 sp<IGraphicBufferProducer> producer; 204 sp<IGraphicBufferConsumer> consumer; 205 BufferQueue::createBufferQueue(&producer, &consumer); 206 sp<GLConsumer> glc = new GLConsumer(consumer, name, 207 GL_TEXTURE_EXTERNAL_OES, false, true); 208 glc->setDefaultBufferSize(w, h); 209 producer->setMaxDequeuedBufferCount(2); 210 glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); 211 212 sp<ANativeWindow> anw = new Surface(producer); 213 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); 214 if (s == EGL_NO_SURFACE) { 215 fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); 216 return false; 217 } 218 219 *glConsumer = glc; 220 *surface = s; 221 return true; 222 } 223 224 bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) { 225 sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0); 226 if (dpy == NULL) { 227 fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n"); 228 return false; 229 } 230 231 DisplayInfo info; 232 status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info); 233 if (err != NO_ERROR) { 234 fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err); 235 return false; 236 } 237 238 float scaleX = float(info.w) / float(w); 239 float scaleY = float(info.h) / float(h); 240 *scale = scaleX < scaleY ? scaleX : scaleY; 241 242 return true; 243 } 244 245 bool GLHelper::createWindowSurface(uint32_t w, uint32_t h, 246 sp<SurfaceControl>* surfaceControl, EGLSurface* surface) { 247 bool result; 248 status_t err; 249 250 if (mSurfaceComposerClient == NULL) { 251 mSurfaceComposerClient = new SurfaceComposerClient; 252 } 253 err = mSurfaceComposerClient->initCheck(); 254 if (err != NO_ERROR) { 255 fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err); 256 return false; 257 } 258 259 sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface( 260 String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0); 261 if (sc == NULL || !sc->isValid()) { 262 fprintf(stderr, "Failed to create SurfaceControl.\n"); 263 return false; 264 } 265 266 float scale; 267 result = computeWindowScale(w, h, &scale); 268 if (!result) { 269 return false; 270 } 271 272 SurfaceComposerClient::openGlobalTransaction(); 273 err = sc->setLayer(0x7FFFFFFF); 274 if (err != NO_ERROR) { 275 fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err); 276 return false; 277 } 278 err = sc->setMatrix(scale, 0.0f, 0.0f, scale); 279 if (err != NO_ERROR) { 280 fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err); 281 return false; 282 } 283 284 err = sc->show(); 285 if (err != NO_ERROR) { 286 fprintf(stderr, "SurfaceComposer::show error: %#x\n", err); 287 return false; 288 } 289 SurfaceComposerClient::closeGlobalTransaction(); 290 291 sp<ANativeWindow> anw = sc->getSurface(); 292 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); 293 if (s == EGL_NO_SURFACE) { 294 fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); 295 return false; 296 } 297 298 *surfaceControl = sc; 299 *surface = s; 300 return true; 301 } 302 303 static bool compileShader(GLenum shaderType, const char* src, 304 GLuint* outShader) { 305 GLuint shader = glCreateShader(shaderType); 306 if (shader == 0) { 307 fprintf(stderr, "glCreateShader error: %#x\n", glGetError()); 308 return false; 309 } 310 311 glShaderSource(shader, 1, &src, NULL); 312 glCompileShader(shader); 313 314 GLint compiled = 0; 315 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 316 if (!compiled) { 317 GLint infoLen = 0; 318 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 319 if (infoLen) { 320 char* buf = new char[infoLen]; 321 if (buf) { 322 glGetShaderInfoLog(shader, infoLen, NULL, buf); 323 fprintf(stderr, "Shader compile log:\n%s\n", buf); 324 delete[] buf; 325 } 326 } 327 glDeleteShader(shader); 328 return false; 329 } 330 *outShader = shader; 331 return true; 332 } 333 334 static void printShaderSource(const char* const* src) { 335 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 336 fprintf(stderr, "%3zu: %s\n", i+1, src[i]); 337 } 338 } 339 340 static const char* makeShaderString(const char* const* src) { 341 size_t len = 0; 342 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 343 // The +1 is for the '\n' that will be added. 344 len += strlen(src[i]) + 1; 345 } 346 347 char* result = new char[len+1]; 348 char* end = result; 349 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 350 strcpy(end, src[i]); 351 end += strlen(src[i]); 352 *end = '\n'; 353 end++; 354 } 355 *end = '\0'; 356 357 return result; 358 } 359 360 static bool compileShaderLines(GLenum shaderType, const char* const* lines, 361 GLuint* outShader) { 362 const char* src = makeShaderString(lines); 363 bool result = compileShader(shaderType, src, outShader); 364 if (!result) { 365 fprintf(stderr, "Shader source:\n"); 366 printShaderSource(lines); 367 delete[] src; 368 return false; 369 } 370 delete[] src; 371 372 return true; 373 } 374 375 static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) { 376 GLuint program = glCreateProgram(); 377 if (program == 0) { 378 fprintf(stderr, "glCreateProgram error: %#x\n", glGetError()); 379 return false; 380 } 381 382 glAttachShader(program, vs); 383 glAttachShader(program, fs); 384 glLinkProgram(program); 385 GLint linkStatus = GL_FALSE; 386 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 387 if (linkStatus != GL_TRUE) { 388 GLint bufLength = 0; 389 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); 390 if (bufLength) { 391 char* buf = new char[bufLength]; 392 if (buf) { 393 glGetProgramInfoLog(program, bufLength, NULL, buf); 394 fprintf(stderr, "Program link log:\n%s\n", buf); 395 delete[] buf; 396 } 397 } 398 glDeleteProgram(program); 399 program = 0; 400 } 401 402 *outPgm = program; 403 return program != 0; 404 } 405 406 bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) { 407 mShaderPrograms = new GLuint[numShaders]; 408 bool result = true; 409 410 for (size_t i = 0; i < numShaders && result; i++) { 411 GLuint vs, fs; 412 413 result = compileShaderLines(GL_VERTEX_SHADER, 414 shaderDescs[i].vertexShader, &vs); 415 if (!result) { 416 return false; 417 } 418 419 result = compileShaderLines(GL_FRAGMENT_SHADER, 420 shaderDescs[i].fragmentShader, &fs); 421 if (!result) { 422 glDeleteShader(vs); 423 return false; 424 } 425 426 result = linkShaderProgram(vs, fs, &mShaderPrograms[i]); 427 glDeleteShader(vs); 428 glDeleteShader(fs); 429 } 430 431 mNumShaders = numShaders; 432 mShaderDescs = shaderDescs; 433 434 return result; 435 } 436 437 bool GLHelper::getDitherTexture(GLuint* outTexName) { 438 if (mDitherTexture == 0) { 439 const uint8_t pattern[] = { 440 0, 8, 2, 10, 441 12, 4, 14, 6, 442 3, 11, 1, 9, 443 15, 7, 13, 5 444 }; 445 446 glGenTextures(1, &mDitherTexture); 447 glBindTexture(GL_TEXTURE_2D, mDitherTexture); 448 449 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 450 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 451 452 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 453 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 454 455 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, 456 DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern); 457 } 458 459 *outTexName = mDitherTexture; 460 461 return true; 462 } 463 464 } 465