Tizen 2.0 Release
[profile/ivi/osmesa.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    driReleaseDrawables(&pcp->base);
507
508    if (context->xid)
509       glx_send_destroy_context(psc->base.dpy, context->xid);
510
511    if (context->extensions)
512       XFree((char *) context->extensions);
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    driReleaseDrawables(&pcp->base);
532
533    if (pdraw == NULL || pread == NULL)
534       return GLXBadDrawable;
535
536    if ((*psc->core->bindContext) (pcp->driContext,
537                                   pdraw->driDrawable, pread->driDrawable))
538       return Success;
539
540    return GLXBadContext;
541 }
542
543 static void
544 dri_unbind_context(struct glx_context *context, struct glx_context *new)
545 {
546    struct dri_context *pcp = (struct dri_context *) context;
547    struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
548
549    (*psc->core->unbindContext) (pcp->driContext);
550 }
551
552 static const struct glx_context_vtable dri_context_vtable = {
553    dri_destroy_context,
554    dri_bind_context,
555    dri_unbind_context,
556    NULL,
557    NULL,
558    DRI_glXUseXFont,
559    NULL,
560    NULL,
561    NULL, /* get_proc_address */
562 };
563
564 static struct glx_context *
565 dri_create_context(struct glx_screen *base,
566                    struct glx_config *config_base,
567                    struct glx_context *shareList, int renderType)
568 {
569    struct dri_context *pcp, *pcp_shared;
570    struct dri_screen *psc = (struct dri_screen *) base;
571    drm_context_t hwContext;
572    __DRIcontext *shared = NULL;
573    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
574
575    if (!psc->base.driScreen)
576       return NULL;
577
578    if (shareList) {
579       pcp_shared = (struct dri_context *) shareList;
580       shared = pcp_shared->driContext;
581    }
582
583    pcp = Xmalloc(sizeof *pcp);
584    if (pcp == NULL)
585       return NULL;
586
587    memset(pcp, 0, sizeof *pcp);
588    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
589       Xfree(pcp);
590       return NULL;
591    }
592
593    if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
594                                        config->base.visualID,
595                                        &pcp->hwContextID, &hwContext)) {
596       Xfree(pcp);
597       return NULL;
598    }
599
600    pcp->driContext =
601       (*psc->legacy->createNewContext) (psc->driScreen,
602                                         config->driConfig,
603                                         renderType, shared, hwContext, pcp);
604    if (pcp->driContext == NULL) {
605       XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
606       Xfree(pcp);
607       return NULL;
608    }
609
610    pcp->base.vtable = &dri_context_vtable;
611
612    return &pcp->base;
613 }
614
615 static void
616 driDestroyDrawable(__GLXDRIdrawable * pdraw)
617 {
618    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
619    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
620
621    (*psc->core->destroyDrawable) (pdp->driDrawable);
622    XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
623    Xfree(pdraw);
624 }
625
626 static __GLXDRIdrawable *
627 driCreateDrawable(struct glx_screen *base,
628                   XID xDrawable,
629                   GLXDrawable drawable, struct glx_config *config_base)
630 {
631    drm_drawable_t hwDrawable;
632    void *empty_attribute_list = NULL;
633    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
634    struct dri_screen *psc = (struct dri_screen *) base;
635    struct dri_drawable *pdp;
636
637    /* Old dri can't handle GLX 1.3+ drawable constructors. */
638    if (xDrawable != drawable)
639       return NULL;
640
641    pdp = Xmalloc(sizeof *pdp);
642    if (!pdp)
643       return NULL;
644
645    memset(pdp, 0, sizeof *pdp);
646    pdp->base.drawable = drawable;
647    pdp->base.psc = &psc->base;
648
649    if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
650                               drawable, &hwDrawable)) {
651       Xfree(pdp);
652       return NULL;
653    }
654
655    /* Create a new drawable */
656    pdp->driDrawable =
657       (*psc->legacy->createNewDrawable) (psc->driScreen,
658                                          config->driConfig,
659                                          hwDrawable,
660                                          GLX_WINDOW_BIT,
661                                          empty_attribute_list, pdp);
662
663    if (!pdp->driDrawable) {
664       XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
665       Xfree(pdp);
666       return NULL;
667    }
668
669    pdp->base.destroyDrawable = driDestroyDrawable;
670
671    return &pdp->base;
672 }
673
674 static int64_t
675 driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
676                int64_t unused3)
677 {
678    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
679    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
680
681    (*psc->core->swapBuffers) (pdp->driDrawable);
682    return 0;
683 }
684
685 static void
686 driCopySubBuffer(__GLXDRIdrawable * pdraw,
687                  int x, int y, int width, int height)
688 {
689    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
690    struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
691
692    (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
693                                             x, y, width, height);
694 }
695
696 static void
697 driDestroyScreen(struct glx_screen *base)
698 {
699    struct dri_screen *psc = (struct dri_screen *) base;
700
701    /* Free the direct rendering per screen data */
702    if (psc->driScreen)
703       (*psc->core->destroyScreen) (psc->driScreen);
704    driDestroyConfigs(psc->driver_configs);
705    psc->driScreen = NULL;
706    if (psc->driver)
707       dlclose(psc->driver);
708 }
709
710 #ifdef __DRI_SWAP_BUFFER_COUNTER
711
712 static int
713 driDrawableGetMSC(struct glx_screen *base, __GLXDRIdrawable *pdraw,
714                    int64_t *ust, int64_t *msc, int64_t *sbc)
715 {
716    struct dri_screen *psc = (struct dri_screen *) base;
717    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
718
719    if (pdp && psc->sbc && psc->msc)
720       return ( (*psc->msc->getMSC)(psc->driScreen, msc) == 0 &&
721                (*psc->sbc->getSBC)(pdp->driDrawable, sbc) == 0 && 
722                __glXGetUST(ust) == 0 );
723 }
724
725 static int
726 driWaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
727                int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
728 {
729    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
730    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
731
732    if (pdp != NULL && psc->msc != NULL) {
733       ret = (*psc->msc->waitForMSC) (pdp->driDrawable, target_msc,
734                                      divisor, remainder, msc, sbc);
735
736       /* __glXGetUST returns zero on success and non-zero on failure.
737        * This function returns True on success and False on failure.
738        */
739       return ret == 0 && __glXGetUST(ust) == 0;
740    }
741 }
742
743 static int
744 driWaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
745                int64_t *msc, int64_t *sbc)
746 {
747    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
748
749    if (pdp != NULL && psc->sbc != NULL) {
750       ret =
751          (*psc->sbc->waitForSBC) (pdp->driDrawable, target_sbc, msc, sbc);
752
753       /* __glXGetUST returns zero on success and non-zero on failure.
754        * This function returns True on success and False on failure.
755        */
756       return ((ret == 0) && (__glXGetUST(ust) == 0));
757    }
758
759    return DRI2WaitSBC(pdp->base.psc->dpy,
760                       pdp->base.xDrawable, target_sbc, ust, msc, sbc);
761 }
762
763 #endif
764
765 static int
766 driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
767 {
768    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
769    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
770
771    if (psc->swapControl != NULL && pdraw != NULL) {
772       psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
773       return 0;
774    }
775
776    return GLX_BAD_CONTEXT;
777 }
778
779 static int
780 driGetSwapInterval(__GLXDRIdrawable *pdraw)
781 {
782    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
783    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
784
785    if (psc->swapControl != NULL && pdraw != NULL)
786       return psc->swapControl->getSwapInterval(pdp->driDrawable);
787
788    return 0;
789 }
790
791 /* Bind DRI1 specific extensions */
792 static void
793 driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
794 {
795    int i;
796
797    for (i = 0; extensions[i]; i++) {
798       /* No DRI2 support for swap_control at the moment, since SwapBuffers
799        * is done by the X server */
800       if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
801          psc->swapControl = (__DRIswapControlExtension *) extensions[i];
802          __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
803          __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
804       }
805
806       if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
807          psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
808          __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
809       }
810
811       if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
812          psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
813          __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
814       }
815
816       if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
817          __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
818       }
819       /* Ignore unknown extensions */
820    }
821 }
822
823 static const struct glx_screen_vtable dri_screen_vtable = {
824    dri_create_context
825 };
826
827 static struct glx_screen *
828 driCreateScreen(int screen, struct glx_display *priv)
829 {
830    struct dri_display *pdp;
831    __GLXDRIscreen *psp;
832    const __DRIextension **extensions;
833    struct dri_screen *psc;
834    char *driverName;
835    int i;
836
837    psc = Xcalloc(1, sizeof *psc);
838    if (psc == NULL)
839       return NULL;
840
841    memset(psc, 0, sizeof *psc);
842    if (!glx_screen_init(&psc->base, screen, priv)) {
843       Xfree(psc);
844       return NULL;
845    }
846
847    if (!driGetDriverName(priv->dpy, screen, &driverName)) {
848       goto cleanup;
849    }
850
851    psc->driver = driOpenDriver(driverName);
852    Xfree(driverName);
853    if (psc->driver == NULL)
854       goto cleanup;
855
856    extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
857    if (extensions == NULL) {
858       ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
859       goto cleanup;
860    }
861
862    for (i = 0; extensions[i]; i++) {
863       if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
864          psc->core = (__DRIcoreExtension *) extensions[i];
865       if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
866          psc->legacy = (__DRIlegacyExtension *) extensions[i];
867    }
868
869    if (psc->core == NULL || psc->legacy == NULL)
870       goto cleanup;
871
872    pdp = (struct dri_display *) priv->driDisplay;
873    psc->driScreen =
874       CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
875    if (psc->driScreen == NULL)
876       goto cleanup;
877
878    extensions = psc->core->getExtensions(psc->driScreen);
879    driBindExtensions(psc, extensions);
880
881    psc->base.vtable = &dri_screen_vtable;
882    psp = &psc->vtable;
883    psc->base.driScreen = psp;
884    if (psc->driCopySubBuffer)
885       psp->copySubBuffer = driCopySubBuffer;
886
887    psp->destroyScreen = driDestroyScreen;
888    psp->createDrawable = driCreateDrawable;
889    psp->swapBuffers = driSwapBuffers;
890
891 #ifdef __DRI_SWAP_BUFFER_COUNTER
892    psp->getDrawableMSC = driDrawableGetMSC;
893    psp->waitForMSC = driWaitForMSC;
894    psp->waitForSBC = driWaitForSBC;
895 #endif
896
897    psp->setSwapInterval = driSetSwapInterval;
898    psp->getSwapInterval = driGetSwapInterval;
899
900    return &psc->base;
901
902 cleanup:
903    if (psc->driver)
904       dlclose(psc->driver);
905    glx_screen_cleanup(&psc->base);
906    Xfree(psc);
907
908    return NULL;
909 }
910
911 /* Called from __glXFreeDisplayPrivate.
912  */
913 static void
914 driDestroyDisplay(__GLXDRIdisplay * dpy)
915 {
916    Xfree(dpy);
917 }
918
919 /*
920  * Allocate, initialize and return a __DRIdisplayPrivate object.
921  * This is called from __glXInitialize() when we are given a new
922  * display pointer.
923  */
924 _X_HIDDEN __GLXDRIdisplay *
925 driCreateDisplay(Display * dpy)
926 {
927    struct dri_display *pdpyp;
928    int eventBase, errorBase;
929    int major, minor, patch;
930
931    if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
932       return NULL;
933    }
934
935    if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
936       return NULL;
937    }
938
939    pdpyp = Xmalloc(sizeof *pdpyp);
940    if (!pdpyp) {
941       return NULL;
942    }
943
944    pdpyp->driMajor = major;
945    pdpyp->driMinor = minor;
946    pdpyp->driPatch = patch;
947
948    pdpyp->base.destroyDisplay = driDestroyDisplay;
949    pdpyp->base.createScreen = driCreateScreen;
950
951    return &pdpyp->base;
952 }
953
954 #endif /* GLX_DIRECT_RENDERING */