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