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