Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  
  3. Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
  4. All Rights Reserved.
  5.  
  6. Permission is hereby granted, free of charge, to any person obtaining a
  7. copy of this software and associated documentation files (the
  8. "Software"), to deal in the Software without restriction, including
  9. without limitation the rights to use, copy, modify, merge, publish,
  10. distribute, sub license, and/or sell copies of the Software, and to
  11. permit persons to whom the Software is furnished to do so, subject to
  12. the following conditions:
  13.  
  14. The above copyright notice and this permission notice (including the
  15. next paragraph) shall be included in all copies or substantial portions
  16. of the Software.
  17.  
  18. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19. OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21. IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
  22. ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23. TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  
  26. **************************************************************************/
  27.  
  28. /*
  29.  * Authors:
  30.  *   Kevin E. Martin <kevin@precisioninsight.com>
  31.  *   Brian Paul <brian@precisioninsight.com>
  32.  *
  33.  */
  34.  
  35. #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
  36.  
  37. #include <X11/Xlib.h>
  38. #include <X11/extensions/Xfixes.h>
  39. #include <X11/extensions/Xdamage.h>
  40. #include "glxclient.h"
  41. #include "xf86dri.h"
  42. #include "dri2.h"
  43. #include "dri_sarea.h"
  44. #include <dlfcn.h>
  45. #include <sys/types.h>
  46. #include <sys/mman.h>
  47. #include "xf86drm.h"
  48. #include "dri_common.h"
  49.  
  50. struct dri_display
  51. {
  52.    __GLXDRIdisplay base;
  53.  
  54.    /*
  55.     ** XFree86-DRI version information
  56.     */
  57.    int driMajor;
  58.    int driMinor;
  59.    int driPatch;
  60. };
  61.  
  62. struct dri_screen
  63. {
  64.    struct glx_screen base;
  65.  
  66.    __DRIscreen *driScreen;
  67.    __GLXDRIscreen vtable;
  68.    const __DRIlegacyExtension *legacy;
  69.    const __DRIcoreExtension *core;
  70.    const __DRIswapControlExtension *swapControl;
  71.    const __DRImediaStreamCounterExtension *msc;
  72.    const __DRIconfig **driver_configs;
  73.    const __DRIcopySubBufferExtension *driCopySubBuffer;
  74.  
  75.    void *driver;
  76.    int fd;
  77. };
  78.  
  79. struct dri_context
  80. {
  81.    struct glx_context base;
  82.    __DRIcontext *driContext;
  83.    XID hwContextID;
  84. };
  85.  
  86. struct dri_drawable
  87. {
  88.    __GLXDRIdrawable base;
  89.  
  90.    __DRIdrawable *driDrawable;
  91. };
  92.  
  93. /*
  94.  * Given a display pointer and screen number, determine the name of
  95.  * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc).
  96.  * Return True for success, False for failure.
  97.  */
  98. static Bool
  99. driGetDriverName(Display * dpy, int scrNum, char **driverName)
  100. {
  101.    int directCapable;
  102.    Bool b;
  103.    int event, error;
  104.    int driverMajor, driverMinor, driverPatch;
  105.  
  106.    *driverName = NULL;
  107.  
  108.    if (XF86DRIQueryExtension(dpy, &event, &error)) {    /* DRI1 */
  109.       if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
  110.          ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
  111.          return False;
  112.       }
  113.       if (!directCapable) {
  114.          ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
  115.          return False;
  116.       }
  117.  
  118.       b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
  119.                                      &driverPatch, driverName);
  120.       if (!b) {
  121.          ErrorMessageF("Cannot determine driver name for screen %d\n",
  122.                        scrNum);
  123.          return False;
  124.       }
  125.  
  126.       InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
  127.                    driverMajor, driverMinor, driverPatch, *driverName,
  128.                    scrNum);
  129.  
  130.       return True;
  131.    }
  132.    else if (DRI2QueryExtension(dpy, &event, &error)) {  /* DRI2 */
  133.       char *dev;
  134.       Bool ret = DRI2Connect(dpy, RootWindow(dpy, scrNum), driverName, &dev);
  135.  
  136.       if (ret)
  137.          free(dev);
  138.  
  139.       return ret;
  140.    }
  141.  
  142.    return False;
  143. }
  144.  
  145. /*
  146.  * Exported function for querying the DRI driver for a given screen.
  147.  *
  148.  * The returned char pointer points to a static array that will be
  149.  * overwritten by subsequent calls.
  150.  */
  151. _X_EXPORT const char *
  152. glXGetScreenDriver(Display * dpy, int scrNum)
  153. {
  154.    static char ret[32];
  155.    char *driverName;
  156.    if (driGetDriverName(dpy, scrNum, &driverName)) {
  157.       int len;
  158.       if (!driverName)
  159.          return NULL;
  160.       len = strlen(driverName);
  161.       if (len >= 31)
  162.          return NULL;
  163.       memcpy(ret, driverName, len + 1);
  164.       free(driverName);
  165.       return ret;
  166.    }
  167.    return NULL;
  168. }
  169.  
  170. /*
  171.  * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
  172.  *
  173.  * The returned char pointer points directly into the driver. Therefore
  174.  * it should be treated as a constant.
  175.  *
  176.  * If the driver was not found or does not support configuration NULL is
  177.  * returned.
  178.  *
  179.  * Note: The driver remains opened after this function returns.
  180.  */
  181. _X_EXPORT const char *
  182. glXGetDriverConfig(const char *driverName)
  183. {
  184.    void *handle = driOpenDriver(driverName);
  185.    const __DRIextension **extensions;
  186.  
  187.    if (!handle)
  188.       return NULL;
  189.  
  190.    extensions = driGetDriverExtensions(handle, driverName);
  191.    if (extensions) {
  192.       for (int i = 0; extensions[i]; i++) {
  193.          if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) == 0)
  194.             return ((__DRIconfigOptionsExtension *)extensions[i])->xml;
  195.       }
  196.    }
  197.  
  198.    /* Fall back to the old method */
  199.    return dlsym(handle, "__driConfigOptions");
  200. }
  201.  
  202. #ifdef XDAMAGE_1_1_INTERFACE
  203.  
  204. static GLboolean
  205. has_damage_post(Display * dpy)
  206. {
  207.    static GLboolean inited = GL_FALSE;
  208.    static GLboolean has_damage;
  209.  
  210.    if (!inited) {
  211.       int major, minor;
  212.  
  213.       if (XDamageQueryVersion(dpy, &major, &minor) &&
  214.           major == 1 && minor >= 1) {
  215.          has_damage = GL_TRUE;
  216.       }
  217.       else {
  218.          has_damage = GL_FALSE;
  219.       }
  220.       inited = GL_TRUE;
  221.    }
  222.  
  223.    return has_damage;
  224. }
  225.  
  226. static void
  227. __glXReportDamage(__DRIdrawable * driDraw,
  228.                   int x, int y,
  229.                   drm_clip_rect_t * rects, int num_rects,
  230.                   GLboolean front_buffer, void *loaderPrivate)
  231. {
  232.    XRectangle *xrects;
  233.    XserverRegion region;
  234.    int i;
  235.    int x_off, y_off;
  236.    __GLXDRIdrawable *glxDraw = loaderPrivate;
  237.    struct glx_screen *psc = glxDraw->psc;
  238.    Display *dpy = psc->dpy;
  239.    Drawable drawable;
  240.  
  241.    if (!has_damage_post(dpy))
  242.       return;
  243.  
  244.    if (front_buffer) {
  245.       x_off = x;
  246.       y_off = y;
  247.       drawable = RootWindow(dpy, psc->scr);
  248.    }
  249.    else {
  250.       x_off = 0;
  251.       y_off = 0;
  252.       drawable = glxDraw->xDrawable;
  253.    }
  254.  
  255.    xrects = malloc(sizeof(XRectangle) * num_rects);
  256.    if (xrects == NULL)
  257.       return;
  258.  
  259.    for (i = 0; i < num_rects; i++) {
  260.       xrects[i].x = rects[i].x1 + x_off;
  261.       xrects[i].y = rects[i].y1 + y_off;
  262.       xrects[i].width = rects[i].x2 - rects[i].x1;
  263.       xrects[i].height = rects[i].y2 - rects[i].y1;
  264.    }
  265.    region = XFixesCreateRegion(dpy, xrects, num_rects);
  266.    free(xrects);
  267.    XDamageAdd(dpy, drawable, region);
  268.    XFixesDestroyRegion(dpy, region);
  269. }
  270.  
  271. static const __DRIdamageExtension damageExtension = {
  272.    .base = {__DRI_DAMAGE, 1 },
  273.  
  274.    .reportDamage        = __glXReportDamage,
  275. };
  276.  
  277. #endif
  278.  
  279. static GLboolean
  280. __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
  281.                         unsigned int *index, unsigned int *stamp,
  282.                         int *X, int *Y, int *W, int *H,
  283.                         int *numClipRects, drm_clip_rect_t ** pClipRects,
  284.                         int *backX, int *backY,
  285.                         int *numBackClipRects,
  286.                         drm_clip_rect_t ** pBackClipRects,
  287.                         void *loaderPrivate)
  288. {
  289.    __GLXDRIdrawable *glxDraw = loaderPrivate;
  290.    struct glx_screen *psc = glxDraw->psc;
  291.    Display *dpy = psc->dpy;
  292.  
  293.    return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
  294.                                  index, stamp, X, Y, W, H,
  295.                                  numClipRects, pClipRects,
  296.                                  backX, backY,
  297.                                  numBackClipRects, pBackClipRects);
  298. }
  299.  
  300. static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
  301.    .base = {__DRI_GET_DRAWABLE_INFO, 1 },
  302.  
  303.    .getDrawableInfo     = __glXDRIGetDrawableInfo
  304. };
  305.  
  306. static const __DRIextension *loader_extensions[] = {
  307.    &systemTimeExtension.base,
  308.    &getDrawableInfoExtension.base,
  309. #ifdef XDAMAGE_1_1_INTERFACE
  310.    &damageExtension.base,
  311. #endif
  312.    NULL
  313. };
  314.  
  315. /**
  316.  * Perform the required libGL-side initialization and call the client-side
  317.  * driver's \c __driCreateNewScreen function.
  318.  *
  319.  * \param dpy    Display pointer.
  320.  * \param scrn   Screen number on the display.
  321.  * \param psc    DRI screen information.
  322.  * \param driDpy DRI display information.
  323.  * \param createNewScreen  Pointer to the client-side driver's
  324.  *               \c __driCreateNewScreen function.
  325.  * \returns A pointer to the \c __DRIscreen structure returned by
  326.  *          the client-side driver on success, or \c NULL on failure.
  327.  */
  328. static void *
  329. CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
  330.                     struct dri_display * driDpy)
  331. {
  332.    void *psp = NULL;
  333.    drm_handle_t hSAREA;
  334.    drmAddress pSAREA = MAP_FAILED;
  335.    char *BusID;
  336.    __DRIversion ddx_version;
  337.    __DRIversion dri_version;
  338.    __DRIversion drm_version;
  339.    __DRIframebuffer framebuffer;
  340.    int fd = -1;
  341.    int status;
  342.  
  343.    drm_magic_t magic;
  344.    drmVersionPtr version;
  345.    int newlyopened;
  346.    char *driverName;
  347.    drm_handle_t hFB;
  348.    int junk;
  349.    const __DRIconfig **driver_configs;
  350.    struct glx_config *visual, *configs = NULL, *visuals = NULL;
  351.  
  352.    /* DRI protocol version. */
  353.    dri_version.major = driDpy->driMajor;
  354.    dri_version.minor = driDpy->driMinor;
  355.    dri_version.patch = driDpy->driPatch;
  356.  
  357.    framebuffer.base = MAP_FAILED;
  358.    framebuffer.dev_priv = NULL;
  359.    framebuffer.size = 0;
  360.  
  361.    if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
  362.       ErrorMessageF("XF86DRIOpenConnection failed\n");
  363.       goto handle_error;
  364.    }
  365.  
  366.    fd = drmOpenOnce(NULL, BusID, &newlyopened);
  367.  
  368.    free(BusID);                /* No longer needed */
  369.  
  370.    if (fd < 0) {
  371.       ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
  372.       goto handle_error;
  373.    }
  374.  
  375.    if (drmGetMagic(fd, &magic)) {
  376.       ErrorMessageF("drmGetMagic failed\n");
  377.       goto handle_error;
  378.    }
  379.  
  380.    version = drmGetVersion(fd);
  381.    if (version) {
  382.       drm_version.major = version->version_major;
  383.       drm_version.minor = version->version_minor;
  384.       drm_version.patch = version->version_patchlevel;
  385.       drmFreeVersion(version);
  386.    }
  387.    else {
  388.       drm_version.major = -1;
  389.       drm_version.minor = -1;
  390.       drm_version.patch = -1;
  391.    }
  392.  
  393.    if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
  394.       ErrorMessageF("XF86DRIAuthConnection failed\n");
  395.       goto handle_error;
  396.    }
  397.  
  398.    /* Get device name (like "radeon") and the ddx version numbers.
  399.     * We'll check the version in each DRI driver's "createNewScreen"
  400.     * function. */
  401.    if (!XF86DRIGetClientDriverName(dpy, scrn,
  402.                                    &ddx_version.major,
  403.                                    &ddx_version.minor,
  404.                                    &ddx_version.patch, &driverName)) {
  405.       ErrorMessageF("XF86DRIGetClientDriverName failed\n");
  406.       goto handle_error;
  407.    }
  408.  
  409.    free(driverName);           /* No longer needed. */
  410.  
  411.    /*
  412.     * Get device-specific info.  pDevPriv will point to a struct
  413.     * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
  414.     * has information about the screen size, depth, pitch, ancilliary
  415.     * buffers, DRM mmap handles, etc.
  416.     */
  417.    if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
  418.                              &framebuffer.size, &framebuffer.stride,
  419.                              &framebuffer.dev_priv_size,
  420.                              &framebuffer.dev_priv)) {
  421.       ErrorMessageF("XF86DRIGetDeviceInfo failed\n");
  422.       goto handle_error;
  423.    }
  424.  
  425.    framebuffer.width = DisplayWidth(dpy, scrn);
  426.    framebuffer.height = DisplayHeight(dpy, scrn);
  427.  
  428.    /* Map the framebuffer region. */
  429.    status = drmMap(fd, hFB, framebuffer.size,
  430.                    (drmAddressPtr) & framebuffer.base);
  431.    if (status != 0) {
  432.       ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status));
  433.       goto handle_error;
  434.    }
  435.  
  436.    /* Map the SAREA region.  Further mmap regions may be setup in
  437.     * each DRI driver's "createNewScreen" function.
  438.     */
  439.    status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
  440.    if (status != 0) {
  441.       ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status));
  442.       goto handle_error;
  443.    }
  444.  
  445.    psp = (*psc->legacy->createNewScreen) (scrn,
  446.                                           &ddx_version,
  447.                                           &dri_version,
  448.                                           &drm_version,
  449.                                           &framebuffer,
  450.                                           pSAREA,
  451.                                           fd,
  452.                                           loader_extensions,
  453.                                           &driver_configs, psc);
  454.  
  455.    if (psp == NULL) {
  456.       ErrorMessageF("Calling driver entry point failed\n");
  457.       goto handle_error;
  458.    }
  459.  
  460.    configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
  461.    visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
  462.  
  463.    if (!configs || !visuals) {
  464.        ErrorMessageF("No matching fbConfigs or visuals found\n");
  465.        goto handle_error;
  466.    }
  467.  
  468.    glx_config_destroy_list(psc->base.configs);
  469.    psc->base.configs = configs;
  470.    glx_config_destroy_list(psc->base.visuals);
  471.    psc->base.visuals = visuals;
  472.  
  473.    psc->driver_configs = driver_configs;
  474.  
  475.    /* Visuals with depth != screen depth are subject to automatic compositing
  476.     * in the X server, so DRI1 can't render to them properly. Mark them as
  477.     * non-conformant to prevent apps from picking them up accidentally.
  478.     */
  479.    for (visual = psc->base.visuals; visual; visual = visual->next) {
  480.       XVisualInfo template;
  481.       XVisualInfo *visuals;
  482.       int num_visuals;
  483.       long mask;
  484.  
  485.       template.visualid = visual->visualID;
  486.       mask = VisualIDMask;
  487.       visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
  488.  
  489.       if (visuals) {
  490.          if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
  491.             visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
  492.  
  493.          free(visuals);
  494.       }
  495.    }
  496.  
  497.    return psp;
  498.  
  499.  handle_error:
  500.    if (configs)
  501.        glx_config_destroy_list(configs);
  502.    if (visuals)
  503.        glx_config_destroy_list(visuals);
  504.  
  505.    if (pSAREA != MAP_FAILED)
  506.       drmUnmap(pSAREA, SAREA_MAX);
  507.  
  508.    if (framebuffer.base != MAP_FAILED)
  509.       drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
  510.  
  511.    free(framebuffer.dev_priv);
  512.  
  513.    if (fd >= 0)
  514.       drmCloseOnce(fd);
  515.  
  516.    XF86DRICloseConnection(dpy, scrn);
  517.  
  518.    ErrorMessageF("reverting to software direct rendering\n");
  519.  
  520.    return NULL;
  521. }
  522.  
  523. static void
  524. dri_destroy_context(struct glx_context * context)
  525. {
  526.    struct dri_context *pcp = (struct dri_context *) context;
  527.    struct dri_screen *psc = (struct dri_screen *) context->psc;
  528.  
  529.    driReleaseDrawables(&pcp->base);
  530.  
  531.    free((char *) context->extensions);
  532.  
  533.    (*psc->core->destroyContext) (pcp->driContext);
  534.  
  535.    XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
  536.    free(pcp);
  537. }
  538.  
  539. static int
  540. dri_bind_context(struct glx_context *context, struct glx_context *old,
  541.                  GLXDrawable draw, GLXDrawable read)
  542. {
  543.    struct dri_context *pcp = (struct dri_context *) context;
  544.    struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
  545.    struct dri_drawable *pdraw, *pread;
  546.  
  547.    pdraw = (struct dri_drawable *) driFetchDrawable(context, draw);
  548.    pread = (struct dri_drawable *) driFetchDrawable(context, read);
  549.  
  550.    driReleaseDrawables(&pcp->base);
  551.  
  552.    if (pdraw == NULL || pread == NULL)
  553.       return GLXBadDrawable;
  554.  
  555.    if ((*psc->core->bindContext) (pcp->driContext,
  556.                                   pdraw->driDrawable, pread->driDrawable))
  557.       return Success;
  558.  
  559.    return GLXBadContext;
  560. }
  561.  
  562. static void
  563. dri_unbind_context(struct glx_context *context, struct glx_context *new)
  564. {
  565.    struct dri_context *pcp = (struct dri_context *) context;
  566.    struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
  567.  
  568.    (*psc->core->unbindContext) (pcp->driContext);
  569. }
  570.  
  571. static const struct glx_context_vtable dri_context_vtable = {
  572.    .destroy             = dri_destroy_context,
  573.    .bind                = dri_bind_context,
  574.    .unbind              = dri_unbind_context,
  575.    .wait_gl             = NULL,
  576.    .wait_x              = NULL,
  577.    .use_x_font          = DRI_glXUseXFont,
  578.    .bind_tex_image      = NULL,
  579.    .release_tex_image   = NULL,
  580.    .get_proc_address    = NULL,
  581. };
  582.  
  583. static struct glx_context *
  584. dri_create_context(struct glx_screen *base,
  585.                    struct glx_config *config_base,
  586.                    struct glx_context *shareList, int renderType)
  587. {
  588.    struct dri_context *pcp, *pcp_shared;
  589.    struct dri_screen *psc = (struct dri_screen *) base;
  590.    drm_context_t hwContext;
  591.    __DRIcontext *shared = NULL;
  592.    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
  593.  
  594.    if (!psc->base.driScreen)
  595.       return NULL;
  596.  
  597.    /* Check the renderType value */
  598.    if (!validate_renderType_against_config(config_base, renderType))
  599.        return NULL;
  600.  
  601.    if (shareList) {
  602.       /* If the shareList context is not a DRI context, we cannot possibly
  603.        * create a DRI context that shares it.
  604.        */
  605.       if (shareList->vtable->destroy != dri_destroy_context) {
  606.          return NULL;
  607.       }
  608.  
  609.       pcp_shared = (struct dri_context *) shareList;
  610.       shared = pcp_shared->driContext;
  611.    }
  612.  
  613.    pcp = calloc(1, sizeof *pcp);
  614.    if (pcp == NULL)
  615.       return NULL;
  616.  
  617.    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
  618.       free(pcp);
  619.       return NULL;
  620.    }
  621.  
  622.    pcp->base.renderType = renderType;
  623.  
  624.    if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
  625.                                        config->base.visualID,
  626.                                        &pcp->hwContextID, &hwContext)) {
  627.       free(pcp);
  628.       return NULL;
  629.    }
  630.  
  631.    pcp->driContext =
  632.       (*psc->legacy->createNewContext) (psc->driScreen,
  633.                                         config->driConfig,
  634.                                         renderType, shared, hwContext, pcp);
  635.    if (pcp->driContext == NULL) {
  636.       XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
  637.       free(pcp);
  638.       return NULL;
  639.    }
  640.  
  641.    pcp->base.vtable = &dri_context_vtable;
  642.  
  643.    return &pcp->base;
  644. }
  645.  
  646. static void
  647. driDestroyDrawable(__GLXDRIdrawable * pdraw)
  648. {
  649.    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
  650.    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
  651.  
  652.    (*psc->core->destroyDrawable) (pdp->driDrawable);
  653.    XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
  654.    free(pdraw);
  655. }
  656.  
  657. static __GLXDRIdrawable *
  658. driCreateDrawable(struct glx_screen *base,
  659.                   XID xDrawable,
  660.                   GLXDrawable drawable, struct glx_config *config_base)
  661. {
  662.    drm_drawable_t hwDrawable;
  663.    void *empty_attribute_list = NULL;
  664.    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
  665.    struct dri_screen *psc = (struct dri_screen *) base;
  666.    struct dri_drawable *pdp;
  667.  
  668.    /* Old dri can't handle GLX 1.3+ drawable constructors. */
  669.    if (xDrawable != drawable)
  670.       return NULL;
  671.  
  672.    pdp = calloc(1, sizeof *pdp);
  673.    if (!pdp)
  674.       return NULL;
  675.  
  676.    pdp->base.drawable = drawable;
  677.    pdp->base.psc = &psc->base;
  678.  
  679.    if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
  680.                               drawable, &hwDrawable)) {
  681.       free(pdp);
  682.       return NULL;
  683.    }
  684.  
  685.    /* Create a new drawable */
  686.    pdp->driDrawable =
  687.       (*psc->legacy->createNewDrawable) (psc->driScreen,
  688.                                          config->driConfig,
  689.                                          hwDrawable,
  690.                                          GLX_WINDOW_BIT,
  691.                                          empty_attribute_list, pdp);
  692.  
  693.    if (!pdp->driDrawable) {
  694.       XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
  695.       free(pdp);
  696.       return NULL;
  697.    }
  698.  
  699.    pdp->base.destroyDrawable = driDestroyDrawable;
  700.  
  701.    return &pdp->base;
  702. }
  703.  
  704. static int64_t
  705. driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
  706.                int64_t unused3, Bool flush)
  707. {
  708.    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
  709.    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
  710.  
  711.    if (flush) {
  712.       glFlush();
  713.    }
  714.  
  715.    (*psc->core->swapBuffers) (pdp->driDrawable);
  716.    return 0;
  717. }
  718.  
  719. static void
  720. driCopySubBuffer(__GLXDRIdrawable * pdraw,
  721.                  int x, int y, int width, int height, Bool flush)
  722. {
  723.    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
  724.    struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
  725.  
  726.    if (flush) {
  727.       glFlush();
  728.    }
  729.  
  730.    (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
  731.                                             x, y, width, height);
  732. }
  733.  
  734. static void
  735. driDestroyScreen(struct glx_screen *base)
  736. {
  737.    struct dri_screen *psc = (struct dri_screen *) base;
  738.  
  739.    /* Free the direct rendering per screen data */
  740.    if (psc->driScreen)
  741.       (*psc->core->destroyScreen) (psc->driScreen);
  742.    driDestroyConfigs(psc->driver_configs);
  743.    psc->driScreen = NULL;
  744.    if (psc->driver)
  745.       dlclose(psc->driver);
  746. }
  747.  
  748. static int
  749. driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
  750. {
  751.    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
  752.  
  753.    if (pdraw != NULL) {
  754.       struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
  755.  
  756.       if (psc->swapControl != NULL) {
  757.          psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
  758.          return 0;
  759.       }
  760.    }
  761.    return GLX_BAD_CONTEXT;
  762. }
  763.  
  764. static int
  765. driGetSwapInterval(__GLXDRIdrawable *pdraw)
  766. {
  767.    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
  768.  
  769.    if (pdraw != NULL) {
  770.       struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
  771.  
  772.       if (psc->swapControl != NULL)
  773.          return psc->swapControl->getSwapInterval(pdp->driDrawable);
  774.    }
  775.    return 0;
  776. }
  777.  
  778. /* Bind DRI1 specific extensions */
  779. static void
  780. driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
  781. {
  782.    int i;
  783.  
  784.    for (i = 0; extensions[i]; i++) {
  785.       /* No DRI2 support for swap_control at the moment, since SwapBuffers
  786.        * is done by the X server */
  787.       if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
  788.          psc->swapControl = (__DRIswapControlExtension *) extensions[i];
  789.          __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
  790.          __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
  791.       }
  792.  
  793.       if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
  794.          psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
  795.          __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
  796.       }
  797.  
  798.       if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
  799.          psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
  800.          __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
  801.       }
  802.  
  803.       if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
  804.          __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
  805.       }
  806.       /* Ignore unknown extensions */
  807.    }
  808. }
  809.  
  810. static const struct glx_screen_vtable dri_screen_vtable = {
  811.    .create_context         = dri_create_context,
  812.    .create_context_attribs = NULL,
  813.    .query_renderer_integer = NULL,
  814.    .query_renderer_string  = NULL,
  815. };
  816.  
  817. static struct glx_screen *
  818. driCreateScreen(int screen, struct glx_display *priv)
  819. {
  820.    struct dri_display *pdp;
  821.    __GLXDRIscreen *psp;
  822.    const __DRIextension **extensions;
  823.    struct dri_screen *psc;
  824.    char *driverName;
  825.    int i;
  826.  
  827.    psc = calloc(1, sizeof *psc);
  828.    if (psc == NULL)
  829.       return NULL;
  830.  
  831.    if (!glx_screen_init(&psc->base, screen, priv)) {
  832.       free(psc);
  833.       return NULL;
  834.    }
  835.  
  836.    if (!driGetDriverName(priv->dpy, screen, &driverName)) {
  837.       goto cleanup;
  838.    }
  839.  
  840.    psc->driver = driOpenDriver(driverName);
  841.    if (psc->driver == NULL)
  842.       goto cleanup;
  843.  
  844.    extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
  845.    if (extensions == NULL) {
  846.       ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
  847.       goto cleanup;
  848.    }
  849.  
  850.    for (i = 0; extensions[i]; i++) {
  851.       if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
  852.          psc->core = (__DRIcoreExtension *) extensions[i];
  853.       if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
  854.          psc->legacy = (__DRIlegacyExtension *) extensions[i];
  855.    }
  856.  
  857.    if (psc->core == NULL || psc->legacy == NULL)
  858.       goto cleanup;
  859.  
  860.    pdp = (struct dri_display *) priv->driDisplay;
  861.    psc->driScreen =
  862.       CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
  863.    if (psc->driScreen == NULL)
  864.       goto cleanup;
  865.  
  866.    extensions = psc->core->getExtensions(psc->driScreen);
  867.    driBindExtensions(psc, extensions);
  868.  
  869.    psc->base.vtable = &dri_screen_vtable;
  870.    psp = &psc->vtable;
  871.    psc->base.driScreen = psp;
  872.    if (psc->driCopySubBuffer)
  873.       psp->copySubBuffer = driCopySubBuffer;
  874.  
  875.    psp->destroyScreen = driDestroyScreen;
  876.    psp->createDrawable = driCreateDrawable;
  877.    psp->swapBuffers = driSwapBuffers;
  878.  
  879.    psp->setSwapInterval = driSetSwapInterval;
  880.    psp->getSwapInterval = driGetSwapInterval;
  881.  
  882.    free(driverName);
  883.  
  884.    return &psc->base;
  885.  
  886. cleanup:
  887.    CriticalErrorMessageF("failed to load driver: %s\n", driverName);
  888.  
  889.    free(driverName);
  890.  
  891.    if (psc->driver)
  892.       dlclose(psc->driver);
  893.    glx_screen_cleanup(&psc->base);
  894.    free(psc);
  895.  
  896.    return NULL;
  897. }
  898.  
  899. /* Called from __glXFreeDisplayPrivate.
  900.  */
  901. static void
  902. driDestroyDisplay(__GLXDRIdisplay * dpy)
  903. {
  904.    free(dpy);
  905. }
  906.  
  907. /*
  908.  * Allocate, initialize and return a __DRIdisplayPrivate object.
  909.  * This is called from __glXInitialize() when we are given a new
  910.  * display pointer.
  911.  */
  912. _X_HIDDEN __GLXDRIdisplay *
  913. driCreateDisplay(Display * dpy)
  914. {
  915.    struct dri_display *pdpyp;
  916.    int eventBase, errorBase;
  917.    int major, minor, patch;
  918.  
  919.    if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
  920.       return NULL;
  921.    }
  922.  
  923.    if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
  924.       return NULL;
  925.    }
  926.  
  927.    pdpyp = malloc(sizeof *pdpyp);
  928.    if (!pdpyp) {
  929.       return NULL;
  930.    }
  931.  
  932.    pdpyp->driMajor = major;
  933.    pdpyp->driMinor = minor;
  934.    pdpyp->driPatch = patch;
  935.  
  936.    pdpyp->base.destroyDisplay = driDestroyDisplay;
  937.    pdpyp->base.createScreen = driCreateScreen;
  938.  
  939.    return &pdpyp->base;
  940. }
  941.  
  942. #endif /* GLX_DIRECT_RENDERING */
  943.