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