simple-egl: implement destructors
[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 display {
38         struct wl_display *display;
39         struct wl_compositor *compositor;
40         struct wl_shell *shell;
41         struct {
42                 EGLDisplay dpy;
43                 EGLContext ctx;
44                 EGLConfig conf;
45         } egl;
46         uint32_t mask;
47 };
48
49 struct window {
50         struct display *display;
51         struct {
52                 int width, height;
53         } geometry;
54         struct {
55                 GLuint fbo;
56                 GLuint color_rbo;
57
58                 GLuint program;
59                 GLuint rotation_uniform;
60
61                 GLuint pos;
62                 GLuint col;
63         } gl;
64
65         struct wl_egl_window *native;
66         struct wl_surface *surface;
67         struct wl_shell_surface *shell_surface;
68         EGLSurface egl_surface;
69         struct wl_callback *callback;
70 };
71
72 static const char *vert_shader_text =
73         "uniform mat4 rotation;\n"
74         "attribute vec4 pos;\n"
75         "attribute vec4 color;\n"
76         "varying vec4 v_color;\n"
77         "void main() {\n"
78         "  gl_Position = rotation * pos;\n"
79         "  v_color = color;\n"
80         "}\n";
81
82 static const char *frag_shader_text =
83         "precision mediump float;\n"
84         "varying vec4 v_color;\n"
85         "void main() {\n"
86         "  gl_FragColor = v_color;\n"
87         "}\n";
88
89 static void
90 init_egl(struct display *display)
91 {
92         static const EGLint context_attribs[] = {
93                 EGL_CONTEXT_CLIENT_VERSION, 2,
94                 EGL_NONE
95         };
96
97         static const EGLint config_attribs[] = {
98                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT,
99                 EGL_RED_SIZE, 1,
100                 EGL_GREEN_SIZE, 1,
101                 EGL_BLUE_SIZE, 1,
102                 EGL_ALPHA_SIZE, 1,
103                 EGL_DEPTH_SIZE, 1,
104                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
105                 EGL_NONE
106         };
107
108         EGLint major, minor, n;
109         EGLBoolean ret;
110
111         display->egl.dpy = eglGetDisplay(display->display);
112         assert(display->egl.dpy);
113
114         ret = eglInitialize(display->egl.dpy, &major, &minor);
115         assert(ret == EGL_TRUE);
116         ret = eglBindAPI(EGL_OPENGL_ES_API);
117         assert(ret == EGL_TRUE);
118
119         assert(eglChooseConfig(display->egl.dpy, config_attribs,
120                                &display->egl.conf, 1, &n) && n == 1);
121
122         display->egl.ctx = eglCreateContext(display->egl.dpy,
123                                             display->egl.conf,
124                                             EGL_NO_CONTEXT, context_attribs);
125         assert(display->egl.ctx);
126
127 }
128
129 static void
130 fini_egl(struct display *display)
131 {
132         /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
133          * on eglReleaseThread(). */
134         eglMakeCurrent(display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
135                        EGL_NO_CONTEXT);
136
137         eglTerminate(display->egl.dpy);
138         eglReleaseThread();
139 }
140
141 static GLuint
142 create_shader(struct window *window, const char *source, GLenum shader_type)
143 {
144         GLuint shader;
145         GLint status;
146
147         shader = glCreateShader(shader_type);
148         assert(shader != 0);
149
150         glShaderSource(shader, 1, (const char **) &source, NULL);
151         glCompileShader(shader);
152
153         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
154         if (!status) {
155                 char log[1000];
156                 GLsizei len;
157                 glGetShaderInfoLog(shader, 1000, &len, log);
158                 fprintf(stderr, "Error: compiling %s: %*s\n",
159                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
160                         len, log);
161                 exit(1);
162         }
163
164         return shader;
165 }
166
167 static void
168 init_gl(struct window *window)
169 {
170         GLuint frag, vert;
171         GLint status;
172
173         glViewport(0, 0, window->geometry.width, window->geometry.height);
174
175         frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
176         vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
177
178         window->gl.program = glCreateProgram();
179         glAttachShader(window->gl.program, frag);
180         glAttachShader(window->gl.program, vert);
181         glLinkProgram(window->gl.program);
182
183         glGetProgramiv(window->gl.program, GL_LINK_STATUS, &status);
184         if (!status) {
185                 char log[1000];
186                 GLsizei len;
187                 glGetProgramInfoLog(window->gl.program, 1000, &len, log);
188                 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
189                 exit(1);
190         }
191
192         glUseProgram(window->gl.program);
193         
194         window->gl.pos = 0;
195         window->gl.pos = 1;
196
197         glBindAttribLocation(window->gl.program, window->gl.pos, "pos");
198         glBindAttribLocation(window->gl.program, window->gl.col, "color");
199         glLinkProgram(window->gl.program);
200
201         window->gl.rotation_uniform =
202                 glGetUniformLocation(window->gl.program, "rotation");
203 }
204
205 static void
206 create_surface(struct window *window)
207 {
208         struct display *display = window->display;
209         EGLBoolean ret;
210         static const EGLint surface_attribs[] = {
211                 EGL_ALPHA_FORMAT, EGL_ALPHA_FORMAT_PRE,
212                 EGL_NONE
213         };
214         
215         window->surface = wl_compositor_create_surface(display->compositor);
216         window->shell_surface = wl_shell_get_shell_surface(display->shell,
217                                                            window->surface);
218         window->native =
219                 wl_egl_window_create(window->surface,
220                                      window->geometry.width,
221                                      window->geometry.height);
222         window->egl_surface =
223                 eglCreateWindowSurface(display->egl.dpy,
224                                        display->egl.conf,
225                                        window->native,
226                                        surface_attribs);
227
228         wl_shell_surface_set_toplevel(window->shell_surface);
229
230         ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
231                              window->egl_surface, window->display->egl.ctx);
232         assert(ret == EGL_TRUE);
233 }
234
235 static void
236 destroy_surface(struct window *window)
237 {
238         wl_egl_window_destroy(window->native);
239
240         wl_shell_surface_destroy(window->shell_surface);
241         wl_surface_destroy(window->surface);
242
243         if (window->callback)
244                 wl_callback_destroy(window->callback);
245 }
246
247 static const struct wl_callback_listener frame_listener;
248
249 static void
250 redraw(void *data, struct wl_callback *callback, uint32_t time)
251 {
252         struct window *window = data;
253         static const GLfloat verts[3][2] = {
254                 { -0.5, -0.5 },
255                 {  0.5, -0.5 },
256                 {  0,    0.5 }
257         };
258         static const GLfloat colors[3][3] = {
259                 { 1, 0, 0 },
260                 { 0, 1, 0 },
261                 { 0, 0, 1 }
262         };
263         GLfloat angle;
264         GLfloat rotation[4][4] = {
265                 { 1, 0, 0, 0 },
266                 { 0, 1, 0, 0 },
267                 { 0, 0, 1, 0 },
268                 { 0, 0, 0, 1 }
269         };
270         static const int32_t speed_div = 5;
271         static uint32_t start_time = 0;
272
273         if (start_time == 0)
274                 start_time = time;
275
276         angle = ((time-start_time) / speed_div) % 360 * M_PI / 180.0;
277         rotation[0][0] =  cos(angle);
278         rotation[0][2] =  sin(angle);
279         rotation[2][0] = -sin(angle);
280         rotation[2][2] =  cos(angle);
281
282         glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
283                            (GLfloat *) rotation);
284
285         glClearColor(0.0, 0.0, 0.0, 0.5);
286         glClear(GL_COLOR_BUFFER_BIT);
287
288         glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
289         glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);
290         glEnableVertexAttribArray(window->gl.pos);
291         glEnableVertexAttribArray(window->gl.col);
292
293         glDrawArrays(GL_TRIANGLES, 0, 3);
294
295         glDisableVertexAttribArray(window->gl.pos);
296         glDisableVertexAttribArray(window->gl.col);
297
298         glFlush();
299
300         eglSwapBuffers(window->display->egl.dpy, window->egl_surface);
301         if (callback)
302                 wl_callback_destroy(callback);
303
304         window->callback = wl_surface_frame(window->surface);
305         wl_callback_add_listener(window->callback, &frame_listener, window);
306 }
307
308 static const struct wl_callback_listener frame_listener = {
309         redraw
310 };
311
312 static void
313 display_handle_global(struct wl_display *display, uint32_t id,
314                       const char *interface, uint32_t version, void *data)
315 {
316         struct display *d = data;
317
318         if (strcmp(interface, "wl_compositor") == 0) {
319                 d->compositor =
320                         wl_display_bind(display, id, &wl_compositor_interface);
321         } else if (strcmp(interface, "wl_shell") == 0) {
322                 d->shell = wl_display_bind(display, id, &wl_shell_interface);
323         }
324 }
325
326 static int
327 event_mask_update(uint32_t mask, void *data)
328 {
329         struct display *d = data;
330
331         d->mask = mask;
332
333         return 0;
334 }
335
336 static int running = 1;
337
338 static void
339 signal_int(int signum)
340 {
341         running = 0;
342 }
343
344 int
345 main(int argc, char **argv)
346 {
347         struct sigaction sigint;
348         struct display display = { 0 };
349         struct window  window  = { 0 };
350
351         window.display = &display;
352         window.geometry.width  = 250;
353         window.geometry.height = 250;
354
355         display.display = wl_display_connect(NULL);
356         assert(display.display);
357
358         wl_display_add_global_listener(display.display,
359                                        display_handle_global, &display);
360
361         wl_display_get_fd(display.display, event_mask_update, &display);
362         wl_display_iterate(display.display, WL_DISPLAY_READABLE);
363
364         init_egl(&display);
365         create_surface(&window);
366         init_gl(&window);
367
368         sigint.sa_handler = signal_int;
369         sigemptyset(&sigint.sa_mask);
370         sigint.sa_flags = SA_RESETHAND;
371         sigaction(SIGINT, &sigint, NULL);
372
373         redraw(&window, NULL, 0);
374
375         while (running)
376                 wl_display_iterate(display.display, display.mask);
377
378         fprintf(stderr, "simple-egl exiting\n");
379
380         destroy_surface(&window);
381         fini_egl(&display);
382
383         if (display.shell)
384                 wl_shell_destroy(display.shell);
385
386         if (display.compositor)
387                 wl_compositor_destroy(display.compositor);
388
389         wl_display_destroy(display.display);
390
391         return 0;
392 }