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::Transaction{}.setLayer(sc, 0x7FFFFFFF) 273 .setMatrix(sc, scale, 0.0f, 0.0f, scale) 274 .show(sc) 275 .apply(); 276 277 sp<ANativeWindow> anw = sc->getSurface(); 278 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL); 279 if (s == EGL_NO_SURFACE) { 280 fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); 281 return false; 282 } 283 284 *surfaceControl = sc; 285 *surface = s; 286 return true; 287 } 288 289 static bool compileShader(GLenum shaderType, const char* src, 290 GLuint* outShader) { 291 GLuint shader = glCreateShader(shaderType); 292 if (shader == 0) { 293 fprintf(stderr, "glCreateShader error: %#x\n", glGetError()); 294 return false; 295 } 296 297 glShaderSource(shader, 1, &src, NULL); 298 glCompileShader(shader); 299 300 GLint compiled = 0; 301 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 302 if (!compiled) { 303 GLint infoLen = 0; 304 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 305 if (infoLen) { 306 char* buf = new char[infoLen]; 307 if (buf) { 308 glGetShaderInfoLog(shader, infoLen, NULL, buf); 309 fprintf(stderr, "Shader compile log:\n%s\n", buf); 310 delete[] buf; 311 } 312 } 313 glDeleteShader(shader); 314 return false; 315 } 316 *outShader = shader; 317 return true; 318 } 319 320 static void printShaderSource(const char* const* src) { 321 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 322 fprintf(stderr, "%3zu: %s\n", i+1, src[i]); 323 } 324 } 325 326 static const char* makeShaderString(const char* const* src) { 327 size_t len = 0; 328 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 329 // The +1 is for the '\n' that will be added. 330 len += strlen(src[i]) + 1; 331 } 332 333 char* result = new char[len+1]; 334 char* end = result; 335 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) { 336 strcpy(end, src[i]); 337 end += strlen(src[i]); 338 *end = '\n'; 339 end++; 340 } 341 *end = '\0'; 342 343 return result; 344 } 345 346 static bool compileShaderLines(GLenum shaderType, const char* const* lines, 347 GLuint* outShader) { 348 const char* src = makeShaderString(lines); 349 bool result = compileShader(shaderType, src, outShader); 350 if (!result) { 351 fprintf(stderr, "Shader source:\n"); 352 printShaderSource(lines); 353 delete[] src; 354 return false; 355 } 356 delete[] src; 357 358 return true; 359 } 360 361 static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) { 362 GLuint program = glCreateProgram(); 363 if (program == 0) { 364 fprintf(stderr, "glCreateProgram error: %#x\n", glGetError()); 365 return false; 366 } 367 368 glAttachShader(program, vs); 369 glAttachShader(program, fs); 370 glLinkProgram(program); 371 GLint linkStatus = GL_FALSE; 372 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 373 if (linkStatus != GL_TRUE) { 374 GLint bufLength = 0; 375 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); 376 if (bufLength) { 377 char* buf = new char[bufLength]; 378 if (buf) { 379 glGetProgramInfoLog(program, bufLength, NULL, buf); 380 fprintf(stderr, "Program link log:\n%s\n", buf); 381 delete[] buf; 382 } 383 } 384 glDeleteProgram(program); 385 program = 0; 386 } 387 388 *outPgm = program; 389 return program != 0; 390 } 391 392 bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) { 393 mShaderPrograms = new GLuint[numShaders]; 394 bool result = true; 395 396 for (size_t i = 0; i < numShaders && result; i++) { 397 GLuint vs, fs; 398 399 result = compileShaderLines(GL_VERTEX_SHADER, 400 shaderDescs[i].vertexShader, &vs); 401 if (!result) { 402 return false; 403 } 404 405 result = compileShaderLines(GL_FRAGMENT_SHADER, 406 shaderDescs[i].fragmentShader, &fs); 407 if (!result) { 408 glDeleteShader(vs); 409 return false; 410 } 411 412 result = linkShaderProgram(vs, fs, &mShaderPrograms[i]); 413 glDeleteShader(vs); 414 glDeleteShader(fs); 415 } 416 417 mNumShaders = numShaders; 418 mShaderDescs = shaderDescs; 419 420 return result; 421 } 422 423 bool GLHelper::getDitherTexture(GLuint* outTexName) { 424 if (mDitherTexture == 0) { 425 const uint8_t pattern[] = { 426 0, 8, 2, 10, 427 12, 4, 14, 6, 428 3, 11, 1, 9, 429 15, 7, 13, 5 430 }; 431 432 glGenTextures(1, &mDitherTexture); 433 glBindTexture(GL_TEXTURE_2D, mDitherTexture); 434 435 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 436 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 437 438 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 439 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 440 441 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, 442 DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern); 443 } 444 445 *outTexName = mDitherTexture; 446 447 return true; 448 } 449 450 } 451