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 mGraphicBufferAlloc(new GraphicBufferAlloc()), 29 mDisplay(EGL_NO_DISPLAY), 30 mContext(EGL_NO_CONTEXT), 31 mDummySurface(EGL_NO_SURFACE), 32 mConfig(0), 33 mShaderPrograms(NULL), 34 mDitherTexture(0) { 35 } 36 37 GLHelper::~GLHelper() { 38 } 39 40 bool GLHelper::setUp(const ShaderDesc* shaderDescs, size_t numShaders) { 41 bool result; 42 43 mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 44 if (mDisplay == EGL_NO_DISPLAY) { 45 fprintf(stderr, "eglGetDisplay error: %#x\n", eglGetError()); 46 return false; 47 } 48 49 EGLint majorVersion; 50 EGLint minorVersion; 51 result = eglInitialize(mDisplay, &majorVersion, &minorVersion); 52 if (result != EGL_TRUE) { 53 fprintf(stderr, "eglInitialize error: %#x\n", eglGetError()); 54 return false; 55 } 56 57 EGLint numConfigs = 0; 58 EGLint configAttribs[] = { 59 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 60 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 61 EGL_RED_SIZE, 8, 62 EGL_GREEN_SIZE, 8, 63 EGL_BLUE_SIZE, 8, 64 EGL_ALPHA_SIZE, 8, 65 EGL_NONE 66 }; 67 result = eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, 68 &numConfigs); 69 if (result != EGL_TRUE) { 70 fprintf(stderr, "eglChooseConfig error: %#x\n", eglGetError()); 71 return false; 72 } 73 74 EGLint contextAttribs[] = { 75 EGL_CONTEXT_CLIENT_VERSION, 2, 76 EGL_NONE 77 }; 78 mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, 79 contextAttribs); 80 if (mContext == EGL_NO_CONTEXT) { 81 fprintf(stderr, "eglCreateContext error: %#x\n", eglGetError()); 82 return false; 83 } 84 85 bool resultb = createNamedSurfaceTexture(0, 1, 1, &mDummyGLConsumer, 86 &mDummySurface); 87 if (!resultb) { 88 return false; 89 } 90 91 resultb = makeCurrent(mDummySurface); 92 if (!resultb) { 93 return false; 94 } 95 96 resultb = setUpShaders(shaderDescs, numShaders); 97 if (!resultb) { 98 return false; 99 } 100 101 return true; 102 } 103 104 void GLHelper::tearDown() { 105 if (mShaderPrograms != NULL) { 106 delete[] mShaderPrograms; 107 mShaderPrograms = NULL; 108 } 109 110 if (mSurfaceComposerClient != NULL) { 111 mSurfaceComposerClient->dispose(); 112 mSurfaceComposerClient.clear(); 113 } 114 115 if (mDisplay != EGL_NO_DISPLAY) { 116 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 117 EGL_NO_CONTEXT); 118 } 119 120 if (mContext != EGL_NO_CONTEXT) { 121 eglDestroyContext(mDisplay, mContext); 122 } 123 124 if (mDummySurface != EGL_NO_SURFACE) { 125 eglDestroySurface(mDisplay, mDummySurface); 126 } 127 128 mDisplay = EGL_NO_DISPLAY; 129 mContext = EGL_NO_CONTEXT; 130 mDummySurface = EGL_NO_SURFACE; 131 mDummyGLConsumer.clear(); 132 mConfig = 0; 133 } 134 135 bool GLHelper::makeCurrent(EGLSurface surface) { 136 EGLint result; 137 138 result = eglMakeCurrent(mDisplay, surface, surface, mContext); 139 if (result != EGL_TRUE) { 140 fprintf(stderr, "eglMakeCurrent error: %#x\n", eglGetError()); 141 return false; 142 } 143 144 EGLint w, h; 145 eglQuerySurface(mDisplay, surface, EGL_WIDTH, &w); 146 eglQuerySurface(mDisplay, surface, EGL_HEIGHT, &h); 147 glViewport(0, 0, w, h); 148 149 return true; 150 } 151 152 bool GLHelper::createSurfaceTexture(uint32_t w, uint32_t h, 153 sp<GLConsumer>* glConsumer, EGLSurface* surface, 154 GLuint* name) { 155 if (!makeCurrent(mDummySurface)) { 156 return false; 157 } 158 159 *name = 0; 160 glGenTextures(1, name); 161 if (*name == 0) { 162 fprintf(stderr, "glGenTextures error: %#x\n", glGetError()); 163 return false; 164 } 165 166 return createNamedSurfaceTexture(*name, w, h, glConsumer, surface); 167 } 168 169 void GLHelper::destroySurface(EGLSurface* surface) { 170 if (eglGetCurrentSurface(EGL_READ) == *surface || 171 eglGetCurrentSurface(EGL_DRAW) == *surface) { 172 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 173 EGL_NO_CONTEXT); 174 } 175 eglDestroySurface(mDisplay, *surface); 176 *surface = EGL_NO_SURFACE; 177 } 178 179 bool GLHelper::swapBuffers(EGLSurface surface) { 180 EGLint result; 181 result = eglSwapBuffers(mDisplay, surface); 182 if (result != EGL_TRUE) { 183 fprintf(stderr, "eglSwapBuffers error: %#x\n", eglGetError()); 184 return false; 185 } 186 return true; 187 } 188 189 bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) { 190 for (size_t i = 0; i < mNumShaders; i++) { 191 if (strcmp(mShaderDescs[i].name, name) == 0) { 192 *outPgm = mShaderPrograms[i]; 193 return true; 194 } 195 } 196 197 fprintf(stderr, "unknown shader name: \"%s\"\n", name); 198 199 return false; 200 } 201 202 bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, 203 sp<GLConsumer>* glConsumer, EGLSurface* surface) { 204 sp<IGraphicBufferProducer> producer; 205 sp<IGraphicBufferConsumer> consumer; 206 BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc); 207 sp<GLConsumer> glc = new GLConsumer(consumer, name, 208 GL_TEXTURE_EXTERNAL_OES, false, true); 209 glc->setDefaultBufferSize(w, h); 210 producer->setMaxDequeuedBufferCount(2); 211 glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); 212 213 sp<ANativeWindow> anw = new Surface(producer); 214 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); 215 if (s == EGL_NO_SURFACE) { 216 fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); 217 return false; 218 } 219 220 *glConsumer = glc; 221 *surface = s; 222 return true; 223 } 224 225 bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) { 226 sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0); 227 if (dpy == NULL) { 228 fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n"); 229 return false; 230 } 231 232 DisplayInfo info; 233 status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info); 234 if (err != NO_ERROR) { 235 fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err); 236 return false; 237 } 238 239 float scaleX = float(info.w) / float(w); 240 float scaleY = float(info.h) / float(h); 241 *scale = scaleX < scaleY ? scaleX : scaleY; 242 243 return true; 244 } 245 246 bool GLHelper::createWindowSurface(uint32_t w, uint32_t h, 247 sp<SurfaceControl>* surfaceControl, EGLSurface* surface) { 248 bool result; 249 status_t err; 250 251 if (mSurfaceComposerClient == NULL) { 252 mSurfaceComposerClient = new SurfaceComposerClient; 253 } 254 err = mSurfaceComposerClient->initCheck(); 255 if (err != NO_ERROR) { 256 fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err); 257 return false; 258 } 259 260 sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface( 261 String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0); 262 if (sc == NULL || !sc->isValid()) { 263 fprintf(stderr, "Failed to create SurfaceControl.\n"); 264 return false; 265 } 266 267 float scale; 268 result = computeWindowScale(w, h, &scale); 269 if (!result) { 270 return false; 271 } 272 273 SurfaceComposerClient::openGlobalTransaction(); 274 err = sc->setLayer(0x7FFFFFFF); 275 if (err != NO_ERROR) { 276 fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err); 277 return false; 278 } 279 err = sc->setMatrix(scale, 0.0f, 0.0f, scale); 280 if (err != NO_ERROR) { 281 fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err); 282 return false; 283 } 284 285 err = sc->show(); 286 if (err != NO_ERROR) { 287 fprintf(stderr, "SurfaceComposer::show error: %#x\n", err); 288 return false; 289 } 290 SurfaceComposerClient::closeGlobalTransaction(); 291 292 sp<ANativeWindow> anw = sc->getSurface(); 293 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); 294 if (s == EGL_NO_SURFACE) { 295 fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); 296 return false; 297 } 298 299 *surfaceControl = sc; 300 *surface = s; 301 return true; 302 } 303 304 static bool compileShader(GLenum shaderType, const char* src, 305 GLuint* outShader) { 306 GLuint shader = glCreateShader(shaderType); 307 if (shader == 0) { 308 fprintf(stderr, "glCreateShader error: %#x\n", glGetError()); 309 return false; 310 } 311 312 glShaderSource(shader, 1, &src, NULL); 313 glCompileShader(shader); 314 315 GLint compiled = 0; 316 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 317 if (!compiled) { 318 GLint infoLen = 0; 319 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 320 if (infoLen) { 321 char* buf = new char[infoLen]; 322 if (buf) { 323 glGetShaderInfoLog(shader, infoLen, NULL, buf); 324 fprintf(stderr, "Shader compile log:\n%s\n", buf); 325 delete[] buf; 326 } 327 } 328 glDeleteShader(shader); 329 return false; 330 } 331 *outShader = shader; 332 return true; 333 } 334 335 static void printShaderSource(const char* const* src) { 336 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 337 fprintf(stderr, "%3zu: %s\n", i+1, src[i]); 338 } 339 } 340 341 static const char* makeShaderString(const char* const* src) { 342 size_t len = 0; 343 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 344 // The +1 is for the '\n' that will be added. 345 len += strlen(src[i]) + 1; 346 } 347 348 char* result = new char[len+1]; 349 char* end = result; 350 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 351 strcpy(end, src[i]); 352 end += strlen(src[i]); 353 *end = '\n'; 354 end++; 355 } 356 *end = '\0'; 357 358 return result; 359 } 360 361 static bool compileShaderLines(GLenum shaderType, const char* const* lines, 362 GLuint* outShader) { 363 const char* src = makeShaderString(lines); 364 bool result = compileShader(shaderType, src, outShader); 365 if (!result) { 366 fprintf(stderr, "Shader source:\n"); 367 printShaderSource(lines); 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