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 
34 using namespace android;
35 
printGLString(const char * name,GLenum s)36 static 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 
checkEglError(const char * op,EGLBoolean returnVal=EGL_TRUE)49 static 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 
checkGlError(const char * op)61 static 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 
setupGraphics(int w,int h)68 bool setupGraphics(int w, int h) {
69     glViewport(0, 0, w, h);
70     checkGlError("glViewport");
71     return true;
72 }
73 
align(int x,int a)74 int align(int x, int a) {
75     return (x + (a-1)) & (~(a-1));
76 }
77 
78 const int yuvTexWidth = 600;
79 const int yuvTexHeight = 480;
80 const int yuvTexUsage = GraphicBuffer::USAGE_HW_TEXTURE |
81         GraphicBuffer::USAGE_SW_WRITE_RARELY;
82 const int yuvTexFormat = HAL_PIXEL_FORMAT_YV12;
83 const int yuvTexOffsetY = 0;
84 const int yuvTexStrideY = (yuvTexWidth + 0xf) & ~0xf;
85 const int yuvTexOffsetV = yuvTexStrideY * yuvTexHeight;
86 const int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
87 const int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * yuvTexHeight/2;
88 const int yuvTexStrideU = yuvTexStrideV;
89 const bool yuvTexSameUV = false;
90 static sp<GraphicBuffer> yuvTexBuffer;
91 static GLuint yuvTex;
92 
setupYuvTexSurface(EGLDisplay dpy,EGLContext context)93 bool 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 
renderFrame(int w,int h)158 void 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 
printEGLConfiguration(EGLDisplay dpy,EGLConfig config)173 void 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 
main(int argc,char ** argv)224 int 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