compositor-wayland: Use wayland-egl window surfaces
[profile/ivi/weston.git] / compositor / compositor-wayland.c
1 /*
2  * Copyright © 2010 Benjamin Franzke
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <stddef.h>
24 #define _GNU_SOURCE
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30
31 #include <wayland-client.h>
32 #include <wayland-egl.h>
33
34 #include <GLES2/gl2.h>
35 #include <GLES2/gl2ext.h>
36 #include <EGL/egl.h>
37 #include <EGL/eglext.h>
38
39 #include "compositor.h"
40
41 struct wayland_compositor {
42         struct wlsc_compositor   base;
43
44         struct {
45                 struct wl_display *display;
46                 struct wl_egl_display *egl_display;
47                 struct wl_compositor *compositor;
48                 struct wl_shell *shell;
49                 struct wl_output *output;
50
51                 struct {
52                         int32_t x, y, width, height;
53                 } screen_allocation;
54
55                 struct wl_event_source *wl_source;
56                 uint32_t event_mask;
57         } parent;
58
59         struct wl_list input_list;
60 };
61
62 struct wayland_output {
63         struct wlsc_output      base;
64
65         struct {
66                 struct wl_surface       *surface;
67                 struct wl_egl_window    *egl_window;
68         } parent;
69         EGLSurface egl_surface;
70 };
71
72 struct wayland_input {
73         struct wayland_compositor *compositor;
74         struct wl_input_device *input_device;
75         struct wl_list link;
76 };
77
78 static int
79 wayland_input_create(struct wayland_compositor *c)
80 {
81         struct wlsc_input_device *input;
82
83         input = malloc(sizeof *input);
84         if (input == NULL)
85                 return -1;
86
87         memset(input, 0, sizeof *input);
88         wlsc_input_device_init(input, &c->base);
89
90         c->base.input_device = &input->input_device;
91
92         return 0;
93 }
94
95 static int
96 wayland_compositor_init_egl(struct wayland_compositor *c)
97 {
98         EGLint major, minor;
99         EGLint n;
100         const char *extensions;
101         EGLint config_attribs[] = {
102                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
103                 EGL_RED_SIZE, 1,
104                 EGL_GREEN_SIZE, 1,
105                 EGL_BLUE_SIZE, 1,
106                 EGL_DEPTH_SIZE, 1,
107                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
108                 EGL_NONE
109         };
110         static const EGLint context_attribs[] = {
111                 EGL_CONTEXT_CLIENT_VERSION, 2,
112                 EGL_NONE
113         };
114
115         c->base.display = eglGetDisplay(c->parent.egl_display);
116         if (c->base.display == NULL) {
117                 fprintf(stderr, "failed to create display\n");
118                 return -1;
119         }
120
121         if (!eglInitialize(c->base.display, &major, &minor)) {
122                 fprintf(stderr, "failed to initialize display\n");
123                 return -1;
124         }
125
126         extensions = eglQueryString(c->base.display, EGL_EXTENSIONS);
127         if (!strstr(extensions, "EGL_KHR_surfaceless_opengl")) {
128                 fprintf(stderr, "EGL_KHR_surfaceless_opengl not available\n");
129                 return -1;
130         }
131
132         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
133                 fprintf(stderr, "failed to bind EGL_OPENGL_ES_API\n");
134                 return -1;
135         }
136         if (!eglChooseConfig(c->base.display, config_attribs,
137                              &c->base.config, 1, &n) || n == 0) {
138                 fprintf(stderr, "failed to choose config: %d\n", n);
139                 return -1;
140         }
141
142         c->base.context = eglCreateContext(c->base.display, c->base.config,
143                                            EGL_NO_CONTEXT, context_attribs);
144         if (c->base.context == NULL) {
145                 fprintf(stderr, "failed to create context\n");
146                 return -1;
147         }
148
149         if (!eglMakeCurrent(c->base.display, EGL_NO_SURFACE,
150                             EGL_NO_SURFACE, c->base.context)) {
151                 fprintf(stderr, "failed to make context current\n");
152                 return -1;
153         }
154
155         return 0;
156 }
157
158 static void
159 frame_callback(void *data, uint32_t time)
160 {
161         struct wayland_compositor *c = (struct wayland_compositor *) data;
162
163         wlsc_compositor_finish_frame(&c->base, time);
164 }
165
166 static void
167 wayland_compositor_present(struct wlsc_compositor *base)
168 {
169         struct wayland_compositor *c = (struct wayland_compositor *) base;
170         struct wayland_output *output;
171
172
173         wl_list_for_each(output, &base->output_list, base.link) {
174                 if (!eglMakeCurrent(c->base.display, output->egl_surface,
175                                     output->egl_surface, c->base.context)) {
176                         fprintf(stderr, "failed to make current\n");
177                         continue;
178                 }
179                 eglSwapBuffers(c->base.display, output->egl_surface);
180         }
181
182         wl_display_frame_callback(c->parent.display, frame_callback, c);
183 }
184
185 static int
186 wayland_compositor_create_output(struct wayland_compositor *c,
187                                  int width, int height)
188 {
189         struct wayland_output *output;
190         struct wl_visual *visual;
191
192         output = malloc(sizeof *output);
193         if (output == NULL)
194                 return -1;
195         memset(output, 0, sizeof *output);
196
197         wlsc_output_init(&output->base, &c->base, 0, 0, width, height,
198                          WL_OUTPUT_FLIPPED);
199         output->parent.surface =
200                 wl_compositor_create_surface(c->parent.compositor);
201         wl_surface_set_user_data(output->parent.surface, output);
202
203         visual = wl_display_get_premultiplied_argb_visual(c->parent.display);
204
205         output->parent.egl_window =
206                 wl_egl_window_create(c->parent.egl_display,
207                                      output->parent.surface,
208                                      width, height, visual);
209         if (!output->parent.egl_window) {
210                 fprintf(stderr, "failure to create wl_egl_window\n");
211                 goto cleanup_output;
212         }
213
214         output->egl_surface =
215                 eglCreateWindowSurface(c->base.display, c->base.config,
216                                        output->parent.egl_window, NULL);
217         if (!output->egl_surface) {
218                 fprintf(stderr, "failed to create window surface\n");
219                 goto cleanup_window;
220         }
221
222         if (!eglMakeCurrent(c->base.display, output->egl_surface,
223                             output->egl_surface, c->base.context)) {
224                 fprintf(stderr, "failed to make surface current\n");
225                 goto cleanup_surface;
226                 return -1;
227         }
228
229         wl_surface_map_toplevel(output->parent.surface);
230
231         glClearColor(0, 0, 0, 0.5);
232
233         wl_list_insert(c->base.output_list.prev, &output->base.link);
234
235         return 0;
236
237 cleanup_surface:
238         eglDestroySurface(c->base.display, output->egl_surface);
239 cleanup_window:
240         wl_egl_window_destroy(output->parent.egl_window);
241 cleanup_output:
242         /* FIXME: cleanup wlsc_output */
243         free(output);
244
245         return -1;
246 }
247
248 /* Events received from the wayland-server this compositor is client of: */
249
250 /* parent output interface */
251 static void
252 display_handle_geometry(void *data,
253                         struct wl_output *output,
254                         int32_t x, int32_t y,
255                         int32_t width, int32_t height)
256 {
257         struct wayland_compositor *c = data;
258
259         c->parent.screen_allocation.x = x;
260         c->parent.screen_allocation.y = y;
261         c->parent.screen_allocation.width = width;
262         c->parent.screen_allocation.height = height;
263 }
264
265 static const struct wl_output_listener output_listener = {
266         display_handle_geometry,
267 };
268
269 /* parent shell interface */
270 static void
271 handle_configure(void *data, struct wl_shell *shell,
272                  uint32_t time, uint32_t edges,
273                  struct wl_surface *surface, int32_t width, int32_t height)
274 {
275 #if 0
276         struct output *output = wl_surface_get_user_data(surface);
277
278         /* FIXME: add resize? */
279 #endif
280 }
281
282 static const struct wl_shell_listener shell_listener = {
283         handle_configure,
284 };
285
286 /* parent input interface */
287 static void
288 input_handle_motion(void *data, struct wl_input_device *input_device,
289                      uint32_t time,
290                      int32_t x, int32_t y, int32_t sx, int32_t sy)
291 {
292         struct wayland_input *input = data;
293         struct wayland_compositor *c = input->compositor;
294
295         notify_motion(c->base.input_device, time, sx, sy);
296 }
297
298 static void
299 input_handle_button(void *data,
300                      struct wl_input_device *input_device,
301                      uint32_t time, uint32_t button, uint32_t state)
302 {
303         struct wayland_input *input = data;
304         struct wayland_compositor *c = input->compositor;
305
306         notify_button(c->base.input_device, time, button, state);
307 }
308
309 static void
310 input_handle_key(void *data, struct wl_input_device *input_device,
311                   uint32_t time, uint32_t key, uint32_t state)
312 {
313         struct wayland_input *input = data;
314         struct wayland_compositor *c = input->compositor;
315
316         notify_key(c->base.input_device, time, key, state);
317 }
318
319 static void
320 input_handle_pointer_focus(void *data,
321                             struct wl_input_device *input_device,
322                             uint32_t time, struct wl_surface *surface,
323                             int32_t x, int32_t y, int32_t sx, int32_t sy)
324 {
325         struct wayland_input *input = data;
326         struct wayland_output *output;
327         struct wayland_compositor *c = input->compositor;
328
329         if (surface) {
330                 output = wl_surface_get_user_data(surface);
331                 notify_pointer_focus(c->base.input_device,
332                                      time, &output->base, sx, sy);
333         } else {
334                 notify_pointer_focus(c->base.input_device, time, NULL, 0, 0);
335         }
336 }
337
338 static void
339 input_handle_keyboard_focus(void *data,
340                              struct wl_input_device *input_device,
341                              uint32_t time,
342                              struct wl_surface *surface,
343                              struct wl_array *keys)
344 {
345         struct wayland_input *input = data;
346         struct wayland_compositor *c = input->compositor;
347         struct wayland_output *output;
348
349         if (surface) {
350                 output = wl_surface_get_user_data(surface);
351                 notify_keyboard_focus(c->base.input_device,
352                                       time, &output->base, keys);
353         } else {
354                 notify_keyboard_focus(c->base.input_device, time, NULL, NULL);
355         }
356 }
357
358 static const struct wl_input_device_listener input_device_listener = {
359         input_handle_motion,
360         input_handle_button,
361         input_handle_key,
362         input_handle_pointer_focus,
363         input_handle_keyboard_focus,
364 };
365
366 static void
367 display_add_input(struct wayland_compositor *c, uint32_t id)
368 {
369         struct wayland_input *input;
370
371         input = malloc(sizeof *input);
372         if (input == NULL)
373                 return;
374
375         memset(input, 0, sizeof *input);
376
377         input->compositor = c;
378         input->input_device = wl_input_device_create(c->parent.display, id);
379         wl_list_insert(c->input_list.prev, &input->link);
380
381         wl_input_device_add_listener(input->input_device,
382                                      &input_device_listener, input);
383         wl_input_device_set_user_data(input->input_device, input);
384 }
385
386 static void
387 display_handle_global(struct wl_display *display, uint32_t id,
388                       const char *interface, uint32_t version, void *data)
389 {
390         struct wayland_compositor *c = data;
391
392         if (strcmp(interface, "compositor") == 0) {
393                 c->parent.compositor = wl_compositor_create(display, id);
394         } else if (strcmp(interface, "output") == 0) {
395                 c->parent.output = wl_output_create(display, id);
396                 wl_output_add_listener(c->parent.output, &output_listener, c);
397         } else if (strcmp(interface, "input_device") == 0) {
398                 display_add_input(c, id);
399         } else if (strcmp(interface, "shell") == 0) {
400                 c->parent.shell = wl_shell_create(display, id);
401                 wl_shell_add_listener(c->parent.shell, &shell_listener, c);
402         }
403 }
404
405 static int
406 update_event_mask(uint32_t mask, void *data)
407 {
408         struct wayland_compositor *c = data;
409
410         c->parent.event_mask = mask;
411         if (c->parent.wl_source)
412                 wl_event_source_fd_update(c->parent.wl_source, mask);
413
414         return 0;
415 }
416
417 static void
418 wayland_compositor_handle_event(int fd, uint32_t mask, void *data)
419 {
420         struct wayland_compositor *c = data;
421
422         if (mask & WL_EVENT_READABLE)
423                 wl_display_iterate(c->parent.display, WL_DISPLAY_READABLE);
424         if (mask & WL_EVENT_WRITEABLE)
425                 wl_display_iterate(c->parent.display, WL_DISPLAY_WRITABLE);
426 }
427
428 static void
429 wayland_destroy(struct wlsc_compositor *ec)
430 {
431         free(ec);
432 }
433
434 struct wlsc_compositor *
435 wayland_compositor_create(struct wl_display *display, int width, int height)
436 {
437         struct wayland_compositor *c;
438         struct wl_event_loop *loop;
439         int fd;
440
441         c = malloc(sizeof *c);
442         if (c == NULL)
443                 return NULL;
444
445         memset(c, 0, sizeof *c);
446
447         c->parent.display = wl_display_connect(NULL);
448
449         if (c->parent.display == NULL) {
450                 fprintf(stderr, "failed to create display: %m\n");
451                 return NULL;
452         }
453
454         wl_list_init(&c->input_list);
455         c->parent.egl_display = wl_egl_display_create(c->parent.display);
456         wl_display_add_global_listener(c->parent.display,
457                                 display_handle_global, c);
458
459         wl_display_iterate(c->parent.display, WL_DISPLAY_READABLE);
460
461         c->base.wl_display = display;
462         if (wayland_compositor_init_egl(c) < 0)
463                 return NULL;
464
465         c->base.destroy = wayland_destroy;
466         c->base.present = wayland_compositor_present;
467         c->base.create_buffer = wlsc_drm_buffer_create;
468
469         /* Can't init base class until we have a current egl context */
470         if (wlsc_compositor_init(&c->base, display) < 0)
471                 return NULL;
472
473         if (wayland_compositor_create_output(c, width, height) < 0)
474                 return NULL;
475
476         if (wayland_input_create(c) < 0)
477                 return NULL;
478
479         loop = wl_display_get_event_loop(c->base.wl_display);
480
481         fd = wl_display_get_fd(c->parent.display, update_event_mask, c);
482         c->parent.wl_source =
483                 wl_event_loop_add_fd(loop, fd, c->parent.event_mask,
484                                      wayland_compositor_handle_event, c);
485         if (c->parent.wl_source == NULL)
486                 return NULL;
487
488         return &c->base;
489 }