1/* 2 * Copyright (C) 2007 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 <stdlib.h> 18#include <stdio.h> 19#include <time.h> 20#include <sched.h> 21#include <sys/resource.h> 22 23#include <EGL/egl.h> 24#include <GLES2/gl2.h> 25#include <GLES2/gl2ext.h> 26 27#include <utils/Timers.h> 28 29#include <ui/FramebufferNativeWindow.h> 30#include "EGLUtils.h" 31 32using namespace android; 33 34static void printGLString(const char *name, GLenum s) { 35 // fprintf(stderr, "printGLString %s, %d\n", name, s); 36 const char *v = (const char *) glGetString(s); 37 // int error = glGetError(); 38 // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, 39 // (unsigned int) v); 40 // if ((v < (const char*) 0) || (v > (const char*) 0x10000)) 41 // fprintf(stderr, "GL %s = %s\n", name, v); 42 // else 43 // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v); 44 fprintf(stderr, "GL %s = %s\n", name, v); 45} 46 47static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { 48 if (returnVal != EGL_TRUE) { 49 fprintf(stderr, "%s() returned %d\n", op, returnVal); 50 } 51 52 for (EGLint error = eglGetError(); error != EGL_SUCCESS; error 53 = eglGetError()) { 54 fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), 55 error); 56 } 57} 58 59static void checkGlError(const char* op) { 60 for (GLint error = glGetError(); error; error 61 = glGetError()) { 62 fprintf(stderr, "after %s() glError (0x%x)\n", op, error); 63 } 64} 65 66static const char gVertexShader[] = "attribute vec4 vPosition;\n" 67 "void main() {\n" 68 " gl_Position = vPosition;\n" 69 "}\n"; 70 71static const char gFragmentShader[] = "precision mediump float;\n" 72 "void main() {\n" 73 " gl_FragColor = vec4(0.0, 1.0, 0.0, 0.5);\n" 74 "}\n"; 75 76GLuint loadShader(GLenum shaderType, const char* pSource) { 77 GLuint shader = glCreateShader(shaderType); 78 if (shader) { 79 glShaderSource(shader, 1, &pSource, NULL); 80 glCompileShader(shader); 81 GLint compiled = 0; 82 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 83 if (!compiled) { 84 GLint infoLen = 0; 85 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 86 if (infoLen) { 87 char* buf = (char*) malloc(infoLen); 88 if (buf) { 89 glGetShaderInfoLog(shader, infoLen, NULL, buf); 90 fprintf(stderr, "Could not compile shader %d:\n%s\n", 91 shaderType, buf); 92 free(buf); 93 } 94 glDeleteShader(shader); 95 shader = 0; 96 } 97 } 98 } 99 return shader; 100} 101 102GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { 103 GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); 104 if (!vertexShader) { 105 return 0; 106 } 107 108 GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); 109 if (!pixelShader) { 110 return 0; 111 } 112 113 GLuint program = glCreateProgram(); 114 if (program) { 115 glAttachShader(program, vertexShader); 116 checkGlError("glAttachShader"); 117 glAttachShader(program, pixelShader); 118 checkGlError("glAttachShader"); 119 glLinkProgram(program); 120 GLint linkStatus = GL_FALSE; 121 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 122 if (linkStatus != GL_TRUE) { 123 GLint bufLength = 0; 124 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); 125 if (bufLength) { 126 char* buf = (char*) malloc(bufLength); 127 if (buf) { 128 glGetProgramInfoLog(program, bufLength, NULL, buf); 129 fprintf(stderr, "Could not link program:\n%s\n", buf); 130 free(buf); 131 } 132 } 133 glDeleteProgram(program); 134 program = 0; 135 } 136 } 137 return program; 138} 139 140GLuint gProgram; 141GLuint gTextureProgram; 142GLuint gvPositionHandle; 143GLuint gvTexturePositionHandle; 144GLuint gvTextureTexCoordsHandle; 145GLuint gvTextureSamplerHandle; 146GLuint gFbo; 147GLuint gTexture; 148GLuint gBufferTexture; 149 150static const char gSimpleVS[] = 151 "attribute vec4 position;\n" 152 "attribute vec2 texCoords;\n" 153 "varying vec2 outTexCoords;\n" 154 "\nvoid main(void) {\n" 155 " outTexCoords = texCoords;\n" 156 " gl_Position = position;\n" 157 "}\n\n"; 158static const char gSimpleFS[] = 159 "precision mediump float;\n\n" 160 "varying vec2 outTexCoords;\n" 161 "uniform sampler2D texture;\n" 162 "\nvoid main(void) {\n" 163 " gl_FragColor = texture2D(texture, outTexCoords);\n" 164 "}\n\n"; 165 166bool setupGraphics(int w, int h) { 167 gProgram = createProgram(gVertexShader, gFragmentShader); 168 if (!gProgram) { 169 return false; 170 } 171 gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); 172 checkGlError("glGetAttribLocation"); 173 fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle); 174 175 gTextureProgram = createProgram(gSimpleVS, gSimpleFS); 176 if (!gTextureProgram) { 177 return false; 178 } 179 gvTexturePositionHandle = glGetAttribLocation(gTextureProgram, "position"); 180 checkGlError("glGetAttribLocation"); 181 gvTextureTexCoordsHandle = glGetAttribLocation(gTextureProgram, "texCoords"); 182 checkGlError("glGetAttribLocation"); 183 gvTextureSamplerHandle = glGetUniformLocation(gTextureProgram, "texture"); 184 checkGlError("glGetAttribLocation"); 185 186 glActiveTexture(GL_TEXTURE0); 187 188 glGenTextures(1, &gTexture); 189 glBindTexture(GL_TEXTURE_2D, gTexture); 190 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 191 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 192 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 193 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 194 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 195 196 glGenTextures(1, &gBufferTexture); 197 glBindTexture(GL_TEXTURE_2D, gBufferTexture); 198 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 202 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 203 204 glGenFramebuffers(1, &gFbo); 205 glBindFramebuffer(GL_FRAMEBUFFER, gFbo); 206 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gTexture, 0); 207 208 glBindFramebuffer(GL_FRAMEBUFFER, 0); 209 210 glViewport(0, 0, w, h); 211 checkGlError("glViewport"); 212 return true; 213} 214 215const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, 216 0.5f, -0.5f }; 217 218const GLint FLOAT_SIZE_BYTES = 4; 219const GLint TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; 220const GLfloat gTriangleVerticesData[] = { 221 // X, Y, Z, U, V 222 -1.0f, -1.0f, 0, 0.f, 0.f, 223 1.0f, -1.0f, 0, 1.f, 0.f, 224 -1.0f, 1.0f, 0, 0.f, 1.f, 225 1.0f, 1.0f, 0, 1.f, 1.f, 226}; 227 228void renderFrame(GLint w, GLint h) { 229 glClearColor(1.0f, 0.0f, 0.0f, 1.0f); 230 checkGlError("glClearColor"); 231 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 232 checkGlError("glClear"); 233 234 // Bind FBO and draw into it 235 glBindFramebuffer(GL_FRAMEBUFFER, gFbo); 236 checkGlError("glBindFramebuffer"); 237 238 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 239 checkGlError("glClearColor"); 240 glClear(GL_COLOR_BUFFER_BIT); 241 checkGlError("glClear"); 242 243 glUseProgram(gProgram); 244 checkGlError("glUseProgram"); 245 246 glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); 247 checkGlError("glVertexAttribPointer"); 248 glEnableVertexAttribArray(gvPositionHandle); 249 checkGlError("glEnableVertexAttribArray"); 250 glDrawArrays(GL_TRIANGLES, 0, 3); 251 checkGlError("glDrawArrays"); 252 253 // Copy content of FBO into a texture 254 glBindTexture(GL_TEXTURE_2D, gBufferTexture); 255 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w / 2, h / 2); 256 checkGlError("glCopyTexSubImage2D"); 257 258 // Back to the display 259 glBindFramebuffer(GL_FRAMEBUFFER, 0); 260 checkGlError("glBindFramebuffer"); 261 262 // Draw copied content on the screen 263 glUseProgram(gTextureProgram); 264 checkGlError("glUseProgram"); 265 266 glEnable(GL_BLEND); 267 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 268 269 glVertexAttribPointer(gvTexturePositionHandle, 3, GL_FLOAT, GL_FALSE, 270 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, gTriangleVerticesData); 271 checkGlError("glVertexAttribPointer"); 272 glVertexAttribPointer(gvTextureTexCoordsHandle, 2, GL_FLOAT, GL_FALSE, 273 TRIANGLE_VERTICES_DATA_STRIDE_BYTES, &gTriangleVerticesData[3]); 274 checkGlError("glVertexAttribPointer"); 275 glEnableVertexAttribArray(gvTexturePositionHandle); 276 glEnableVertexAttribArray(gvTextureTexCoordsHandle); 277 checkGlError("glEnableVertexAttribArray"); 278 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 279 checkGlError("glDrawArrays"); 280} 281 282void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { 283 284#define X(VAL) {VAL, #VAL} 285 struct {EGLint attribute; const char* name;} names[] = { 286 X(EGL_BUFFER_SIZE), 287 X(EGL_ALPHA_SIZE), 288 X(EGL_BLUE_SIZE), 289 X(EGL_GREEN_SIZE), 290 X(EGL_RED_SIZE), 291 X(EGL_DEPTH_SIZE), 292 X(EGL_STENCIL_SIZE), 293 X(EGL_CONFIG_CAVEAT), 294 X(EGL_CONFIG_ID), 295 X(EGL_LEVEL), 296 X(EGL_MAX_PBUFFER_HEIGHT), 297 X(EGL_MAX_PBUFFER_PIXELS), 298 X(EGL_MAX_PBUFFER_WIDTH), 299 X(EGL_NATIVE_RENDERABLE), 300 X(EGL_NATIVE_VISUAL_ID), 301 X(EGL_NATIVE_VISUAL_TYPE), 302 X(EGL_SAMPLES), 303 X(EGL_SAMPLE_BUFFERS), 304 X(EGL_SURFACE_TYPE), 305 X(EGL_TRANSPARENT_TYPE), 306 X(EGL_TRANSPARENT_RED_VALUE), 307 X(EGL_TRANSPARENT_GREEN_VALUE), 308 X(EGL_TRANSPARENT_BLUE_VALUE), 309 X(EGL_BIND_TO_TEXTURE_RGB), 310 X(EGL_BIND_TO_TEXTURE_RGBA), 311 X(EGL_MIN_SWAP_INTERVAL), 312 X(EGL_MAX_SWAP_INTERVAL), 313 X(EGL_LUMINANCE_SIZE), 314 X(EGL_ALPHA_MASK_SIZE), 315 X(EGL_COLOR_BUFFER_TYPE), 316 X(EGL_RENDERABLE_TYPE), 317 X(EGL_CONFORMANT), 318 }; 319#undef X 320 321 for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { 322 EGLint value = -1; 323 EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); 324 EGLint error = eglGetError(); 325 if (returnVal && error == EGL_SUCCESS) { 326 printf(" %s: ", names[j].name); 327 printf("%d (0x%x)", value, value); 328 } 329 } 330 printf("\n"); 331} 332 333int printEGLConfigurations(EGLDisplay dpy) { 334 EGLint numConfig = 0; 335 EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig); 336 checkEglError("eglGetConfigs", returnVal); 337 if (!returnVal) { 338 return false; 339 } 340 341 printf("Number of EGL configuration: %d\n", numConfig); 342 343 EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig); 344 if (! configs) { 345 printf("Could not allocate configs.\n"); 346 return false; 347 } 348 349 returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig); 350 checkEglError("eglGetConfigs", returnVal); 351 if (!returnVal) { 352 free(configs); 353 return false; 354 } 355 356 for(int i = 0; i < numConfig; i++) { 357 printf("Configuration %d\n", i); 358 printEGLConfiguration(dpy, configs[i]); 359 } 360 361 free(configs); 362 return true; 363} 364 365int main(int argc, char** argv) { 366 EGLBoolean returnValue; 367 EGLConfig myConfig = {0}; 368 369 EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 370 EGLint s_configAttribs[] = { 371 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 372 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 373 EGL_RED_SIZE, 8, 374 EGL_GREEN_SIZE, 8, 375 EGL_BLUE_SIZE, 8, 376 EGL_ALPHA_SIZE, 8, 377 EGL_NONE }; 378 EGLint majorVersion; 379 EGLint minorVersion; 380 EGLContext context; 381 EGLSurface surface; 382 EGLint w, h; 383 384 EGLDisplay dpy; 385 386 checkEglError("<init>"); 387 dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 388 checkEglError("eglGetDisplay"); 389 if (dpy == EGL_NO_DISPLAY) { 390 printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); 391 return 0; 392 } 393 394 returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); 395 checkEglError("eglInitialize", returnValue); 396 fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); 397 if (returnValue != EGL_TRUE) { 398 printf("eglInitialize failed\n"); 399 return 0; 400 } 401 402 if (!printEGLConfigurations(dpy)) { 403 printf("printEGLConfigurations failed\n"); 404 return 0; 405 } 406 407 checkEglError("printEGLConfigurations"); 408 409 EGLNativeWindowType window = android_createDisplaySurface(); 410 EGLint numConfigs = -1, n = 0; 411 eglChooseConfig(dpy, s_configAttribs, 0, 0, &numConfigs); 412 if (numConfigs) { 413 EGLConfig* const configs = new EGLConfig[numConfigs]; 414 eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n); 415 myConfig = configs[0]; 416 delete[] configs; 417 } 418 419 checkEglError("EGLUtils::selectConfigForNativeWindow"); 420 421 printf("Chose this configuration:\n"); 422 printEGLConfiguration(dpy, myConfig); 423 424 surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); 425 checkEglError("eglCreateWindowSurface"); 426 if (surface == EGL_NO_SURFACE) { 427 printf("gelCreateWindowSurface failed.\n"); 428 return 0; 429 } 430 431 context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); 432 checkEglError("eglCreateContext"); 433 if (context == EGL_NO_CONTEXT) { 434 printf("eglCreateContext failed\n"); 435 return 0; 436 } 437 returnValue = eglMakeCurrent(dpy, surface, surface, context); 438 checkEglError("eglMakeCurrent", returnValue); 439 if (returnValue != EGL_TRUE) { 440 return 0; 441 } 442 eglQuerySurface(dpy, surface, EGL_WIDTH, &w); 443 checkEglError("eglQuerySurface"); 444 eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); 445 checkEglError("eglQuerySurface"); 446 GLint dim = w < h ? w : h; 447 448 fprintf(stderr, "Window dimensions: %d x %d\n", w, h); 449 450 printGLString("Version", GL_VERSION); 451 printGLString("Vendor", GL_VENDOR); 452 printGLString("Renderer", GL_RENDERER); 453 printGLString("Extensions", GL_EXTENSIONS); 454 455 if(!setupGraphics(w, h)) { 456 fprintf(stderr, "Could not set up graphics.\n"); 457 return 0; 458 } 459 460 for (;;) { 461 renderFrame(w, h); 462 eglSwapBuffers(dpy, surface); 463 checkEglError("eglSwapBuffers"); 464 } 465 466 return 0; 467} 468