OSDN Git Service

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