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