• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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., "i965", "radeon", "nouveau", etc).
98  * Return True for success, False for failure.
99  */
100 static Bool
driGetDriverName(Display * dpy,int scrNum,char ** driverName)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 *
glXGetScreenDriver(Display * dpy,int scrNum)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 *
glXGetDriverConfig(const char * driverName)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
has_damage_post(Display * dpy)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
__glXReportDamage(__DRIdrawable * driDraw,int x,int y,drm_clip_rect_t * rects,int num_rects,GLboolean front_buffer,void * loaderPrivate)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
__glXDRIGetDrawableInfo(__DRIdrawable * drawable,unsigned int * index,unsigned int * stamp,int * X,int * Y,int * W,int * H,int * numClipRects,drm_clip_rect_t ** pClipRects,int * backX,int * backY,int * numBackClipRects,drm_clip_rect_t ** pBackClipRects,void * loaderPrivate)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 *
CallCreateNewScreen(Display * dpy,int scrn,struct dri_screen * psc,struct dri_display * driDpy)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, *configs = NULL, *visuals = NULL;
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 "radeon") 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    configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
450    visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
451 
452    if (!configs || !visuals)
453        goto handle_error;
454 
455    glx_config_destroy_list(psc->base.configs);
456    psc->base.configs = configs;
457    glx_config_destroy_list(psc->base.visuals);
458    psc->base.visuals = visuals;
459 
460    psc->driver_configs = driver_configs;
461 
462    /* Visuals with depth != screen depth are subject to automatic compositing
463     * in the X server, so DRI1 can't render to them properly. Mark them as
464     * non-conformant to prevent apps from picking them up accidentally.
465     */
466    for (visual = psc->base.visuals; visual; visual = visual->next) {
467       XVisualInfo template;
468       XVisualInfo *visuals;
469       int num_visuals;
470       long mask;
471 
472       template.visualid = visual->visualID;
473       mask = VisualIDMask;
474       visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
475 
476       if (visuals) {
477          if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
478             visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
479 
480          XFree(visuals);
481       }
482    }
483 
484    return psp;
485 
486  handle_error:
487    if (configs)
488        glx_config_destroy_list(configs);
489    if (visuals)
490        glx_config_destroy_list(visuals);
491 
492    if (pSAREA != MAP_FAILED)
493       drmUnmap(pSAREA, SAREA_MAX);
494 
495    if (framebuffer.base != MAP_FAILED)
496       drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
497 
498    if (framebuffer.dev_priv != NULL)
499       Xfree(framebuffer.dev_priv);
500 
501    if (fd >= 0)
502       drmCloseOnce(fd);
503 
504    XF86DRICloseConnection(dpy, scrn);
505 
506    ErrorMessageF("reverting to software direct rendering\n");
507 
508    return NULL;
509 }
510 
511 static void
dri_destroy_context(struct glx_context * context)512 dri_destroy_context(struct glx_context * context)
513 {
514    struct dri_context *pcp = (struct dri_context *) context;
515    struct dri_screen *psc = (struct dri_screen *) context->psc;
516 
517    driReleaseDrawables(&pcp->base);
518 
519    if (context->extensions)
520       XFree((char *) context->extensions);
521 
522    (*psc->core->destroyContext) (pcp->driContext);
523 
524    XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
525    Xfree(pcp);
526 }
527 
528 static int
dri_bind_context(struct glx_context * context,struct glx_context * old,GLXDrawable draw,GLXDrawable read)529 dri_bind_context(struct glx_context *context, struct glx_context *old,
530 		 GLXDrawable draw, GLXDrawable read)
531 {
532    struct dri_context *pcp = (struct dri_context *) context;
533    struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
534    struct dri_drawable *pdraw, *pread;
535 
536    pdraw = (struct dri_drawable *) driFetchDrawable(context, draw);
537    pread = (struct dri_drawable *) driFetchDrawable(context, read);
538 
539    driReleaseDrawables(&pcp->base);
540 
541    if (pdraw == NULL || pread == NULL)
542       return GLXBadDrawable;
543 
544    if ((*psc->core->bindContext) (pcp->driContext,
545 				  pdraw->driDrawable, pread->driDrawable))
546       return Success;
547 
548    return GLXBadContext;
549 }
550 
551 static void
dri_unbind_context(struct glx_context * context,struct glx_context * new)552 dri_unbind_context(struct glx_context *context, struct glx_context *new)
553 {
554    struct dri_context *pcp = (struct dri_context *) context;
555    struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
556 
557    (*psc->core->unbindContext) (pcp->driContext);
558 }
559 
560 static const struct glx_context_vtable dri_context_vtable = {
561    dri_destroy_context,
562    dri_bind_context,
563    dri_unbind_context,
564    NULL,
565    NULL,
566    DRI_glXUseXFont,
567    NULL,
568    NULL,
569    NULL, /* get_proc_address */
570 };
571 
572 static struct glx_context *
dri_create_context(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,int renderType)573 dri_create_context(struct glx_screen *base,
574 		   struct glx_config *config_base,
575 		   struct glx_context *shareList, int renderType)
576 {
577    struct dri_context *pcp, *pcp_shared;
578    struct dri_screen *psc = (struct dri_screen *) base;
579    drm_context_t hwContext;
580    __DRIcontext *shared = NULL;
581    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
582 
583    if (!psc->base.driScreen)
584       return NULL;
585 
586    if (shareList) {
587       /* If the shareList context is not a DRI context, we cannot possibly
588        * create a DRI context that shares it.
589        */
590       if (shareList->vtable->destroy != dri_destroy_context) {
591 	 return NULL;
592       }
593 
594       pcp_shared = (struct dri_context *) shareList;
595       shared = pcp_shared->driContext;
596    }
597 
598    pcp = Xmalloc(sizeof *pcp);
599    if (pcp == NULL)
600       return NULL;
601 
602    memset(pcp, 0, sizeof *pcp);
603    if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
604       Xfree(pcp);
605       return NULL;
606    }
607 
608    if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
609                                        config->base.visualID,
610                                        &pcp->hwContextID, &hwContext)) {
611       Xfree(pcp);
612       return NULL;
613    }
614 
615    pcp->driContext =
616       (*psc->legacy->createNewContext) (psc->driScreen,
617                                         config->driConfig,
618                                         renderType, shared, hwContext, pcp);
619    if (pcp->driContext == NULL) {
620       XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
621       Xfree(pcp);
622       return NULL;
623    }
624 
625    pcp->base.vtable = &dri_context_vtable;
626 
627    return &pcp->base;
628 }
629 
630 static void
driDestroyDrawable(__GLXDRIdrawable * pdraw)631 driDestroyDrawable(__GLXDRIdrawable * pdraw)
632 {
633    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
634    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
635 
636    (*psc->core->destroyDrawable) (pdp->driDrawable);
637    XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
638    Xfree(pdraw);
639 }
640 
641 static __GLXDRIdrawable *
driCreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,struct glx_config * config_base)642 driCreateDrawable(struct glx_screen *base,
643                   XID xDrawable,
644                   GLXDrawable drawable, struct glx_config *config_base)
645 {
646    drm_drawable_t hwDrawable;
647    void *empty_attribute_list = NULL;
648    __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
649    struct dri_screen *psc = (struct dri_screen *) base;
650    struct dri_drawable *pdp;
651 
652    /* Old dri can't handle GLX 1.3+ drawable constructors. */
653    if (xDrawable != drawable)
654       return NULL;
655 
656    pdp = Xmalloc(sizeof *pdp);
657    if (!pdp)
658       return NULL;
659 
660    memset(pdp, 0, sizeof *pdp);
661    pdp->base.drawable = drawable;
662    pdp->base.psc = &psc->base;
663 
664    if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
665 			      drawable, &hwDrawable)) {
666       Xfree(pdp);
667       return NULL;
668    }
669 
670    /* Create a new drawable */
671    pdp->driDrawable =
672       (*psc->legacy->createNewDrawable) (psc->driScreen,
673                                          config->driConfig,
674                                          hwDrawable,
675                                          GLX_WINDOW_BIT,
676                                          empty_attribute_list, pdp);
677 
678    if (!pdp->driDrawable) {
679       XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
680       Xfree(pdp);
681       return NULL;
682    }
683 
684    pdp->base.destroyDrawable = driDestroyDrawable;
685 
686    return &pdp->base;
687 }
688 
689 static int64_t
driSwapBuffers(__GLXDRIdrawable * pdraw,int64_t unused1,int64_t unused2,int64_t unused3)690 driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
691 	       int64_t unused3)
692 {
693    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
694    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
695 
696    (*psc->core->swapBuffers) (pdp->driDrawable);
697    return 0;
698 }
699 
700 static void
driCopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height)701 driCopySubBuffer(__GLXDRIdrawable * pdraw,
702                  int x, int y, int width, int height)
703 {
704    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
705    struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
706 
707    (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
708 					    x, y, width, height);
709 }
710 
711 static void
driDestroyScreen(struct glx_screen * base)712 driDestroyScreen(struct glx_screen *base)
713 {
714    struct dri_screen *psc = (struct dri_screen *) base;
715 
716    /* Free the direct rendering per screen data */
717    if (psc->driScreen)
718       (*psc->core->destroyScreen) (psc->driScreen);
719    driDestroyConfigs(psc->driver_configs);
720    psc->driScreen = NULL;
721    if (psc->driver)
722       dlclose(psc->driver);
723 }
724 
725 #ifdef __DRI_SWAP_BUFFER_COUNTER
726 
727 static int
driDrawableGetMSC(struct glx_screen * base,__GLXDRIdrawable * pdraw,int64_t * ust,int64_t * msc,int64_t * sbc)728 driDrawableGetMSC(struct glx_screen *base, __GLXDRIdrawable *pdraw,
729 		   int64_t *ust, int64_t *msc, int64_t *sbc)
730 {
731    struct dri_screen *psc = (struct dri_screen *) base;
732    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
733 
734    if (pdp && psc->sbc && psc->msc)
735       return ( (*psc->msc->getMSC)(psc->driScreen, msc) == 0 &&
736 	       (*psc->sbc->getSBC)(pdp->driDrawable, sbc) == 0 &&
737 	       __glXGetUST(ust) == 0 );
738 }
739 
740 static int
driWaitForMSC(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,int64_t * ust,int64_t * msc,int64_t * sbc)741 driWaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
742 	       int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
743 {
744    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
745    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
746 
747    if (pdp != NULL && psc->msc != NULL) {
748       ret = (*psc->msc->waitForMSC) (pdp->driDrawable, target_msc,
749 				     divisor, remainder, msc, sbc);
750 
751       /* __glXGetUST returns zero on success and non-zero on failure.
752        * This function returns True on success and False on failure.
753        */
754       return ret == 0 && __glXGetUST(ust) == 0;
755    }
756 }
757 
758 static int
driWaitForSBC(__GLXDRIdrawable * pdraw,int64_t target_sbc,int64_t * ust,int64_t * msc,int64_t * sbc)759 driWaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
760 	       int64_t *msc, int64_t *sbc)
761 {
762    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
763 
764    if (pdp != NULL && psc->sbc != NULL) {
765       ret =
766          (*psc->sbc->waitForSBC) (pdp->driDrawable, target_sbc, msc, sbc);
767 
768       /* __glXGetUST returns zero on success and non-zero on failure.
769        * This function returns True on success and False on failure.
770        */
771       return ((ret == 0) && (__glXGetUST(ust) == 0));
772    }
773 
774    return DRI2WaitSBC(pdp->base.psc->dpy,
775 		      pdp->base.xDrawable, target_sbc, ust, msc, sbc);
776 }
777 
778 #endif
779 
780 static int
driSetSwapInterval(__GLXDRIdrawable * pdraw,int interval)781 driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
782 {
783    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
784    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
785 
786    if (psc->swapControl != NULL && pdraw != NULL) {
787       psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
788       return 0;
789    }
790 
791    return GLX_BAD_CONTEXT;
792 }
793 
794 static int
driGetSwapInterval(__GLXDRIdrawable * pdraw)795 driGetSwapInterval(__GLXDRIdrawable *pdraw)
796 {
797    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
798    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
799 
800    if (psc->swapControl != NULL && pdraw != NULL)
801       return psc->swapControl->getSwapInterval(pdp->driDrawable);
802 
803    return 0;
804 }
805 
806 /* Bind DRI1 specific extensions */
807 static void
driBindExtensions(struct dri_screen * psc,const __DRIextension ** extensions)808 driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
809 {
810    int i;
811 
812    for (i = 0; extensions[i]; i++) {
813       /* No DRI2 support for swap_control at the moment, since SwapBuffers
814        * is done by the X server */
815       if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
816 	 psc->swapControl = (__DRIswapControlExtension *) extensions[i];
817 	 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
818 	 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
819       }
820 
821       if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
822          psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
823          __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
824       }
825 
826       if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
827 	 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
828 	 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
829       }
830 
831       if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
832 	 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
833       }
834       /* Ignore unknown extensions */
835    }
836 }
837 
838 static const struct glx_screen_vtable dri_screen_vtable = {
839    dri_create_context,
840    NULL
841 };
842 
843 static struct glx_screen *
driCreateScreen(int screen,struct glx_display * priv)844 driCreateScreen(int screen, struct glx_display *priv)
845 {
846    struct dri_display *pdp;
847    __GLXDRIscreen *psp;
848    const __DRIextension **extensions;
849    struct dri_screen *psc;
850    char *driverName;
851    int i;
852 
853    psc = Xcalloc(1, sizeof *psc);
854    if (psc == NULL)
855       return NULL;
856 
857    memset(psc, 0, sizeof *psc);
858    if (!glx_screen_init(&psc->base, screen, priv)) {
859       Xfree(psc);
860       return NULL;
861    }
862 
863    if (!driGetDriverName(priv->dpy, screen, &driverName)) {
864       goto cleanup;
865    }
866 
867    psc->driver = driOpenDriver(driverName);
868    if (psc->driver == NULL)
869       goto cleanup;
870 
871    extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
872    if (extensions == NULL) {
873       ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
874       goto cleanup;
875    }
876 
877    for (i = 0; extensions[i]; i++) {
878       if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
879 	 psc->core = (__DRIcoreExtension *) extensions[i];
880       if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
881 	 psc->legacy = (__DRIlegacyExtension *) extensions[i];
882    }
883 
884    if (psc->core == NULL || psc->legacy == NULL)
885       goto cleanup;
886 
887    pdp = (struct dri_display *) priv->driDisplay;
888    psc->driScreen =
889       CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
890    if (psc->driScreen == NULL)
891       goto cleanup;
892 
893    extensions = psc->core->getExtensions(psc->driScreen);
894    driBindExtensions(psc, extensions);
895 
896    psc->base.vtable = &dri_screen_vtable;
897    psp = &psc->vtable;
898    psc->base.driScreen = psp;
899    if (psc->driCopySubBuffer)
900       psp->copySubBuffer = driCopySubBuffer;
901 
902    psp->destroyScreen = driDestroyScreen;
903    psp->createDrawable = driCreateDrawable;
904    psp->swapBuffers = driSwapBuffers;
905 
906 #ifdef __DRI_SWAP_BUFFER_COUNTER
907    psp->getDrawableMSC = driDrawableGetMSC;
908    psp->waitForMSC = driWaitForMSC;
909    psp->waitForSBC = driWaitForSBC;
910 #endif
911 
912    psp->setSwapInterval = driSetSwapInterval;
913    psp->getSwapInterval = driGetSwapInterval;
914 
915    free(driverName);
916 
917    return &psc->base;
918 
919 cleanup:
920    CriticalErrorMessageF("failed to load driver: %s\n", driverName);
921 
922    free(driverName);
923 
924    if (psc->driver)
925       dlclose(psc->driver);
926    glx_screen_cleanup(&psc->base);
927    Xfree(psc);
928 
929    return NULL;
930 }
931 
932 /* Called from __glXFreeDisplayPrivate.
933  */
934 static void
driDestroyDisplay(__GLXDRIdisplay * dpy)935 driDestroyDisplay(__GLXDRIdisplay * dpy)
936 {
937    Xfree(dpy);
938 }
939 
940 /*
941  * Allocate, initialize and return a __DRIdisplayPrivate object.
942  * This is called from __glXInitialize() when we are given a new
943  * display pointer.
944  */
945 _X_HIDDEN __GLXDRIdisplay *
driCreateDisplay(Display * dpy)946 driCreateDisplay(Display * dpy)
947 {
948    struct dri_display *pdpyp;
949    int eventBase, errorBase;
950    int major, minor, patch;
951 
952    if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
953       return NULL;
954    }
955 
956    if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
957       return NULL;
958    }
959 
960    pdpyp = Xmalloc(sizeof *pdpyp);
961    if (!pdpyp) {
962       return NULL;
963    }
964 
965    pdpyp->driMajor = major;
966    pdpyp->driMinor = minor;
967    pdpyp->driPatch = patch;
968 
969    pdpyp->base.destroyDisplay = driDestroyDisplay;
970    pdpyp->base.createScreen = driCreateScreen;
971 
972    return &pdpyp->base;
973 }
974 
975 #endif /* GLX_DIRECT_RENDERING */
976