16ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold/* 26ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * Copyright (C) 2010 The Android Open Source Project 36ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * 46ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * Licensed under the Apache License, Version 2.0 (the "License"); 56ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * you may not use this file except in compliance with the License. 66ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * You may obtain a copy of the License at 76ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * 86ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * http://www.apache.org/licenses/LICENSE-2.0 96ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * 106ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * Unless required by applicable law or agreed to in writing, software 116ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * distributed under the License is distributed on an "AS IS" BASIS, 126ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * See the License for the specific language governing permissions and 146ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold * limitations under the License. 156ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold */ 166ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 176ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <stdlib.h> 186ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <stdio.h> 196ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <time.h> 206ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <sched.h> 216ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <sys/resource.h> 226ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 236ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <EGL/egl.h> 246ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <EGL/eglext.h> 256ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <GLES2/gl2.h> 266ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <GLES2/gl2ext.h> 276ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 286ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <utils/Timers.h> 296ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 306ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <ui/FramebufferNativeWindow.h> 316ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#include <ui/GraphicBuffer.h> 32870b8aa15cb5c722b5d8eb7726eaa5f1a7c23d69Mathias Agopian#include "EGLUtils.h" 336ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 346ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldusing namespace android; 356ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 366ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldstatic void printGLString(const char *name, GLenum s) { 376ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold // fprintf(stderr, "printGLString %s, %d\n", name, s); 386ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold const char *v = (const char *) glGetString(s); 396ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold // int error = glGetError(); 406ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, 416ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold // (unsigned int) v); 426ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold // if ((v < (const char*) 0) || (v > (const char*) 0x10000)) 436ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold // fprintf(stderr, "GL %s = %s\n", name, v); 446ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold // else 456ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v); 466ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "GL %s = %s\n", name, v); 476ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 486ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 496ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldstatic void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { 506ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (returnVal != EGL_TRUE) { 516ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "%s() returned %d\n", op, returnVal); 526ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 536ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 546ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold for (EGLint error = eglGetError(); error != EGL_SUCCESS; error 556ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold = eglGetError()) { 566ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), 576ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold error); 586ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 596ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 606ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 616ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldstatic void checkGlError(const char* op) { 626ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold for (GLint error = glGetError(); error; error 636ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold = glGetError()) { 646ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "after %s() glError (0x%x)\n", op, error); 656ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 666ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 676ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 686ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldstatic const char gVertexShader[] = "attribute vec4 vPosition;\n" 696ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold "varying vec2 yuvTexCoords;\n" 706ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold "void main() {\n" 716ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold " yuvTexCoords = vPosition.xy + vec2(0.5, 0.5);\n" 726ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold " gl_Position = vPosition;\n" 736ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold "}\n"; 746ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 756ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldstatic const char gFragmentShader[] = "#extension GL_OES_EGL_image_external : require\n" 766ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold "precision mediump float;\n" 776ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold "uniform samplerExternalOES yuvTexSampler;\n" 786ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold "varying vec2 yuvTexCoords;\n" 796ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold "void main() {\n" 806ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold " gl_FragColor = texture2D(yuvTexSampler, yuvTexCoords);\n" 816ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold "}\n"; 826ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 836ecdb49b2545add54e68cb935f71ed456320078eMichael I. GoldGLuint loadShader(GLenum shaderType, const char* pSource) { 846ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLuint shader = glCreateShader(shaderType); 856ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (shader) { 866ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glShaderSource(shader, 1, &pSource, NULL); 876ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glCompileShader(shader); 886ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLint compiled = 0; 896ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 906ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (!compiled) { 916ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLint infoLen = 0; 926ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 936ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (infoLen) { 946ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold char* buf = (char*) malloc(infoLen); 956ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (buf) { 966ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glGetShaderInfoLog(shader, infoLen, NULL, buf); 976ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "Could not compile shader %d:\n%s\n", 986ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold shaderType, buf); 996ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold free(buf); 1006ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1016ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } else { 1026ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "Guessing at GL_INFO_LOG_LENGTH size\n"); 1036ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold char* buf = (char*) malloc(0x1000); 1046ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (buf) { 1056ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glGetShaderInfoLog(shader, 0x1000, NULL, buf); 1066ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "Could not compile shader %d:\n%s\n", 1076ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold shaderType, buf); 1086ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold free(buf); 1096ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1106ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1116ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glDeleteShader(shader); 1126ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold shader = 0; 1136ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1146ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1156ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return shader; 1166ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 1176ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1186ecdb49b2545add54e68cb935f71ed456320078eMichael I. GoldGLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { 1196ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); 1206ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (!vertexShader) { 1216ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 0; 1226ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1236ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1246ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); 1256ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (!pixelShader) { 1266ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 0; 1276ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1286ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1296ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLuint program = glCreateProgram(); 1306ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (program) { 1316ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glAttachShader(program, vertexShader); 1326ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glAttachShader"); 1336ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glAttachShader(program, pixelShader); 1346ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glAttachShader"); 1356ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glLinkProgram(program); 1366ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLint linkStatus = GL_FALSE; 1376ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 1386ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (linkStatus != GL_TRUE) { 1396ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLint bufLength = 0; 1406ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); 1416ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (bufLength) { 1426ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold char* buf = (char*) malloc(bufLength); 1436ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (buf) { 1446ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glGetProgramInfoLog(program, bufLength, NULL, buf); 1456ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "Could not link program:\n%s\n", buf); 1466ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold free(buf); 1476ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1486ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1496ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glDeleteProgram(program); 1506ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold program = 0; 1516ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1526ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1536ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return program; 1546ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 1556ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1566ecdb49b2545add54e68cb935f71ed456320078eMichael I. GoldGLuint gProgram; 1576ecdb49b2545add54e68cb935f71ed456320078eMichael I. GoldGLint gvPositionHandle; 1586ecdb49b2545add54e68cb935f71ed456320078eMichael I. GoldGLint gYuvTexSamplerHandle; 1596ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1606ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldbool setupGraphics(int w, int h) { 1616ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold gProgram = createProgram(gVertexShader, gFragmentShader); 1626ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (!gProgram) { 1636ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return false; 1646ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 1656ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); 1666ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glGetAttribLocation"); 1676ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n", 1686ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold gvPositionHandle); 1696ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold gYuvTexSamplerHandle = glGetUniformLocation(gProgram, "yuvTexSampler"); 1706ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glGetUniformLocation"); 1716ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "glGetUniformLocation(\"yuvTexSampler\") = %d\n", 1726ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold gYuvTexSamplerHandle); 1736ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1746ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glViewport(0, 0, w, h); 1756ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glViewport"); 1766ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return true; 1776ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 1786ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1796ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldint align(int x, int a) { 1806ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return (x + (a-1)) & (~(a-1)); 1816ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 1826ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1836ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldconst int yuvTexWidth = 608; 1846ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldconst int yuvTexHeight = 480; 1856ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldconst int yuvTexUsage = GraphicBuffer::USAGE_HW_TEXTURE | 1866ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GraphicBuffer::USAGE_SW_WRITE_RARELY; 1876ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldconst int yuvTexFormat = HAL_PIXEL_FORMAT_YV12; 1886ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldconst int yuvTexOffsetY = 0; 1896ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldconst bool yuvTexSameUV = false; 1906ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldstatic sp<GraphicBuffer> yuvTexBuffer; 1916ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldstatic GLuint yuvTex; 1926ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 1936ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldbool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) { 1946ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1; 1956ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1; 1966ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat, 1976ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold yuvTexUsage); 198181f1c33c254496f2252efd41a4d1db5399c5ad2Jamie Gennis int yuvTexStrideY = yuvTexBuffer->getStride(); 199181f1c33c254496f2252efd41a4d1db5399c5ad2Jamie Gennis int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight; 200181f1c33c254496f2252efd41a4d1db5399c5ad2Jamie Gennis int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; 201181f1c33c254496f2252efd41a4d1db5399c5ad2Jamie Gennis int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2; 202181f1c33c254496f2252efd41a4d1db5399c5ad2Jamie Gennis int yuvTexStrideU = yuvTexStrideV; 2036ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold char* buf = NULL; 2046ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); 2056ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (err != 0) { 2066ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "yuvTexBuffer->lock(...) failed: %d\n", err); 2076ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return false; 2086ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 2096ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold for (int x = 0; x < yuvTexWidth; x++) { 2106ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold for (int y = 0; y < yuvTexHeight; y++) { 2116ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold int parityX = (x / blockWidth) & 1; 2126ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold int parityY = (y / blockHeight) & 1; 2136ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold unsigned char intensity = (parityX ^ parityY) ? 63 : 191; 2146ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; 2156ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (x < yuvTexWidth / 2 && y < yuvTexHeight / 2) { 2166ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity; 2176ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (yuvTexSameUV) { 2186ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = intensity; 2196ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } else if (x < yuvTexWidth / 4 && y < yuvTexHeight / 4) { 2206ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] = 2216ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] = 2226ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] = 2236ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = intensity; 2246ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 2256ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 2266ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 2276ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 2286ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2296ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold err = yuvTexBuffer->unlock(); 2306ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (err != 0) { 2316ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "yuvTexBuffer->unlock() failed: %d\n", err); 2326ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return false; 2336ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 2346ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2356ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLClientBuffer clientBuffer = (EGLClientBuffer)yuvTexBuffer->getNativeBuffer(); 2366ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLImageKHR img = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, 2376ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold clientBuffer, 0); 2386ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglCreateImageKHR"); 2396ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (img == EGL_NO_IMAGE_KHR) { 2406ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return false; 2416ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 2426ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2436ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glGenTextures(1, &yuvTex); 2446ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glGenTextures"); 2456ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex); 2466ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glBindTexture"); 2476ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)img); 2486ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glEGLImageTargetTexture2DOES"); 2496ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2506ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return true; 2516ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 2526ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2536ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldconst GLfloat gTriangleVertices[] = { 2546ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold -0.5f, 0.5f, 2556ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold -0.5f, -0.5f, 2566ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 0.5f, -0.5f, 2576ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 0.5f, 0.5f, 2586ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold}; 2596ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2606ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldvoid renderFrame() { 2616ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glClearColor(0.0f, 0.0f, 1.0f, 1.0f); 2626ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glClearColor"); 2636ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 2646ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glClear"); 2656ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2666ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glUseProgram(gProgram); 2676ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glUseProgram"); 2686ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2696ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); 2706ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glVertexAttribPointer"); 2716ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glEnableVertexAttribArray(gvPositionHandle); 2726ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glEnableVertexAttribArray"); 2736ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2746ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glUniform1i(gYuvTexSamplerHandle, 0); 2756ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glUniform1i"); 2766ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex); 2776ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glBindTexture"); 2786ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2796ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 2806ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkGlError("glDrawArrays"); 2816ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 2826ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2836ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldvoid printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { 2846ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 2856ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#define X(VAL) {VAL, #VAL} 2866ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold struct {EGLint attribute; const char* name;} names[] = { 2876ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_BUFFER_SIZE), 2886ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_ALPHA_SIZE), 2896ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_BLUE_SIZE), 2906ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_GREEN_SIZE), 2916ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_RED_SIZE), 2926ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_DEPTH_SIZE), 2936ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_STENCIL_SIZE), 2946ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_CONFIG_CAVEAT), 2956ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_CONFIG_ID), 2966ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_LEVEL), 2976ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_MAX_PBUFFER_HEIGHT), 2986ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_MAX_PBUFFER_PIXELS), 2996ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_MAX_PBUFFER_WIDTH), 3006ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_NATIVE_RENDERABLE), 3016ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_NATIVE_VISUAL_ID), 3026ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_NATIVE_VISUAL_TYPE), 3036ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_SAMPLES), 3046ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_SAMPLE_BUFFERS), 3056ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_SURFACE_TYPE), 3066ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_TRANSPARENT_TYPE), 3076ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_TRANSPARENT_RED_VALUE), 3086ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_TRANSPARENT_GREEN_VALUE), 3096ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_TRANSPARENT_BLUE_VALUE), 3106ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_BIND_TO_TEXTURE_RGB), 3116ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_BIND_TO_TEXTURE_RGBA), 3126ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_MIN_SWAP_INTERVAL), 3136ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_MAX_SWAP_INTERVAL), 3146ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_LUMINANCE_SIZE), 3156ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_ALPHA_MASK_SIZE), 3166ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_COLOR_BUFFER_TYPE), 3176ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_RENDERABLE_TYPE), 3186ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold X(EGL_CONFORMANT), 3196ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold }; 3206ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold#undef X 3216ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3226ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { 3236ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLint value = -1; 3246ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); 3256ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLint error = eglGetError(); 3266ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (returnVal && error == EGL_SUCCESS) { 3276ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf(" %s: ", names[j].name); 3286ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf("%d (0x%x)", value, value); 3296ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 3306ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 3316ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf("\n"); 3326ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 3336ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3346ecdb49b2545add54e68cb935f71ed456320078eMichael I. Goldint main(int argc, char** argv) { 3356ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLBoolean returnValue; 3366ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLConfig myConfig = {0}; 3376ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3386ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 3396ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLint s_configAttribs[] = { 3406ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 3416ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 3426ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGL_NONE }; 3436ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLint majorVersion; 3446ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLint minorVersion; 3456ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLContext context; 3466ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLSurface surface; 3476ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLint w, h; 3486ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3496ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLDisplay dpy; 3506ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3516ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("<init>"); 3526ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 3536ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglGetDisplay"); 3546ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (dpy == EGL_NO_DISPLAY) { 3556ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); 3566ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 0; 3576ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 3586ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3596ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); 3606ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglInitialize", returnValue); 3616ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); 3626ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (returnValue != EGL_TRUE) { 3636ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf("eglInitialize failed\n"); 3646ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 0; 3656ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 3666ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3676ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold EGLNativeWindowType window = android_createDisplaySurface(); 3686ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig); 3696ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (returnValue) { 3706ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue); 3716ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 1; 3726ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 3736ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3746ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("EGLUtils::selectConfigForNativeWindow"); 3756ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3766ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf("Chose this configuration:\n"); 3776ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printEGLConfiguration(dpy, myConfig); 3786ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3796ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); 3806ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglCreateWindowSurface"); 3816ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (surface == EGL_NO_SURFACE) { 3826ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf("gelCreateWindowSurface failed.\n"); 3836ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 1; 3846ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 3856ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 3866ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); 3876ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglCreateContext"); 3886ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (context == EGL_NO_CONTEXT) { 3896ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printf("eglCreateContext failed\n"); 3906ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 1; 3916ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 3926ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold returnValue = eglMakeCurrent(dpy, surface, surface, context); 3936ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglMakeCurrent", returnValue); 3946ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if (returnValue != EGL_TRUE) { 3956ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 1; 3966ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 3976ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold eglQuerySurface(dpy, surface, EGL_WIDTH, &w); 3986ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglQuerySurface"); 3996ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); 4006ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglQuerySurface"); 4016ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold GLint dim = w < h ? w : h; 4026ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 4036ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "Window dimensions: %d x %d\n", w, h); 4046ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 4056ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printGLString("Version", GL_VERSION); 4066ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printGLString("Vendor", GL_VENDOR); 4076ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printGLString("Renderer", GL_RENDERER); 4086ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold printGLString("Extensions", GL_EXTENSIONS); 4096ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 4106ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if(!setupYuvTexSurface(dpy, context)) { 4116ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "Could not set up texture surface.\n"); 4126ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 1; 4136ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 4146ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 4156ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold if(!setupGraphics(w, h)) { 4166ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold fprintf(stderr, "Could not set up graphics.\n"); 4176ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 1; 4186ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 4196ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 4206ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold for (;;) { 4216ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold renderFrame(); 4226ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold eglSwapBuffers(dpy, surface); 4236ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold checkEglError("eglSwapBuffers"); 4246ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold } 4256ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold 4266ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold return 0; 4276ecdb49b2545add54e68cb935f71ed456320078eMichael I. Gold} 428