simple-egl: Minor fix ups.
[profile/ivi/weston.git] / clients / simple-egl.c
1 /*
2  * Copyright © 2011 Benjamin Franzke
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdbool.h>
27 #include <math.h>
28 #include <assert.h>
29 #include <signal.h>
30
31 #include <wayland-client.h>
32 #include <wayland-egl.h>
33
34 #include <GLES2/gl2.h>
35 #include <EGL/egl.h>
36
37 struct window;
38 struct seat;
39
40 struct display {
41         struct wl_display *display;
42         struct wl_compositor *compositor;
43         struct wl_shell *shell;
44         struct wl_seat *seat;
45         struct wl_pointer *pointer;
46         struct {
47                 EGLDisplay dpy;
48                 EGLContext ctx;
49                 EGLConfig conf;
50         } egl;
51         uint32_t mask;
52         struct window *window;
53 };
54
55 struct window {
56         struct display *display;
57         struct {
58                 int width, height;
59         } geometry;
60         struct {
61                 GLuint fbo;
62                 GLuint color_rbo;
63
64                 GLuint rotation_uniform;
65
66                 GLuint pos;
67                 GLuint col;
68         } gl;
69
70         struct wl_egl_window *native;
71         struct wl_surface *surface;
72         struct wl_shell_surface *shell_surface;
73         EGLSurface egl_surface;
74         struct wl_callback *callback;
75         int fullscreen, configured;
76 };
77
78 static const char *vert_shader_text =
79         "uniform mat4 rotation;\n"
80         "attribute vec4 pos;\n"
81         "attribute vec4 color;\n"
82         "varying vec4 v_color;\n"
83         "void main() {\n"
84         "  gl_Position = rotation * pos;\n"
85         "  v_color = color;\n"
86         "}\n";
87
88 static const char *frag_shader_text =
89         "precision mediump float;\n"
90         "varying vec4 v_color;\n"
91         "void main() {\n"
92         "  gl_FragColor = v_color;\n"
93         "}\n";
94
95 static void
96 init_egl(struct display *display, EGLint alpha_size)
97 {
98         static const EGLint context_attribs[] = {
99                 EGL_CONTEXT_CLIENT_VERSION, 2,
100                 EGL_NONE
101         };
102
103         EGLint config_attribs[] = {
104                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
105                 EGL_RED_SIZE, 1,
106                 EGL_GREEN_SIZE, 1,
107                 EGL_BLUE_SIZE, 1,
108                 EGL_ALPHA_SIZE, alpha_size,
109                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
110                 EGL_NONE
111         };
112
113         EGLint major, minor, n;
114         EGLBoolean ret;
115
116         display->egl.dpy = eglGetDisplay(display->display);
117         assert(display->egl.dpy);
118
119         ret = eglInitialize(display->egl.dpy, &major, &minor);
120         assert(ret == EGL_TRUE);
121         ret = eglBindAPI(EGL_OPENGL_ES_API);
122         assert(ret == EGL_TRUE);
123
124         ret = eglChooseConfig(display->egl.dpy, config_attribs,
125                               &display->egl.conf, 1, &n);
126         assert(ret && n == 1);
127
128         display->egl.ctx = eglCreateContext(display->egl.dpy,
129                                             display->egl.conf,
130                                             EGL_NO_CONTEXT, context_attribs);
131         assert(display->egl.ctx);
132
133 }
134
135 static void
136 fini_egl(struct display *display)
137 {
138         /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
139          * on eglReleaseThread(). */
140         eglMakeCurrent(display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
141                        EGL_NO_CONTEXT);
142
143         eglTerminate(display->egl.dpy);
144         eglReleaseThread();
145 }
146
147 static GLuint
148 create_shader(struct window *window, const char *source, GLenum shader_type)
149 {
150         GLuint shader;
151         GLint status;
152
153         shader = glCreateShader(shader_type);
154         assert(shader != 0);
155
156         glShaderSource(shader, 1, (const char **) &source, NULL);
157         glCompileShader(shader);
158
159         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
160         if (!status) {
161                 char log[1000];
162                 GLsizei len;
163                 glGetShaderInfoLog(shader, 1000, &len, log);
164                 fprintf(stderr, "Error: compiling %s: %*s\n",
165                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
166                         len, log);
167                 exit(1);
168         }
169
170         return shader;
171 }
172
173 static void
174 init_gl(struct window *window)
175 {
176         GLuint frag, vert;
177         GLuint program;
178         GLint status;
179
180         glViewport(0, 0, window->geometry.width, window->geometry.height);
181
182         frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
183         vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
184
185         program = glCreateProgram();
186         glAttachShader(program, frag);
187         glAttachShader(program, vert);
188         glLinkProgram(program);
189
190         glGetProgramiv(program, GL_LINK_STATUS, &status);
191         if (!status) {
192                 char log[1000];
193                 GLsizei len;
194                 glGetProgramInfoLog(program, 1000, &len, log);
195                 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
196                 exit(1);
197         }
198
199         glUseProgram(program);
200         
201         window->gl.pos = 0;
202         window->gl.col = 1;
203
204         glBindAttribLocation(program, window->gl.pos, "pos");
205         glBindAttribLocation(program, window->gl.col, "color");
206         glLinkProgram(program);
207
208         window->gl.rotation_uniform =
209                 glGetUniformLocation(program, "rotation");
210 }
211
212 static void
213 handle_ping(void *data, struct wl_shell_surface *shell_surface,
214             uint32_t serial)
215 {
216         wl_shell_surface_pong(shell_surface, serial);
217 }
218
219 static void
220 handle_configure(void *data, struct wl_shell_surface *shell_surface,
221                  uint32_t edges, int32_t width, int32_t height)
222 {
223         struct window *window = data;
224
225         window->geometry.width = width;
226         window->geometry.height = height;
227         window->configured = 1;
228 }
229
230 static void
231 handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
232 {
233 }
234
235 static const struct wl_shell_surface_listener shell_surface_listener = {
236         handle_ping,
237         handle_configure,
238         handle_popup_done
239 };
240
241 static void
242 create_surface(struct window *window)
243 {
244         struct display *display = window->display;
245         EGLBoolean ret;
246         
247         window->surface = wl_compositor_create_surface(display->compositor);
248         window->shell_surface = wl_shell_get_shell_surface(display->shell,
249                                                            window->surface);
250
251         wl_shell_surface_add_listener(window->shell_surface,
252                                       &shell_surface_listener, window);
253
254         if (window->fullscreen) {
255                 window->configured = 0;
256                 wl_shell_surface_set_fullscreen(window->shell_surface,
257                                                 WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
258                                                 0, NULL);
259
260                 while (!window->configured)
261                         wl_display_iterate(display->display, display->mask);
262         }
263         else
264                 wl_shell_surface_set_toplevel(window->shell_surface);
265
266         window->native =
267                 wl_egl_window_create(window->surface,
268                                      window->geometry.width,
269                                      window->geometry.height);
270         window->egl_surface =
271                 eglCreateWindowSurface(display->egl.dpy,
272                                        display->egl.conf,
273                                        window->native, NULL);
274
275         ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
276                              window->egl_surface, window->display->egl.ctx);
277         assert(ret == EGL_TRUE);
278 }
279
280 static void
281 destroy_surface(struct window *window)
282 {
283         wl_egl_window_destroy(window->native);
284
285         wl_shell_surface_destroy(window->shell_surface);
286         wl_surface_destroy(window->surface);
287
288         if (window->callback)
289                 wl_callback_destroy(window->callback);
290 }
291
292 static const struct wl_callback_listener frame_listener;
293
294 static void
295 redraw(void *data, struct wl_callback *callback, uint32_t time)
296 {
297         struct window *window = data;
298         static const GLfloat verts[3][2] = {
299                 { -0.5, -0.5 },
300                 {  0.5, -0.5 },
301                 {  0,    0.5 }
302         };
303         static const GLfloat colors[3][3] = {
304                 { 1, 0, 0 },
305                 { 0, 1, 0 },
306                 { 0, 0, 1 }
307         };
308         GLfloat angle;
309         GLfloat rotation[4][4] = {
310                 { 1, 0, 0, 0 },
311                 { 0, 1, 0, 0 },
312                 { 0, 0, 1, 0 },
313                 { 0, 0, 0, 1 }
314         };
315         static const int32_t speed_div = 5;
316         static uint32_t start_time = 0;
317
318         if (start_time == 0)
319                 start_time = time;
320
321         angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;
322         rotation[0][0] =  cos(angle);
323         rotation[0][2] =  sin(angle);
324         rotation[2][0] = -sin(angle);
325         rotation[2][2] =  cos(angle);
326
327         glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
328                            (GLfloat *) rotation);
329
330         glClearColor(0.0, 0.0, 0.0, 0.5);
331         glClear(GL_COLOR_BUFFER_BIT);
332
333         glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
334         glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);
335         glEnableVertexAttribArray(window->gl.pos);
336         glEnableVertexAttribArray(window->gl.col);
337
338         glDrawArrays(GL_TRIANGLES, 0, 3);
339
340         glDisableVertexAttribArray(window->gl.pos);
341         glDisableVertexAttribArray(window->gl.col);
342
343         eglSwapBuffers(window->display->egl.dpy, window->egl_surface);
344         if (callback)
345                 wl_callback_destroy(callback);
346
347         window->callback = wl_surface_frame(window->surface);
348         wl_callback_add_listener(window->callback, &frame_listener, window);
349 }
350
351 static const struct wl_callback_listener frame_listener = {
352         redraw
353 };
354
355 static void
356 pointer_handle_enter(void *data, struct wl_pointer *pointer,
357                      uint32_t serial, struct wl_surface *surface,
358                      wl_fixed_t sx, wl_fixed_t sy)
359 {
360         struct display *display = data;
361
362         if (display->window->fullscreen)
363                 wl_pointer_attach(pointer, serial, NULL, 0, 0);
364 }
365
366 static void
367 pointer_handle_leave(void *data, struct wl_pointer *pointer,
368                      uint32_t serial, struct wl_surface *surface)
369 {
370 }
371
372 static void
373 pointer_handle_motion(void *data, struct wl_pointer *pointer,
374                       uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
375 {
376 }
377
378 static void
379 pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
380                       uint32_t serial, uint32_t time, uint32_t button,
381                       uint32_t state)
382 {
383 }
384
385 static void
386 pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
387                     uint32_t time, uint32_t axis, wl_fixed_t value)
388 {
389 }
390
391 static const struct wl_pointer_listener pointer_listener = {
392         pointer_handle_enter,
393         pointer_handle_leave,
394         pointer_handle_motion,
395         pointer_handle_button,
396         pointer_handle_axis,
397 };
398
399 static void
400 seat_handle_capabilities(void *data, struct wl_seat *seat,
401                          enum wl_seat_capability caps)
402 {
403         struct display *d = data;
404
405         if ((caps & WL_SEAT_CAPABILITY_POINTER) && !d->pointer) {
406                 d->pointer = wl_seat_get_pointer(seat);
407                 wl_pointer_add_listener(d->pointer, &pointer_listener, d);
408         } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && d->pointer) {
409                 wl_pointer_destroy(d->pointer);
410                 d->pointer = NULL;
411         }
412 }
413
414 static const struct wl_seat_listener seat_listener = {
415         seat_handle_capabilities,
416 };
417
418 static void
419 display_handle_global(struct wl_display *display, uint32_t id,
420                       const char *interface, uint32_t version, void *data)
421 {
422         struct display *d = data;
423
424         if (strcmp(interface, "wl_compositor") == 0) {
425                 d->compositor =
426                         wl_display_bind(display, id, &wl_compositor_interface);
427         } else if (strcmp(interface, "wl_shell") == 0) {
428                 d->shell = wl_display_bind(display, id, &wl_shell_interface);
429         } else if (strcmp(interface, "wl_seat") == 0) {
430                 d->seat = wl_display_bind(d->display, id, &wl_seat_interface);
431                 wl_seat_add_listener(d->seat, &seat_listener, d);
432         }
433 }
434
435 static int
436 event_mask_update(uint32_t mask, void *data)
437 {
438         struct display *d = data;
439
440         d->mask = mask;
441
442         return 0;
443 }
444
445 static int running = 1;
446
447 static void
448 signal_int(int signum)
449 {
450         running = 0;
451 }
452
453 int
454 main(int argc, char **argv)
455 {
456         struct sigaction sigint;
457         struct display display = { 0 };
458         struct window  window  = { 0 };
459         int alpha_size, i;
460
461         window.display = &display;
462         display.window = &window;
463         window.geometry.width  = 250;
464         window.geometry.height = 250;
465
466         alpha_size = 1;
467         for (i = 1; i < argc; i++) {
468                 if (strcmp("-f", argv[i]) == 0)
469                         window.fullscreen = 1;
470                 if (strcmp("-o", argv[i]) == 0)
471                         alpha_size = 0;
472         }
473
474         display.display = wl_display_connect(NULL);
475         assert(display.display);
476
477         wl_display_add_global_listener(display.display,
478                                        display_handle_global, &display);
479
480         wl_display_get_fd(display.display, event_mask_update, &display);
481         wl_display_iterate(display.display, WL_DISPLAY_READABLE);
482
483         if (window.fullscreen)
484                 alpha_size = 0;
485
486         init_egl(&display, alpha_size);
487         create_surface(&window);
488         init_gl(&window);
489
490         sigint.sa_handler = signal_int;
491         sigemptyset(&sigint.sa_mask);
492         sigint.sa_flags = SA_RESETHAND;
493         sigaction(SIGINT, &sigint, NULL);
494
495         redraw(&window, NULL, 0);
496
497         while (running)
498                 wl_display_iterate(display.display, display.mask);
499
500         fprintf(stderr, "simple-egl exiting\n");
501
502         destroy_surface(&window);
503         fini_egl(&display);
504
505         if (display.shell)
506                 wl_shell_destroy(display.shell);
507
508         if (display.compositor)
509                 wl_compositor_destroy(display.compositor);
510
511         wl_display_flush(display.display);
512         wl_display_disconnect(display.display);
513
514         return 0;
515 }