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