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