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