blob: 12a5464ed473db57abb8a04012acfb7b6c6624da [file] [log] [blame]
Zach Reiznere60ae5d2014-12-03 15:55:53 -08001/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6#include <errno.h>
7#include <fcntl.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <string.h>
11#include <sys/types.h>
12#include <unistd.h>
13
14#define EGL_EGLEXT_PROTOTYPES
15#define GL_GLEXT_PROTOTYPES
16
17#include <EGL/egl.h>
18#include <EGL/eglext.h>
19#include <GLES2/gl2.h>
20#include <GLES2/gl2ext.h>
21
22const char * get_gl_error()
23{
24 switch (glGetError()) {
25 case GL_NO_ERROR:
26 return "No error has been recorded.";
27 case GL_INVALID_ENUM:
28 return "An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.";
29 case GL_INVALID_VALUE:
30 return "A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.";
31 case GL_INVALID_OPERATION:
32 return "The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.";
33 case GL_INVALID_FRAMEBUFFER_OPERATION:
34 return "The command is trying to render to or read from the framebuffer while the currently bound framebuffer is not framebuffer complete (i.e. the return value from glCheckFramebufferStatus is not GL_FRAMEBUFFER_COMPLETE). The offending command is ignored and has no other side effect than to set the error flag.";
35 case GL_OUT_OF_MEMORY:
36 return "There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.";
37 default:
38 return "Unknown error";
39 }
40}
41
42const char * get_egl_error()
43{
44 switch (eglGetError()) {
45 case EGL_SUCCESS:
46 return "The last function succeeded without error.";
47 case EGL_NOT_INITIALIZED:
48 return "EGL is not initialized, or could not be initialized, for the specified EGL display connection.";
49 case EGL_BAD_ACCESS:
50 return "EGL cannot access a requested resource (for example a context is bound in another thread).";
51 case EGL_BAD_ALLOC:
52 return "EGL failed to allocate resources for the requested operation.";
53 case EGL_BAD_ATTRIBUTE:
54 return "An unrecognized attribute or attribute value was passed in the attribute list.";
55 case EGL_BAD_CONTEXT:
56 return "An EGLContext argument does not name a valid EGL rendering context.";
57 case EGL_BAD_CONFIG:
58 return "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
59 case EGL_BAD_CURRENT_SURFACE:
60 return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid.";
61 case EGL_BAD_DISPLAY:
62 return "An EGLDisplay argument does not name a valid EGL display connection.";
63 case EGL_BAD_SURFACE:
64 return "An EGLSurface argument does not name a valid surface (window, pixel buffer or pixmap) configured for GL rendering.";
65 case EGL_BAD_MATCH:
66 return "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface).";
67 case EGL_BAD_PARAMETER:
68 return "One or more argument values are invalid.";
69 case EGL_BAD_NATIVE_PIXMAP:
70 return "A NativePixmapType argument does not refer to a valid native pixmap.";
71 case EGL_BAD_NATIVE_WINDOW:
72 return "A NativeWindowType argument does not refer to a valid native window.";
73 case EGL_CONTEXT_LOST:
74 return "A power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering.";
75 default:
76 return "Unknown error";
77 }
78}
79
80struct context {
81 unsigned width;
82 unsigned height;
83 EGLDisplay egl_display;
84 EGLContext egl_ctx;
85
86 unsigned gl_fb;
87 unsigned gl_rb;
88
89};
90
91float f(int i) {
92 int a = i % 40;
93 int b = (i / 40) % 6;
94 switch (b) {
95 case 0:
96 case 1:
97 return 0.0f;
98 case 3:
99 case 4:
100 return 1.0f;
101 case 2:
102 return (a / 40.0f);
103 case 5:
104 return 1.0f - (a / 40.0f);
105 default:
106 return 0.0f;
107 }
108}
109
110void draw(struct context * ctx)
111{
112 int i;
113 const GLchar *vertexShaderStr =
114 "attribute vec4 vPosition;\n"
115 "attribute vec4 vColor;\n"
116 "varying vec4 vFillColor;\n"
117 "void main() {\n"
118 " gl_Position = vPosition;\n"
119 " vFillColor = vColor;\n"
120 "}\n";
121 const GLchar *fragmentShaderStr =
122 "precision mediump float;\n"
123 "varying vec4 vFillColor;\n"
124 "void main() {\n"
125 " gl_FragColor = vFillColor;\n"
126 "}\n";
127 GLint vertexShader, fragmentShader, program, status;
128
129 vertexShader = glCreateShader(GL_VERTEX_SHADER);
130 if (!vertexShader) {
131 fprintf(stderr, "Failed to create vertex shader. Error=0x%x\n", glGetError());
132 return;
133 }
134 glShaderSource(vertexShader, 1, &vertexShaderStr, NULL);
135 glCompileShader(vertexShader);
136 glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
137 if (!status) {
138 fprintf(stderr, "Failed to compile vertex shader. Error=0x%x\n", glGetError());
139 return;
140 }
141
142 fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
143 if (!fragmentShader) {
144 fprintf(stderr, "Failed to create fragment shader. Error=0x%x\n", glGetError());
145 return;
146 }
147 glShaderSource(fragmentShader, 1, &fragmentShaderStr, NULL);
148 glCompileShader(fragmentShader);
149 glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);
150 if (!status) {
151 fprintf(stderr, "Failed to compile fragment shader. Error=0x%x\n", glGetError());
152 return;
153 }
154
155
156 program = glCreateProgram();
157 if (!program) {
158 fprintf(stderr, "Failed to create program.\n");
159 return;
160 }
161 glAttachShader(program, vertexShader);
162 glAttachShader(program, fragmentShader);
163 glBindAttribLocation(program, 0, "vPosition");
164 glBindAttribLocation(program, 1, "vColor");
165 glLinkProgram(program);
166 glGetShaderiv(program, GL_LINK_STATUS, &status);
167 if (!status) {
168 fprintf(stderr, "Failed to link program.\n");
169 return;
170 }
171
172
173 glViewport(0, 0,(GLint) ctx->width,
174 (GLint) ctx->height);
175
176 for (i = 0; i <= 500; i++) {
177 GLfloat verts[] = {
178 0.0f, -0.5f, 0.0f,
179 -0.5f, 0.5f, 0.0f,
180 0.5f, 0.5f, 0.0f
181 };
182 GLfloat colors[] = {
183 1.0f, 0.0f, 0.0f, 1.0f,
184 0.0f, 1.0f, 0.0f, 1.0f,
185 0.0f, 0.0f, 1.0f, 1.0f
186 };
187
188 glClearColor(f(i), f(i + 80), f(i + 160), 0.0f);
189 glClear(GL_COLOR_BUFFER_BIT);
190
191 glUseProgram(program);
192 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, verts);
193 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, colors);
194 glEnableVertexAttribArray(0);
195 glEnableVertexAttribArray(1);
196 glDrawArrays(GL_TRIANGLES, 0, 3);
197
198 usleep(1e6 / 120); /* 120 Hz */
199 glFinish();
200
201 unsigned char pixels[4];
202 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
203 fprintf(stderr, "color = %hhu %hhu %hhu %hhu\n",
204 pixels[0], pixels[1], pixels[2], pixels[3]);
205 }
206
207 glDeleteProgram(program);
208}
209
210int main(int argc, char ** argv)
211{
212 int ret = 0;
213 struct context ctx;
214 EGLint egl_major, egl_minor;
215 const char * extensions;
216 EGLint num_configs;
217 EGLConfig egl_config;
218
219 ctx.width = 800;
220 ctx.height = 600;
221
222 const EGLint config_attribs[] = {
223 EGL_RED_SIZE, 1,
224 EGL_GREEN_SIZE, 1,
225 EGL_BLUE_SIZE, 1,
226 EGL_DEPTH_SIZE, 1,
227 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
228 EGL_NONE
229 };
230 const EGLint context_attribs[] = {
231 EGL_CONTEXT_CLIENT_VERSION, 2,
232 EGL_NONE
233 };
234
235 ctx.egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
236 if (ctx.egl_display == EGL_NO_DISPLAY) {
237 fprintf(stderr, "failed to get egl display\n");
238 ret = 1;
239 goto fail;
240 }
241
242 if (!eglInitialize(ctx.egl_display, &egl_major, &egl_minor)) {
243 fprintf(stderr, "failed to initialize egl: %s\n",
244 get_egl_error());
245 ret = 1;
246 goto terminate_display;
247 }
248
249 fprintf(stderr, "EGL %d.%d\n", egl_major, egl_minor);
250 fprintf(stderr, "EGL %s\n",
251 eglQueryString(ctx.egl_display, EGL_VERSION));
252
253 extensions = eglQueryString(ctx.egl_display, EGL_EXTENSIONS);
254 fprintf(stderr, "EGL Extensions: %s\n", extensions);
255
256 if (!eglChooseConfig(ctx.egl_display, config_attribs, NULL, 0,
257 &num_configs)) {
258 fprintf(stderr, "eglChooseConfig() failed with error: %x\n",
259 eglGetError());
260 goto terminate_display;
261 }
262 if (!eglChooseConfig(ctx.egl_display, config_attribs, &egl_config, 1,
263 &num_configs)) {
264 fprintf(stderr, "eglChooseConfig() failed with error: %x\n",
265 eglGetError());
266 goto terminate_display;
267 }
268
269 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
270 fprintf(stderr, "failed to bind OpenGL ES: %s\n",
271 get_egl_error());
272 ret = 1;
273 goto terminate_display;
274 }
275
276 ctx.egl_ctx = eglCreateContext(ctx.egl_display,
277 NULL /* No framebuffer */,
278 EGL_NO_CONTEXT /* No shared context */,
279 context_attribs);
280 if (ctx.egl_ctx == EGL_NO_CONTEXT) {
281 fprintf(stderr, "failed to create OpenGL ES Context: %s\n",
282 get_egl_error());
283 ret = 1;
284 goto terminate_display;
285 }
286
287 if (!eglMakeCurrent(ctx.egl_display,
288 EGL_NO_SURFACE /* No default draw surface */,
289 EGL_NO_SURFACE /* No default draw read */,
290 ctx.egl_ctx)) {
291 fprintf(stderr, "failed to make the OpenGL ES Context current: %s\n",
292 get_egl_error());
293 ret = 1;
294 goto destroy_context;
295 }
296
297 fprintf(stderr, "GL extensions: %s\n", glGetString(GL_EXTENSIONS));
298
299 glGenFramebuffers(1, &ctx.gl_fb);
300 glBindFramebuffer(GL_FRAMEBUFFER, ctx.gl_fb);
301 glGenRenderbuffers(1, &ctx.gl_rb);
302 glBindRenderbuffer(GL_RENDERBUFFER, ctx.gl_rb);
303 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES,
304 ctx.width, ctx.height);
305 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
306 GL_RENDERBUFFER, ctx.gl_rb);
307
308 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
309 GL_FRAMEBUFFER_COMPLETE) {
310 fprintf(stderr, "failed to create framebuffer: %s\n",
311 get_gl_error());
312 ret = 1;
313 goto delete_gl_buffers;
314 }
315
316 draw(&ctx);
317
318delete_gl_buffers:
319 glBindRenderbuffer(GL_RENDERBUFFER, 0);
320 glBindFramebuffer(GL_FRAMEBUFFER, 0);
321 glDeleteFramebuffers(1, &ctx.gl_fb);
322 glDeleteRenderbuffers(1, &ctx.gl_rb);
323destroy_context:
324 eglDestroyContext(ctx.egl_display, ctx.egl_ctx);
325terminate_display:
326 eglTerminate(ctx.egl_display);
327fail:
328 return ret;
329}