Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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