"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / winsys / cogl-winsys-egl.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
7  *
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.
12  *
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.
17  *
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/>.
21  *
22  *
23  * Authors:
24  *   Robert Bragg <robert@linux.intel.com>
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
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"
41
42 #include "cogl-private.h"
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49
50 #include <glib/gi18n-lib.h>
51
52 #define MAX_EGL_CONFIG_ATTRIBS 30
53
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,    \
57                                   egl_private_flags)                    \
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()               \
63   { NULL, 0 },                                  \
64     };
65 #include "cogl-winsys-egl-feature-functions.h"
66
67 /* Define an array of features */
68 #undef COGL_WINSYS_FEATURE_BEGIN
69 #define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names,    \
70                                   egl_private_flags)                    \
71   { 255, 255, 0, namespaces, extension_names,                           \
72       0, egl_private_flags,                                             \
73       0,                                                                \
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()
79
80 static const CoglFeatureData winsys_feature_data[] =
81   {
82 #include "cogl-winsys-egl-feature-functions.h"
83   };
84
85 static CoglFuncPtr
86 _cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer,
87                                         const char *name)
88 {
89   void *ptr;
90
91   ptr = eglGetProcAddress (name);
92
93   /* eglGetProcAddress doesn't support fetching core API so we need to
94      get that separately with GModule */
95   if (ptr == NULL)
96     g_module_symbol (renderer->libgl_module, name, &ptr);
97
98   return ptr;
99 }
100
101 static void
102 _cogl_winsys_renderer_disconnect (CoglRenderer *renderer)
103 {
104   /* This function must be overridden by a platform winsys */
105   g_assert_not_reached ();
106 }
107
108 /* Updates all the function pointers */
109 static void
110 check_egl_extensions (CoglRenderer *renderer)
111 {
112   CoglRendererEGL *egl_renderer = renderer->winsys;
113   const char *egl_extensions;
114   int i;
115
116   egl_extensions = eglQueryString (egl_renderer->edpy, EGL_EXTENSIONS);
117
118   COGL_NOTE (WINSYS, "  EGL Extensions: %s", egl_extensions);
119
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 */
125                              egl_extensions,
126                              egl_renderer))
127       {
128         egl_renderer->private_features |=
129           winsys_feature_data[i].feature_flags_private;
130       }
131 }
132
133 gboolean
134 _cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
135                                           GError **error)
136 {
137   CoglRendererEGL *egl_renderer = renderer->winsys;
138
139   if (!eglInitialize (egl_renderer->edpy,
140                       &egl_renderer->egl_version_major,
141                       &egl_renderer->egl_version_minor))
142     {
143       g_set_error (error, COGL_WINSYS_ERROR,
144                    COGL_WINSYS_ERROR_INIT,
145                    "Couldn't initialize EGL");
146       return FALSE;
147     }
148
149   check_egl_extensions (renderer);
150
151   return TRUE;
152 }
153
154 static gboolean
155 _cogl_winsys_renderer_connect (CoglRenderer *renderer,
156                                GError **error)
157 {
158   /* This function must be overridden by a platform winsys */
159   g_assert_not_reached ();
160 }
161
162 static void
163 egl_attributes_from_framebuffer_config (CoglDisplay *display,
164                                         CoglFramebufferConfig *config,
165                                         gboolean needs_stencil_override,
166                                         EGLint *attributes)
167 {
168   CoglRenderer *renderer = display->renderer;
169   CoglRendererEGL *egl_renderer = renderer->winsys;
170   int i = 0;
171
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,
175                                                               config,
176                                                               attributes);
177
178   attributes[i++] = EGL_STENCIL_SIZE;
179   attributes[i++] = needs_stencil_override ? 2 : 0;
180
181   attributes[i++] = EGL_RED_SIZE;
182   attributes[i++] = 1;
183   attributes[i++] = EGL_GREEN_SIZE;
184   attributes[i++] = 1;
185   attributes[i++] = EGL_BLUE_SIZE;
186   attributes[i++] = 1;
187
188   attributes[i++] = EGL_ALPHA_SIZE;
189   attributes[i++] = config->swap_chain->has_alpha ? 1 : EGL_DONT_CARE;
190
191   attributes[i++] = EGL_DEPTH_SIZE;
192   attributes[i++] = 1;
193
194   attributes[i++] = EGL_BUFFER_SIZE;
195   attributes[i++] = EGL_DONT_CARE;
196
197   attributes[i++] = EGL_RENDERABLE_TYPE;
198   attributes[i++] = (renderer->driver == COGL_DRIVER_GL ?
199                       EGL_OPENGL_BIT :
200                       renderer->driver == COGL_DRIVER_GLES1 ?
201                       EGL_OPENGL_ES_BIT :
202                       EGL_OPENGL_ES2_BIT);
203
204   attributes[i++] = EGL_SURFACE_TYPE;
205   attributes[i++] = EGL_WINDOW_BIT;
206
207   if (config->samples_per_pixel)
208     {
209        attributes[i++] = EGL_SAMPLE_BUFFERS;
210        attributes[i++] = 1;
211        attributes[i++] = EGL_SAMPLES;
212        attributes[i++] = config->samples_per_pixel;
213     }
214
215   attributes[i++] = EGL_NONE;
216
217   g_assert (i < MAX_EGL_CONFIG_ATTRIBS);
218 }
219
220 static gboolean
221 try_create_context (CoglDisplay *display,
222                     gboolean with_stencil_buffer,
223                     GError **error)
224 {
225   CoglRenderer *renderer = display->renderer;
226   CoglDisplayEGL *egl_display = display->winsys;
227   CoglRendererEGL *egl_renderer = renderer->winsys;
228   EGLDisplay edpy;
229   EGLConfig config;
230   EGLint config_count = 0;
231   EGLBoolean status;
232   EGLint attribs[3];
233   EGLint cfg_attribs[MAX_EGL_CONFIG_ATTRIBS];
234   const char *error_message;
235
236   _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context == NULL, TRUE);
237
238   if (renderer->driver == COGL_DRIVER_GL)
239     eglBindAPI (EGL_OPENGL_API);
240
241   if (display->renderer->driver == COGL_DRIVER_GLES2)
242     {
243       attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
244       attribs[1] = 2;
245       attribs[2] = EGL_NONE;
246     }
247   else
248     attribs[0] = EGL_NONE;
249
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);
254
255   egl_attributes_from_framebuffer_config (display,
256                                           &display->onscreen_template->config,
257                                           with_stencil_buffer,
258                                           cfg_attribs);
259
260   edpy = egl_renderer->edpy;
261
262   status = eglChooseConfig (edpy,
263                             cfg_attribs,
264                             &config, 1,
265                             &config_count);
266   if (status != EGL_TRUE || config_count == 0)
267     {
268       error_message = "Unable to find a usable EGL configuration";
269       goto fail;
270     }
271
272   egl_display->egl_config = config;
273
274   egl_display->egl_context = eglCreateContext (edpy,
275                                                config,
276                                                EGL_NO_CONTEXT,
277                                                attribs);
278   if (egl_display->egl_context == EGL_NO_CONTEXT)
279     {
280       error_message = "Unable to create a suitable EGL context";
281       goto fail;
282     }
283
284   if (egl_renderer->platform_vtable->context_created &&
285       !egl_renderer->platform_vtable->context_created (display, error))
286     return FALSE;
287
288   return TRUE;
289
290 fail:
291   g_set_error (error, COGL_WINSYS_ERROR,
292                COGL_WINSYS_ERROR_CREATE_CONTEXT,
293                "%s", error_message);
294   return FALSE;
295 }
296
297 static void
298 cleanup_context (CoglDisplay *display)
299 {
300   CoglRenderer *renderer = display->renderer;
301   CoglDisplayEGL *egl_display = display->winsys;
302   CoglRendererEGL *egl_renderer = renderer->winsys;
303
304   if (egl_display->egl_context != EGL_NO_CONTEXT)
305     {
306       eglMakeCurrent (egl_renderer->edpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
307                       EGL_NO_CONTEXT);
308       eglDestroyContext (egl_renderer->edpy, egl_display->egl_context);
309       egl_display->egl_context = EGL_NO_CONTEXT;
310     }
311
312   if (egl_renderer->platform_vtable->cleanup_context)
313     egl_renderer->platform_vtable->cleanup_context (display);
314 }
315
316 static gboolean
317 create_context (CoglDisplay *display, GError **error)
318 {
319   CoglDisplayEGL *egl_display = display->winsys;
320
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.
326    */
327   if (try_create_context (display, TRUE, error))
328     {
329       egl_display->stencil_disabled = FALSE;
330       return TRUE;
331     }
332   else
333     {
334       g_clear_error (error);
335       cleanup_context (display);
336       egl_display->stencil_disabled = TRUE;
337       return try_create_context (display, FALSE, error);
338     }
339 }
340
341 static void
342 _cogl_winsys_display_destroy (CoglDisplay *display)
343 {
344   CoglRendererEGL *egl_renderer = display->renderer->winsys;
345   CoglDisplayEGL *egl_display = display->winsys;
346
347   _COGL_RETURN_IF_FAIL (egl_display != NULL);
348
349   cleanup_context (display);
350
351   if (egl_renderer->platform_vtable->display_destroy)
352     egl_renderer->platform_vtable->display_destroy (display);
353
354   g_slice_free (CoglDisplayEGL, display->winsys);
355   display->winsys = NULL;
356 }
357
358 static gboolean
359 _cogl_winsys_display_setup (CoglDisplay *display,
360                             GError **error)
361 {
362   CoglDisplayEGL *egl_display;
363   CoglRenderer *renderer = display->renderer;
364   CoglRendererEGL *egl_renderer = renderer->winsys;
365
366   _COGL_RETURN_VAL_IF_FAIL (display->winsys == NULL, FALSE);
367
368   egl_display = g_slice_new0 (CoglDisplayEGL);
369   display->winsys = egl_display;
370
371 #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
372   if (display->wayland_compositor_display)
373     {
374       struct wl_display *wayland_display = display->wayland_compositor_display;
375       CoglRendererEGL *egl_renderer = display->renderer->winsys;
376
377       egl_renderer->pf_eglBindWaylandDisplay (egl_renderer->edpy,
378                                               wayland_display);
379     }
380 #endif
381
382   if (egl_renderer->platform_vtable->display_setup &&
383       !egl_renderer->platform_vtable->display_setup (display, error))
384     goto error;
385
386   if (!create_context (display, error))
387     goto error;
388
389   egl_display->found_egl_config = TRUE;
390
391   return TRUE;
392
393 error:
394   _cogl_winsys_display_destroy (display);
395   return FALSE;
396 }
397
398 static gboolean
399 _cogl_winsys_context_init (CoglContext *context, GError **error)
400 {
401   CoglRenderer *renderer = context->display->renderer;
402   CoglDisplayEGL *egl_display = context->display->winsys;
403   CoglRendererEGL *egl_renderer = renderer->winsys;
404
405   context->winsys = g_new0 (CoglContextEGL, 1);
406
407   _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
408
409   memset (context->winsys_features, 0, sizeof (context->winsys_features));
410
411   check_egl_extensions (renderer);
412
413   if (!_cogl_context_update_features (context, error))
414     return FALSE;
415
416   if (egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_SWAP_REGION)
417     {
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);
422     }
423
424   if (egl_renderer->platform_vtable->context_init &&
425       !egl_renderer->platform_vtable->context_init (context, error))
426     return FALSE;
427
428   return TRUE;
429 }
430
431 static void
432 _cogl_winsys_context_deinit (CoglContext *context)
433 {
434   CoglRenderer *renderer = context->display->renderer;
435   CoglRendererEGL *egl_renderer = renderer->winsys;
436
437   if (egl_renderer->platform_vtable->context_deinit)
438     egl_renderer->platform_vtable->context_deinit (context);
439
440   g_free (context->winsys);
441 }
442
443 static gboolean
444 _cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
445                             GError **error)
446 {
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;
456   EGLBoolean status;
457   gboolean need_stencil =
458     egl_display->stencil_disabled ? FALSE : framebuffer->config.need_stencil;
459
460   _COGL_RETURN_VAL_IF_FAIL (egl_display->egl_context, FALSE);
461
462   egl_attributes_from_framebuffer_config (display,
463                                           &framebuffer->config,
464                                           need_stencil,
465                                           attributes);
466
467   status = eglChooseConfig (egl_renderer->edpy,
468                             attributes,
469                             &egl_config, 1,
470                             &config_count);
471   if (status != EGL_TRUE || config_count == 0)
472     {
473       g_set_error (error, COGL_WINSYS_ERROR,
474                    COGL_WINSYS_ERROR_CREATE_ONSCREEN,
475                    "Failed to find a suitable EGL configuration");
476       return FALSE;
477     }
478
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)
482     {
483       EGLint samples;
484       status = eglGetConfigAttrib (egl_renderer->edpy,
485                                    egl_config,
486                                    EGL_SAMPLES, &samples);
487       g_return_val_if_fail (status == EGL_TRUE, TRUE);
488       framebuffer->samples_per_pixel = samples;
489     }
490
491   onscreen->winsys = g_slice_new0 (CoglOnscreenEGL);
492
493   if (egl_renderer->platform_vtable->onscreen_init &&
494       !egl_renderer->platform_vtable->onscreen_init (onscreen,
495                                                      egl_config,
496                                                      error))
497     {
498       g_slice_free (CoglOnscreenEGL, onscreen->winsys);
499       return FALSE;
500     }
501
502   return TRUE;
503 }
504
505 static void
506 _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
507 {
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;
513
514   /* If we never successfully allocated then there's nothing to do */
515   if (egl_onscreen == NULL)
516     return;
517   if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
518     {
519       if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface)
520           == EGL_FALSE)
521         g_warning ("Failed to destroy EGL surface");
522       egl_onscreen->egl_surface = EGL_NO_SURFACE;
523     }
524
525   if (egl_renderer->platform_vtable->onscreen_deinit)
526     egl_renderer->platform_vtable->onscreen_deinit (onscreen);
527
528   g_slice_free (CoglOnscreenEGL, onscreen->winsys);
529   onscreen->winsys = NULL;
530 }
531
532 static void
533 _cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
534 {
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;
542
543   if (egl_context->current_surface == egl_onscreen->egl_surface)
544     return;
545
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;
551
552   if (fb->config.swap_throttled)
553     eglSwapInterval (egl_renderer->edpy, 1);
554   else
555     eglSwapInterval (egl_renderer->edpy, 0);
556 }
557
558 static void
559 _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
560                                    const int *user_rectangles,
561                                    int n_rectangles)
562 {
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);
570   int i;
571
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++)
577     {
578       int *rect = &rectangles[4 * i];
579       rect[1] = framebuffer_height - rect[1] - rect[3];
580     }
581
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);
589
590   if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy,
591                                              egl_onscreen->egl_surface,
592                                              n_rectangles,
593                                              rectangles) == EGL_FALSE)
594     g_warning ("Error reported by eglSwapBuffersRegion");
595 }
596
597 static void
598 _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
599 {
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;
604
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);
613
614   eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface);
615 }
616
617 static void
618 _cogl_winsys_onscreen_update_swap_throttled (CoglOnscreen *onscreen)
619 {
620   CoglContext *context = COGL_FRAMEBUFFER (onscreen)->context;
621   CoglContextEGL *egl_context = context->winsys;
622   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
623
624   if (egl_context->current_surface != egl_onscreen->egl_surface)
625     return;
626
627   egl_context->current_surface = EGL_NO_SURFACE;
628
629   _cogl_winsys_onscreen_bind (onscreen);
630 }
631
632 static EGLDisplay
633 _cogl_winsys_context_egl_get_egl_display (CoglContext *context)
634 {
635   CoglRendererEGL *egl_renderer = context->display->renderer->winsys;
636
637   return egl_renderer->edpy;
638 }
639
640 static CoglWinsysVtable _cogl_winsys_vtable =
641   {
642     .constraints = COGL_RENDERER_CONSTRAINT_USES_EGL,
643
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 */
646
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,
663   };
664
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.
673  */
674 const CoglWinsysVtable *
675 _cogl_winsys_egl_get_vtable (void)
676 {
677   return &_cogl_winsys_vtable;
678 }
679
680 #ifdef EGL_KHR_image_base
681 EGLImageKHR
682 _cogl_egl_create_image (CoglContext *ctx,
683                         EGLenum target,
684                         EGLClientBuffer buffer,
685                         const EGLint *attribs)
686 {
687   CoglDisplayEGL *egl_display = ctx->display->winsys;
688   CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys;
689   EGLContext egl_ctx;
690
691   _COGL_RETURN_VAL_IF_FAIL (egl_renderer->pf_eglCreateImage, EGL_NO_IMAGE_KHR);
692
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;
698   else
699 #endif
700     egl_ctx = egl_display->egl_context;
701
702   return egl_renderer->pf_eglCreateImage (egl_renderer->edpy,
703                                           egl_ctx,
704                                           target,
705                                           buffer,
706                                           attribs);
707 }
708
709 void
710 _cogl_egl_destroy_image (CoglContext *ctx,
711                          EGLImageKHR image)
712 {
713   CoglRendererEGL *egl_renderer = ctx->display->renderer->winsys;
714
715   _COGL_RETURN_IF_FAIL (egl_renderer->pf_eglDestroyImage);
716
717   egl_renderer->pf_eglDestroyImage (egl_renderer->edpy, image);
718 }
719 #endif