GLHelper.cpp revision 9c183f2493222000fa512d927cfde3f4c748eda0
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 <ui/Fence.h> 18 19#include <ui/DisplayInfo.h> 20#include <gui/SurfaceComposerClient.h> 21 22#include "GLHelper.h" 23 24 namespace android { 25 26GLHelper::GLHelper() : 27 mGraphicBufferAlloc(new GraphicBufferAlloc()), 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 36GLHelper::~GLHelper() { 37} 38 39bool 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 103void 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 134bool 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 151bool 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 168void 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 178bool 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 188bool 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 201bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, 202 sp<GLConsumer>* glConsumer, EGLSurface* surface) { 203 sp<BufferQueue> bq = new BufferQueue(true, mGraphicBufferAlloc); 204 sp<GLConsumer> glc = new GLConsumer(name, true, 205 GL_TEXTURE_EXTERNAL_OES, false, bq); 206 glc->setDefaultBufferSize(w, h); 207 glc->setDefaultMaxBufferCount(3); 208 glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); 209 210 sp<ANativeWindow> anw = new SurfaceTextureClient(bq); 211 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); 212 if (s == EGL_NO_SURFACE) { 213 fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); 214 return false; 215 } 216 217 *glConsumer = glc; 218 *surface = s; 219 return true; 220} 221 222bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) { 223 sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0); 224 if (dpy == NULL) { 225 fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n"); 226 return false; 227 } 228 229 DisplayInfo info; 230 status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info); 231 if (err != NO_ERROR) { 232 fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err); 233 return false; 234 } 235 236 float scaleX = float(info.w) / float(w); 237 float scaleY = float(info.h) / float(h); 238 *scale = scaleX < scaleY ? scaleX : scaleY; 239 240 return true; 241} 242 243bool GLHelper::createWindowSurface(uint32_t w, uint32_t h, 244 sp<SurfaceControl>* surfaceControl, EGLSurface* surface) { 245 bool result; 246 status_t err; 247 248 if (mSurfaceComposerClient == NULL) { 249 mSurfaceComposerClient = new SurfaceComposerClient; 250 } 251 err = mSurfaceComposerClient->initCheck(); 252 if (err != NO_ERROR) { 253 fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err); 254 return false; 255 } 256 257 sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface( 258 String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0); 259 if (sc == NULL || !sc->isValid()) { 260 fprintf(stderr, "Failed to create SurfaceControl.\n"); 261 return false; 262 } 263 264 float scale; 265 result = computeWindowScale(w, h, &scale); 266 if (!result) { 267 return false; 268 } 269 270 SurfaceComposerClient::openGlobalTransaction(); 271 err = sc->setLayer(0x7FFFFFFF); 272 if (err != NO_ERROR) { 273 fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err); 274 return false; 275 } 276 err = sc->setMatrix(scale, 0.0f, 0.0f, scale); 277 if (err != NO_ERROR) { 278 fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err); 279 return false; 280 } 281 282 err = sc->show(); 283 if (err != NO_ERROR) { 284 fprintf(stderr, "SurfaceComposer::show error: %#x\n", err); 285 return false; 286 } 287 SurfaceComposerClient::closeGlobalTransaction(); 288 289 sp<ANativeWindow> anw = sc->getSurface(); 290 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); 291 if (s == EGL_NO_SURFACE) { 292 fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); 293 return false; 294 } 295 296 *surfaceControl = sc; 297 *surface = s; 298 return true; 299} 300 301static bool compileShader(GLenum shaderType, const char* src, 302 GLuint* outShader) { 303 GLuint shader = glCreateShader(shaderType); 304 if (shader == 0) { 305 fprintf(stderr, "glCreateShader error: %#x\n", glGetError()); 306 return false; 307 } 308 309 glShaderSource(shader, 1, &src, NULL); 310 glCompileShader(shader); 311 312 GLint compiled = 0; 313 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 314 if (!compiled) { 315 GLint infoLen = 0; 316 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 317 if (infoLen) { 318 char* buf = new char[infoLen]; 319 if (buf) { 320 glGetShaderInfoLog(shader, infoLen, NULL, buf); 321 fprintf(stderr, "Shader compile log:\n%s\n", buf); 322 delete[] buf; 323 } 324 } 325 glDeleteShader(shader); 326 return false; 327 } 328 *outShader = shader; 329 return true; 330} 331 332static void printShaderSource(const char* const* src) { 333 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 334 fprintf(stderr, "%3d: %s\n", i+1, src[i]); 335 } 336} 337 338static const char* makeShaderString(const char* const* src) { 339 size_t len = 0; 340 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 341 // The +1 is for the '\n' that will be added. 342 len += strlen(src[i]) + 1; 343 } 344 345 char* result = new char[len+1]; 346 char* end = result; 347 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 348 strcpy(end, src[i]); 349 end += strlen(src[i]); 350 *end = '\n'; 351 end++; 352 } 353 *end = '\0'; 354 355 return result; 356} 357 358static bool compileShaderLines(GLenum shaderType, const char* const* lines, 359 GLuint* outShader) { 360 const char* src = makeShaderString(lines); 361 bool result = compileShader(shaderType, src, outShader); 362 if (!result) { 363 fprintf(stderr, "Shader source:\n"); 364 printShaderSource(lines); 365 return false; 366 } 367 delete[] src; 368 369 return true; 370} 371 372static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) { 373 GLuint program = glCreateProgram(); 374 if (program == 0) { 375 fprintf(stderr, "glCreateProgram error: %#x\n", glGetError()); 376 return false; 377 } 378 379 glAttachShader(program, vs); 380 glAttachShader(program, fs); 381 glLinkProgram(program); 382 GLint linkStatus = GL_FALSE; 383 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 384 if (linkStatus != GL_TRUE) { 385 GLint bufLength = 0; 386 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); 387 if (bufLength) { 388 char* buf = new char[bufLength]; 389 if (buf) { 390 glGetProgramInfoLog(program, bufLength, NULL, buf); 391 fprintf(stderr, "Program link log:\n%s\n", buf); 392 delete[] buf; 393 } 394 } 395 glDeleteProgram(program); 396 program = 0; 397 } 398 399 *outPgm = program; 400 return program != 0; 401} 402 403bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) { 404 mShaderPrograms = new GLuint[numShaders]; 405 bool result = true; 406 407 for (size_t i = 0; i < numShaders && result; i++) { 408 GLuint vs, fs; 409 410 result = compileShaderLines(GL_VERTEX_SHADER, 411 shaderDescs[i].vertexShader, &vs); 412 if (!result) { 413 return false; 414 } 415 416 result = compileShaderLines(GL_FRAGMENT_SHADER, 417 shaderDescs[i].fragmentShader, &fs); 418 if (!result) { 419 glDeleteShader(vs); 420 return false; 421 } 422 423 result = linkShaderProgram(vs, fs, &mShaderPrograms[i]); 424 glDeleteShader(vs); 425 glDeleteShader(fs); 426 } 427 428 mNumShaders = numShaders; 429 mShaderDescs = shaderDescs; 430 431 return result; 432} 433 434bool GLHelper::getDitherTexture(GLuint* outTexName) { 435 if (mDitherTexture == 0) { 436 const uint8_t pattern[] = { 437 0, 8, 2, 10, 438 12, 4, 14, 6, 439 3, 11, 1, 9, 440 15, 7, 13, 5 441 }; 442 443 glGenTextures(1, &mDitherTexture); 444 glBindTexture(GL_TEXTURE_2D, mDitherTexture); 445 446 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 447 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 448 449 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 450 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 451 452 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, 453 DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern); 454 } 455 456 *outTexName = mDitherTexture; 457 458 return true; 459} 460 461} 462