4cb5bc79635c8b2f7aef83c4ce40c937dbd8db21
[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 program;
65                 GLuint rotation_uniform;
66
67                 GLuint pos;
68                 GLuint col;
69         } gl;
70
71         struct wl_egl_window *native;
72         struct wl_surface *surface;
73         struct wl_shell_surface *shell_surface;
74         EGLSurface egl_surface;
75         struct wl_callback *callback;
76         int fullscreen, configured;
77 };
78
79 static const char *vert_shader_text =
80         "uniform mat4 rotation;\n"
81         "attribute vec4 pos;\n"
82         "attribute vec4 color;\n"
83         "varying vec4 v_color;\n"
84         "void main() {\n"
85         "  gl_Position = rotation * pos;\n"
86         "  v_color = color;\n"
87         "}\n";
88
89 static const char *frag_shader_text =
90         "precision mediump float;\n"
91         "varying vec4 v_color;\n"
92         "void main() {\n"
93         "  gl_FragColor = v_color;\n"
94         "}\n";
95
96 static void
97 init_egl(struct display *display, EGLint alpha_size)
98 {
99         static const EGLint context_attribs[] = {
100                 EGL_CONTEXT_CLIENT_VERSION, 2,
101                 EGL_NONE
102         };
103
104         EGLint config_attribs[] = {
105                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
106                 EGL_RED_SIZE, 1,
107                 EGL_GREEN_SIZE, 1,
108                 EGL_BLUE_SIZE, 1,
109                 EGL_ALPHA_SIZE, alpha_size,
110                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
111                 EGL_NONE
112         };
113
114         EGLint major, minor, n;
115         EGLBoolean ret;
116
117         display->egl.dpy = eglGetDisplay(display->display);
118         assert(display->egl.dpy);
119
120         ret = eglInitialize(display->egl.dpy, &major, &minor);
121         assert(ret == EGL_TRUE);
122         ret = eglBindAPI(EGL_OPENGL_ES_API);
123         assert(ret == EGL_TRUE);
124
125         ret = eglChooseConfig(display->egl.dpy, config_attribs,
126                               &display->egl.conf, 1, &n);
127         assert(ret && n == 1);
128
129         display->egl.ctx = eglCreateContext(display->egl.dpy,
130                                             display->egl.conf,
131                                             EGL_NO_CONTEXT, context_attribs);
132         assert(display->egl.ctx);
133
134 }
135
136 static void
137 fini_egl(struct display *display)
138 {
139         /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
140          * on eglReleaseThread(). */
141         eglMakeCurrent(display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
142                        EGL_NO_CONTEXT);
143
144         eglTerminate(display->egl.dpy);
145         eglReleaseThread();
146 }
147
148 static GLuint
149 create_shader(struct window *window, const char *source, GLenum shader_type)
150 {
151         GLuint shader;
152         GLint status;
153
154         shader = glCreateShader(shader_type);
155         assert(shader != 0);
156
157         glShaderSource(shader, 1, (const char **) &source, NULL);
158         glCompileShader(shader);
159
160         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
161         if (!status) {
162                 char log[1000];
163                 GLsizei len;
164                 glGetShaderInfoLog(shader, 1000, &len, log);
165                 fprintf(stderr, "Error: compiling %s: %*s\n",
166                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
167                         len, log);
168                 exit(1);
169         }
170
171         return shader;
172 }
173
174 static void
175 init_gl(struct window *window)
176 {
177         GLuint frag, vert;
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         window->gl.program = glCreateProgram();
186         glAttachShader(window->gl.program, frag);
187         glAttachShader(window->gl.program, vert);
188         glLinkProgram(window->gl.program);
189
190         glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status);
191         if (!status) {
192                 char log[1000];
193                 GLsizei len;
194                 glGetProgramInfoLog(window->gl.program, 1000, &len, log);
195                 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
196                 exit(1);
197         }
198
199         glUseProgram(window->gl.program);
200         
201         window->gl.pos = 0;
202         window->gl.pos = 1;
203
204         glBindAttribLocation(window->gl.program, window->gl.pos, "pos");
205         glBindAttribLocation(window->gl.program, window->gl.col, "color");
206         glLinkProgram(window->gl.program);
207
208         window->gl.rotation_uniform =
209                 glGetUniformLocation(window->gl.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         glFlush();
344
345         eglSwapBuffers(window->display->egl.dpy, window->egl_surface);
346         if (callback)
347                 wl_callback_destroy(callback);
348
349         window->callback = wl_surface_frame(window->surface);
350         wl_callback_add_listener(window->callback, &frame_listener, window);
351 }
352
353 static const struct wl_callback_listener frame_listener = {
354         redraw
355 };
356
357 static void
358 pointer_handle_enter(void *data, struct wl_pointer *pointer,
359                      uint32_t serial, struct wl_surface *surface,
360                      wl_fixed_t sx, wl_fixed_t sy)
361 {
362         struct display *display = data;
363
364         if (display->window->fullscreen)
365                 wl_pointer_attach(pointer, serial, NULL, 0, 0);
366 }
367
368 static void
369 pointer_handle_leave(void *data, struct wl_pointer *pointer,
370                      uint32_t serial, struct wl_surface *surface)
371 {
372 }
373
374 static void
375 pointer_handle_motion(void *data, struct wl_pointer *pointer,
376                       uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
377 {
378 }
379
380 static void
381 pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
382                       uint32_t serial, uint32_t time, uint32_t button,
383                       uint32_t state)
384 {
385 }
386
387 static void
388 pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
389                     uint32_t time, uint32_t axis, wl_fixed_t value)
390 {
391 }
392
393 static const struct wl_pointer_listener pointer_listener = {
394         pointer_handle_enter,
395         pointer_handle_leave,
396         pointer_handle_motion,
397         pointer_handle_button,
398         pointer_handle_axis,
399 };
400
401 static void
402 seat_handle_capabilities(void *data, struct wl_seat *seat,
403                          enum wl_seat_capability caps)
404 {
405         struct display *d = data;
406
407         if ((caps & WL_SEAT_CAPABILITY_POINTER) && !d->pointer) {
408                 d->pointer = wl_seat_get_pointer(seat);
409                 wl_pointer_add_listener(d->pointer, &pointer_listener, d);
410         } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && d->pointer) {
411                 wl_pointer_destroy(d->pointer);
412                 d->pointer = NULL;
413         }
414 }
415
416 static const struct wl_seat_listener seat_listener = {
417         seat_handle_capabilities,
418 };
419
420 static void
421 display_handle_global(struct wl_display *display, uint32_t id,
422                       const char *interface, uint32_t version, void *data)
423 {
424         struct display *d = data;
425
426         if (strcmp(interface, "wl_compositor") == 0) {
427                 d->compositor =
428                         wl_display_bind(display, id, &wl_compositor_interface);
429         } else if (strcmp(interface, "wl_shell") == 0) {
430                 d->shell = wl_display_bind(display, id, &wl_shell_interface);
431         } else if (strcmp(interface, "wl_seat") == 0) {
432                 d->seat = wl_display_bind(d->display, id, &wl_seat_interface);
433                 wl_seat_add_listener(d->seat, &seat_listener, d);
434         }
435 }
436
437 static int
438 event_mask_update(uint32_t mask, void *data)
439 {
440         struct display *d = data;
441
442         d->mask = mask;
443
444         return 0;
445 }
446
447 static int running = 1;
448
449 static void
450 signal_int(int signum)
451 {
452         running = 0;
453 }
454
455 int
456 main(int argc, char **argv)
457 {
458         struct sigaction sigint;
459         struct display display = { 0 };
460         struct window  window  = { 0 };
461         int alpha_size, i;
462
463         window.display = &display;
464         display.window = &window;
465         window.geometry.width  = 250;
466         window.geometry.height = 250;
467
468         alpha_size = 1;
469         for (i = 1; i < argc; i++) {
470                 if (strcmp("-f", argv[i]) == 0)
471                         window.fullscreen = 1;
472                 if (strcmp("-o", argv[i]) == 0)
473                         alpha_size = 0;
474         }
475
476         display.display = wl_display_connect(NULL);
477         assert(display.display);
478
479         wl_display_add_global_listener(display.display,
480                                        display_handle_global, &display);
481
482         wl_display_get_fd(display.display, event_mask_update, &display);
483         wl_display_iterate(display.display, WL_DISPLAY_READABLE);
484
485         if (window.fullscreen)
486                 alpha_size = 0;
487
488         init_egl(&display, alpha_size);
489         create_surface(&window);
490         init_gl(&window);
491
492         sigint.sa_handler = signal_int;
493         sigemptyset(&sigint.sa_mask);
494         sigint.sa_flags = SA_RESETHAND;
495         sigaction(SIGINT, &sigint, NULL);
496
497         redraw(&window, NULL, 0);
498
499         while (running)
500                 wl_display_iterate(display.display, display.mask);
501
502         fprintf(stderr, "simple-egl exiting\n");
503
504         destroy_surface(&window);
505         fini_egl(&display);
506
507         if (display.shell)
508                 wl_shell_destroy(display.shell);
509
510         if (display.compositor)
511                 wl_compositor_destroy(display.compositor);
512
513         wl_display_flush(display.display);
514         wl_display_disconnect(display.display);
515
516         return 0;
517 }