8e39a8588e2da87df6a77e3f3bc0f29cd35f49aa
[profile/ivi/mesa.git] / src / gallium / state_trackers / egl / common / egl_g3d.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.8
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 <assert.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include "pipe/p_screen.h"
30 #include "util/u_memory.h"
31 #include "util/u_rect.h"
32 #include "util/u_inlines.h"
33 #include "egldriver.h"
34 #include "eglcurrent.h"
35 #include "eglconfigutil.h"
36 #include "egllog.h"
37
38 #include "native.h"
39 #include "egl_g3d.h"
40 #include "egl_g3d_st.h"
41 #include "egl_g3d_image.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 {
49    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
50    struct st_api *stapi;
51    EGLint idx = -1;
52
53    switch (ctx->ClientAPI) {
54    case EGL_OPENGL_ES_API:
55       switch (ctx->ClientVersion) {
56       case 1:
57          idx = ST_API_OPENGL_ES1;
58          break;
59       case 2:
60          idx = ST_API_OPENGL_ES2;
61          break;
62       default:
63          _eglLog(_EGL_WARNING, "unknown client version %d",
64                ctx->ClientVersion);
65          break;
66       }
67       break;
68    case EGL_OPENVG_API:
69       idx = ST_API_OPENVG;
70       break;
71    case EGL_OPENGL_API:
72       idx = ST_API_OPENGL;
73       break;
74    default:
75       _eglLog(_EGL_WARNING, "unknown client API 0x%04x", ctx->ClientAPI);
76       break;
77    }
78
79    stapi = (idx >= 0) ? gdrv->stapis[idx] : NULL;
80    return stapi;
81 }
82
83 /**
84  * Initialize the state trackers.
85  */
86 static void
87 egl_g3d_init_st(_EGLDriver *drv)
88 {
89    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
90    EGLint i;
91
92    /* already initialized */
93    if (gdrv->api_mask)
94       return;
95
96    for (i = 0; i < ST_API_COUNT; i++) {
97       gdrv->stapis[i] = egl_g3d_create_st_api(i);
98       if (gdrv->stapis[i])
99          gdrv->api_mask |= egl_g3d_st_api_bit(i);
100    }
101
102    if (gdrv->api_mask)
103       _eglLog(_EGL_DEBUG, "Driver API mask: 0x%x", gdrv->api_mask);
104    else
105       _eglLog(_EGL_WARNING, "No supported client API");
106 }
107
108 /**
109  * Get the probe object of the display.
110  *
111  * Note that this function may be called before the display is initialized.
112  */
113 static struct native_probe *
114 egl_g3d_get_probe(_EGLDriver *drv, _EGLDisplay *dpy)
115 {
116    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
117    struct native_probe *nprobe;
118
119    nprobe = (struct native_probe *) _eglGetProbeCache(gdrv->probe_key);
120    if (!nprobe || nprobe->display != dpy->NativeDisplay) {
121       if (nprobe)
122          nprobe->destroy(nprobe);
123       nprobe = native_create_probe(dpy->NativeDisplay);
124       _eglSetProbeCache(gdrv->probe_key, (void *) nprobe);
125    }
126
127    return nprobe;
128 }
129
130 /**
131  * Destroy the probe object of the display.  The display may be NULL.
132  *
133  * Note that this function may be called before the display is initialized.
134  */
135 static void
136 egl_g3d_destroy_probe(_EGLDriver *drv, _EGLDisplay *dpy)
137 {
138    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
139    struct native_probe *nprobe;
140
141    nprobe = (struct native_probe *) _eglGetProbeCache(gdrv->probe_key);
142    if (nprobe && (!dpy || nprobe->display == dpy->NativeDisplay)) {
143       nprobe->destroy(nprobe);
144       _eglSetProbeCache(gdrv->probe_key, NULL);
145    }
146 }
147
148 #ifdef EGL_MESA_screen_surface
149
150 static void
151 egl_g3d_add_screens(_EGLDriver *drv, _EGLDisplay *dpy)
152 {
153    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
154    const struct native_connector **native_connectors;
155    EGLint num_connectors, i;
156
157    native_connectors =
158       gdpy->native->modeset->get_connectors(gdpy->native, &num_connectors, NULL);
159    if (!num_connectors) {
160       if (native_connectors)
161          free(native_connectors);
162       return;
163    }
164
165    for (i = 0; i < num_connectors; i++) {
166       const struct native_connector *nconn = native_connectors[i];
167       struct egl_g3d_screen *gscr;
168       const struct native_mode **native_modes;
169       EGLint num_modes, j;
170
171       /* TODO support for hotplug */
172       native_modes =
173          gdpy->native->modeset->get_modes(gdpy->native, nconn, &num_modes);
174       if (!num_modes) {
175          if (native_modes)
176             free(native_modes);
177          continue;
178       }
179
180       gscr = CALLOC_STRUCT(egl_g3d_screen);
181       if (!gscr) {
182          free(native_modes);
183          continue;
184       }
185
186       _eglInitScreen(&gscr->base);
187
188       for (j = 0; j < num_modes; j++) {
189          const struct native_mode *nmode = native_modes[j];
190          _EGLMode *mode;
191
192          mode = _eglAddNewMode(&gscr->base, nmode->width, nmode->height,
193                nmode->refresh_rate, nmode->desc);
194          if (!mode)
195             break;
196          /* gscr->native_modes and gscr->base.Modes should be consistent */
197          assert(mode == &gscr->base.Modes[j]);
198       }
199
200       gscr->native = nconn;
201       gscr->native_modes = native_modes;
202
203       _eglAddScreen(dpy, &gscr->base);
204    }
205
206    free(native_connectors);
207 }
208
209 #endif /* EGL_MESA_screen_surface */
210
211 /**
212  * Initialize an EGL config from the native config.
213  */
214 static EGLBoolean
215 egl_g3d_init_config(_EGLDriver *drv, _EGLDisplay *dpy,
216                     _EGLConfig *conf, const struct native_config *nconf)
217 {
218    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
219    struct egl_g3d_config *gconf = egl_g3d_config(conf);
220    const __GLcontextModes *mode = &nconf->mode;
221    EGLint buffer_mask, api_mask;
222    EGLBoolean valid;
223    EGLint i;
224
225    buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
226    if (mode->doubleBufferMode)
227       buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
228    if (mode->stereoMode) {
229       buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
230       if (mode->doubleBufferMode)
231          buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
232    }
233
234    gconf->stvis.buffer_mask = buffer_mask;
235    gconf->stvis.color_format = nconf->color_format;
236    gconf->stvis.depth_stencil_format = nconf->depth_format;
237    gconf->stvis.accum_format = PIPE_FORMAT_NONE;
238    gconf->stvis.samples = 0;
239
240    gconf->stvis.render_buffer = (buffer_mask & ST_ATTACHMENT_BACK_LEFT_MASK) ?
241       ST_ATTACHMENT_BACK_LEFT : ST_ATTACHMENT_FRONT_LEFT;
242
243    api_mask = 0;
244    for (i = 0; i < ST_API_COUNT; i++) {
245       struct st_api *stapi = gdrv->stapis[i];
246       if (stapi) {
247          if (stapi->is_visual_supported(stapi, &gconf->stvis))
248             api_mask |= egl_g3d_st_api_bit(i);
249       }
250    }
251    /* this is required by EGL, not by OpenGL ES */
252    if ((mode->drawableType & GLX_WINDOW_BIT) && !mode->doubleBufferMode)
253       api_mask &= ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT);
254
255    if (!api_mask) {
256       _eglLog(_EGL_DEBUG, "no state tracker supports config 0x%x",
257             mode->visualID);
258    }
259
260    valid = _eglConfigFromContextModesRec(&gconf->base,
261          mode, api_mask, api_mask);
262    if (valid) {
263 #ifdef EGL_MESA_screen_surface
264       /* check if scanout surface bit is set */
265       if (nconf->scanout_bit) {
266          EGLint val = GET_CONFIG_ATTRIB(&gconf->base, EGL_SURFACE_TYPE);
267          val |= EGL_SCREEN_BIT_MESA;
268          SET_CONFIG_ATTRIB(&gconf->base, EGL_SURFACE_TYPE, val);
269       }
270 #endif
271       valid = _eglValidateConfig(&gconf->base, EGL_FALSE);
272    }
273    if (!valid) {
274       _eglLog(_EGL_DEBUG, "skip invalid config 0x%x", mode->visualID);
275       return EGL_FALSE;
276    }
277
278    gconf->native = nconf;
279
280    return EGL_TRUE;
281 }
282
283 /**
284  * Add configs to display and return the next config ID.
285  */
286 static EGLint
287 egl_g3d_add_configs(_EGLDriver *drv, _EGLDisplay *dpy, EGLint id)
288 {
289    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
290    const struct native_config **native_configs;
291    int num_configs, i;
292
293    native_configs = gdpy->native->get_configs(gdpy->native, &num_configs);
294    if (!num_configs) {
295       if (native_configs)
296          free(native_configs);
297       return id;
298    }
299
300    for (i = 0; i < num_configs; i++) {
301       struct egl_g3d_config *gconf;
302
303       gconf = CALLOC_STRUCT(egl_g3d_config);
304       if (gconf) {
305          _eglInitConfig(&gconf->base, dpy, id);
306          if (!egl_g3d_init_config(drv, dpy, &gconf->base, native_configs[i])) {
307             free(gconf);
308             continue;
309          }
310
311          _eglAddConfig(dpy, &gconf->base);
312          id++;
313       }
314    }
315
316    free(native_configs);
317    return id;
318 }
319
320 static void
321 egl_g3d_invalid_surface(struct native_display *ndpy,
322                         struct native_surface *nsurf,
323                         unsigned int seq_num)
324 {
325    /* XXX not thread safe? */
326    struct egl_g3d_surface *gsurf = egl_g3d_surface(nsurf->user_data);
327    struct egl_g3d_context *gctx;
328    
329    /*
330     * Some functions such as egl_g3d_copy_buffers create a temporary native
331     * surface.  There is no gsurf associated with it.
332     */
333    gctx = (gsurf) ? egl_g3d_context(gsurf->base.CurrentContext) : NULL;
334    if (gctx)
335       gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gsurf->stfbi);
336 }
337
338 static struct native_event_handler egl_g3d_native_event_handler = {
339    .invalid_surface = egl_g3d_invalid_surface
340 };
341
342 static EGLBoolean
343 egl_g3d_terminate(_EGLDriver *drv, _EGLDisplay *dpy)
344 {
345    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
346    EGLint i;
347
348    _eglReleaseDisplayResources(drv, dpy);
349    _eglCleanupDisplay(dpy);
350
351    if (gdpy->pipe)
352       gdpy->pipe->destroy(gdpy->pipe);
353
354    if (dpy->Screens) {
355       for (i = 0; i < dpy->NumScreens; i++) {
356          struct egl_g3d_screen *gscr = egl_g3d_screen(dpy->Screens[i]);
357          free(gscr->native_modes);
358          free(gscr);
359       }
360       free(dpy->Screens);
361    }
362
363    if (gdpy->smapi)
364       egl_g3d_destroy_st_manager(gdpy->smapi);
365
366    if (gdpy->native)
367       gdpy->native->destroy(gdpy->native);
368
369    free(gdpy);
370    dpy->DriverData = NULL;
371
372    return EGL_TRUE;
373 }
374
375 static EGLBoolean
376 egl_g3d_initialize(_EGLDriver *drv, _EGLDisplay *dpy,
377                    EGLint *major, EGLint *minor)
378 {
379    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
380    struct egl_g3d_display *gdpy;
381
382    /* the probe object is unlikely to be needed again */
383    egl_g3d_destroy_probe(drv, dpy);
384
385    gdpy = CALLOC_STRUCT(egl_g3d_display);
386    if (!gdpy) {
387       _eglError(EGL_BAD_ALLOC, "eglInitialize");
388       goto fail;
389    }
390    dpy->DriverData = gdpy;
391
392    gdpy->native = native_create_display(dpy->NativeDisplay,
393          &egl_g3d_native_event_handler);
394    if (!gdpy->native) {
395       _eglError(EGL_NOT_INITIALIZED, "eglInitialize(no usable display)");
396       goto fail;
397    }
398
399    gdpy->native->user_data = (void *) dpy;
400
401    egl_g3d_init_st(&gdrv->base);
402    dpy->ClientAPIsMask = gdrv->api_mask;
403
404    gdpy->smapi = egl_g3d_create_st_manager(dpy);
405    if (!gdpy->smapi) {
406       _eglError(EGL_NOT_INITIALIZED,
407             "eglInitialize(failed to create st manager)");
408       goto fail;
409    }
410
411 #ifdef EGL_MESA_screen_surface
412    /* enable MESA_screen_surface before adding (and validating) configs */
413    if (gdpy->native->modeset) {
414       dpy->Extensions.MESA_screen_surface = EGL_TRUE;
415       egl_g3d_add_screens(drv, dpy);
416    }
417 #endif
418
419    dpy->Extensions.KHR_image_base = EGL_TRUE;
420    if (gdpy->native->get_param(gdpy->native, NATIVE_PARAM_USE_NATIVE_BUFFER))
421       dpy->Extensions.KHR_image_pixmap = EGL_TRUE;
422
423    if (egl_g3d_add_configs(drv, dpy, 1) == 1) {
424       _eglError(EGL_NOT_INITIALIZED, "eglInitialize(unable to add configs)");
425       goto fail;
426    }
427
428    *major = 1;
429    *minor = 4;
430
431    return EGL_TRUE;
432
433 fail:
434    if (gdpy)
435       egl_g3d_terminate(drv, dpy);
436    return EGL_FALSE;
437 }
438
439 static _EGLContext *
440 egl_g3d_create_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
441                        _EGLContext *share, const EGLint *attribs)
442 {
443    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
444    struct egl_g3d_context *gshare = egl_g3d_context(share);
445    struct egl_g3d_config *gconf = egl_g3d_config(conf);
446    struct egl_g3d_context *gctx;
447
448    gctx = CALLOC_STRUCT(egl_g3d_context);
449    if (!gctx) {
450       _eglError(EGL_BAD_ALLOC, "eglCreateContext");
451       return NULL;
452    }
453
454    if (!_eglInitContext(&gctx->base, dpy, conf, attribs)) {
455       free(gctx);
456       return NULL;
457    }
458
459    gctx->stapi = egl_g3d_choose_st(drv, &gctx->base);
460    if (!gctx->stapi) {
461       free(gctx);
462       return NULL;
463    }
464
465    gctx->stctxi = gctx->stapi->create_context(gctx->stapi, gdpy->smapi,
466          &gconf->stvis, (gshare) ? gshare->stctxi : NULL);
467    if (!gctx->stctxi) {
468       free(gctx);
469       return NULL;
470    }
471
472    gctx->stctxi->st_manager_private = (void *) &gctx->base;
473
474    return &gctx->base;
475 }
476
477 /**
478  * Destroy a context.
479  */
480 static void
481 destroy_context(_EGLDisplay *dpy, _EGLContext *ctx)
482 {
483    struct egl_g3d_context *gctx = egl_g3d_context(ctx);
484
485    /* FIXME a context might live longer than its display */
486    if (!dpy->Initialized)
487       _eglLog(_EGL_FATAL, "destroy a context with an unitialized display");
488
489    gctx->stctxi->destroy(gctx->stctxi);
490
491    free(gctx);
492 }
493
494 static EGLBoolean
495 egl_g3d_destroy_context(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
496 {
497    if (!_eglIsContextBound(ctx))
498       destroy_context(dpy, ctx);
499    return EGL_TRUE;
500 }
501
502 struct egl_g3d_create_surface_arg {
503    EGLint type;
504    union {
505       EGLNativeWindowType win;
506       EGLNativePixmapType pix;
507    } u;
508 };
509
510 static _EGLSurface *
511 egl_g3d_create_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
512                        struct egl_g3d_create_surface_arg *arg,
513                        const EGLint *attribs)
514 {
515    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
516    struct egl_g3d_config *gconf = egl_g3d_config(conf);
517    struct egl_g3d_surface *gsurf;
518    struct native_surface *nsurf;
519    const char *err;
520
521    switch (arg->type) {
522    case EGL_WINDOW_BIT:
523       err = "eglCreateWindowSurface";
524       break;
525    case EGL_PIXMAP_BIT:
526       err = "eglCreatePixmapSurface";
527       break;
528 #ifdef EGL_MESA_screen_surface
529    case EGL_SCREEN_BIT_MESA:
530       err = "eglCreateScreenSurface";
531       break;
532 #endif
533    default:
534       err = "eglCreateUnknownSurface";
535       break;
536    }
537
538    gsurf = CALLOC_STRUCT(egl_g3d_surface);
539    if (!gsurf) {
540       _eglError(EGL_BAD_ALLOC, err);
541       return NULL;
542    }
543
544    if (!_eglInitSurface(&gsurf->base, dpy, arg->type, conf, attribs)) {
545       free(gsurf);
546       return NULL;
547    }
548
549    /* create the native surface */
550    switch (arg->type) {
551    case EGL_WINDOW_BIT:
552       nsurf = gdpy->native->create_window_surface(gdpy->native,
553             arg->u.win, gconf->native);
554       break;
555    case EGL_PIXMAP_BIT:
556       nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
557             arg->u.pix, gconf->native);
558       break;
559 #ifdef EGL_MESA_screen_surface
560    case EGL_SCREEN_BIT_MESA:
561       /* prefer back buffer (move to _eglInitSurface?) */
562       gsurf->base.RenderBuffer = EGL_BACK_BUFFER;
563       nsurf = gdpy->native->modeset->create_scanout_surface(gdpy->native,
564             gconf->native, gsurf->base.Width, gsurf->base.Height);
565       break;
566 #endif
567    default:
568       nsurf = NULL;
569       break;
570    }
571
572    if (!nsurf) {
573       free(gsurf);
574       return NULL;
575    }
576    /* initialize the geometry */
577    if (!nsurf->validate(nsurf, 0x0, &gsurf->sequence_number, NULL,
578             &gsurf->base.Width, &gsurf->base.Height)) {
579       nsurf->destroy(nsurf);
580       free(gsurf);
581       return NULL;
582    }
583
584    gsurf->stvis = gconf->stvis;
585    if (gsurf->base.RenderBuffer == EGL_SINGLE_BUFFER)
586       gsurf->stvis.render_buffer = ST_ATTACHMENT_FRONT_LEFT;
587
588    gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
589    if (!gsurf->stfbi) {
590       nsurf->destroy(nsurf);
591       free(gsurf);
592       return NULL;
593    }
594
595    nsurf->user_data = &gsurf->base;
596    gsurf->native = nsurf;
597
598    return &gsurf->base;
599 }
600
601 static _EGLSurface *
602 egl_g3d_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
603                               _EGLConfig *conf, EGLNativeWindowType win,
604                               const EGLint *attribs)
605 {
606    struct egl_g3d_create_surface_arg arg;
607
608    memset(&arg, 0, sizeof(arg));
609    arg.type = EGL_WINDOW_BIT;
610    arg.u.win = win;
611
612    return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
613 }
614
615 static _EGLSurface *
616 egl_g3d_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
617                               _EGLConfig *conf, EGLNativePixmapType pix,
618                               const EGLint *attribs)
619 {
620    struct egl_g3d_create_surface_arg arg;
621
622    memset(&arg, 0, sizeof(arg));
623    arg.type = EGL_PIXMAP_BIT;
624    arg.u.pix = pix;
625
626    return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
627 }
628
629 static _EGLSurface *
630 egl_g3d_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
631                                _EGLConfig *conf, const EGLint *attribs)
632 {
633    struct egl_g3d_config *gconf = egl_g3d_config(conf);
634    struct egl_g3d_surface *gsurf;
635
636    gsurf = CALLOC_STRUCT(egl_g3d_surface);
637    if (!gsurf) {
638       _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface");
639       return NULL;
640    }
641
642    if (!_eglInitSurface(&gsurf->base, dpy, EGL_PBUFFER_BIT, conf, attribs)) {
643       free(gsurf);
644       return NULL;
645    }
646
647    gsurf->stvis = gconf->stvis;
648
649    gsurf->stfbi = egl_g3d_create_st_framebuffer(&gsurf->base);
650    if (!gsurf->stfbi) {
651       free(gsurf);
652       return NULL;
653    }
654
655    return &gsurf->base;
656 }
657
658 /**
659  * Destroy a surface.
660  */
661 static void
662 destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf)
663 {
664    struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
665
666    /* FIXME a surface might live longer than its display */
667    if (!dpy->Initialized)
668       _eglLog(_EGL_FATAL, "destroy a surface with an unitialized display");
669
670    pipe_texture_reference(&gsurf->render_texture, NULL);
671    egl_g3d_destroy_st_framebuffer(gsurf->stfbi);
672    if (gsurf->native)
673       gsurf->native->destroy(gsurf->native);
674    free(gsurf);
675 }
676
677 static EGLBoolean
678 egl_g3d_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
679 {
680    if (!_eglIsSurfaceBound(surf))
681       destroy_surface(dpy, surf);
682    return EGL_TRUE;
683 }
684
685 static EGLBoolean
686 egl_g3d_make_current(_EGLDriver *drv, _EGLDisplay *dpy,
687                      _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx)
688 {
689    struct egl_g3d_context *gctx = egl_g3d_context(ctx);
690    struct egl_g3d_surface *gdraw = egl_g3d_surface(draw);
691    struct egl_g3d_surface *gread = egl_g3d_surface(read);
692    struct egl_g3d_context *old_gctx;
693    EGLBoolean ok = EGL_TRUE;
694
695    /* bind the new context and return the "orphaned" one */
696    if (!_eglBindContext(&ctx, &draw, &read))
697       return EGL_FALSE;
698    old_gctx = egl_g3d_context(ctx);
699
700    if (old_gctx) {
701       /* flush old context */
702       old_gctx->stctxi->flush(old_gctx->stctxi,
703             PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
704    }
705
706    if (gctx) {
707       ok = gctx->stapi->make_current(gctx->stapi, gctx->stctxi,
708             (gdraw) ? gdraw->stfbi : NULL, (gread) ? gread->stfbi : NULL);
709       if (ok) {
710          gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi, gdraw->stfbi);
711          if (gread != gdraw) {
712             gctx->stctxi->notify_invalid_framebuffer(gctx->stctxi,
713                   gread->stfbi);
714          }
715
716          if (gdraw->base.Type == EGL_WINDOW_BIT) {
717             gctx->base.WindowRenderBuffer =
718                (gdraw->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT) ?
719                EGL_SINGLE_BUFFER : EGL_BACK_BUFFER;
720          }
721       }
722    }
723    else if (old_gctx) {
724       ok = old_gctx->stapi->make_current(old_gctx->stapi, NULL, NULL, NULL);
725       old_gctx->base.WindowRenderBuffer = EGL_NONE;
726    }
727
728    if (ctx && !_eglIsContextLinked(ctx))
729       destroy_context(dpy, ctx);
730    if (draw && !_eglIsSurfaceLinked(draw))
731       destroy_surface(dpy, draw);
732    if (read && read != draw && !_eglIsSurfaceLinked(read))
733       destroy_surface(dpy, read);
734
735    return ok;
736 }
737
738 static EGLBoolean
739 egl_g3d_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
740 {
741    struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
742    _EGLContext *ctx = _eglGetCurrentContext();
743    struct egl_g3d_context *gctx = NULL;
744
745    /* no-op for pixmap or pbuffer surface */
746    if (gsurf->base.Type == EGL_PIXMAP_BIT ||
747        gsurf->base.Type == EGL_PBUFFER_BIT)
748       return EGL_TRUE;
749
750    /* or when the surface is single-buffered */
751    if (gsurf->stvis.render_buffer == ST_ATTACHMENT_FRONT_LEFT)
752       return EGL_TRUE;
753
754    if (ctx && ctx->DrawSurface == surf)
755       gctx = egl_g3d_context(ctx);
756
757    /* flush if the surface is current */
758    if (gctx) {
759       gctx->stctxi->flush(gctx->stctxi,
760             PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
761    }
762
763    return gsurf->native->swap_buffers(gsurf->native);
764 }
765
766 /**
767  * Find a config that supports the pixmap.
768  */
769 _EGLConfig *
770 egl_g3d_find_pixmap_config(_EGLDisplay *dpy, EGLNativePixmapType pix)
771 {
772    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
773    struct egl_g3d_config *gconf;
774    EGLint i;
775
776    for (i = 0; i < dpy->NumConfigs; i++) {
777       gconf = egl_g3d_config(dpy->Configs[i]);
778       if (gdpy->native->is_pixmap_supported(gdpy->native, pix, gconf->native))
779          break;
780    }
781
782    return (i < dpy->NumConfigs) ? &gconf->base : NULL;
783 }
784
785 /**
786  * Get the pipe surface of the given attachment of the native surface.
787  */
788 static struct pipe_surface *
789 get_pipe_surface(struct native_display *ndpy, struct native_surface *nsurf,
790                  enum native_attachment natt)
791 {
792    struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS];
793    struct pipe_surface *psurf;
794
795    textures[natt] = NULL;
796    nsurf->validate(nsurf, 1 << natt, NULL, textures, NULL, NULL);
797    if (!textures[natt])
798       return NULL;
799
800    psurf = ndpy->screen->get_tex_surface(ndpy->screen, textures[natt],
801          0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE);
802    pipe_texture_reference(&textures[natt], NULL);
803
804    return psurf;
805 }
806
807 static EGLBoolean
808 egl_g3d_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
809                      EGLNativePixmapType target)
810 {
811    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
812    struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
813    _EGLContext *ctx = _eglGetCurrentContext();
814    struct egl_g3d_config *gconf;
815    struct native_surface *nsurf;
816    struct pipe_screen *screen = gdpy->native->screen;
817    struct pipe_surface *psurf;
818
819    if (!gsurf->render_texture)
820       return EGL_TRUE;
821
822    gconf = egl_g3d_config(egl_g3d_find_pixmap_config(dpy, target));
823    if (!gconf)
824       return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers");
825
826    nsurf = gdpy->native->create_pixmap_surface(gdpy->native,
827          target, gconf->native);
828    if (!nsurf)
829       return _eglError(EGL_BAD_NATIVE_PIXMAP, "eglCopyBuffers");
830
831    /* flush if the surface is current */
832    if (ctx && ctx->DrawSurface == &gsurf->base) {
833       struct egl_g3d_context *gctx = egl_g3d_context(ctx);
834       gctx->stctxi->flush(gctx->stctxi,
835             PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
836    }
837
838    /* create a pipe context to copy surfaces */
839    if (!gdpy->pipe) {
840       gdpy->pipe =
841          gdpy->native->screen->context_create(gdpy->native->screen, NULL);
842       if (!gdpy->pipe)
843          return EGL_FALSE;
844    }
845
846    psurf = get_pipe_surface(gdpy->native, nsurf, NATIVE_ATTACHMENT_FRONT_LEFT);
847    if (psurf) {
848       struct pipe_surface *psrc;
849
850       psrc = screen->get_tex_surface(screen, gsurf->render_texture,
851             0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ);
852       if (psrc) {
853          gdpy->pipe->surface_copy(gdpy->pipe, psurf, 0, 0,
854                psrc, 0, 0, psurf->width, psurf->height);
855          pipe_surface_reference(&psrc, NULL);
856
857          nsurf->flush_frontbuffer(nsurf);
858       }
859
860       pipe_surface_reference(&psurf, NULL);
861    }
862
863    nsurf->destroy(nsurf);
864
865    return EGL_TRUE;
866 }
867
868 static EGLBoolean
869 egl_g3d_wait_client(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx)
870 {
871    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
872    struct egl_g3d_context *gctx = egl_g3d_context(ctx);
873    struct pipe_screen *screen = gdpy->native->screen;
874    struct pipe_fence_handle *fence = NULL;
875
876    gctx->stctxi->flush(gctx->stctxi,
877          PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence);
878    screen->fence_finish(screen, fence, 0);
879    screen->fence_reference(screen, &fence, NULL);
880
881    return EGL_TRUE;
882 }
883
884 static EGLBoolean
885 egl_g3d_wait_native(_EGLDriver *drv, _EGLDisplay *dpy, EGLint engine)
886 {
887    _EGLContext *ctx = _eglGetCurrentContext();
888
889    if (engine != EGL_CORE_NATIVE_ENGINE)
890       return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
891
892    if (ctx && ctx->DrawSurface) {
893       struct egl_g3d_surface *gsurf = egl_g3d_surface(ctx->DrawSurface);
894
895       if (gsurf->native)
896          gsurf->native->wait(gsurf->native);
897    }
898
899    return EGL_TRUE;
900 }
901
902 static _EGLProc
903 egl_g3d_get_proc_address(_EGLDriver *drv, const char *procname)
904 {
905    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
906    _EGLProc proc;
907    EGLint i;
908
909    /* in case this is called before a display is initialized */
910    egl_g3d_init_st(&gdrv->base);
911
912    for (i = 0; i < ST_API_COUNT; i++) {
913       struct st_api *stapi = gdrv->stapis[i];
914       if (stapi) {
915          proc = (_EGLProc) stapi->get_proc_address(stapi, procname);
916          if (proc)
917             return proc;
918       }
919    }
920
921    return (_EGLProc) NULL;
922 }
923
924 static EGLBoolean
925 egl_g3d_bind_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
926                        _EGLSurface *surf, EGLint buffer)
927 {
928    struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
929    _EGLContext *es1 = _eglGetAPIContext(EGL_OPENGL_ES_API);
930    struct egl_g3d_context *gctx;
931    enum pipe_format internal_format;
932    enum st_texture_type target;
933
934    if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT)
935       return _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
936    if (buffer != EGL_BACK_BUFFER)
937       return _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
938    if (gsurf->base.BoundToTexture)
939       return _eglError(EGL_BAD_ACCESS, "eglBindTexImage");
940
941    switch (gsurf->base.TextureFormat) {
942    case EGL_TEXTURE_RGB:
943       internal_format = PIPE_FORMAT_R8G8B8_UNORM;
944       break;
945    case EGL_TEXTURE_RGBA:
946       internal_format = PIPE_FORMAT_B8G8R8A8_UNORM;
947       break;
948    default:
949       return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
950    }
951
952    switch (gsurf->base.TextureTarget) {
953    case EGL_TEXTURE_2D:
954       target = ST_TEXTURE_2D;
955       break;
956    default:
957       return _eglError(EGL_BAD_MATCH, "eglBindTexImage");
958    }
959
960    if (!es1)
961       return EGL_TRUE;
962    if (!gsurf->render_texture)
963       return EGL_FALSE;
964
965    /* flush properly if the surface is bound */
966    if (gsurf->base.CurrentContext) {
967       gctx = egl_g3d_context(gsurf->base.CurrentContext);
968       gctx->stctxi->flush(gctx->stctxi,
969             PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, NULL);
970    }
971
972    gctx = egl_g3d_context(es1);
973    if (gctx->stctxi->teximage) {
974       if (!gctx->stctxi->teximage(gctx->stctxi, target,
975                gsurf->base.MipmapLevel, internal_format,
976                gsurf->render_texture, gsurf->base.MipmapTexture))
977          return EGL_FALSE;
978       gsurf->base.BoundToTexture = EGL_TRUE;
979    }
980
981    return EGL_TRUE;
982 }
983
984 static EGLBoolean
985 egl_g3d_release_tex_image(_EGLDriver *drv, _EGLDisplay *dpy,
986                           _EGLSurface *surf, EGLint buffer)
987 {
988    struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
989
990    if (!gsurf || gsurf->base.Type != EGL_PBUFFER_BIT ||
991        !gsurf->base.BoundToTexture)
992       return _eglError(EGL_BAD_SURFACE, "eglReleaseTexImage");
993    if (buffer != EGL_BACK_BUFFER)
994       return _eglError(EGL_BAD_PARAMETER, "eglReleaseTexImage");
995
996    if (gsurf->render_texture) {
997       _EGLContext *ctx = _eglGetAPIContext(EGL_OPENGL_ES_API);
998       struct egl_g3d_context *gctx = egl_g3d_context(ctx);
999
1000       /* what if the context the surface binds to is no longer current? */
1001       if (gctx) {
1002          gctx->stctxi->teximage(gctx->stctxi, ST_TEXTURE_2D,
1003                gsurf->base.MipmapLevel, PIPE_FORMAT_NONE, NULL, FALSE);
1004       }
1005    }
1006
1007    gsurf->base.BoundToTexture = EGL_FALSE;
1008
1009    return EGL_TRUE;
1010 }
1011
1012 #ifdef EGL_MESA_screen_surface
1013
1014 static _EGLSurface *
1015 egl_g3d_create_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
1016                               _EGLConfig *conf, const EGLint *attribs)
1017 {
1018    struct egl_g3d_create_surface_arg arg;
1019
1020    memset(&arg, 0, sizeof(arg));
1021    arg.type = EGL_SCREEN_BIT_MESA;
1022
1023    return egl_g3d_create_surface(drv, dpy, conf, &arg, attribs);
1024 }
1025
1026 static EGLBoolean
1027 egl_g3d_show_screen_surface(_EGLDriver *drv, _EGLDisplay *dpy,
1028                             _EGLScreen *scr, _EGLSurface *surf,
1029                             _EGLMode *mode)
1030 {
1031    struct egl_g3d_display *gdpy = egl_g3d_display(dpy);
1032    struct egl_g3d_screen *gscr = egl_g3d_screen(scr);
1033    struct egl_g3d_surface *gsurf = egl_g3d_surface(surf);
1034    struct native_surface *nsurf;
1035    const struct native_mode *nmode;
1036    EGLBoolean changed;
1037
1038    if (gsurf) {
1039       EGLint idx;
1040
1041       if (!mode)
1042          return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
1043       if (gsurf->base.Type != EGL_SCREEN_BIT_MESA)
1044          return _eglError(EGL_BAD_SURFACE, "eglShowScreenSurfaceMESA");
1045       if (gsurf->base.Width < mode->Width || gsurf->base.Height < mode->Height)
1046          return _eglError(EGL_BAD_MATCH,
1047                "eglShowSurfaceMESA(surface smaller than mode size)");
1048
1049       /* find the index of the mode */
1050       for (idx = 0; idx < gscr->base.NumModes; idx++)
1051          if (mode == &gscr->base.Modes[idx])
1052             break;
1053       if (idx >= gscr->base.NumModes) {
1054          return _eglError(EGL_BAD_MODE_MESA,
1055                "eglShowSurfaceMESA(unknown mode)");
1056       }
1057
1058       nsurf = gsurf->native;
1059       nmode = gscr->native_modes[idx];
1060    }
1061    else {
1062       if (mode)
1063          return _eglError(EGL_BAD_MATCH, "eglShowSurfaceMESA");
1064
1065       /* disable the screen */
1066       nsurf = NULL;
1067       nmode = NULL;
1068    }
1069
1070    /* TODO surface panning by CRTC choosing */
1071    changed = gdpy->native->modeset->program(gdpy->native, 0, nsurf,
1072          gscr->base.OriginX, gscr->base.OriginY, &gscr->native, 1, nmode);
1073    if (changed) {
1074       gscr->base.CurrentSurface = &gsurf->base;
1075       gscr->base.CurrentMode = mode;
1076    }
1077
1078    return changed;
1079 }
1080
1081 #endif /* EGL_MESA_screen_surface */
1082
1083 static EGLint
1084 egl_g3d_probe(_EGLDriver *drv, _EGLDisplay *dpy)
1085 {
1086    struct native_probe *nprobe;
1087    enum native_probe_result res;
1088    EGLint score;
1089
1090    nprobe = egl_g3d_get_probe(drv, dpy);
1091    res = native_get_probe_result(nprobe);
1092
1093    switch (res) {
1094    case NATIVE_PROBE_UNKNOWN:
1095    default:
1096       score = 0;
1097       break;
1098    case NATIVE_PROBE_FALLBACK:
1099       score = 40;
1100       break;
1101    case NATIVE_PROBE_SUPPORTED:
1102       score = 50;
1103       break;
1104    case NATIVE_PROBE_EXACT:
1105       score = 100;
1106       break;
1107    }
1108
1109    return score;
1110 }
1111
1112 static void
1113 egl_g3d_unload(_EGLDriver *drv)
1114 {
1115    struct egl_g3d_driver *gdrv = egl_g3d_driver(drv);
1116    EGLint i;
1117
1118    for (i = 0; i < ST_API_COUNT; i++) {
1119       if (gdrv->stapis[i])
1120          gdrv->stapis[i]->destroy(gdrv->stapis[i]);
1121    }
1122
1123    egl_g3d_destroy_probe(drv, NULL);
1124    free(gdrv);
1125 }
1126
1127 _EGLDriver *
1128 _eglMain(const char *args)
1129 {
1130    static char driver_name[64];
1131    struct egl_g3d_driver *gdrv;
1132
1133    snprintf(driver_name, sizeof(driver_name),
1134          "Gallium/%s", native_get_name());
1135
1136    gdrv = CALLOC_STRUCT(egl_g3d_driver);
1137    if (!gdrv)
1138       return NULL;
1139
1140    _eglInitDriverFallbacks(&gdrv->base);
1141
1142    gdrv->base.API.Initialize = egl_g3d_initialize;
1143    gdrv->base.API.Terminate = egl_g3d_terminate;
1144    gdrv->base.API.CreateContext = egl_g3d_create_context;
1145    gdrv->base.API.DestroyContext = egl_g3d_destroy_context;
1146    gdrv->base.API.CreateWindowSurface = egl_g3d_create_window_surface;
1147    gdrv->base.API.CreatePixmapSurface = egl_g3d_create_pixmap_surface;
1148    gdrv->base.API.CreatePbufferSurface = egl_g3d_create_pbuffer_surface;
1149    gdrv->base.API.DestroySurface = egl_g3d_destroy_surface;
1150    gdrv->base.API.MakeCurrent = egl_g3d_make_current;
1151    gdrv->base.API.SwapBuffers = egl_g3d_swap_buffers;
1152    gdrv->base.API.CopyBuffers = egl_g3d_copy_buffers;
1153    gdrv->base.API.WaitClient = egl_g3d_wait_client;
1154    gdrv->base.API.WaitNative = egl_g3d_wait_native;
1155    gdrv->base.API.GetProcAddress = egl_g3d_get_proc_address;
1156
1157    gdrv->base.API.BindTexImage = egl_g3d_bind_tex_image;
1158    gdrv->base.API.ReleaseTexImage = egl_g3d_release_tex_image;
1159
1160    gdrv->base.API.CreateImageKHR = egl_g3d_create_image;
1161    gdrv->base.API.DestroyImageKHR = egl_g3d_destroy_image;
1162
1163 #ifdef EGL_MESA_screen_surface
1164    gdrv->base.API.CreateScreenSurfaceMESA = egl_g3d_create_screen_surface;
1165    gdrv->base.API.ShowScreenSurfaceMESA = egl_g3d_show_screen_surface;
1166 #endif
1167
1168    gdrv->base.Name = driver_name;
1169    gdrv->base.Probe = egl_g3d_probe;
1170    gdrv->base.Unload = egl_g3d_unload;
1171
1172    /* the key is " EGL G3D" */
1173    gdrv->probe_key = 0x0E61063D;
1174
1175    return &gdrv->base;
1176 }