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