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