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