4 * An object oriented GL/GLES Abstraction/Utility Layer
6 * Copyright (C) 2007,2008,2009,2010,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>
31 #include "cogl-util.h"
32 #include "cogl-winsys-egl-private.h"
33 #include "cogl-winsys-private.h"
34 #include "cogl-feature-private.h"
35 #include "cogl-context-private.h"
36 #include "cogl-framebuffer.h"
37 #include "cogl-onscreen-private.h"
38 #include "cogl-swap-chain-private.h"
39 #include "cogl-renderer-private.h"
40 #include "cogl-onscreen-template-private.h"
42 #include "cogl-private.h"
46 #include <sys/types.h>
50 #include <glib/gi18n-lib.h>
52 #define MAX_EGL_CONFIG_ATTRIBS 30
54 /* Define a set of arrays containing the functions required from GL
55 for each winsys feature */
56 #define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \
58 static const CoglFeatureFunction \
59 cogl_egl_feature_ ## name ## _funcs[] = {
60 #define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args) \
61 { G_STRINGIFY (name), G_STRUCT_OFFSET (CoglRendererEGL, pf_ ## name) },
62 #define COGL_WINSYS_FEATURE_END() \
65 #include "cogl-winsys-egl-feature-functions.h"
67 /* Define an array of features */
68 #undef COGL_WINSYS_FEATURE_BEGIN
69 #define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \
71 { 255, 255, 0, namespaces, extension_names, \
72 0, egl_private_flags, \
74 cogl_egl_feature_ ## name ## _funcs },
75 #undef COGL_WINSYS_FEATURE_FUNCTION
76 #define COGL_WINSYS_FEATURE_FUNCTION(ret, name, args)
77 #undef COGL_WINSYS_FEATURE_END
78 #define COGL_WINSYS_FEATURE_END()
80 static const CoglFeatureData winsys_feature_data[] =
82 #include "cogl-winsys-egl-feature-functions.h"
86 _cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer,
91 ptr = eglGetProcAddress (name);
93 /* eglGetProcAddress doesn't support fetching core API so we need to
94 get that separately with GModule */
96 g_module_symbol (renderer->libgl_module, name, &ptr);
102 _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
104 /* This function must be overridden by a platform winsys */
105 g_assert_not_reached ();
108 /* Updates all the function pointers */
110 check_egl_extensions (CoglRenderer *renderer)
112 CoglRendererEGL *egl_renderer = renderer->winsys;
113 const char *egl_extensions;
116 egl_extensions = eglQueryString (egl_renderer->edpy, EGL_EXTENSIONS);
118 COGL_NOTE (WINSYS, " EGL Extensions: %s", egl_extensions);
120 egl_renderer->private_features = 0;
121 for (i = 0; i < G_N_ELEMENTS (winsys_feature_data); i++)
122 if (_cogl_feature_check (renderer,
123 "EGL", winsys_feature_data + i, 0, 0,
124 COGL_DRIVER_GL, /* the driver isn't used */
128 egl_renderer->private_features |=
129 winsys_feature_data[i].feature_flags_private;
134 _cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
137 CoglRendererEGL *egl_renderer = renderer->winsys;
139 if (!eglInitialize (egl_renderer->edpy,
140 &egl_renderer->egl_version_major,
141 &egl_renderer->egl_version_minor))
143 g_set_error (error, COGL_WINSYS_ERROR,
144 COGL_WINSYS_ERROR_INIT,
145 "Couldn't initialize EGL");
149 check_egl_extensions (renderer);
155 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
158 /* This function must be overridden by a platform winsys */
159 g_assert_not_reached ();
163 egl_attributes_from_framebuffer_config (CoglDisplay *display,
164 CoglFramebufferConfig *config,
165 gboolean needs_stencil_override,
168 CoglRenderer *renderer = display->renderer;
169 CoglRendererEGL *egl_renderer = renderer->winsys;
172 /* Let the platform add attributes first */
173 if (egl_renderer->platform_vtable->add_config_attributes)
174 i = egl_renderer->platform_vtable->add_config_attributes (display,
178 attributes[i++] = EGL_STENCIL_SIZE;
179 attributes[i++] = needs_stencil_override ? 2 : 0;
181 attributes[i++] = EGL_RED_SIZE;
183 attributes[i++] = EGL_GREEN_SIZE;
185 attributes[i++] = EGL_BLUE_SIZE;
188 attributes[i++] = EGL_ALPHA_SIZE;
189 attributes[i++] = config->swap_chain->has_alpha ? 1 : EGL_DONT_CARE;
191 attributes[i++] = EGL_DEPTH_SIZE;
194 attributes[i++] = EGL_BUFFER_SIZE;
195 attributes[i++] = EGL_DONT_CARE;
197 attributes[i++] = EGL_RENDERABLE_TYPE;
198 attributes[i++] = (renderer->driver == COGL_DRIVER_GL ?
200 renderer->driver == COGL_DRIVER_GLES1 ?
204 attributes[i++] = EGL_SURFACE_TYPE;
205 attributes[i++] = EGL_WINDOW_BIT;
207 if (config->samples_per_pixel)
209 attributes[i++] = EGL_SAMPLE_BUFFERS;
211 attributes[i++] = EGL_SAMPLES;
212 attributes[i++] = config->samples_per_pixel;
215 attributes[i++] = EGL_NONE;
217 g_assert (i < MAX_EGL_CONFIG_ATTRIBS);
221 try_create_context (CoglDisplay *display,
222 gboolean with_stencil_buffer,
225 CoglRenderer *renderer = display->renderer;
226 CoglDisplayEGL *egl_display = display->winsys;
227 CoglRendererEGL *egl_renderer = renderer->winsys;
230 EGLint config_count = 0;
233 EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS];
234 const char *error_message;
236 _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context == NULL, TRUE);
238 if (renderer->driver == COGL_DRIVER_GL)
239 eglBindAPI (EGL_OPENGL_API);
241 if (display->renderer->driver == COGL_DRIVER_GLES2)
243 attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
245 attribs[2] = EGL_NONE;
248 attribs[0] = EGL_NONE;
250 /* Divert to the platform implementation if one is defined */
251 if (egl_renderer->platform_vtable->try_create_context)
252 return egl_renderer->platform_vtable->
253 try_create_context (display, attribs, error);
255 egl_attributes_from_framebuffer_config (display,
256 &display->onscreen_template->config,
260 edpy = egl_renderer->edpy;
262 status = eglChooseConfig (edpy,
266 if (status != EGL_TRUE || config_count == 0)
268 error_message = "Unable to find a usable EGL configuration";
272 egl_display->egl_config = config;
274 egl_display->egl_context = eglCreateContext (edpy,
278 if (egl_display->egl_context == EGL_NO_CONTEXT)
280 error_message = "Unable to create a suitable EGL context";
284 if (egl_renderer->platform_vtable->context_created &&
285 !egl_renderer->platform_vtable->context_created (display, error))
291 g_set_error (error, COGL_WINSYS_ERROR,
292 COGL_WINSYS_ERROR_CREATE_CONTEXT,
293 "%s", error_message);
298 cleanup_context (CoglDisplay *display)
300 CoglRenderer *renderer = display->renderer;
301 CoglDisplayEGL *egl_display = display->winsys;
302 CoglRendererEGL *egl_renderer = renderer->winsys;
304 if (egl_display->egl_context != EGL_NO_CONTEXT)
306 eglMakeCurrent (egl_renderer->edpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
308 eglDestroyContext (egl_renderer->edpy, egl_display->egl_context);
309 egl_display->egl_context = EGL_NO_CONTEXT;
312 if (egl_renderer->platform_vtable->cleanup_context)
313 egl_renderer->platform_vtable->cleanup_context (display);
317 create_context (CoglDisplay *display, GError **error)
319 CoglDisplayEGL *egl_display = display->winsys;
321 /* Note: we don't just rely on eglChooseConfig to correctly
322 * report that the driver doesn't support a stencil buffer
323 * because we've seen PVR drivers that claim stencil buffer
324 * support according to the EGLConfig but then later fail
325 * when trying to create a context with such a config.
327 if (try_create_context (display, TRUE, error))
329 egl_display->stencil_disabled = FALSE;
334 g_clear_error (error);
335 cleanup_context (display);
336 egl_display->stencil_disabled = TRUE;
337 return try_create_context (display, FALSE, error);
342 _cogl_winsys_display_destroy (CoglDisplay *display)
344 CoglRendererEGL *egl_renderer = display->renderer->winsys;
345 CoglDisplayEGL *egl_display = display->winsys;
347 _COGL_RETURN_IF_FAIL (egl_display != NULL);
349 cleanup_context (display);
351 if (egl_renderer->platform_vtable->display_destroy)
352 egl_renderer->platform_vtable->display_destroy (display);
354 g_slice_free (CoglDisplayEGL, display->winsys);
355 display->winsys = NULL;
359 _cogl_winsys_display_setup (CoglDisplay *display,
362 CoglDisplayEGL *egl_display;
363 CoglRenderer *renderer = display->renderer;
364 CoglRendererEGL *egl_renderer = renderer->winsys;
366 _COGL_RETURN_VAL_IF_FAIL (display->winsys == NULL, FALSE);
368 egl_display = g_slice_new0 (CoglDisplayEGL);
369 display->winsys = egl_display;
371 #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
372 if (display->wayland_compositor_display)
374 struct wl_display *wayland_display = display->wayland_compositor_display;
375 CoglRendererEGL *egl_renderer = display->renderer->winsys;
377 egl_renderer->pf_eglBindWaylandDisplay (egl_renderer->edpy,
382 if (egl_renderer->platform_vtable->display_setup &&
383 !egl_renderer->platform_vtable->display_setup (display, error))
386 if (!create_context (display, error))
389 egl_display->found_egl_config = TRUE;
394 _cogl_winsys_display_destroy (display);
399 _cogl_winsys_context_init (CoglContext *context, GError **error)
401 CoglRenderer *renderer = context->display->renderer;
402 CoglDisplayEGL *egl_display = context->display->winsys;
403 CoglRendererEGL *egl_renderer = renderer->winsys;
405 context->winsys = g_new0 (CoglContextEGL, 1);
407 _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
409 memset (context->winsys_features, 0, sizeof (context->winsys_features));
411 check_egl_extensions (renderer);
413 if (!_cogl_context_update_features (context, error))
416 if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_SWAP_REGION)
418 COGL_FLAGS_SET (context->winsys_features,
419 COGL_WINSYS_FEATURE_SWAP_REGION, TRUE);
420 COGL_FLAGS_SET (context->winsys_features,
421 COGL_WINSYS_FEATURE_SWAP_REGION_THROTTLE, TRUE);
424 if (egl_renderer->platform_vtable->context_init &&
425 !egl_renderer->platform_vtable->context_init (context, error))
432 _cogl_winsys_context_deinit (CoglContext *context)
434 CoglRenderer *renderer = context->display->renderer;
435 CoglRendererEGL *egl_renderer = renderer->winsys;
437 if (egl_renderer->platform_vtable->context_deinit)
438 egl_renderer->platform_vtable->context_deinit (context);
440 g_free (context->winsys);
444 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
447 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
448 CoglContext *context = framebuffer->context;
449 CoglDisplay *display = context->display;
450 CoglDisplayEGL *egl_display = display->winsys;
451 CoglRenderer *renderer = display->renderer;
452 CoglRendererEGL *egl_renderer = renderer->winsys;
453 EGLint attributes[MAX_EGL_CONFIG_ATTRIBS];
454 EGLConfig egl_config;
455 EGLint config_count = 0;
457 gboolean need_stencil =
458 egl_display->stencil_disabled ? FALSE : framebuffer->config.need_stencil;
460 _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
462 egl_attributes_from_framebuffer_config (display,
463 &framebuffer->config,
467 status = eglChooseConfig (egl_renderer->edpy,
471 if (status != EGL_TRUE || config_count == 0)
473 g_set_error (error, COGL_WINSYS_ERROR,
474 COGL_WINSYS_ERROR_CREATE_ONSCREEN,
475 "Failed to find a suitable EGL configuration");
479 /* Update the real number of samples_per_pixel now that we have
480 * found an egl_config... */
481 if (framebuffer->config.samples_per_pixel)
484 status = eglGetConfigAttrib (egl_renderer->edpy,
486 EGL_SAMPLES, &samples);
487 g_return_val_if_fail (status == EGL_TRUE, TRUE);
488 framebuffer->samples_per_pixel = samples;
491 onscreen->winsys = g_slice_new0 (CoglOnscreenEGL);
493 if (egl_renderer->platform_vtable->onscreen_init &&
494 !egl_renderer->platform_vtable->onscreen_init (onscreen,
498 g_slice_free (CoglOnscreenEGL, onscreen->winsys);
506 _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
508 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
509 CoglContext *context = framebuffer->context;
510 CoglRenderer *renderer = context->display->renderer;
511 CoglRendererEGL *egl_renderer = renderer->winsys;
512 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
514 /* If we never successfully allocated then there's nothing to do */
515 if (egl_onscreen == NULL)
517 if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
519 if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface)
521 g_warning ("Failed to destroy EGL surface");
522 egl_onscreen->egl_surface = EGL_NO_SURFACE;
525 if (egl_renderer->platform_vtable->onscreen_deinit)
526 egl_renderer->platform_vtable->onscreen_deinit (onscreen);
528 g_slice_free (CoglOnscreenEGL, onscreen->winsys);
529 onscreen->winsys = NULL;
533 _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
535 CoglFramebuffer *fb = COGL_FRAMEBUFFER (onscreen);
536 CoglContext *context = fb->context;
537 CoglDisplayEGL *egl_display = context->display->winsys;
538 CoglRenderer *renderer = context->display->renderer;
539 CoglRendererEGL *egl_renderer = renderer->winsys;
540 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
541 CoglContextEGL *egl_context = context->winsys;
543 if (egl_context->current_surface == egl_onscreen->egl_surface)
546 eglMakeCurrent (egl_renderer->edpy,
547 egl_onscreen->egl_surface,
548 egl_onscreen->egl_surface,
549 egl_display->egl_context);
550 egl_context->current_surface = egl_onscreen->egl_surface;
552 if (fb->config.swap_throttled)
553 eglSwapInterval (egl_renderer->edpy, 1);
555 eglSwapInterval (egl_renderer->edpy, 0);
559 _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
560 const int *user_rectangles,
563 CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
564 CoglRenderer *renderer = context->display->renderer;
565 CoglRendererEGL *egl_renderer = renderer->winsys;
566 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
567 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
568 int framebuffer_height = cogl_framebuffer_get_height (framebuffer);
569 int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4);
572 /* eglSwapBuffersRegion expects rectangles relative to the
573 * bottom left corner but we are given rectangles relative to
574 * the top left so we need to flip them... */
575 memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
576 for (i = 0; i < n_rectangles; i++)
578 int *rect = &rectangles[4 * i];
579 rect[1] = framebuffer_height - rect[1] - rect[3];
582 /* At least for eglSwapBuffers the EGL spec says that the surface to
583 swap must be bound to the current context. It looks like Mesa
584 also validates that this is the case for eglSwapBuffersRegion so
585 we must bind here too */
586 _cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
587 COGL_FRAMEBUFFER (onscreen),
588 COGL_FRAMEBUFFER_STATE_BIND);
590 if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy,
591 egl_onscreen->egl_surface,
593 rectangles) == EGL_FALSE)
594 g_warning ("Error reported by eglSwapBuffersRegion");
598 _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
600 CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
601 CoglRenderer *renderer = context->display->renderer;
602 CoglRendererEGL *egl_renderer = renderer->winsys;
603 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
605 /* The specification for EGL (at least in 1.4) says that the surface
606 needs to be bound to the current context for the swap to work
607 although it may change in future. Mesa explicitly checks for this
608 and just returns an error if this is not the case so we can't
609 just pretend this isn't in the spec. */
610 _cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
611 COGL_FRAMEBUFFER (onscreen),
612 COGL_FRAMEBUFFER_STATE_BIND);
614 eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface);
618 _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
620 CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
621 CoglContextEGL *egl_context = context->winsys;
622 CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
624 if (egl_context->current_surface != egl_onscreen->egl_surface)
627 egl_context->current_surface = EGL_NO_SURFACE;
629 _cogl_winsys_onscreen_bind (onscreen);
633 _cogl_winsys_context_egl_get_egl_display (CoglContext *context)
635 CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
637 return egl_renderer->edpy;
640 static CoglWinsysVtable _cogl_winsys_vtable =
642 .constraints = COGL_RENDERER_CONSTRAINT_USES_EGL,
644 /* This winsys is only used as a base for the EGL-platform
645 winsys's so it does not have an ID or a name */
647 .renderer_get_proc_address = _cogl_winsys_renderer_get_proc_address,
648 .renderer_connect = _cogl_winsys_renderer_connect,
649 .renderer_disconnect = _cogl_winsys_renderer_disconnect,
650 .display_setup = _cogl_winsys_display_setup,
651 .display_destroy = _cogl_winsys_display_destroy,
652 .context_init = _cogl_winsys_context_init,
653 .context_deinit = _cogl_winsys_context_deinit,
654 .context_egl_get_egl_display =
655 _cogl_winsys_context_egl_get_egl_display,
656 .onscreen_init = _cogl_winsys_onscreen_init,
657 .onscreen_deinit = _cogl_winsys_onscreen_deinit,
658 .onscreen_bind = _cogl_winsys_onscreen_bind,
659 .onscreen_swap_buffers = _cogl_winsys_onscreen_swap_buffers,
660 .onscreen_swap_region = _cogl_winsys_onscreen_swap_region,
661 .onscreen_update_swap_throttled =
662 _cogl_winsys_onscreen_update_swap_throttled,
665 /* XXX: we use a function because no doubt someone will complain
666 * about using c99 member initializers because they aren't portable
667 * to windows. We want to avoid having to rigidly follow the real
668 * order of members since some members are #ifdefd and we'd have
669 * to mirror the #ifdefing to add padding etc. For any winsys that
670 * can assume the platform has a sane compiler then we can just use
671 * c99 initializers for insane platforms they can initialize
672 * the members by name in a function.
674 const CoglWinsysVtable *
675 _cogl_winsys_egl_get_vtable (void)
677 return &_cogl_winsys_vtable;
680 #ifdef EGL_KHR_image_base
682 _cogl_egl_create_image (CoglContext *ctx,
684 EGLClientBuffer buffer,
685 const EGLint *attribs)
687 CoglDisplayEGL *egl_display = ctx->display->winsys;
688 CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys;
691 _COGL_RETURN_VAL_IF_FAIL (egl_renderer->pf_eglCreateImage, EGL_NO_IMAGE_KHR);
693 /* The EGL_KHR_image_pixmap spec explicitly states that EGL_NO_CONTEXT must
694 * always be used in conjunction with the EGL_NATIVE_PIXMAP_KHR target */
695 #ifdef EGL_KHR_image_pixmap
696 if (target == EGL_NATIVE_PIXMAP_KHR)
697 egl_ctx = EGL_NO_CONTEXT;
700 egl_ctx = egl_display->egl_context;
702 return egl_renderer->pf_eglCreateImage (egl_renderer->edpy,
710 _cogl_egl_destroy_image (CoglContext *ctx,
713 CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys;
715 _COGL_RETURN_IF_FAIL (egl_renderer->pf_eglDestroyImage);
717 egl_renderer->pf_eglDestroyImage (egl_renderer->edpy, image);