Home | History | Annotate | Download | only in glx
      1 /*
      2  * Copyright  2014 Jon Turney
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #include "glxclient.h"
     25 #include "glx_error.h"
     26 #include "dri_common.h"
     27 #include "util/macros.h"
     28 #include "windows/xwindowsdri.h"
     29 #include "windows/windowsgl.h"
     30 
     31 struct driwindows_display
     32 {
     33    __GLXDRIdisplay base;
     34    int event_base;
     35 };
     36 
     37 struct driwindows_context
     38 {
     39    struct glx_context base;
     40    windowsContext *windowsContext;
     41 };
     42 
     43 struct driwindows_config
     44 {
     45    struct glx_config base;
     46    int pxfi;
     47 };
     48 
     49 struct driwindows_screen
     50 {
     51    struct glx_screen base;
     52    __DRIscreen *driScreen;
     53    __GLXDRIscreen vtable;
     54    Bool copySubBuffer;
     55 };
     56 
     57 struct driwindows_drawable
     58 {
     59    __GLXDRIdrawable base;
     60    windowsDrawable *windowsDrawable;
     61 };
     62 
     63 /**
     64  * GLXDRI functions
     65  */
     66 
     67 static void
     68 driwindows_destroy_context(struct glx_context *context)
     69 {
     70    struct driwindows_context *pcp = (struct driwindows_context *) context;
     71 
     72    driReleaseDrawables(&pcp->base);
     73 
     74    free((char *) context->extensions);
     75 
     76    windows_destroy_context(pcp->windowsContext);
     77 
     78    free(pcp);
     79 }
     80 
     81 static int
     82 driwindows_bind_context(struct glx_context *context, struct glx_context *old,
     83                         GLXDrawable draw, GLXDrawable read)
     84 {
     85    struct driwindows_context *pcp = (struct driwindows_context *) context;
     86    struct driwindows_drawable *pdraw, *pread;
     87 
     88    pdraw = (struct driwindows_drawable *) driFetchDrawable(context, draw);
     89    pread = (struct driwindows_drawable *) driFetchDrawable(context, read);
     90 
     91    driReleaseDrawables(&pcp->base);
     92 
     93    if (pdraw == NULL || pread == NULL)
     94       return GLXBadDrawable;
     95 
     96    if (windows_bind_context(pcp->windowsContext,
     97                            pdraw->windowsDrawable, pread->windowsDrawable))
     98       return Success;
     99 
    100    return GLXBadContext;
    101 }
    102 
    103 static void
    104 driwindows_unbind_context(struct glx_context *context, struct glx_context *new)
    105 {
    106    struct driwindows_context *pcp = (struct driwindows_context *) context;
    107 
    108    windows_unbind_context(pcp->windowsContext);
    109 }
    110 
    111 static void
    112 driwindows_bind_tex_image(Display * dpy,
    113                     GLXDrawable drawable,
    114                     int buffer, const int *attrib_list)
    115 {
    116    struct glx_context *gc = __glXGetCurrentContext();
    117    struct driwindows_context *pcp = (struct driwindows_context *) gc;
    118    __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
    119    struct driwindows_drawable *pdraw = (struct driwindows_drawable *) base;
    120 
    121    __glXInitialize(dpy);
    122 
    123    if (pdraw != NULL) {
    124       windows_setTexBuffer(pcp->windowsContext,
    125                           pdraw->base.textureTarget,
    126                           pdraw->base.textureFormat,
    127                           pdraw->windowsDrawable);
    128    }
    129 }
    130 
    131 static void
    132 driwindows_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
    133 {
    134    struct glx_context *gc = __glXGetCurrentContext();
    135    struct driwindows_context *pcp = (struct driwindows_context *) gc;
    136    __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
    137    struct glx_display *dpyPriv = __glXInitialize(dpy);
    138    struct driwindows_drawable *pdraw = (struct driwindows_drawable *) base;
    139 
    140    if (dpyPriv != NULL && pdraw != NULL) {
    141       windows_releaseTexBuffer(pcp->windowsContext,
    142                               pdraw->base.textureTarget,
    143                               pdraw->windowsDrawable);
    144       }
    145 }
    146 
    147 static const struct glx_context_vtable driwindows_context_vtable = {
    148    .destroy             = driwindows_destroy_context,
    149    .bind                = driwindows_bind_context,
    150    .unbind              = driwindows_unbind_context,
    151    .wait_gl             = NULL,
    152    .wait_x              = NULL,
    153    .use_x_font          = DRI_glXUseXFont,
    154    .bind_tex_image      = driwindows_bind_tex_image,
    155    .release_tex_image   = driwindows_release_tex_image,
    156    .get_proc_address    = NULL,
    157 };
    158 
    159 static struct glx_context *
    160 driwindows_create_context(struct glx_screen *base,
    161                           struct glx_config *config_base,
    162                           struct glx_context *shareList, int renderType)
    163 {
    164    struct driwindows_context *pcp, *pcp_shared;
    165    struct driwindows_config *config = (struct driwindows_config *) config_base;
    166    struct driwindows_screen *psc = (struct driwindows_screen *) base;
    167    windowsContext *shared = NULL;
    168 
    169    if (!psc->base.driScreen)
    170       return NULL;
    171 
    172    /* Check the renderType value */
    173    if (!validate_renderType_against_config(config_base, renderType))
    174        return NULL;
    175 
    176    if (shareList) {
    177       /* If the shareList context is not on this renderer, we cannot possibly
    178        * create a context that shares with it.
    179        */
    180       if (shareList->vtable->destroy != driwindows_destroy_context) {
    181          return NULL;
    182       }
    183 
    184       pcp_shared = (struct driwindows_context *) shareList;
    185       shared = pcp_shared->windowsContext;
    186    }
    187 
    188    pcp = calloc(1, sizeof *pcp);
    189    if (pcp == NULL)
    190       return NULL;
    191 
    192    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
    193       free(pcp);
    194       return NULL;
    195    }
    196 
    197    pcp->base.renderType = renderType;
    198 
    199    InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
    200 
    201    pcp->windowsContext = windows_create_context(config->pxfi, shared);
    202 
    203    if (!pcp->windowsContext) {
    204       free(pcp);
    205       return NULL;
    206    }
    207 
    208    pcp->base.vtable = &driwindows_context_vtable;
    209 
    210    return &pcp->base;
    211 }
    212 
    213 static struct glx_context *
    214 driwindows_create_context_attribs(struct glx_screen *base,
    215                                   struct glx_config *config_base,
    216                                   struct glx_context *shareList,
    217                                   unsigned num_attribs,
    218                                   const uint32_t *attribs,
    219                                   unsigned *error)
    220 {
    221    struct driwindows_context *pcp, *pcp_shared;
    222    struct driwindows_config *config = (struct driwindows_config *) config_base;
    223    struct driwindows_screen *psc = (struct driwindows_screen *) base;
    224    windowsContext *shared = NULL;
    225 
    226    int i;
    227    uint32_t renderType = GLX_RGBA_TYPE;
    228 
    229    /* Extract renderType from attribs */
    230    for (i = 0; i < num_attribs; i++) {
    231       switch (attribs[i * 2]) {
    232       case GLX_RENDER_TYPE:
    233          renderType = attribs[i * 2 + 1];
    234          break;
    235       }
    236    }
    237 
    238    /*
    239      Perhaps we should map GLX tokens to WGL tokens, but they appear to have
    240      identical values, so far
    241    */
    242 
    243    if (!psc->base.driScreen)
    244       return NULL;
    245 
    246    /* Check the renderType value */
    247    if (!validate_renderType_against_config(config_base, renderType)) {
    248        return NULL;
    249    }
    250 
    251    if (shareList) {
    252       /* If the shareList context is not on this renderer, we cannot possibly
    253        * create a context that shares with it.
    254        */
    255       if (shareList->vtable->destroy != driwindows_destroy_context) {
    256          return NULL;
    257       }
    258 
    259       pcp_shared = (struct driwindows_context *) shareList;
    260       shared = pcp_shared->windowsContext;
    261    }
    262 
    263    pcp = calloc(1, sizeof *pcp);
    264    if (pcp == NULL)
    265       return NULL;
    266 
    267    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
    268       free(pcp);
    269       return NULL;
    270    }
    271 
    272    pcp->base.renderType = renderType;
    273 
    274    InfoMessageF("visualID %x, fbConfigID %x -> pxfi %d\n", config_base->visualID, config_base->fbconfigID, config->pxfi);
    275 
    276    pcp->windowsContext = windows_create_context_attribs(config->pxfi,
    277                                                       shared,
    278                                                       (const int *)attribs);
    279    if (pcp->windowsContext == NULL) {
    280       free(pcp);
    281       return NULL;
    282    }
    283 
    284    pcp->base.vtable = &driwindows_context_vtable;
    285 
    286    return &pcp->base;
    287 }
    288 
    289 static void
    290 driwindowsDestroyDrawable(__GLXDRIdrawable * pdraw)
    291 {
    292    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
    293 
    294    windows_destroy_drawable(pdp->windowsDrawable);
    295 
    296    free(pdp);
    297 }
    298 
    299 static __GLXDRIdrawable *
    300 driwindowsCreateDrawable(struct glx_screen *base, XID xDrawable,
    301                          GLXDrawable drawable, struct glx_config *modes)
    302 {
    303    struct driwindows_drawable *pdp;
    304    struct driwindows_screen *psc = (struct driwindows_screen *) base;
    305 
    306    pdp = calloc(1, sizeof(*pdp));
    307    if (!pdp)
    308       return NULL;
    309 
    310    pdp->base.xDrawable = xDrawable;
    311    pdp->base.drawable = drawable;
    312    pdp->base.psc = &psc->base;
    313 
    314    /*
    315       By this stage, the X drawable already exists, but the GLX drawable may
    316       not.
    317 
    318       Query the server with the XID to find the correct HWND, HPBUFFERARB or
    319       HBITMAP
    320    */
    321 
    322    unsigned int type;
    323    void *handle;
    324 
    325    if (!XWindowsDRIQueryDrawable(psc->base.dpy, base->scr, drawable, &type, &handle))
    326    {
    327       free(pdp);
    328       return NULL;
    329    }
    330 
    331    /* No handle found is a failure */
    332    if (!handle) {
    333       free(pdp);
    334       return NULL;
    335    }
    336 
    337    /* Create a new drawable */
    338    pdp->windowsDrawable = windows_create_drawable(type, handle);
    339 
    340    if (!pdp->windowsDrawable) {
    341       free(pdp);
    342       return NULL;
    343    }
    344 
    345    pdp->base.destroyDrawable = driwindowsDestroyDrawable;
    346 
    347    return &pdp->base;
    348 }
    349 
    350 static int64_t
    351 driwindowsSwapBuffers(__GLXDRIdrawable * pdraw,
    352                  int64_t target_msc, int64_t divisor, int64_t remainder,
    353                  Bool flush)
    354 {
    355    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
    356 
    357    (void) target_msc;
    358    (void) divisor;
    359    (void) remainder;
    360 
    361    if (flush) {
    362       glFlush();
    363    }
    364 
    365    windows_swap_buffers(pdp->windowsDrawable);
    366 
    367    return 0;
    368 }
    369 
    370 static void
    371 driwindowsCopySubBuffer(__GLXDRIdrawable * pdraw,
    372                    int x, int y, int width, int height, Bool flush)
    373 {
    374    struct driwindows_drawable *pdp = (struct driwindows_drawable *) pdraw;
    375 
    376    if (flush) {
    377       glFlush();
    378    }
    379 
    380    windows_copy_subbuffer(pdp->windowsDrawable, x, y, width, height);
    381 }
    382 
    383 static void
    384 driwindowsDestroyScreen(struct glx_screen *base)
    385 {
    386    struct driwindows_screen *psc = (struct driwindows_screen *) base;
    387 
    388    /* Free the direct rendering per screen data */
    389    psc->driScreen = NULL;
    390    free(psc);
    391 }
    392 
    393 static const struct glx_screen_vtable driwindows_screen_vtable = {
    394    .create_context         = driwindows_create_context,
    395    .create_context_attribs = driwindows_create_context_attribs,
    396    .query_renderer_integer = NULL,
    397    .query_renderer_string  = NULL,
    398 };
    399 
    400 static Bool
    401 driwindowsBindExtensions(struct driwindows_screen *psc)
    402 {
    403    Bool result = 1;
    404 
    405    const struct
    406    {
    407       char *wglext;
    408       char *glxext;
    409       Bool mandatory;
    410    } extensionMap[] = {
    411       { "WGL_ARB_make_current_read", "GLX_SGI_make_current_read", 0 },
    412       { "WGL_EXT_swap_control", "GLX_SGI_swap_control", 0 },
    413       { "WGL_EXT_swap_control", "GLX_MESA_swap_control", 0 },
    414 //      { "WGL_ARB_render_texture", "GLX_EXT_texture_from_pixmap", 0 },
    415 // Not exactly equivalent, needs some more glue to be written
    416       { "WGL_ARB_pbuffer", "GLX_SGIX_pbuffer", 1 },
    417       { "WGL_ARB_multisample", "GLX_ARB_multisample", 1 },
    418       { "WGL_ARB_multisample", "GLX_SGIS_multisample", 1 },
    419       { "WGL_ARB_create_context", "GLX_ARB_create_context", 0 },
    420       { "WGL_ARB_create_context_profile", "GLX_ARB_create_context_profile", 0 },
    421       { "WGL_ARB_create_context_robustness", "GLX_ARB_create_context_robustness", 0 },
    422       { "WGL_EXT_create_context_es2_profile", "GLX_EXT_create_context_es2_profile", 0 },
    423    };
    424 
    425    char *wgl_extensions;
    426    char *gl_extensions;
    427    int i;
    428 
    429    windows_extensions(&gl_extensions, &wgl_extensions);
    430 
    431    for (i = 0; i < ARRAY_SIZE(extensionMap); i++) {
    432       if (strstr(wgl_extensions, extensionMap[i].wglext)) {
    433           __glXEnableDirectExtension(&psc->base, extensionMap[i].glxext);
    434           InfoMessageF("enabled %s\n", extensionMap[i].glxext);
    435       }
    436       else if (extensionMap[i].mandatory) {
    437          ErrorMessageF("required WGL extension %s is missing\n", extensionMap[i].wglext);
    438          result = 0;
    439       }
    440    }
    441 
    442    /*
    443        Because it pre-dates WGL_EXT_extensions_string, GL_WIN_swap_hint might
    444        only be in GL_EXTENSIONS
    445    */
    446    if (strstr(gl_extensions, "GL_WIN_swap_hint")) {
    447       psc->copySubBuffer = 1;
    448       __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
    449       InfoMessageF("enabled GLX_MESA_copy_sub_buffer\n");
    450    }
    451 
    452    free(gl_extensions);
    453    free(wgl_extensions);
    454 
    455    return result;
    456 }
    457 
    458 static struct glx_config *
    459 driwindowsMapConfigs(struct glx_display *priv, int screen, struct glx_config *configs, struct glx_config *fbconfigs)
    460 {
    461    struct glx_config head, *tail, *m;
    462 
    463    tail = &head;
    464    head.next = NULL;
    465 
    466    for (m = configs; m; m = m->next) {
    467       int fbconfigID = GLX_DONT_CARE;
    468       if (fbconfigs) {
    469          /*
    470            visuals have fbconfigID of GLX_DONT_CARE, so search for a fbconfig
    471            with matching visualID and get the fbconfigID from there
    472          */
    473          struct glx_config *f;
    474          for (f = fbconfigs; f; f = f->next) {
    475             if (f->visualID == m->visualID)
    476                fbconfigID = f->fbconfigID;
    477          }
    478       }
    479       else {
    480          fbconfigID = m->fbconfigID;
    481       }
    482 
    483       int pxfi;
    484       XWindowsDRIFBConfigToPixelFormat(priv->dpy, screen, fbconfigID, &pxfi);
    485       if (pxfi == 0)
    486          continue;
    487 
    488       struct driwindows_config *config = malloc(sizeof(*config));
    489 
    490       tail->next = &config->base;
    491       if (tail->next == NULL)
    492          continue;
    493 
    494       config->base = *m;
    495       config->pxfi = pxfi;
    496 
    497       tail = tail->next;
    498    }
    499 
    500    return head.next;
    501 }
    502 
    503 static struct glx_screen *
    504 driwindowsCreateScreen(int screen, struct glx_display *priv)
    505 {
    506    __GLXDRIscreen *psp;
    507    struct driwindows_screen *psc;
    508    struct glx_config *configs = NULL, *visuals = NULL;
    509    int directCapable;
    510 
    511    psc = calloc(1, sizeof *psc);
    512    if (psc == NULL)
    513       return NULL;
    514 
    515    if (!glx_screen_init(&psc->base, screen, priv)) {
    516       free(psc);
    517       return NULL;
    518    }
    519 
    520    if (!XWindowsDRIQueryDirectRenderingCapable(psc->base.dpy, screen, &directCapable) ||
    521        !directCapable) {
    522       ErrorMessageF("Screen is not Windows-DRI capable\n");
    523       goto handle_error;
    524    }
    525 
    526    /* discover native supported extensions */
    527    if (!driwindowsBindExtensions(psc)) {
    528       goto handle_error;
    529    }
    530 
    531    /* Augment configs with pxfi information */
    532    configs = driwindowsMapConfigs(priv, screen, psc->base.configs, NULL);
    533    visuals = driwindowsMapConfigs(priv, screen, psc->base.visuals, configs);
    534 
    535    if (!configs || !visuals) {
    536        ErrorMessageF("No fbConfigs or visuals found\n");
    537        goto handle_error;
    538    }
    539 
    540    glx_config_destroy_list(psc->base.configs);
    541    psc->base.configs = configs;
    542    glx_config_destroy_list(psc->base.visuals);
    543    psc->base.visuals = visuals;
    544 
    545    psc->base.vtable = &driwindows_screen_vtable;
    546    psp = &psc->vtable;
    547    psc->base.driScreen = psp;
    548    psp->destroyScreen = driwindowsDestroyScreen;
    549    psp->createDrawable = driwindowsCreateDrawable;
    550    psp->swapBuffers = driwindowsSwapBuffers;
    551 
    552    if (psc->copySubBuffer)
    553       psp->copySubBuffer = driwindowsCopySubBuffer;
    554 
    555    return &psc->base;
    556 
    557 handle_error:
    558    glx_screen_cleanup(&psc->base);
    559 
    560    return NULL;
    561 }
    562 
    563 /* Called from __glXFreeDisplayPrivate.
    564  */
    565 static void
    566 driwindowsDestroyDisplay(__GLXDRIdisplay * dpy)
    567 {
    568    free(dpy);
    569 }
    570 
    571 /*
    572  * Allocate, initialize and return a  __GLXDRIdisplay object.
    573  * This is called from __glXInitialize() when we are given a new
    574  * display pointer.
    575  */
    576 _X_HIDDEN __GLXDRIdisplay *
    577 driwindowsCreateDisplay(Display * dpy)
    578 {
    579    struct driwindows_display *pdpyp;
    580 
    581    int eventBase, errorBase;
    582    int major, minor, patch;
    583 
    584    /* Verify server has Windows-DRI extension */
    585    if (!XWindowsDRIQueryExtension(dpy, &eventBase, &errorBase)) {
    586       ErrorMessageF("Windows-DRI extension not available\n");
    587       return NULL;
    588    }
    589 
    590    if (!XWindowsDRIQueryVersion(dpy, &major, &minor, &patch)) {
    591       ErrorMessageF("Fetching Windows-DRI extension version failed\n");
    592       return NULL;
    593    }
    594 
    595    if (!windows_check_renderer()) {
    596       ErrorMessageF("Windows-DRI extension disabled for GDI Generic renderer\n");
    597       return NULL;
    598    }
    599 
    600    pdpyp = malloc(sizeof *pdpyp);
    601    if (pdpyp == NULL)
    602       return NULL;
    603 
    604    pdpyp->base.destroyDisplay = driwindowsDestroyDisplay;
    605    pdpyp->base.createScreen = driwindowsCreateScreen;
    606 
    607    pdpyp->event_base = eventBase;
    608 
    609    return &pdpyp->base;
    610 }
    611