4 * An object oriented GL/GLES Abstraction/Utility Layer
6 * Copyright (C) 2011 Intel Corporation.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see
20 * <http://www.gnu.org/licenses/>.
24 * Robert Bragg <robert@linux.intel.com>
25 * Neil Roberts <neil@linux.intel.com>
32 #include <wayland-client.h>
33 #include <wayland-egl.h>
36 #include "cogl-winsys-egl-wayland-private.h"
37 #include "cogl-winsys-egl-private.h"
38 #include "cogl-renderer-private.h"
39 #include "cogl-onscreen-private.h"
40 #include "cogl-wayland-renderer.h"
42 static const CoglWinsysEGLVtable _cogl_winsys_egl_vtable;
44 static const CoglWinsysVtable *parent_vtable;
46 typedef struct _CoglRendererWayland
48 struct wl_display *wayland_display;
49 struct wl_compositor *wayland_compositor;
50 struct wl_shell *wayland_shell;
51 } CoglRendererWayland;
53 typedef struct _CoglDisplayWayland
55 struct wl_surface *wayland_surface;
56 struct wl_egl_window *wayland_egl_native_window;
59 typedef struct _CoglOnscreenWayland
61 struct wl_egl_window *wayland_egl_native_window;
62 struct wl_surface *wayland_surface;
63 struct wl_shell_surface *wayland_shell_surface;
65 /* Resizing a wayland framebuffer doesn't take affect
66 * until the next swap buffers request, so we have to
67 * track the resize geometry until then... */
73 } CoglOnscreenWayland;
76 display_handle_global_cb (struct wl_display *display,
78 const char *interface,
82 CoglRendererEGL *egl_renderer = (CoglRendererEGL *)data;
83 CoglRendererWayland *wayland_renderer = egl_renderer->platform;
85 if (strcmp (interface, "wl_compositor") == 0)
86 wayland_renderer->wayland_compositor =
87 wl_display_bind (display, id, &wl_compositor_interface);
88 else if (strcmp(interface, "wl_shell") == 0)
89 wayland_renderer->wayland_shell =
90 wl_display_bind (display, id, &wl_shell_interface);
94 _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
96 CoglRendererEGL *egl_renderer = renderer->winsys;
98 eglTerminate (egl_renderer->edpy);
100 g_slice_free (CoglRendererWayland, egl_renderer->platform);
101 g_slice_free (CoglRendererEGL, egl_renderer);
105 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
108 CoglRendererEGL *egl_renderer;
109 CoglRendererWayland *wayland_renderer;
111 renderer->winsys = g_slice_new0 (CoglRendererEGL);
112 egl_renderer = renderer->winsys;
113 wayland_renderer = g_slice_new0 (CoglRendererWayland);
114 egl_renderer->platform = wayland_renderer;
116 egl_renderer->platform_vtable = &_cogl_winsys_egl_vtable;
118 /* The EGL API doesn't provide for a way to explicitly select a
119 * platform when the driver can support multiple. Mesa allows
120 * selection using an environment variable though so that's what
121 * we're doing here... */
122 g_setenv ("EGL_PLATFORM", "wayland", 1);
124 if (renderer->foreign_wayland_display)
126 wayland_renderer->wayland_display = renderer->foreign_wayland_display;
127 /* XXX: For now we have to assume that if a foreign display is
128 * given then a foreign compositor and shell must also have been
129 * given because wayland doesn't provide a way to
130 * retrospectively be notified of the these objects. */
131 g_assert (renderer->foreign_wayland_compositor);
132 g_assert (renderer->foreign_wayland_shell);
133 wayland_renderer->wayland_compositor =
134 renderer->foreign_wayland_compositor;
135 wayland_renderer->wayland_shell = renderer->foreign_wayland_shell;
139 wayland_renderer->wayland_display = wl_display_connect (NULL);
140 if (!wayland_renderer->wayland_display)
142 g_set_error (error, COGL_WINSYS_ERROR,
143 COGL_WINSYS_ERROR_INIT,
144 "Failed to connect wayland display");
148 wl_display_add_global_listener (wayland_renderer->wayland_display,
149 display_handle_global_cb,
154 * Ensure that that we've received the messages setting up the
155 * compostor and shell object. This is better than just
156 * wl_display_iterate since it will always ensure that something
157 * is available to be read
159 while (!(wayland_renderer->wayland_compositor &&
160 wayland_renderer->wayland_shell))
161 wl_display_roundtrip (wayland_renderer->wayland_display);
164 eglGetDisplay ((EGLNativeDisplayType) wayland_renderer->wayland_display);
166 if (!_cogl_winsys_egl_renderer_connect_common (renderer, error))
172 _cogl_winsys_renderer_disconnect (renderer);
177 _cogl_winsys_egl_display_setup (CoglDisplay *display,
180 CoglDisplayEGL *egl_display = display->winsys;
181 CoglDisplayWayland *wayland_display;
183 wayland_display = g_slice_new0 (CoglDisplayWayland);
184 egl_display->platform = wayland_display;
190 _cogl_winsys_egl_display_destroy (CoglDisplay *display)
192 CoglDisplayEGL *egl_display = display->winsys;
194 g_slice_free (CoglDisplayWayland, egl_display->platform);
198 _cogl_winsys_egl_context_created (CoglDisplay *display,
201 CoglRenderer *renderer = display->renderer;
202 CoglRendererEGL *egl_renderer = renderer->winsys;
203 CoglRendererWayland *wayland_renderer = egl_renderer->platform;
204 CoglDisplayEGL *egl_display = display->winsys;
205 CoglDisplayWayland *wayland_display = egl_display->platform;
206 const char *error_message;
208 wayland_display->wayland_surface =
209 wl_compositor_create_surface (wayland_renderer->wayland_compositor);
210 if (!wayland_display->wayland_surface)
212 error_message= "Failed to create a dummy wayland surface";
216 wayland_display->wayland_egl_native_window =
217 wl_egl_window_create (wayland_display->wayland_surface,
220 if (!wayland_display->wayland_egl_native_window)
222 error_message= "Failed to create a dummy wayland native egl surface";
226 egl_display->dummy_surface =
227 eglCreateWindowSurface (egl_renderer->edpy,
228 egl_display->egl_config,
229 (EGLNativeWindowType)
230 wayland_display->wayland_egl_native_window,
232 if (egl_display->dummy_surface == EGL_NO_SURFACE)
234 error_message= "Unable to eglMakeCurrent with dummy surface";
238 if (!eglMakeCurrent (egl_renderer->edpy,
239 egl_display->dummy_surface,
240 egl_display->dummy_surface,
241 egl_display->egl_context))
243 error_message = "Unable to eglMakeCurrent with dummy surface";
250 g_set_error (error, COGL_WINSYS_ERROR,
251 COGL_WINSYS_ERROR_CREATE_CONTEXT,
252 "%s", error_message);
257 _cogl_winsys_egl_cleanup_context (CoglDisplay *display)
259 CoglRenderer *renderer = display->renderer;
260 CoglRendererEGL *egl_renderer = renderer->winsys;
261 CoglDisplayEGL *egl_display = display->winsys;
262 CoglDisplayWayland *wayland_display = egl_display->platform;
264 if (egl_display->dummy_surface != EGL_NO_SURFACE)
266 eglDestroySurface (egl_renderer->edpy, egl_display->dummy_surface);
267 egl_display->dummy_surface = EGL_NO_SURFACE;
270 if (wayland_display->wayland_egl_native_window)
272 wl_egl_window_destroy (wayland_display->wayland_egl_native_window);
273 wayland_display->wayland_egl_native_window = NULL;
276 if (wayland_display->wayland_surface)
278 wl_surface_destroy (wayland_display->wayland_surface);
279 wayland_display->wayland_surface = NULL;
284 _cogl_winsys_egl_context_init (CoglContext *context,
287 context->feature_flags |= COGL_FEATURE_ONSCREEN_MULTIPLE;
288 COGL_FLAGS_SET (context->features,
289 COGL_FEATURE_ID_ONSCREEN_MULTIPLE, TRUE);
290 COGL_FLAGS_SET (context->winsys_features,
291 COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN,
298 _cogl_winsys_egl_onscreen_init (CoglOnscreen *onscreen,
299 EGLConfig egl_config,
302 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
303 CoglOnscreenWayland *wayland_onscreen;
304 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
305 CoglContext *context = framebuffer->context;
306 CoglRenderer *renderer = context->display->renderer;
307 CoglRendererEGL *egl_renderer = renderer->winsys;
308 CoglRendererWayland *wayland_renderer = egl_renderer->platform;
310 wayland_onscreen = g_slice_new0 (CoglOnscreenWayland);
311 egl_onscreen->platform = wayland_onscreen;
313 wayland_onscreen->wayland_surface =
314 wl_compositor_create_surface (wayland_renderer->wayland_compositor);
315 if (!wayland_onscreen->wayland_surface)
317 g_set_error (error, COGL_WINSYS_ERROR,
318 COGL_WINSYS_ERROR_CREATE_ONSCREEN,
319 "Error while creating wayland surface for CoglOnscreen");
323 wayland_onscreen->wayland_shell_surface =
324 wl_shell_get_shell_surface (wayland_renderer->wayland_shell,
325 wayland_onscreen->wayland_surface);
327 wayland_onscreen->wayland_egl_native_window =
328 wl_egl_window_create (wayland_onscreen->wayland_surface,
329 cogl_framebuffer_get_width (framebuffer),
330 cogl_framebuffer_get_height (framebuffer));
331 if (!wayland_onscreen->wayland_egl_native_window)
333 g_set_error (error, COGL_WINSYS_ERROR,
334 COGL_WINSYS_ERROR_CREATE_ONSCREEN,
335 "Error while creating wayland egl native window "
340 egl_onscreen->egl_surface =
341 eglCreateWindowSurface (egl_renderer->edpy,
343 (EGLNativeWindowType)
344 wayland_onscreen->wayland_egl_native_window,
347 wl_shell_surface_set_toplevel (wayland_onscreen->wayland_shell_surface);
353 _cogl_winsys_egl_onscreen_deinit (CoglOnscreen *onscreen)
355 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
356 CoglOnscreenWayland *wayland_onscreen = egl_onscreen->platform;
358 if (wayland_onscreen->wayland_egl_native_window)
360 wl_egl_window_destroy (wayland_onscreen->wayland_egl_native_window);
361 wayland_onscreen->wayland_egl_native_window = NULL;
364 if (wayland_onscreen->wayland_surface)
366 wl_surface_destroy (wayland_onscreen->wayland_surface);
367 wayland_onscreen->wayland_surface = NULL;
370 g_slice_free (CoglOnscreenWayland, wayland_onscreen);
374 _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
376 CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
377 CoglContext *context = fb->context;
378 CoglRenderer *renderer = context->display->renderer;
379 CoglRendererEGL *egl_renderer = renderer->winsys;
380 CoglRendererWayland *wayland_renderer = egl_renderer->platform;
381 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
382 CoglOnscreenWayland *wayland_onscreen = egl_onscreen->platform;
384 if (wayland_onscreen->has_pending)
386 wl_egl_window_resize (wayland_onscreen->wayland_egl_native_window,
387 wayland_onscreen->pending_width,
388 wayland_onscreen->pending_height,
389 wayland_onscreen->pending_dx,
390 wayland_onscreen->pending_dy);
392 _cogl_framebuffer_winsys_update_size (fb,
393 wayland_onscreen->pending_width,
394 wayland_onscreen->pending_height);
395 wayland_onscreen->has_pending = FALSE;
399 parent_vtable->onscreen_swap_buffers (onscreen);
402 * The implementation of eglSwapBuffers may do a flush however the semantics
403 * of eglSwapBuffers on Wayland has changed in the past. So to be safe to
404 * the implementation changing we should explicitly ensure all messages are
407 wl_display_flush (wayland_renderer->wayland_display);
411 cogl_wayland_renderer_set_foreign_display (CoglRenderer *renderer,
412 struct wl_display *display)
414 _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
416 /* NB: Renderers are considered immutable once connected */
417 _COGL_RETURN_IF_FAIL (!renderer->connected);
419 renderer->foreign_wayland_display = display;
423 cogl_wayland_renderer_get_display (CoglRenderer *renderer)
425 _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL);
427 if (renderer->foreign_wayland_display)
428 return renderer->foreign_wayland_display;
429 else if (renderer->connected)
431 CoglRendererEGL *egl_renderer = renderer->winsys;
432 CoglRendererWayland *wayland_renderer = egl_renderer->platform;
433 return wayland_renderer->wayland_display;
440 cogl_wayland_renderer_set_foreign_compositor (CoglRenderer *renderer,
441 struct wl_compositor *compositor)
443 _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
445 /* NB: Renderers are considered immutable once connected */
446 _COGL_RETURN_IF_FAIL (!renderer->connected);
448 renderer->foreign_wayland_compositor = compositor;
451 struct wl_compositor *
452 cogl_wayland_renderer_get_compositor (CoglRenderer *renderer)
454 _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL);
456 if (renderer->foreign_wayland_compositor)
457 return renderer->foreign_wayland_compositor;
458 else if (renderer->connected)
460 CoglRendererEGL *egl_renderer = renderer->winsys;
461 CoglRendererWayland *wayland_renderer = egl_renderer->platform;
462 return wayland_renderer->wayland_compositor;
469 cogl_wayland_renderer_set_foreign_shell (CoglRenderer *renderer,
470 struct wl_shell *shell)
472 _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
474 /* NB: Renderers are considered immutable once connected */
475 _COGL_RETURN_IF_FAIL (!renderer->connected);
477 renderer->foreign_wayland_shell = shell;
481 cogl_wayland_renderer_get_shell (CoglRenderer *renderer)
483 _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), NULL);
485 if (renderer->foreign_wayland_shell)
486 return renderer->foreign_wayland_shell;
487 else if (renderer->connected)
489 CoglRendererEGL *egl_renderer = renderer->winsys;
490 CoglRendererWayland *wayland_renderer = egl_renderer->platform;
491 return wayland_renderer->wayland_shell;
498 cogl_wayland_onscreen_get_surface (CoglOnscreen *onscreen)
502 fb = COGL_FRAMEBUFFER (onscreen);
505 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
506 CoglOnscreenWayland *wayland_onscreen = egl_onscreen->platform;
507 return wayland_onscreen->wayland_surface;
513 struct wl_shell_surface *
514 cogl_wayland_onscreen_get_shell_surface (CoglOnscreen *onscreen)
518 fb = COGL_FRAMEBUFFER (onscreen);
521 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
522 CoglOnscreenWayland *wayland_onscreen = egl_onscreen->platform;
523 return wayland_onscreen->wayland_shell_surface;
530 cogl_wayland_onscreen_resize (CoglOnscreen *onscreen,
538 fb = COGL_FRAMEBUFFER (onscreen);
541 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
542 CoglOnscreenWayland *wayland_onscreen = egl_onscreen->platform;
544 if (cogl_framebuffer_get_width (fb) != width ||
545 cogl_framebuffer_get_height (fb) != height ||
549 wayland_onscreen->pending_width = width;
550 wayland_onscreen->pending_height = height;
551 wayland_onscreen->pending_dx += offset_x;
552 wayland_onscreen->pending_dy += offset_y;
553 wayland_onscreen->has_pending = TRUE;
557 _cogl_framebuffer_winsys_update_size (fb, width, height);
560 static const CoglWinsysEGLVtable
561 _cogl_winsys_egl_vtable =
563 .display_setup = _cogl_winsys_egl_display_setup,
564 .display_destroy = _cogl_winsys_egl_display_destroy,
565 .context_created = _cogl_winsys_egl_context_created,
566 .cleanup_context = _cogl_winsys_egl_cleanup_context,
567 .context_init = _cogl_winsys_egl_context_init,
568 .onscreen_init = _cogl_winsys_egl_onscreen_init,
569 .onscreen_deinit = _cogl_winsys_egl_onscreen_deinit
572 const CoglWinsysVtable *
573 _cogl_winsys_egl_wayland_get_vtable (void)
575 static gboolean vtable_inited = FALSE;
576 static CoglWinsysVtable vtable;
580 /* The EGL_WAYLAND winsys is a subclass of the EGL winsys so we
581 start by copying its vtable */
583 parent_vtable = _cogl_winsys_egl_get_vtable ();
584 vtable = *parent_vtable;
586 vtable.id = COGL_WINSYS_ID_EGL_WAYLAND;
587 vtable.name = "EGL_WAYLAND";
589 vtable.renderer_connect = _cogl_winsys_renderer_connect;
590 vtable.renderer_disconnect = _cogl_winsys_renderer_disconnect;
592 vtable.onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers;
594 vtable_inited = TRUE;