Home | History | Annotate | Download | only in glx
      1 /*
      2  * Copyright  2010 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Soft-
      6  * ware"), to deal in the Software without restriction, including without
      7  * limitation the rights to use, copy, modify, merge, publish, distribute,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, provided that the above copyright
     10  * notice(s) and this permission notice appear in all copies of the Soft-
     11  * ware and that both the above copyright notice(s) and this permission
     12  * notice appear in supporting documentation.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
     16  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
     17  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
     18  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
     19  * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
     22  * MANCE OF THIS SOFTWARE.
     23  *
     24  * Except as contained in this notice, the name of a copyright holder shall
     25  * not be used in advertising or otherwise to promote the sale, use or
     26  * other dealings in this Software without prior written authorization of
     27  * the copyright holder.
     28  *
     29  * Authors:
     30  *   Kristian Hgsberg (krh (at) bitplanet.net)
     31  */
     32 
     33 #include <stdbool.h>
     34 
     35 #include "glapi.h"
     36 #include "glxclient.h"
     37 
     38 #include "util/debug.h"
     39 
     40 #ifndef GLX_USE_APPLEGL
     41 
     42 extern struct _glapi_table *__glXNewIndirectAPI(void);
     43 
     44 /*
     45 ** All indirect rendering contexts will share the same indirect dispatch table.
     46 */
     47 static struct _glapi_table *IndirectAPI = NULL;
     48 
     49 static void
     50 indirect_destroy_context(struct glx_context *gc)
     51 {
     52    __glXFreeVertexArrayState(gc);
     53 
     54    free((char *) gc->vendor);
     55    free((char *) gc->renderer);
     56    free((char *) gc->version);
     57    free((char *) gc->extensions);
     58    __glFreeAttributeState(gc);
     59    free((char *) gc->buf);
     60    free((char *) gc->client_state_private);
     61    free((char *) gc);
     62 }
     63 
     64 static Bool
     65 SendMakeCurrentRequest(Display * dpy, GLXContextID gc_id,
     66                        GLXContextTag gc_tag, GLXDrawable draw,
     67                        GLXDrawable read, GLXContextTag *out_tag)
     68 {
     69    xGLXMakeCurrentReply reply;
     70    Bool ret;
     71    int opcode = __glXSetupForCommand(dpy);
     72 
     73    LockDisplay(dpy);
     74 
     75    if (draw == read) {
     76       xGLXMakeCurrentReq *req;
     77 
     78       GetReq(GLXMakeCurrent, req);
     79       req->reqType = opcode;
     80       req->glxCode = X_GLXMakeCurrent;
     81       req->drawable = draw;
     82       req->context = gc_id;
     83       req->oldContextTag = gc_tag;
     84    }
     85    else {
     86       struct glx_display *priv = __glXInitialize(dpy);
     87 
     88       /* If the server can support the GLX 1.3 version, we should
     89        * perfer that.  Not only that, some servers support GLX 1.3 but
     90        * not the SGI extension.
     91        */
     92 
     93       if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) {
     94          xGLXMakeContextCurrentReq *req;
     95 
     96          GetReq(GLXMakeContextCurrent, req);
     97          req->reqType = opcode;
     98          req->glxCode = X_GLXMakeContextCurrent;
     99          req->drawable = draw;
    100          req->readdrawable = read;
    101          req->context = gc_id;
    102          req->oldContextTag = gc_tag;
    103       }
    104       else {
    105          xGLXVendorPrivateWithReplyReq *vpreq;
    106          xGLXMakeCurrentReadSGIReq *req;
    107 
    108          GetReqExtra(GLXVendorPrivateWithReply,
    109                      sz_xGLXMakeCurrentReadSGIReq -
    110                      sz_xGLXVendorPrivateWithReplyReq, vpreq);
    111          req = (xGLXMakeCurrentReadSGIReq *) vpreq;
    112          req->reqType = opcode;
    113          req->glxCode = X_GLXVendorPrivateWithReply;
    114          req->vendorCode = X_GLXvop_MakeCurrentReadSGI;
    115          req->drawable = draw;
    116          req->readable = read;
    117          req->context = gc_id;
    118          req->oldContextTag = gc_tag;
    119       }
    120    }
    121 
    122    ret = _XReply(dpy, (xReply *) &reply, 0, False);
    123 
    124    if (out_tag)
    125       *out_tag = reply.contextTag;
    126 
    127    UnlockDisplay(dpy);
    128    SyncHandle();
    129 
    130    return ret;
    131 }
    132 
    133 static int
    134 indirect_bind_context(struct glx_context *gc, struct glx_context *old,
    135 		      GLXDrawable draw, GLXDrawable read)
    136 {
    137    GLXContextTag tag;
    138    Display *dpy = gc->psc->dpy;
    139    Bool sent;
    140 
    141    if (old != &dummyContext && !old->isDirect && old->psc->dpy == dpy) {
    142       tag = old->currentContextTag;
    143       old->currentContextTag = 0;
    144    } else {
    145       tag = 0;
    146    }
    147 
    148    sent = SendMakeCurrentRequest(dpy, gc->xid, tag, draw, read,
    149 				 &gc->currentContextTag);
    150 
    151    if (!IndirectAPI)
    152       IndirectAPI = __glXNewIndirectAPI();
    153    _glapi_set_dispatch(IndirectAPI);
    154 
    155    return !sent;
    156 }
    157 
    158 static void
    159 indirect_unbind_context(struct glx_context *gc, struct glx_context *new)
    160 {
    161    Display *dpy = gc->psc->dpy;
    162 
    163    if (gc == new)
    164       return;
    165 
    166    /* We are either switching to no context, away from an indirect
    167     * context to a direct context or from one dpy to another and have
    168     * to send a request to the dpy to unbind the previous context.
    169     */
    170    if (!new || new->isDirect || new->psc->dpy != dpy) {
    171       SendMakeCurrentRequest(dpy, None, gc->currentContextTag, None, None,
    172                              NULL);
    173       gc->currentContextTag = 0;
    174    }
    175 }
    176 
    177 static void
    178 indirect_wait_gl(struct glx_context *gc)
    179 {
    180    xGLXWaitGLReq *req;
    181    Display *dpy = gc->currentDpy;
    182 
    183    /* Flush any pending commands out */
    184    __glXFlushRenderBuffer(gc, gc->pc);
    185 
    186    /* Send the glXWaitGL request */
    187    LockDisplay(dpy);
    188    GetReq(GLXWaitGL, req);
    189    req->reqType = gc->majorOpcode;
    190    req->glxCode = X_GLXWaitGL;
    191    req->contextTag = gc->currentContextTag;
    192    UnlockDisplay(dpy);
    193    SyncHandle();
    194 }
    195 
    196 static void
    197 indirect_wait_x(struct glx_context *gc)
    198 {
    199    xGLXWaitXReq *req;
    200    Display *dpy = gc->currentDpy;
    201 
    202    /* Flush any pending commands out */
    203    __glXFlushRenderBuffer(gc, gc->pc);
    204 
    205    LockDisplay(dpy);
    206    GetReq(GLXWaitX, req);
    207    req->reqType = gc->majorOpcode;
    208    req->glxCode = X_GLXWaitX;
    209    req->contextTag = gc->currentContextTag;
    210    UnlockDisplay(dpy);
    211    SyncHandle();
    212 }
    213 
    214 static void
    215 indirect_use_x_font(struct glx_context *gc,
    216 		    Font font, int first, int count, int listBase)
    217 {
    218    xGLXUseXFontReq *req;
    219    Display *dpy = gc->currentDpy;
    220 
    221    /* Flush any pending commands out */
    222    __glXFlushRenderBuffer(gc, gc->pc);
    223 
    224    /* Send the glXUseFont request */
    225    LockDisplay(dpy);
    226    GetReq(GLXUseXFont, req);
    227    req->reqType = gc->majorOpcode;
    228    req->glxCode = X_GLXUseXFont;
    229    req->contextTag = gc->currentContextTag;
    230    req->font = font;
    231    req->first = first;
    232    req->count = count;
    233    req->listBase = listBase;
    234    UnlockDisplay(dpy);
    235    SyncHandle();
    236 }
    237 
    238 static void
    239 indirect_bind_tex_image(Display * dpy,
    240 			GLXDrawable drawable,
    241 			int buffer, const int *attrib_list)
    242 {
    243    xGLXVendorPrivateReq *req;
    244    struct glx_context *gc = __glXGetCurrentContext();
    245    CARD32 *drawable_ptr;
    246    INT32 *buffer_ptr;
    247    CARD32 *num_attrib_ptr;
    248    CARD32 *attrib_ptr;
    249    CARD8 opcode;
    250    unsigned int i;
    251 
    252    i = 0;
    253    if (attrib_list) {
    254       while (attrib_list[i * 2] != None)
    255          i++;
    256    }
    257 
    258    opcode = __glXSetupForCommand(dpy);
    259    if (!opcode)
    260       return;
    261 
    262    LockDisplay(dpy);
    263    GetReqExtra(GLXVendorPrivate, 12 + 8 * i, req);
    264    req->reqType = opcode;
    265    req->glxCode = X_GLXVendorPrivate;
    266    req->vendorCode = X_GLXvop_BindTexImageEXT;
    267    req->contextTag = gc->currentContextTag;
    268 
    269    drawable_ptr = (CARD32 *) (req + 1);
    270    buffer_ptr = (INT32 *) (drawable_ptr + 1);
    271    num_attrib_ptr = (CARD32 *) (buffer_ptr + 1);
    272    attrib_ptr = (CARD32 *) (num_attrib_ptr + 1);
    273 
    274    *drawable_ptr = drawable;
    275    *buffer_ptr = buffer;
    276    *num_attrib_ptr = (CARD32) i;
    277 
    278    i = 0;
    279    if (attrib_list) {
    280       while (attrib_list[i * 2] != None) {
    281          *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 0];
    282          *attrib_ptr++ = (CARD32) attrib_list[i * 2 + 1];
    283          i++;
    284       }
    285    }
    286 
    287    UnlockDisplay(dpy);
    288    SyncHandle();
    289 }
    290 
    291 static void
    292 indirect_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
    293 {
    294    xGLXVendorPrivateReq *req;
    295    struct glx_context *gc = __glXGetCurrentContext();
    296    CARD32 *drawable_ptr;
    297    INT32 *buffer_ptr;
    298    CARD8 opcode;
    299 
    300    opcode = __glXSetupForCommand(dpy);
    301    if (!opcode)
    302       return;
    303 
    304    LockDisplay(dpy);
    305    GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32), req);
    306    req->reqType = opcode;
    307    req->glxCode = X_GLXVendorPrivate;
    308    req->vendorCode = X_GLXvop_ReleaseTexImageEXT;
    309    req->contextTag = gc->currentContextTag;
    310 
    311    drawable_ptr = (CARD32 *) (req + 1);
    312    buffer_ptr = (INT32 *) (drawable_ptr + 1);
    313 
    314    *drawable_ptr = drawable;
    315    *buffer_ptr = buffer;
    316 
    317    UnlockDisplay(dpy);
    318    SyncHandle();
    319 }
    320 
    321 static const struct glx_context_vtable indirect_context_vtable = {
    322    .destroy             = indirect_destroy_context,
    323    .bind                = indirect_bind_context,
    324    .unbind              = indirect_unbind_context,
    325    .wait_gl             = indirect_wait_gl,
    326    .wait_x              = indirect_wait_x,
    327    .use_x_font          = indirect_use_x_font,
    328    .bind_tex_image      = indirect_bind_tex_image,
    329    .release_tex_image   = indirect_release_tex_image,
    330    .get_proc_address    = NULL,
    331 };
    332 
    333 /**
    334  * \todo Eliminate \c __glXInitVertexArrayState.  Replace it with a new
    335  * function called \c __glXAllocateClientState that allocates the memory and
    336  * does all the initialization (including the pixel pack / unpack).
    337  *
    338  * \note
    339  * This function is \b not the place to validate the context creation
    340  * parameters.  It is just the allocator for the \c glx_context.
    341  */
    342 _X_HIDDEN struct glx_context *
    343 indirect_create_context(struct glx_screen *psc,
    344 			struct glx_config *mode,
    345 			struct glx_context *shareList, int renderType)
    346 {
    347    struct glx_context *gc;
    348    int bufSize;
    349    CARD8 opcode;
    350    __GLXattribute *state;
    351 
    352    opcode = __glXSetupForCommand(psc->dpy);
    353    if (!opcode) {
    354       return NULL;
    355    }
    356 
    357    /* Allocate our context record */
    358    gc = calloc(1, sizeof *gc);
    359    if (!gc) {
    360       /* Out of memory */
    361       return NULL;
    362    }
    363 
    364    glx_context_init(gc, psc, mode);
    365    gc->isDirect = GL_FALSE;
    366    gc->vtable = &indirect_context_vtable;
    367    state = calloc(1, sizeof(struct __GLXattributeRec));
    368    gc->renderType = renderType;
    369 
    370    if (state == NULL) {
    371       /* Out of memory */
    372       free(gc);
    373       return NULL;
    374    }
    375    gc->client_state_private = state;
    376    state->NoDrawArraysProtocol = env_var_as_boolean("LIBGL_NO_DRAWARRAYS", false);
    377 
    378    /*
    379     ** Create a temporary buffer to hold GLX rendering commands.  The size
    380     ** of the buffer is selected so that the maximum number of GLX rendering
    381     ** commands can fit in a single X packet and still have room in the X
    382     ** packet for the GLXRenderReq header.
    383     */
    384 
    385    bufSize = (XMaxRequestSize(psc->dpy) * 4) - sz_xGLXRenderReq;
    386    gc->buf = malloc(bufSize);
    387    if (!gc->buf) {
    388       free(gc->client_state_private);
    389       free(gc);
    390       return NULL;
    391    }
    392    gc->bufSize = bufSize;
    393 
    394    /* Fill in the new context */
    395    gc->renderMode = GL_RENDER;
    396 
    397    state->storePack.alignment = 4;
    398    state->storeUnpack.alignment = 4;
    399 
    400    gc->attributes.stackPointer = &gc->attributes.stack[0];
    401 
    402    /*
    403     ** PERFORMANCE NOTE: A mode dependent fill image can speed things up.
    404     */
    405    gc->fillImage = __glFillImage;
    406    gc->pc = gc->buf;
    407    gc->bufEnd = gc->buf + bufSize;
    408    gc->isDirect = GL_FALSE;
    409    if (__glXDebug) {
    410       /*
    411        ** Set limit register so that there will be one command per packet
    412        */
    413       gc->limit = gc->buf;
    414    }
    415    else {
    416       gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
    417    }
    418    gc->majorOpcode = opcode;
    419 
    420    /*
    421     ** Constrain the maximum drawing command size allowed to be
    422     ** transfered using the X_GLXRender protocol request.  First
    423     ** constrain by a software limit, then constrain by the protocl
    424     ** limit.
    425     */
    426    if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) {
    427       bufSize = __GLX_RENDER_CMD_SIZE_LIMIT;
    428    }
    429    if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) {
    430       bufSize = __GLX_MAX_RENDER_CMD_SIZE;
    431    }
    432    gc->maxSmallRenderCommandSize = bufSize;
    433 
    434 
    435    return gc;
    436 }
    437 
    438 _X_HIDDEN struct glx_context *
    439 indirect_create_context_attribs(struct glx_screen *base,
    440 				struct glx_config *config_base,
    441 				struct glx_context *shareList,
    442 				unsigned num_attribs,
    443 				const uint32_t *attribs,
    444 				unsigned *error)
    445 {
    446    int renderType = GLX_RGBA_TYPE;
    447    unsigned i;
    448 
    449    /* The error parameter is only used on the server so that correct GLX
    450     * protocol errors can be generated.  On the client, it can be ignored.
    451     */
    452    (void) error;
    453 
    454    /* All of the attribute validation for indirect contexts is handled on the
    455     * server, so there's not much to do here. Still, we need to parse the
    456     * attributes to correctly set renderType.
    457     */
    458    for (i = 0; i < num_attribs; i++) {
    459       if (attribs[i * 2] == GLX_RENDER_TYPE)
    460          renderType = attribs[i * 2 + 1];
    461    }
    462 
    463    return indirect_create_context(base, config_base, shareList, renderType);
    464 }
    465 
    466 static const struct glx_screen_vtable indirect_screen_vtable = {
    467    .create_context         = indirect_create_context,
    468    .create_context_attribs = indirect_create_context_attribs,
    469    .query_renderer_integer = NULL,
    470    .query_renderer_string  = NULL,
    471 };
    472 
    473 _X_HIDDEN struct glx_screen *
    474 indirect_create_screen(int screen, struct glx_display * priv)
    475 {
    476    struct glx_screen *psc;
    477 
    478    psc = calloc(1, sizeof *psc);
    479    if (psc == NULL)
    480       return NULL;
    481 
    482    glx_screen_init(psc, screen, priv);
    483    psc->vtable = &indirect_screen_vtable;
    484 
    485    return psc;
    486 }
    487 
    488 #endif
    489