1/*
2 * Mesa 3-D graphics library
3 * Version:  7.9
4 *
5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 */
25
26#include "egldriver.h"
27#include "eglcurrent.h"
28#include "egllog.h"
29
30#include "pipe/p_screen.h"
31#include "util/u_memory.h"
32#include "util/u_inlines.h"
33#include "util/u_box.h"
34
35#include "egl_g3d.h"
36#include "egl_g3d_api.h"
37#include "egl_g3d_image.h"
38#include "egl_g3d_sync.h"
39#include "egl_g3d_st.h"
40#include "native.h"
41
42/**
43 * Return the state tracker for the given context.
44 */
45static struct st_api *
46egl_g3d_choose_st(_EGLDriver *drv, _EGLContext *ctx,
47                  enum st_profile_type *profile)
48{
49   struct st_api *stapi;
50   EGLint api = -1;
51
52   *profile = ST_PROFILE_DEFAULT;
53
54   switch (ctx->ClientAPI) {
55   case EGL_OPENGL_ES_API:
56      switch (ctx->ClientMajorVersion) {
57      case 1:
58         api = ST_API_OPENGL;
59         *profile = ST_PROFILE_OPENGL_ES1;
60         break;
61      case 2:
62         api = ST_API_OPENGL;
63         *profile = ST_PROFILE_OPENGL_ES2;
64         break;
65      default:
66         _eglLog(_EGL_WARNING, "unknown client major version %d",
67               ctx->ClientMajorVersion);
68         break;
69      }
70      break;
71   case EGL_OPENVG_API:
72      api = ST_API_OPENVG;
73      break;
74   case EGL_OPENGL_API:
75      api = ST_API_OPENGL;
76      break;
77   default:
78      _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI);
79      break;
80   }
81
82   stapi = egl_g3d_get_st_api(drv, api);
83   if (stapi && !(stapi->profile_mask & (1 << *profile)))
84      stapi = NULL;
85
86   return stapi;
87}
88
89struct egl_g3d_choose_config_data {
90   _EGLConfig criteria;
91   enum pipe_format format;
92};
93
94static int
95egl_g3d_compare_config(const _EGLConfig *conf1, const _EGLConfig *conf2,
96                       void *priv_data)
97{
98   struct egl_g3d_choose_config_data *data =
99      (struct egl_g3d_choose_config_data *) priv_data;
100   const _EGLConfig *criteria = &data->criteria;;
101
102   /* EGL_NATIVE_VISUAL_TYPE ignored? */
103   return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE);
104}
105
106static EGLBoolean
107egl_g3d_match_config(const _EGLConfig *conf, void *priv_data)
108{
109   struct egl_g3d_choose_config_data *data =
110      (struct egl_g3d_choose_config_data *) priv_data;
111   struct egl_g3d_config *gconf = egl_g3d_config(conf);
112
113   if (data->format != PIPE_FORMAT_NONE &&
114       data->format != gconf->native->color_format)
115      return EGL_FALSE;
116
117   return _eglMatchConfig(conf, &data->criteria);
118}
119
120static EGLBoolean
121egl_g3d_choose_config(_EGLDriver *drv, _EGLDisplay *dpy, const EGLint *attribs,
122                      EGLConfig *configs, EGLint size, EGLint *num_configs)
123{
124   struct egl_g3d_choose_config_data data;
125
126   if (!_eglParseConfigAttribList(&data.criteria, dpy, attribs))
127      return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
128
129   data.format = PIPE_FORMAT_NONE;
130   if (data.criteria.MatchNativePixmap != EGL_NONE &&
131       data.criteria.MatchNativePixmap != EGL_DONT_CARE) {
132      struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
133
134      if (!gdpy->native->get_pixmap_format(gdpy->native,
135               (EGLNativePixmapType) data.criteria.MatchNativePixmap,
136               &data.format))
137         return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglChooseConfig");
138   }
139
140   return _eglFilterConfigArray(dpy->Configs, configs, size, num_configs,
141         egl_g3d_match_config, egl_g3d_compare_config, &data);
142}
143
144static _EGLContext *
145egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
146                       _EGLContext *share, const EGLint *attribs)
147{
148   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
149   struct egl_g3d_context *gshare = egl_g3d_context(share);
150   struct egl_g3d_config *gconf = egl_g3d_config(conf);
151   struct egl_g3d_context *gctx;
152   struct st_context_attribs stattribs;
153   enum st_context_error ctx_err = 0;
154
155   gctx = CALLOC_STRUCT(egl_g3d_context);
156   if (!gctx) {
157      _eglError(EGL_BAD_ALLOC, "eglCreateContext");
158      return NULL;
159   }
160
161   if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) {
162      FREE(gctx);
163      return NULL;
164   }
165
166   memset(&stattribs, 0, sizeof(stattribs));
167   if (gconf)
168      stattribs.visual = gconf->stvis;
169
170   gctx->stapi = egl_g3d_choose_st(drv, &gctx->base, &stattribs.profile);
171   if (!gctx->stapi) {
172      FREE(gctx);
173      return NULL;
174   }
175
176   gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi,
177         &stattribs, &ctx_err, (gshare) ? gshare->stctxi : NULL);
178   if (!gctx->stctxi) {
179      FREE(gctx);
180      return NULL;
181   }
182
183   gctx->stctxi->st_manager_private = (void *) &gctx->base;
184
185   return &gctx->base;
186}
187
188/**
189 * Destroy a context.
190 */
191static void
192destroy_context(_EGLDisplay *dpy, _EGLContext *ctx)
193{
194   struct egl_g3d_context *gctx = egl_g3d_context(ctx);
195
196   /* FIXME a context might live longer than its display */
197   if (!dpy->Initialized)
198      _eglLog(_EGL_FATAL, "destroy a context with an unitialized display");
199
200   gctx->stctxi->destroy(gctx->stctxi);
201
202   FREE(gctx);
203}
204
205static EGLBoolean
206egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
207{
208   if (_eglPutContext(ctx))
209      destroy_context(dpy, ctx);
210   return EGL_TRUE;
211}
212
213struct egl_g3d_create_surface_arg {
214   EGLint type;
215   union {
216      EGLNativeWindowType win;
217      EGLNativePixmapType pix;
218   } u;
219};
220
221static _EGLSurface *
222egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
223                       struct egl_g3d_create_surface_arg *arg,
224                       const EGLint *attribs)
225{
226   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
227   struct egl_g3d_config *gconf = egl_g3d_config(conf);
228   struct egl_g3d_surface *gsurf;
229   struct native_surface *nsurf;
230   const char *err;
231
232   switch (arg->type) {
233   case EGL_WINDOW_BIT:
234      err = "eglCreateWindowSurface";
235      break;
236   case EGL_PIXMAP_BIT:
237      err = "eglCreatePixmapSurface";
238      break;
239#ifdef EGL_MESA_screen_surface
240   case EGL_SCREEN_BIT_MESA:
241      err = "eglCreateScreenSurface";
242      break;
243#endif
244   default:
245      err = "eglCreateUnknownSurface";
246      break;
247   }
248
249   gsurf = CALLOC_STRUCT(egl_g3d_surface);
250   if (!gsurf) {
251      _eglError(EGL_BAD_ALLOC, err);
252      return NULL;
253   }
254
255   if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) {
256      FREE(gsurf);
257      return NULL;
258   }
259
260   /* create the native surface */
261   switch (arg->type) {
262   case EGL_WINDOW_BIT:
263      nsurf = gdpy->native->create_window_surface(gdpy->native,
264            arg->u.win, gconf->native);
265      break;
266   case EGL_PIXMAP_BIT:
267      nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
268            arg->u.pix, gconf->native);
269      break;
270#ifdef EGL_MESA_screen_surface
271   case EGL_SCREEN_BIT_MESA:
272      /* prefer back buffer (move to _eglInitSurface?) */
273      gsurf->base.RenderBuffer = EGL_BACK_BUFFER;
274      nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native,
275            gconf->native, gsurf->base.Width, gsurf->base.Height);
276      break;
277#endif
278   default:
279      nsurf = NULL;
280      break;
281   }
282
283   if (!nsurf) {
284      FREE(gsurf);
285      return NULL;
286   }
287   /* initialize the geometry */
288   if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL,
289            &gsurf->base.Width, &gsurf->base.Height)) {
290      nsurf->destroy(nsurf);
291      FREE(gsurf);
292      return NULL;
293   }
294
295   gsurf->stvis = gconf->stvis;
296   if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER &&
297       gconf->stvis.buffer_mask & ST_ATTACHMENT_FRONT_LEFT_MASK)
298      gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT;
299
300   /* surfaces can always be posted when the display supports it */
301   if (dpy->Extensions.NV_post_sub_buffer)
302      gsurf->base.PostSubBufferSupportedNV = EGL_TRUE;
303
304   gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
305   if (!gsurf->stfbi) {
306      nsurf->destroy(nsurf);
307      FREE(gsurf);
308      return NULL;
309   }
310
311   nsurf->user_data = &gsurf->base;
312   gsurf->native = nsurf;
313
314   return &gsurf->base;
315}
316
317static _EGLSurface *
318egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
319                              _EGLConfig *conf, EGLNativeWindowType win,
320                              const EGLint *attribs)
321{
322   struct egl_g3d_create_surface_arg arg;
323
324   memset(&arg, 0, sizeof(arg));
325   arg.type = EGL_WINDOW_BIT;
326   arg.u.win = win;
327
328   return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
329}
330
331static _EGLSurface *
332egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
333                              _EGLConfig *conf, EGLNativePixmapType pix,
334                              const EGLint *attribs)
335{
336   struct egl_g3d_create_surface_arg arg;
337
338   memset(&arg, 0, sizeof(arg));
339   arg.type = EGL_PIXMAP_BIT;
340   arg.u.pix = pix;
341
342   return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
343}
344
345static struct egl_g3d_surface *
346create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf,
347                       const EGLint *attribs, const char *func)
348{
349   struct egl_g3d_config *gconf = egl_g3d_config(conf);
350   struct egl_g3d_surface *gsurf;
351
352   gsurf = CALLOC_STRUCT(egl_g3d_surface);
353   if (!gsurf) {
354      _eglError(EGL_BAD_ALLOC, func);
355      return NULL;
356   }
357
358   if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) {
359      FREE(gsurf);
360      return NULL;
361   }
362
363   gsurf->stvis = gconf->stvis;
364
365   gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
366   if (!gsurf->stfbi) {
367      FREE(gsurf);
368      return NULL;
369   }
370
371   return gsurf;
372}
373
374static _EGLSurface *
375egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
376                               _EGLConfig *conf, const EGLint *attribs)
377{
378   struct egl_g3d_surface *gsurf;
379
380   gsurf = create_pbuffer_surface(dpy, conf, attribs,
381         "eglCreatePbufferSurface");
382   if (!gsurf)
383      return NULL;
384
385   gsurf->client_buffer_type = EGL_NONE;
386
387   return &gsurf->base;
388}
389
390static _EGLSurface *
391egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy,
392                                          EGLenum buftype,
393                                          EGLClientBuffer buffer,
394                                          _EGLConfig *conf,
395                                          const EGLint *attribs)
396{
397   struct egl_g3d_surface *gsurf;
398   struct pipe_resource *ptex = NULL;
399   EGLint pbuffer_attribs[32];
400   EGLint count, i;
401
402   switch (buftype) {
403   case EGL_OPENVG_IMAGE:
404      break;
405   default:
406      _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
407      return NULL;
408      break;
409   }
410
411   /* parse the attributes first */
412   count = 0;
413   for (i = 0; attribs && attribs[i] != EGL_NONE; i++) {
414      EGLint attr = attribs[i++];
415      EGLint val = attribs[i];
416      EGLint err = EGL_SUCCESS;
417
418      switch (attr) {
419      case EGL_TEXTURE_FORMAT:
420      case EGL_TEXTURE_TARGET:
421      case EGL_MIPMAP_TEXTURE:
422         pbuffer_attribs[count++] = attr;
423         pbuffer_attribs[count++] = val;
424         break;
425      default:
426         err = EGL_BAD_ATTRIBUTE;
427         break;
428      }
429      /* bail out */
430      if (err != EGL_SUCCESS) {
431         _eglError(err, "eglCreatePbufferFromClientBuffer");
432         return NULL;
433      }
434   }
435
436   pbuffer_attribs[count++] = EGL_NONE;
437
438   gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs,
439         "eglCreatePbufferFromClientBuffer");
440   if (!gsurf)
441      return NULL;
442
443   gsurf->client_buffer_type = buftype;
444   gsurf->client_buffer = buffer;
445
446   /* validate now so that it fails if the client buffer is invalid */
447   if (!gsurf->stfbi->validate(gsurf->stfbi,
448            &gsurf->stvis.render_buffer, 1, &ptex)) {
449      egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
450      FREE(gsurf);
451      return NULL;
452   }
453   pipe_resource_reference(&ptex, NULL);
454
455   return &gsurf->base;
456}
457
458/**
459 * Destroy a surface.
460 */
461static void
462destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
463{
464   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
465
466   /* FIXME a surface might live longer than its display */
467   if (!dpy->Initialized)
468      _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display");
469
470   pipe_resource_reference(&gsurf->render_texture, NULL);
471   egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
472   if (gsurf->native)
473      gsurf->native->destroy(gsurf->native);
474   FREE(gsurf);
475}
476
477static EGLBoolean
478egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
479{
480   if (_eglPutSurface(surf))
481      destroy_surface(dpy, surf);
482   return EGL_TRUE;
483}
484
485static EGLBoolean
486egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
487                     _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx)
488{
489   struct egl_g3d_context *gctx = egl_g3d_context(ctx);
490   struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
491   struct egl_g3d_surface *gread = egl_g3d_surface(read);
492   struct egl_g3d_context *old_gctx;
493   _EGLContext *old_ctx;
494   _EGLSurface *old_draw, *old_read;
495   EGLBoolean ok = EGL_TRUE;
496
497   /* make new bindings */
498   if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read))
499      return EGL_FALSE;
500
501   old_gctx = egl_g3d_context(old_ctx);
502   if (old_gctx) {
503      /* flush old context */
504      old_gctx->stctxi->flush(old_gctx->stctxi, ST_FLUSH_FRONT, NULL);
505   }
506
507   if (gctx) {
508      ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi,
509            (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
510      if (ok) {
511         if (gdraw) {
512            if (gdraw->base.Type == EGL_WINDOW_BIT) {
513               gctx->base.WindowRenderBuffer =
514                  (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
515                  EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
516            }
517         }
518      }
519   }
520   else if (old_gctx) {
521      ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
522      if (ok)
523         old_gctx->base.WindowRenderBuffer = EGL_NONE;
524   }
525
526   if (ok) {
527      if (_eglPutContext(old_ctx))
528         destroy_context(dpy, old_ctx);
529      if (_eglPutSurface(old_draw))
530         destroy_surface(dpy, old_draw);
531      if (_eglPutSurface(old_read))
532         destroy_surface(dpy, old_read);
533   }
534   else {
535      /* undo the previous _eglBindContext */
536      _eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read);
537      assert(&gctx->base == ctx &&
538             &gdraw->base == draw &&
539             &gread->base == read);
540
541      _eglPutSurface(draw);
542      _eglPutSurface(read);
543      _eglPutContext(ctx);
544
545      _eglPutSurface(old_draw);
546      _eglPutSurface(old_read);
547      _eglPutContext(old_ctx);
548   }
549
550   return ok;
551}
552
553static EGLBoolean
554swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
555             EGLint num_rects, const EGLint *rects, EGLBoolean preserve)
556{
557   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
558   _EGLContext *ctx = _eglGetCurrentContext();
559   struct egl_g3d_context *gctx = NULL;
560   struct native_present_control ctrl;
561
562   /* no-op for pixmap or pbuffer surface */
563   if (gsurf->base.Type == EGL_PIXMAP_BIT ||
564       gsurf->base.Type == EGL_PBUFFER_BIT)
565      return EGL_TRUE;
566
567   /* or when the surface is single-buffered */
568   if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
569      return EGL_TRUE;
570
571   if (ctx && ctx->DrawSurface == surf)
572      gctx = egl_g3d_context(ctx);
573
574   /* flush if the surface is current */
575   if (gctx) {
576      gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
577   }
578
579   memset(&ctrl, 0, sizeof(ctrl));
580   ctrl.natt = NATIVE_ATTACHMENT_BACK_LEFT;
581   ctrl.preserve = preserve;
582   ctrl.swap_interval = gsurf->base.SwapInterval;
583   ctrl.premultiplied_alpha = (gsurf->base.VGAlphaFormat == EGL_VG_ALPHA_FORMAT_PRE);
584   ctrl.num_rects = num_rects;
585   ctrl.rects = rects;
586
587   return gsurf->native->present(gsurf->native, &ctrl);
588}
589
590static EGLBoolean
591egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
592{
593   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
594
595   return swap_buffers(drv, dpy, surf, 0, NULL,
596                       (gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED));
597}
598
599#ifdef EGL_NOK_swap_region
600static EGLBoolean
601egl_g3d_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
602                            EGLint num_rects, const EGLint *rects)
603{
604   /* Note: y=0=top */
605   return swap_buffers(drv, dpy, surf, num_rects, rects, EGL_TRUE);
606}
607#endif /* EGL_NOK_swap_region */
608
609static EGLBoolean
610egl_g3d_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
611                        EGLint x, EGLint y, EGLint width, EGLint height)
612{
613   EGLint rect[4];
614
615   if (x < 0 || y < 0 || width < 0 || height < 0)
616      return _eglError(EGL_BAD_PARAMETER, "eglPostSubBufferNV");
617
618   /* clamp */
619   if (x + width > surf->Width)
620      width = surf->Width - x;
621   if (y + height > surf->Height)
622      height = surf->Height - y;
623
624   if (width <= 0 || height <= 0)
625      return EGL_TRUE;
626
627   rect[0] = x;
628   /* Note: y=0=bottom */
629   rect[1] = surf->Height - y - height;
630   rect[2] = width;
631   rect[3] = height;
632
633   return swap_buffers(drv, dpy, surf, 1, rect, EGL_TRUE);
634}
635
636static EGLBoolean
637egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
638                     EGLNativePixmapType target)
639{
640   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
641   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
642   _EGLContext *ctx = _eglGetCurrentContext();
643
644   if (!gsurf->render_texture)
645      return EGL_TRUE;
646
647   /* flush if the surface is current */
648   if (ctx && ctx->DrawSurface == &gsurf->base) {
649      struct egl_g3d_context *gctx = egl_g3d_context(ctx);
650      gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
651   }
652
653   return gdpy->native->copy_to_pixmap(gdpy->native,
654         target, gsurf->render_texture);
655}
656
657static EGLBoolean
658egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
659{
660   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
661   struct egl_g3d_context *gctx = egl_g3d_context(ctx);
662   struct pipe_screen *screen = gdpy->native->screen;
663   struct pipe_fence_handle *fence = NULL;
664
665   gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, &fence);
666   if (fence) {
667      screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
668      screen->fence_reference(screen, &fence, NULL);
669   }
670
671   return EGL_TRUE;
672}
673
674static EGLBoolean
675egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
676{
677   _EGLContext *ctx = _eglGetCurrentContext();
678
679   if (engine != EGL_CORE_NATIVE_ENGINE)
680      return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
681
682   if (ctx && ctx->DrawSurface) {
683      struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
684
685      if (gsurf->native)
686         gsurf->native->wait(gsurf->native);
687   }
688
689   return EGL_TRUE;
690}
691
692static EGLBoolean
693egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
694                       _EGLSurface *surf, EGLint buffer)
695{
696   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
697   _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
698   struct egl_g3d_context *gctx;
699   enum pipe_format internal_format;
700   enum st_texture_type target;
701
702   if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
703      return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
704   if (buffer != EGL_BACK_BUFFER)
705      return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
706   if (gsurf->base.BoundToTexture)
707      return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
708
709   switch (gsurf->base.TextureFormat) {
710   case EGL_TEXTURE_RGB:
711      internal_format = PIPE_FORMAT_R8G8B8_UNORM;
712      break;
713   case EGL_TEXTURE_RGBA:
714      internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
715      break;
716   default:
717      return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
718   }
719
720   switch (gsurf->base.TextureTarget) {
721   case EGL_TEXTURE_2D:
722      target = ST_TEXTURE_2D;
723      break;
724   default:
725      return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
726   }
727
728   if (!es1)
729      return EGL_TRUE;
730   if (!gsurf->render_texture)
731      return EGL_FALSE;
732
733   /* flush properly if the surface is bound */
734   if (gsurf->base.CurrentContext) {
735      gctx = egl_g3d_context(gsurf->base.CurrentContext);
736      gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
737   }
738
739   gctx = egl_g3d_context(es1);
740   if (gctx->stctxi->teximage) {
741      if (!gctx->stctxi->teximage(gctx->stctxi, target,
742               gsurf->base.MipmapLevel, internal_format,
743               gsurf->render_texture, gsurf->base.MipmapTexture))
744         return EGL_FALSE;
745      gsurf->base.BoundToTexture = EGL_TRUE;
746   }
747
748   return EGL_TRUE;
749}
750
751static EGLBoolean
752egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
753                          _EGLSurface *surf, EGLint buffer)
754{
755   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
756
757   if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
758       !gsurf->base.BoundToTexture)
759      return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
760   if (buffer != EGL_BACK_BUFFER)
761      return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
762
763   if (gsurf->render_texture) {
764      _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
765      struct egl_g3d_context *gctx = egl_g3d_context(ctx);
766
767      /* what if the context the surface binds to is no longer current? */
768      if (gctx) {
769         gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
770               gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
771      }
772   }
773
774   gsurf->base.BoundToTexture = EGL_FALSE;
775
776   return EGL_TRUE;
777}
778
779#ifdef EGL_MESA_screen_surface
780
781static _EGLSurface *
782egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
783                              _EGLConfig *conf, const EGLint *attribs)
784{
785   struct egl_g3d_create_surface_arg arg;
786
787   memset(&arg, 0, sizeof(arg));
788   arg.type = EGL_SCREEN_BIT_MESA;
789
790   return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
791}
792
793static EGLBoolean
794egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
795                            _EGLScreen *scr, _EGLSurface *surf,
796                            _EGLMode *mode)
797{
798   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
799   struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
800   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
801   struct native_surface *nsurf;
802   const struct native_mode *nmode;
803   EGLBoolean changed;
804
805   if (gsurf) {
806      EGLint idx;
807
808      if (!mode)
809         return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
810      if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
811         return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
812      if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
813         return _eglError(EGL_BAD_MATCH,
814               "eglShowSurfaceMESA(surface smaller than mode size)");
815
816      /* find the index of the mode */
817      for (idx = 0; idx < gscr->base.NumModes; idx++)
818         if (mode == &gscr->base.Modes[idx])
819            break;
820      if (idx >= gscr->base.NumModes) {
821         return _eglError(EGL_BAD_MODE_MESA,
822               "eglShowSurfaceMESA(unknown mode)");
823      }
824
825      nsurf = gsurf->native;
826      nmode = gscr->native_modes[idx];
827   }
828   else {
829      if (mode)
830         return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
831
832      /* disable the screen */
833      nsurf = NULL;
834      nmode = NULL;
835   }
836
837   /* TODO surface panning by CRTC choosing */
838   changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
839         gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
840   if (changed) {
841      gscr->base.CurrentSurface = &gsurf->base;
842      gscr->base.CurrentMode = mode;
843   }
844
845   return changed;
846}
847
848#endif /* EGL_MESA_screen_surface */
849
850#ifdef EGL_WL_bind_wayland_display
851
852static EGLBoolean
853egl_g3d_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
854                                struct wl_display *wl_dpy)
855{
856   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
857
858   if (!gdpy->native->wayland_bufmgr)
859      return EGL_FALSE;
860
861   return gdpy->native->wayland_bufmgr->bind_display(gdpy->native, wl_dpy);
862}
863
864static EGLBoolean
865egl_g3d_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
866                                  struct wl_display *wl_dpy)
867{
868   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
869
870   if (!gdpy->native->wayland_bufmgr)
871      return EGL_FALSE;
872
873   return gdpy->native->wayland_bufmgr->unbind_display(gdpy->native, wl_dpy);
874}
875
876static EGLBoolean
877egl_g3d_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *dpy,
878                                struct wl_buffer *buffer,
879                                EGLint attribute, EGLint *value)
880{
881   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
882
883   if (!gdpy->native->wayland_bufmgr)
884      return EGL_FALSE;
885
886   return gdpy->native->wayland_bufmgr->query_buffer(gdpy->native,
887                                                     buffer, attribute, value);
888}
889#endif /* EGL_WL_bind_wayland_display */
890
891void
892egl_g3d_init_driver_api(_EGLDriver *drv)
893{
894   _eglInitDriverFallbacks(drv);
895
896   drv->API.ChooseConfig = egl_g3d_choose_config;
897
898   drv->API.CreateContext = egl_g3d_create_context;
899   drv->API.DestroyContext = egl_g3d_destroy_context;
900   drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
901   drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
902   drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
903   drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
904   drv->API.DestroySurface = egl_g3d_destroy_surface;
905   drv->API.MakeCurrent = egl_g3d_make_current;
906   drv->API.SwapBuffers = egl_g3d_swap_buffers;
907   drv->API.CopyBuffers = egl_g3d_copy_buffers;
908   drv->API.WaitClient = egl_g3d_wait_client;
909   drv->API.WaitNative = egl_g3d_wait_native;
910
911   drv->API.BindTexImage = egl_g3d_bind_tex_image;
912   drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
913
914   drv->API.CreateImageKHR = egl_g3d_create_image;
915   drv->API.DestroyImageKHR = egl_g3d_destroy_image;
916#ifdef EGL_MESA_drm_image
917   drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image;
918   drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image;
919#endif
920#ifdef EGL_WL_bind_wayland_display
921   drv->API.BindWaylandDisplayWL = egl_g3d_bind_wayland_display_wl;
922   drv->API.UnbindWaylandDisplayWL = egl_g3d_unbind_wayland_display_wl;
923   drv->API.QueryWaylandBufferWL = egl_g3d_query_wayland_buffer_wl;
924#endif
925
926   drv->API.CreateSyncKHR = egl_g3d_create_sync;
927   drv->API.DestroySyncKHR = egl_g3d_destroy_sync;
928   drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync;
929   drv->API.SignalSyncKHR = egl_g3d_signal_sync;
930
931#ifdef EGL_MESA_screen_surface
932   drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
933   drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
934#endif
935
936#ifdef EGL_NOK_swap_region
937   drv->API.SwapBuffersRegionNOK = egl_g3d_swap_buffers_region;
938#endif
939
940   drv->API.PostSubBufferNV = egl_g3d_post_sub_buffer;
941}
942