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