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