1/* 2 * Copyright (C) 2010 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 <EGL/eglext.h> 25#include <GLES/gl.h> 26#include <GLES/glext.h> 27 28#include <utils/Timers.h> 29 30#include <WindowSurface.h> 31#include <ui/GraphicBuffer.h> 32#include <EGLUtils.h> 33 34using namespace android; 35 36static void printGLString(const char *name, GLenum s) { 37 // fprintf(stderr, "printGLString %s, %d\n", name, s); 38 const char *v = (const char *) glGetString(s); 39 // int error = glGetError(); 40 // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, 41 // (unsigned int) v); 42 // if ((v < (const char*) 0) || (v > (const char*) 0x10000)) 43 // fprintf(stderr, "GL %s = %s\n", name, v); 44 // else 45 // fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v); 46 fprintf(stderr, "GL %s = %s\n", name, v); 47} 48 49static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { 50 if (returnVal != EGL_TRUE) { 51 fprintf(stderr, "%s() returned %d\n", op, returnVal); 52 } 53 54 for (EGLint error = eglGetError(); error != EGL_SUCCESS; error 55 = eglGetError()) { 56 fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), 57 error); 58 } 59} 60 61static void checkGlError(const char* op) { 62 for (GLint error = glGetError(); error; error 63 = glGetError()) { 64 fprintf(stderr, "after %s() glError (0x%x)\n", op, error); 65 } 66} 67 68bool setupGraphics(int w, int h) { 69 glViewport(0, 0, w, h); 70 checkGlError("glViewport"); 71 return true; 72} 73 74int align(int x, int a) { 75 return (x + (a-1)) & (~(a-1)); 76} 77 78const int yuvTexWidth = 600; 79const int yuvTexHeight = 480; 80const int yuvTexUsage = GraphicBuffer::USAGE_HW_TEXTURE | 81 GraphicBuffer::USAGE_SW_WRITE_RARELY; 82const int yuvTexFormat = HAL_PIXEL_FORMAT_YV12; 83const int yuvTexOffsetY = 0; 84const int yuvTexStrideY = (yuvTexWidth + 0xf) & ~0xf; 85const int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight; 86const int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; 87const int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2; 88const int yuvTexStrideU = yuvTexStrideV; 89const bool yuvTexSameUV = false; 90static sp<GraphicBuffer> yuvTexBuffer; 91static GLuint yuvTex; 92 93bool setupYuvTexSurface(EGLDisplay dpy, EGLContext context) { 94 int blockWidth = yuvTexWidth > 16 ? yuvTexWidth / 16 : 1; 95 int blockHeight = yuvTexHeight > 16 ? yuvTexHeight / 16 : 1; 96 yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat, 97 yuvTexUsage); 98 char* buf = NULL; 99 status_t err = yuvTexBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); 100 if (err != 0) { 101 fprintf(stderr, "yuvTexBuffer->lock(...) failed: %d\n", err); 102 return false; 103 } 104 for (int x = 0; x < yuvTexWidth; x++) { 105 for (int y = 0; y < yuvTexHeight; y++) { 106 int parityX = (x / blockWidth) & 1; 107 int parityY = (y / blockHeight) & 1; 108 unsigned char intensity = (parityX ^ parityY) ? 63 : 191; 109 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; 110 if (x < yuvTexWidth / 2 && y < yuvTexHeight / 2) { 111 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity; 112 if (yuvTexSameUV) { 113 buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = intensity; 114 } else if (x < yuvTexWidth / 4 && y < yuvTexHeight / 4) { 115 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] = 116 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] = 117 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] = 118 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = intensity; 119 } 120 } 121 } 122 } 123 124 err = yuvTexBuffer->unlock(); 125 if (err != 0) { 126 fprintf(stderr, "yuvTexBuffer->unlock() failed: %d\n", err); 127 return false; 128 } 129 130 EGLClientBuffer clientBuffer = (EGLClientBuffer)yuvTexBuffer->getNativeBuffer(); 131 EGLImageKHR img = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, 132 clientBuffer, 0); 133 checkEglError("eglCreateImageKHR"); 134 if (img == EGL_NO_IMAGE_KHR) { 135 return false; 136 } 137 138 glGenTextures(1, &yuvTex); 139 checkGlError("glGenTextures"); 140 glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex); 141 checkGlError("glBindTexture"); 142 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)img); 143 checkGlError("glEGLImageTargetTexture2DOES"); 144 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 145 checkGlError("glTexParameteri"); 146 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 147 checkGlError("glTexParameteri"); 148 glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 149 checkGlError("glTexEnvx"); 150 151 GLint crop[4] = { 0, 0, yuvTexWidth, yuvTexHeight }; 152 glTexParameteriv(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_CROP_RECT_OES, crop); 153 checkGlError("glTexParameteriv"); 154 155 return true; 156} 157 158void renderFrame(int w, int h) { 159 glClearColor(0.0f, 0.0f, 1.0f, 1.0f); 160 checkGlError("glClearColor"); 161 glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 162 checkGlError("glClear"); 163 164 glBindTexture(GL_TEXTURE_EXTERNAL_OES, yuvTex); 165 checkGlError("glBindTexture"); 166 glEnable(GL_TEXTURE_EXTERNAL_OES); 167 checkGlError("glEnable"); 168 169 glDrawTexiOES(0, 0, 0, w, h); 170 checkGlError("glDrawTexiOES"); 171} 172 173void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { 174 175#define X(VAL) {VAL, #VAL} 176 struct {EGLint attribute; const char* name;} names[] = { 177 X(EGL_BUFFER_SIZE), 178 X(EGL_ALPHA_SIZE), 179 X(EGL_BLUE_SIZE), 180 X(EGL_GREEN_SIZE), 181 X(EGL_RED_SIZE), 182 X(EGL_DEPTH_SIZE), 183 X(EGL_STENCIL_SIZE), 184 X(EGL_CONFIG_CAVEAT), 185 X(EGL_CONFIG_ID), 186 X(EGL_LEVEL), 187 X(EGL_MAX_PBUFFER_HEIGHT), 188 X(EGL_MAX_PBUFFER_PIXELS), 189 X(EGL_MAX_PBUFFER_WIDTH), 190 X(EGL_NATIVE_RENDERABLE), 191 X(EGL_NATIVE_VISUAL_ID), 192 X(EGL_NATIVE_VISUAL_TYPE), 193 X(EGL_SAMPLES), 194 X(EGL_SAMPLE_BUFFERS), 195 X(EGL_SURFACE_TYPE), 196 X(EGL_TRANSPARENT_TYPE), 197 X(EGL_TRANSPARENT_RED_VALUE), 198 X(EGL_TRANSPARENT_GREEN_VALUE), 199 X(EGL_TRANSPARENT_BLUE_VALUE), 200 X(EGL_BIND_TO_TEXTURE_RGB), 201 X(EGL_BIND_TO_TEXTURE_RGBA), 202 X(EGL_MIN_SWAP_INTERVAL), 203 X(EGL_MAX_SWAP_INTERVAL), 204 X(EGL_LUMINANCE_SIZE), 205 X(EGL_ALPHA_MASK_SIZE), 206 X(EGL_COLOR_BUFFER_TYPE), 207 X(EGL_RENDERABLE_TYPE), 208 X(EGL_CONFORMANT), 209 }; 210#undef X 211 212 for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { 213 EGLint value = -1; 214 EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); 215 EGLint error = eglGetError(); 216 if (returnVal && error == EGL_SUCCESS) { 217 printf(" %s: ", names[j].name); 218 printf("%d (0x%x)", value, value); 219 } 220 } 221 printf("\n"); 222} 223 224int main(int argc, char** argv) { 225 EGLBoolean returnValue; 226 EGLConfig myConfig = {0}; 227 228 EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE }; 229 EGLint s_configAttribs[] = { 230 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 231 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, 232 EGL_NONE }; 233 EGLint majorVersion; 234 EGLint minorVersion; 235 EGLContext context; 236 EGLSurface surface; 237 EGLint w, h; 238 239 EGLDisplay dpy; 240 241 checkEglError("<init>"); 242 dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 243 checkEglError("eglGetDisplay"); 244 if (dpy == EGL_NO_DISPLAY) { 245 printf("eglGetDisplay returned EGL_NO_DISPLAY.\n"); 246 return 0; 247 } 248 249 returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); 250 checkEglError("eglInitialize", returnValue); 251 fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); 252 if (returnValue != EGL_TRUE) { 253 printf("eglInitialize failed\n"); 254 return 0; 255 } 256 257 WindowSurface windowSurface; 258 EGLNativeWindowType window = windowSurface.getSurface(); 259 returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig); 260 if (returnValue) { 261 printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue); 262 return 1; 263 } 264 265 checkEglError("EGLUtils::selectConfigForNativeWindow"); 266 267 printf("Chose this configuration:\n"); 268 printEGLConfiguration(dpy, myConfig); 269 270 surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); 271 checkEglError("eglCreateWindowSurface"); 272 if (surface == EGL_NO_SURFACE) { 273 printf("gelCreateWindowSurface failed.\n"); 274 return 1; 275 } 276 277 context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs); 278 checkEglError("eglCreateContext"); 279 if (context == EGL_NO_CONTEXT) { 280 printf("eglCreateContext failed\n"); 281 return 1; 282 } 283 returnValue = eglMakeCurrent(dpy, surface, surface, context); 284 checkEglError("eglMakeCurrent", returnValue); 285 if (returnValue != EGL_TRUE) { 286 return 1; 287 } 288 eglQuerySurface(dpy, surface, EGL_WIDTH, &w); 289 checkEglError("eglQuerySurface"); 290 eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); 291 checkEglError("eglQuerySurface"); 292 GLint dim = w < h ? w : h; 293 294 fprintf(stderr, "Window dimensions: %d x %d\n", w, h); 295 296 printGLString("Version", GL_VERSION); 297 printGLString("Vendor", GL_VENDOR); 298 printGLString("Renderer", GL_RENDERER); 299 printGLString("Extensions", GL_EXTENSIONS); 300 301 if(!setupYuvTexSurface(dpy, context)) { 302 fprintf(stderr, "Could not set up texture surface.\n"); 303 return 1; 304 } 305 306 if(!setupGraphics(w, h)) { 307 fprintf(stderr, "Could not set up graphics.\n"); 308 return 1; 309 } 310 311 for (;;) { 312 static int dir = -1; 313 314 renderFrame(w, h); 315 eglSwapBuffers(dpy, surface); 316 checkEglError("eglSwapBuffers"); 317 318 if (w <= 10 || h <= 10) 319 { 320 dir = -dir; 321 } 322 323 if (w >= 1300 || h >= 900) 324 { 325 dir = -dir; 326 } 327 328 329 w += dir; 330 h += dir; 331 } 332 333 return 0; 334} 335