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 <WindowSurface.h>
30 #include <EGLUtils.h>
31 
32 using namespace android;
33 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
34 
35 #define METADATA_SCALE(x) (static_cast<EGLint>(x * EGL_METADATA_SCALING_EXT))
36 
printGLString(const char * name,GLenum s)37 static void printGLString(const char *name, GLenum s) {
38     // fprintf(stderr, "printGLString %s, %d\n", name, s);
39     const char *v = (const char *) glGetString(s);
40     // int error = glGetError();
41     // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
42     //        (unsigned int) v);
43     // if ((v < (const char*) 0) || (v > (const char*) 0x10000))
44     //    fprintf(stderr, "GL %s = %s\n", name, v);
45     // else
46     //    fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
47     fprintf(stderr, "GL %s = %s\n", name, v);
48 }
49 
printEGLString(EGLDisplay dpy,const char * name,GLenum s)50 static void printEGLString(EGLDisplay dpy, const char *name, GLenum s) {
51     const char *v = (const char *) eglQueryString(dpy, s);
52     const char* va = (const char*)eglQueryStringImplementationANDROID(dpy, s);
53     fprintf(stderr, "GL %s = %s\nImplementationANDROID: %s\n", name, v, va);
54 }
55 
checkEglError(const char * op,EGLBoolean returnVal=EGL_TRUE)56 static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
57     if (returnVal != EGL_TRUE) {
58         fprintf(stderr, "%s() returned %d\n", op, returnVal);
59     }
60 
61     for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
62             = eglGetError()) {
63         fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
64                 error);
65     }
66 }
67 
checkGlError(const char * op)68 static void checkGlError(const char* op) {
69     for (GLint error = glGetError(); error; error
70             = glGetError()) {
71         fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
72     }
73 }
74 
75 static const char gVertexShader[] = "attribute vec4 vPosition;\n"
76     "void main() {\n"
77     "  gl_Position = vPosition;\n"
78     "}\n";
79 
80 static const char gFragmentShader[] = "precision mediump float;\n"
81     "void main() {\n"
82     "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
83     "}\n";
84 
loadShader(GLenum shaderType,const char * pSource)85 GLuint loadShader(GLenum shaderType, const char* pSource) {
86     GLuint shader = glCreateShader(shaderType);
87     if (shader) {
88         glShaderSource(shader, 1, &pSource, NULL);
89         glCompileShader(shader);
90         GLint compiled = 0;
91         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
92         if (!compiled) {
93             GLint infoLen = 0;
94             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
95             if (infoLen) {
96                 char* buf = (char*) malloc(infoLen);
97                 if (buf) {
98                     glGetShaderInfoLog(shader, infoLen, NULL, buf);
99                     fprintf(stderr, "Could not compile shader %d:\n%s\n",
100                             shaderType, buf);
101                     free(buf);
102                 }
103                 glDeleteShader(shader);
104                 shader = 0;
105             }
106         }
107     }
108     return shader;
109 }
110 
createProgram(const char * pVertexSource,const char * pFragmentSource)111 GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
112     GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
113     if (!vertexShader) {
114         return 0;
115     }
116 
117     GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
118     if (!pixelShader) {
119         return 0;
120     }
121 
122     GLuint program = glCreateProgram();
123     if (program) {
124         glAttachShader(program, vertexShader);
125         checkGlError("glAttachShader");
126         glAttachShader(program, pixelShader);
127         checkGlError("glAttachShader");
128         glLinkProgram(program);
129         GLint linkStatus = GL_FALSE;
130         glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
131         if (linkStatus != GL_TRUE) {
132             GLint bufLength = 0;
133             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
134             if (bufLength) {
135                 char* buf = (char*) malloc(bufLength);
136                 if (buf) {
137                     glGetProgramInfoLog(program, bufLength, NULL, buf);
138                     fprintf(stderr, "Could not link program:\n%s\n", buf);
139                     free(buf);
140                 }
141             }
142             glDeleteProgram(program);
143             program = 0;
144         }
145     }
146     return program;
147 }
148 
149 GLuint gProgram;
150 GLuint gvPositionHandle;
151 
setupGraphics(int w,int h)152 bool setupGraphics(int w, int h) {
153     gProgram = createProgram(gVertexShader, gFragmentShader);
154     if (!gProgram) {
155         return false;
156     }
157     gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
158     checkGlError("glGetAttribLocation");
159     fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n",
160             gvPositionHandle);
161 
162     glViewport(0, 0, w, h);
163     checkGlError("glViewport");
164     return true;
165 }
166 
167 const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
168         0.5f, -0.5f };
169 
renderFrame()170 void renderFrame() {
171     glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
172     checkGlError("glClearColor");
173     glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
174     checkGlError("glClear");
175 
176     glUseProgram(gProgram);
177     checkGlError("glUseProgram");
178 
179     glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
180     checkGlError("glVertexAttribPointer");
181     glEnableVertexAttribArray(gvPositionHandle);
182     checkGlError("glEnableVertexAttribArray");
183     glDrawArrays(GL_TRIANGLES, 0, 3);
184     checkGlError("glDrawArrays");
185 }
186 
printEGLConfiguration(EGLDisplay dpy,EGLConfig config)187 void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
188 
189 #define X(VAL) {VAL, #VAL}
190     struct {EGLint attribute; const char* name;} names[] = {
191     X(EGL_BUFFER_SIZE),
192     X(EGL_ALPHA_SIZE),
193     X(EGL_BLUE_SIZE),
194     X(EGL_GREEN_SIZE),
195     X(EGL_RED_SIZE),
196     X(EGL_DEPTH_SIZE),
197     X(EGL_STENCIL_SIZE),
198     X(EGL_CONFIG_CAVEAT),
199     X(EGL_CONFIG_ID),
200     X(EGL_LEVEL),
201     X(EGL_MAX_PBUFFER_HEIGHT),
202     X(EGL_MAX_PBUFFER_PIXELS),
203     X(EGL_MAX_PBUFFER_WIDTH),
204     X(EGL_NATIVE_RENDERABLE),
205     X(EGL_NATIVE_VISUAL_ID),
206     X(EGL_NATIVE_VISUAL_TYPE),
207     X(EGL_SAMPLES),
208     X(EGL_SAMPLE_BUFFERS),
209     X(EGL_SURFACE_TYPE),
210     X(EGL_TRANSPARENT_TYPE),
211     X(EGL_TRANSPARENT_RED_VALUE),
212     X(EGL_TRANSPARENT_GREEN_VALUE),
213     X(EGL_TRANSPARENT_BLUE_VALUE),
214     X(EGL_BIND_TO_TEXTURE_RGB),
215     X(EGL_BIND_TO_TEXTURE_RGBA),
216     X(EGL_MIN_SWAP_INTERVAL),
217     X(EGL_MAX_SWAP_INTERVAL),
218     X(EGL_LUMINANCE_SIZE),
219     X(EGL_ALPHA_MASK_SIZE),
220     X(EGL_COLOR_BUFFER_TYPE),
221     X(EGL_RENDERABLE_TYPE),
222     X(EGL_CONFORMANT),
223    };
224 #undef X
225 
226     for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
227         EGLint value = -1;
228         EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
229         EGLint error = eglGetError();
230         if (returnVal && error == EGL_SUCCESS) {
231             printf(" %s: ", names[j].name);
232             printf("%d (0x%x)", value, value);
233         }
234     }
235     printf("\n");
236 }
237 
printEGLConfigurations(EGLDisplay dpy)238 int printEGLConfigurations(EGLDisplay dpy) {
239     EGLint numConfig = 0;
240     EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
241     checkEglError("eglGetConfigs", returnVal);
242     if (!returnVal) {
243         return false;
244     }
245 
246     printf("Number of EGL configuration: %d\n", numConfig);
247 
248     EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig);
249     if (! configs) {
250         printf("Could not allocate configs.\n");
251         return false;
252     }
253 
254     returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig);
255     checkEglError("eglGetConfigs", returnVal);
256     if (!returnVal) {
257         free(configs);
258         return false;
259     }
260 
261     for(int i = 0; i < numConfig; i++) {
262         printf("Configuration %d\n", i);
263         printEGLConfiguration(dpy, configs[i]);
264     }
265 
266     free(configs);
267     return true;
268 }
269 
setSurfaceMetadata(EGLDisplay dpy,EGLSurface surface)270 void setSurfaceMetadata(EGLDisplay dpy, EGLSurface surface) {
271     static EGLBoolean toggle = GL_FALSE;
272     if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_SMPTE2086_metadata")) {
273         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT, METADATA_SCALE(0.640));
274         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT, METADATA_SCALE(0.330));
275         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT, METADATA_SCALE(0.290));
276         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT, METADATA_SCALE(0.600));
277         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT, METADATA_SCALE(0.150));
278         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT, METADATA_SCALE(0.060));
279         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_X_EXT, METADATA_SCALE(0.3127));
280         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_WHITE_POINT_Y_EXT, METADATA_SCALE(0.3290));
281         if (toggle) {
282             eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(350));
283         } else {
284             eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MAX_LUMINANCE_EXT, METADATA_SCALE(300));
285         }
286         eglSurfaceAttrib(dpy, surface, EGL_SMPTE2086_MIN_LUMINANCE_EXT, METADATA_SCALE(0.7));
287     }
288 
289     if (EGLUtils::hasEglExtension(dpy, "EGL_EXT_surface_CTA861_3_metadata")) {
290         if (toggle) {
291             eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
292                              METADATA_SCALE(300));
293         } else {
294             eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT,
295                              METADATA_SCALE(325));
296         }
297         eglSurfaceAttrib(dpy, surface, EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT,
298                          METADATA_SCALE(75));
299     }
300     toggle = !toggle;
301 }
302 
main(int,char **)303 int main(int /*argc*/, char** /*argv*/) {
304     EGLBoolean returnValue;
305     EGLConfig myConfig = {0};
306 
307     EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
308     EGLint s_configAttribs[] = {
309             EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
310             EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
311             EGL_NONE };
312     EGLint majorVersion;
313     EGLint minorVersion;
314     EGLContext context;
315     EGLSurface surface;
316     EGLint w, h;
317 
318     EGLDisplay dpy;
319 
320     checkEglError("<init>");
321     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
322     checkEglError("eglGetDisplay");
323     if (dpy == EGL_NO_DISPLAY) {
324         printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
325         return 0;
326     }
327 
328     returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
329     checkEglError("eglInitialize", returnValue);
330     fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
331     if (returnValue != EGL_TRUE) {
332         printf("eglInitialize failed\n");
333         return 0;
334     }
335 
336     if (!printEGLConfigurations(dpy)) {
337         printf("printEGLConfigurations failed\n");
338         return 0;
339     }
340 
341     checkEglError("printEGLConfigurations");
342 
343     WindowSurface windowSurface;
344     EGLNativeWindowType window = windowSurface.getSurface();
345     returnValue = EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &myConfig);
346     if (returnValue) {
347         printf("EGLUtils::selectConfigForNativeWindow() returned %d", returnValue);
348         return 0;
349     }
350 
351     checkEglError("EGLUtils::selectConfigForNativeWindow");
352 
353     printf("Chose this configuration:\n");
354     printEGLConfiguration(dpy, myConfig);
355 
356     EGLint winAttribs[] = {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE};
357     surface = eglCreateWindowSurface(dpy, myConfig, window, winAttribs);
358     checkEglError("eglCreateWindowSurface");
359     if (surface == EGL_NO_SURFACE) {
360         printf("eglCreateWindowSurface failed.\n");
361         return 0;
362     }
363 
364     context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
365     checkEglError("eglCreateContext");
366     if (context == EGL_NO_CONTEXT) {
367         printf("eglCreateContext failed\n");
368         return 0;
369     }
370     returnValue = eglMakeCurrent(dpy, surface, surface, context);
371     checkEglError("eglMakeCurrent", returnValue);
372     if (returnValue != EGL_TRUE) {
373         return 0;
374     }
375     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
376     checkEglError("eglQuerySurface");
377     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
378     checkEglError("eglQuerySurface");
379 
380     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
381 
382     printGLString("Version", GL_VERSION);
383     printGLString("Vendor", GL_VENDOR);
384     printGLString("Renderer", GL_RENDERER);
385     printGLString("Extensions", GL_EXTENSIONS);
386     printEGLString(dpy, "EGL Extensions", EGL_EXTENSIONS);
387 
388     if(!setupGraphics(w, h)) {
389         fprintf(stderr, "Could not set up graphics.\n");
390         return 0;
391     }
392 
393     for (;;) {
394         renderFrame();
395         setSurfaceMetadata(dpy, surface);
396         eglSwapBuffers(dpy, surface);
397         checkEglError("eglSwapBuffers");
398     }
399 
400     return 0;
401 }
402