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