egl_g3d_api.c revision 75772842133d101223ca31400e100b83476f327b
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->ClientVersion) {
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 version %d",
67               ctx->ClientVersion);
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
154   gctx = CALLOC_STRUCT(egl_g3d_context);
155   if (!gctx) {
156      _eglError(EGL_BAD_ALLOC, "eglCreateContext");
157      return NULL;
158   }
159
160   if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) {
161      FREE(gctx);
162      return NULL;
163   }
164
165   memset(&stattribs, 0, sizeof(stattribs));
166   if (gconf)
167      stattribs.visual = gconf->stvis;
168
169   gctx->stapi = egl_g3d_choose_st(drv, &gctx->base, &stattribs.profile);
170   if (!gctx->stapi) {
171      FREE(gctx);
172      return NULL;
173   }
174
175   gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi,
176         &stattribs, (gshare) ? gshare->stctxi : NULL);
177   if (!gctx->stctxi) {
178      FREE(gctx);
179      return NULL;
180   }
181
182   gctx->stctxi->st_manager_private = (void *) &gctx->base;
183
184   return &gctx->base;
185}
186
187/**
188 * Destroy a context.
189 */
190static void
191destroy_context(_EGLDisplay *dpy, _EGLContext *ctx)
192{
193   struct egl_g3d_context *gctx = egl_g3d_context(ctx);
194
195   /* FIXME a context might live longer than its display */
196   if (!dpy->Initialized)
197      _eglLog(_EGL_FATAL, "destroy a context with an unitialized display");
198
199   gctx->stctxi->destroy(gctx->stctxi);
200
201   FREE(gctx);
202}
203
204static EGLBoolean
205egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
206{
207   if (_eglPutContext(ctx))
208      destroy_context(dpy, ctx);
209   return EGL_TRUE;
210}
211
212struct egl_g3d_create_surface_arg {
213   EGLint type;
214   union {
215      EGLNativeWindowType win;
216      EGLNativePixmapType pix;
217   } u;
218};
219
220static _EGLSurface *
221egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
222                       struct egl_g3d_create_surface_arg *arg,
223                       const EGLint *attribs)
224{
225   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
226   struct egl_g3d_config *gconf = egl_g3d_config(conf);
227   struct egl_g3d_surface *gsurf;
228   struct native_surface *nsurf;
229   const char *err;
230
231   switch (arg->type) {
232   case EGL_WINDOW_BIT:
233      err = "eglCreateWindowSurface";
234      break;
235   case EGL_PIXMAP_BIT:
236      err = "eglCreatePixmapSurface";
237      break;
238#ifdef EGL_MESA_screen_surface
239   case EGL_SCREEN_BIT_MESA:
240      err = "eglCreateScreenSurface";
241      break;
242#endif
243   default:
244      err = "eglCreateUnknownSurface";
245      break;
246   }
247
248   gsurf = CALLOC_STRUCT(egl_g3d_surface);
249   if (!gsurf) {
250      _eglError(EGL_BAD_ALLOC, err);
251      return NULL;
252   }
253
254   if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) {
255      FREE(gsurf);
256      return NULL;
257   }
258
259   /* create the native surface */
260   switch (arg->type) {
261   case EGL_WINDOW_BIT:
262      nsurf = gdpy->native->create_window_surface(gdpy->native,
263            arg->u.win, gconf->native);
264      break;
265   case EGL_PIXMAP_BIT:
266      nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
267            arg->u.pix, gconf->native);
268      break;
269#ifdef EGL_MESA_screen_surface
270   case EGL_SCREEN_BIT_MESA:
271      /* prefer back buffer (move to _eglInitSurface?) */
272      gsurf->base.RenderBuffer = EGL_BACK_BUFFER;
273      nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native,
274            gconf->native, gsurf->base.Width, gsurf->base.Height);
275      break;
276#endif
277   default:
278      nsurf = NULL;
279      break;
280   }
281
282   if (!nsurf) {
283      FREE(gsurf);
284      return NULL;
285   }
286   /* initialize the geometry */
287   if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL,
288            &gsurf->base.Width, &gsurf->base.Height)) {
289      nsurf->destroy(nsurf);
290      FREE(gsurf);
291      return NULL;
292   }
293
294   gsurf->stvis = gconf->stvis;
295   if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER &&
296       gconf->stvis.buffer_mask & ST_ATTACHMENT_FRONT_LEFT_MASK)
297      gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT;
298
299   if (dpy->Extensions.NV_post_sub_buffer) {
300      if (gsurf->base.Type == EGL_WINDOW_BIT &&
301          gsurf->base.RenderBuffer == EGL_BACK_BUFFER)
302         gsurf->base.PostSubBufferSupportedNV = EGL_TRUE;
303      else
304         gsurf->base.PostSubBufferSupportedNV = EGL_FALSE;
305   }
306
307   gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
308   if (!gsurf->stfbi) {
309      nsurf->destroy(nsurf);
310      FREE(gsurf);
311      return NULL;
312   }
313
314   nsurf->user_data = &gsurf->base;
315   gsurf->native = nsurf;
316
317   return &gsurf->base;
318}
319
320static _EGLSurface *
321egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
322                              _EGLConfig *conf, EGLNativeWindowType win,
323                              const EGLint *attribs)
324{
325   struct egl_g3d_create_surface_arg arg;
326
327   memset(&arg, 0, sizeof(arg));
328   arg.type = EGL_WINDOW_BIT;
329   arg.u.win = win;
330
331   return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
332}
333
334static _EGLSurface *
335egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
336                              _EGLConfig *conf, EGLNativePixmapType pix,
337                              const EGLint *attribs)
338{
339   struct egl_g3d_create_surface_arg arg;
340
341   memset(&arg, 0, sizeof(arg));
342   arg.type = EGL_PIXMAP_BIT;
343   arg.u.pix = pix;
344
345   return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
346}
347
348static struct egl_g3d_surface *
349create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *conf,
350                       const EGLint *attribs, const char *func)
351{
352   struct egl_g3d_config *gconf = egl_g3d_config(conf);
353   struct egl_g3d_surface *gsurf;
354
355   gsurf = CALLOC_STRUCT(egl_g3d_surface);
356   if (!gsurf) {
357      _eglError(EGL_BAD_ALLOC, func);
358      return NULL;
359   }
360
361   if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) {
362      FREE(gsurf);
363      return NULL;
364   }
365
366   gsurf->stvis = gconf->stvis;
367
368   gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
369   if (!gsurf->stfbi) {
370      FREE(gsurf);
371      return NULL;
372   }
373
374   return gsurf;
375}
376
377static _EGLSurface *
378egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
379                               _EGLConfig *conf, const EGLint *attribs)
380{
381   struct egl_g3d_surface *gsurf;
382
383   gsurf = create_pbuffer_surface(dpy, conf, attribs,
384         "eglCreatePbufferSurface");
385   if (!gsurf)
386      return NULL;
387
388   gsurf->client_buffer_type = EGL_NONE;
389
390   return &gsurf->base;
391}
392
393static _EGLSurface *
394egl_g3d_create_pbuffer_from_client_buffer(_EGLDriver *drv, _EGLDisplay *dpy,
395                                          EGLenum buftype,
396                                          EGLClientBuffer buffer,
397                                          _EGLConfig *conf,
398                                          const EGLint *attribs)
399{
400   struct egl_g3d_surface *gsurf;
401   struct pipe_resource *ptex = NULL;
402   EGLint pbuffer_attribs[32];
403   EGLint count, i;
404
405   switch (buftype) {
406   case EGL_OPENVG_IMAGE:
407      break;
408   default:
409      _eglError(EGL_BAD_PARAMETER, "eglCreatePbufferFromClientBuffer");
410      return NULL;
411      break;
412   }
413
414   /* parse the attributes first */
415   count = 0;
416   for (i = 0; attribs && attribs[i] != EGL_NONE; i++) {
417      EGLint attr = attribs[i++];
418      EGLint val = attribs[i];
419      EGLint err = EGL_SUCCESS;
420
421      switch (attr) {
422      case EGL_TEXTURE_FORMAT:
423      case EGL_TEXTURE_TARGET:
424      case EGL_MIPMAP_TEXTURE:
425         pbuffer_attribs[count++] = attr;
426         pbuffer_attribs[count++] = val;
427         break;
428      default:
429         err = EGL_BAD_ATTRIBUTE;
430         break;
431      }
432      /* bail out */
433      if (err != EGL_SUCCESS) {
434         _eglError(err, "eglCreatePbufferFromClientBuffer");
435         return NULL;
436      }
437   }
438
439   pbuffer_attribs[count++] = EGL_NONE;
440
441   gsurf = create_pbuffer_surface(dpy, conf, pbuffer_attribs,
442         "eglCreatePbufferFromClientBuffer");
443   if (!gsurf)
444      return NULL;
445
446   gsurf->client_buffer_type = buftype;
447   gsurf->client_buffer = buffer;
448
449   /* validate now so that it fails if the client buffer is invalid */
450   if (!gsurf->stfbi->validate(gsurf->stfbi,
451            &gsurf->stvis.render_buffer, 1, &ptex)) {
452      egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
453      FREE(gsurf);
454      return NULL;
455   }
456   pipe_resource_reference(&ptex, NULL);
457
458   return &gsurf->base;
459}
460
461/**
462 * Destroy a surface.
463 */
464static void
465destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
466{
467   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
468
469   /* FIXME a surface might live longer than its display */
470   if (!dpy->Initialized)
471      _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display");
472
473   pipe_resource_reference(&gsurf->render_texture, NULL);
474   egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
475   if (gsurf->native)
476      gsurf->native->destroy(gsurf->native);
477   FREE(gsurf);
478}
479
480static EGLBoolean
481egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
482{
483   if (_eglPutSurface(surf))
484      destroy_surface(dpy, surf);
485   return EGL_TRUE;
486}
487
488static EGLBoolean
489egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
490                     _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx)
491{
492   struct egl_g3d_context *gctx = egl_g3d_context(ctx);
493   struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
494   struct egl_g3d_surface *gread = egl_g3d_surface(read);
495   struct egl_g3d_context *old_gctx;
496   _EGLContext *old_ctx;
497   _EGLSurface *old_draw, *old_read;
498   EGLBoolean ok = EGL_TRUE;
499
500   /* make new bindings */
501   if (!_eglBindContext(ctx, draw, read, &old_ctx, &old_draw, &old_read))
502      return EGL_FALSE;
503
504   old_gctx = egl_g3d_context(old_ctx);
505   if (old_gctx) {
506      /* flush old context */
507      old_gctx->stctxi->flush(old_gctx->stctxi, ST_FLUSH_FRONT, NULL);
508   }
509
510   if (gctx) {
511      ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi,
512            (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
513      if (ok) {
514         if (gdraw) {
515            if (gdraw->base.Type == EGL_WINDOW_BIT) {
516               gctx->base.WindowRenderBuffer =
517                  (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
518                  EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
519            }
520         }
521      }
522   }
523   else if (old_gctx) {
524      ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
525      if (ok)
526         old_gctx->base.WindowRenderBuffer = EGL_NONE;
527   }
528
529   if (ok) {
530      if (_eglPutContext(old_ctx))
531         destroy_context(dpy, old_ctx);
532      if (_eglPutSurface(old_draw))
533         destroy_surface(dpy, old_draw);
534      if (_eglPutSurface(old_read))
535         destroy_surface(dpy, old_read);
536   }
537   else {
538      /* undo the previous _eglBindContext */
539      _eglBindContext(old_ctx, old_draw, old_read, &ctx, &draw, &read);
540      assert(&gctx->base == ctx &&
541             &gdraw->base == draw &&
542             &gread->base == read);
543
544      _eglPutSurface(draw);
545      _eglPutSurface(read);
546      _eglPutContext(ctx);
547
548      _eglPutSurface(old_draw);
549      _eglPutSurface(old_read);
550      _eglPutContext(old_ctx);
551   }
552
553   return ok;
554}
555
556static EGLBoolean
557swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
558             EGLint num_rects, const EGLint *rects, EGLBoolean preserve)
559{
560   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
561   _EGLContext *ctx = _eglGetCurrentContext();
562   struct egl_g3d_context *gctx = NULL;
563   struct native_present_control ctrl;
564
565   /* no-op for pixmap or pbuffer surface */
566   if (gsurf->base.Type == EGL_PIXMAP_BIT ||
567       gsurf->base.Type == EGL_PBUFFER_BIT)
568      return EGL_TRUE;
569
570   /* or when the surface is single-buffered */
571   if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
572      return EGL_TRUE;
573
574   if (ctx && ctx->DrawSurface == surf)
575      gctx = egl_g3d_context(ctx);
576
577   /* flush if the surface is current */
578   if (gctx) {
579      gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
580   }
581
582   memset(&ctrl, 0, sizeof(ctrl));
583   ctrl.natt = NATIVE_ATTACHMENT_BACK_LEFT;
584   ctrl.preserve = preserve;
585   ctrl.swap_interval = gsurf->base.SwapInterval;
586   ctrl.premultiplied_alpha = (gsurf->base.VGAlphaFormat == EGL_VG_ALPHA_FORMAT_PRE);
587   ctrl.num_rects = num_rects;
588   ctrl.rects = rects;
589
590   return gsurf->native->present(gsurf->native, &ctrl);
591}
592
593static EGLBoolean
594egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
595{
596   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
597
598   return swap_buffers(drv, dpy, surf, 0, NULL,
599                       (gsurf->base.SwapBehavior == EGL_BUFFER_PRESERVED));
600}
601
602#ifdef EGL_NOK_swap_region
603static EGLBoolean
604egl_g3d_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
605                            EGLint num_rects, const EGLint *rects)
606{
607   /* Note: y=0=top */
608   return swap_buffers(drv, dpy, surf, num_rects, rects, EGL_TRUE);
609}
610#endif /* EGL_NOK_swap_region */
611
612static EGLBoolean
613egl_g3d_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
614                        EGLint x, EGLint y, EGLint width, EGLint height)
615{
616   /* Note: y=0=bottom */
617   const EGLint rect[4] = { x, surf->Height - y - height, width, height };
618
619   return swap_buffers(drv, dpy, surf, 1, rect, EGL_TRUE);
620}
621
622static EGLBoolean
623egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
624                     EGLNativePixmapType target)
625{
626   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
627   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
628   _EGLContext *ctx = _eglGetCurrentContext();
629
630   if (!gsurf->render_texture)
631      return EGL_TRUE;
632
633   /* flush if the surface is current */
634   if (ctx && ctx->DrawSurface == &gsurf->base) {
635      struct egl_g3d_context *gctx = egl_g3d_context(ctx);
636      gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
637   }
638
639   return gdpy->native->copy_to_pixmap(gdpy->native,
640         target, gsurf->render_texture);
641}
642
643static EGLBoolean
644egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
645{
646   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
647   struct egl_g3d_context *gctx = egl_g3d_context(ctx);
648   struct pipe_screen *screen = gdpy->native->screen;
649   struct pipe_fence_handle *fence = NULL;
650
651   gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, &fence);
652   if (fence) {
653      screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
654      screen->fence_reference(screen, &fence, NULL);
655   }
656
657   return EGL_TRUE;
658}
659
660static EGLBoolean
661egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
662{
663   _EGLContext *ctx = _eglGetCurrentContext();
664
665   if (engine != EGL_CORE_NATIVE_ENGINE)
666      return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
667
668   if (ctx && ctx->DrawSurface) {
669      struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
670
671      if (gsurf->native)
672         gsurf->native->wait(gsurf->native);
673   }
674
675   return EGL_TRUE;
676}
677
678static EGLBoolean
679egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
680                       _EGLSurface *surf, EGLint buffer)
681{
682   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
683   _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
684   struct egl_g3d_context *gctx;
685   enum pipe_format internal_format;
686   enum st_texture_type target;
687
688   if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
689      return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
690   if (buffer != EGL_BACK_BUFFER)
691      return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
692   if (gsurf->base.BoundToTexture)
693      return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
694
695   switch (gsurf->base.TextureFormat) {
696   case EGL_TEXTURE_RGB:
697      internal_format = PIPE_FORMAT_R8G8B8_UNORM;
698      break;
699   case EGL_TEXTURE_RGBA:
700      internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
701      break;
702   default:
703      return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
704   }
705
706   switch (gsurf->base.TextureTarget) {
707   case EGL_TEXTURE_2D:
708      target = ST_TEXTURE_2D;
709      break;
710   default:
711      return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
712   }
713
714   if (!es1)
715      return EGL_TRUE;
716   if (!gsurf->render_texture)
717      return EGL_FALSE;
718
719   /* flush properly if the surface is bound */
720   if (gsurf->base.CurrentContext) {
721      gctx = egl_g3d_context(gsurf->base.CurrentContext);
722      gctx->stctxi->flush(gctx->stctxi, ST_FLUSH_FRONT, NULL);
723   }
724
725   gctx = egl_g3d_context(es1);
726   if (gctx->stctxi->teximage) {
727      if (!gctx->stctxi->teximage(gctx->stctxi, target,
728               gsurf->base.MipmapLevel, internal_format,
729               gsurf->render_texture, gsurf->base.MipmapTexture))
730         return EGL_FALSE;
731      gsurf->base.BoundToTexture = EGL_TRUE;
732   }
733
734   return EGL_TRUE;
735}
736
737static EGLBoolean
738egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
739                          _EGLSurface *surf, EGLint buffer)
740{
741   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
742
743   if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
744       !gsurf->base.BoundToTexture)
745      return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
746   if (buffer != EGL_BACK_BUFFER)
747      return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
748
749   if (gsurf->render_texture) {
750      _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
751      struct egl_g3d_context *gctx = egl_g3d_context(ctx);
752
753      /* what if the context the surface binds to is no longer current? */
754      if (gctx) {
755         gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
756               gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
757      }
758   }
759
760   gsurf->base.BoundToTexture = EGL_FALSE;
761
762   return EGL_TRUE;
763}
764
765#ifdef EGL_MESA_screen_surface
766
767static _EGLSurface *
768egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
769                              _EGLConfig *conf, const EGLint *attribs)
770{
771   struct egl_g3d_create_surface_arg arg;
772
773   memset(&arg, 0, sizeof(arg));
774   arg.type = EGL_SCREEN_BIT_MESA;
775
776   return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
777}
778
779static EGLBoolean
780egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
781                            _EGLScreen *scr, _EGLSurface *surf,
782                            _EGLMode *mode)
783{
784   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
785   struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
786   struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
787   struct native_surface *nsurf;
788   const struct native_mode *nmode;
789   EGLBoolean changed;
790
791   if (gsurf) {
792      EGLint idx;
793
794      if (!mode)
795         return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
796      if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
797         return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
798      if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
799         return _eglError(EGL_BAD_MATCH,
800               "eglShowSurfaceMESA(surface smaller than mode size)");
801
802      /* find the index of the mode */
803      for (idx = 0; idx < gscr->base.NumModes; idx++)
804         if (mode == &gscr->base.Modes[idx])
805            break;
806      if (idx >= gscr->base.NumModes) {
807         return _eglError(EGL_BAD_MODE_MESA,
808               "eglShowSurfaceMESA(unknown mode)");
809      }
810
811      nsurf = gsurf->native;
812      nmode = gscr->native_modes[idx];
813   }
814   else {
815      if (mode)
816         return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
817
818      /* disable the screen */
819      nsurf = NULL;
820      nmode = NULL;
821   }
822
823   /* TODO surface panning by CRTC choosing */
824   changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
825         gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
826   if (changed) {
827      gscr->base.CurrentSurface = &gsurf->base;
828      gscr->base.CurrentMode = mode;
829   }
830
831   return changed;
832}
833
834#endif /* EGL_MESA_screen_surface */
835
836#ifdef EGL_WL_bind_wayland_display
837
838static EGLBoolean
839egl_g3d_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
840                                struct wl_display *wl_dpy)
841{
842   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
843
844   if (!gdpy->native->wayland_bufmgr)
845      return EGL_FALSE;
846
847   return gdpy->native->wayland_bufmgr->bind_display(gdpy->native, wl_dpy);
848}
849
850static EGLBoolean
851egl_g3d_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *dpy,
852                                  struct wl_display *wl_dpy)
853{
854   struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
855
856   if (!gdpy->native->wayland_bufmgr)
857      return EGL_FALSE;
858
859   return gdpy->native->wayland_bufmgr->unbind_display(gdpy->native, wl_dpy);
860}
861
862#endif /* EGL_WL_bind_wayland_display */
863
864void
865egl_g3d_init_driver_api(_EGLDriver *drv)
866{
867   _eglInitDriverFallbacks(drv);
868
869   drv->API.ChooseConfig = egl_g3d_choose_config;
870
871   drv->API.CreateContext = egl_g3d_create_context;
872   drv->API.DestroyContext = egl_g3d_destroy_context;
873   drv->API.CreateWindowSurface = egl_g3d_create_window_surface;
874   drv->API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
875   drv->API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
876   drv->API.CreatePbufferFromClientBuffer = egl_g3d_create_pbuffer_from_client_buffer;
877   drv->API.DestroySurface = egl_g3d_destroy_surface;
878   drv->API.MakeCurrent = egl_g3d_make_current;
879   drv->API.SwapBuffers = egl_g3d_swap_buffers;
880   drv->API.CopyBuffers = egl_g3d_copy_buffers;
881   drv->API.WaitClient = egl_g3d_wait_client;
882   drv->API.WaitNative = egl_g3d_wait_native;
883
884   drv->API.BindTexImage = egl_g3d_bind_tex_image;
885   drv->API.ReleaseTexImage = egl_g3d_release_tex_image;
886
887   drv->API.CreateImageKHR = egl_g3d_create_image;
888   drv->API.DestroyImageKHR = egl_g3d_destroy_image;
889#ifdef EGL_MESA_drm_image
890   drv->API.CreateDRMImageMESA = egl_g3d_create_drm_image;
891   drv->API.ExportDRMImageMESA = egl_g3d_export_drm_image;
892#endif
893#ifdef EGL_WL_bind_wayland_display
894   drv->API.BindWaylandDisplayWL = egl_g3d_bind_wayland_display_wl;
895   drv->API.UnbindWaylandDisplayWL = egl_g3d_unbind_wayland_display_wl;
896
897#endif
898
899   drv->API.CreateSyncKHR = egl_g3d_create_sync;
900   drv->API.DestroySyncKHR = egl_g3d_destroy_sync;
901   drv->API.ClientWaitSyncKHR = egl_g3d_client_wait_sync;
902   drv->API.SignalSyncKHR = egl_g3d_signal_sync;
903
904#ifdef EGL_MESA_screen_surface
905   drv->API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
906   drv->API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
907#endif
908
909#ifdef EGL_NOK_swap_region
910   drv->API.SwapBuffersRegionNOK = egl_g3d_swap_buffers_region;
911#endif
912
913   drv->API.PostSubBufferNV = egl_g3d_post_sub_buffer;
914}
915