925c7efe6e85a76dbf080c267ec167d2bcbc036f
[mesa.git] / src / mesa / drivers / dri / common / dri_util.c
1 /* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */
2 /**
3 * \file dri_util.c
4 * DRI utility functions.
5 *
6 * This module acts as glue between GLX and the actual hardware driver. A DRI
7 * driver doesn't really \e have to use any of this - it's optional. But, some
8 * useful stuff is done here that otherwise would have to be duplicated in most
9 * drivers.
10 *
11 * Basically, these utility functions take care of some of the dirty details of
12 * screen initialization, context creation, context binding, DRM setup, etc.
13 *
14 * These functions are compiled into each DRI driver so libGL.so knows nothing
15 * about them.
16 *
17 * \note
18 * When \c DRI_NEW_INTERFACE_ONLY is defined, code is built / not built so
19 * that only the "new" libGL-to-driver interfaces are supported. This breaks
20 * backwards compatability. However, this may be necessary when DRI drivers
21 * are built to be used in non-XFree86 environments.
22 *
23 * \todo There are still some places in the code that need to be wrapped with
24 * \c DRI_NEW_INTERFACE_ONLY.
25 */
26
27
28 #ifdef GLX_DIRECT_RENDERING
29
30 #include <inttypes.h>
31 #include <assert.h>
32 #include <stdarg.h>
33 #include <unistd.h>
34 #include <sys/mman.h>
35 #include <X11/Xlibint.h>
36 #include <Xext.h>
37 #include <extutil.h>
38 #include <stdio.h>
39 #include "dri_util.h"
40 #include "xf86dri.h"
41 #include "sarea.h"
42 #include "glcontextmodes.h"
43
44 /*#define DRI_NEW_INTERFACE_ONLY*/
45
46 #ifndef GLX_OML_sync_control
47 typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
48 #endif
49
50 /**
51 * This is used in a couple of places that call \c driCreateNewDrawable.
52 */
53 static const int empty_attribute_list[1] = { None };
54
55 /**
56 * Function used to determine if a drawable (window) still exists. Ideally
57 * this function comes from libGL. With older versions of libGL from XFree86
58 * we can fall-back to an internal version.
59 *
60 * \sa __driWindowExists __glXWindowExists
61 */
62 static PFNGLXWINDOWEXISTSPROC window_exists;
63
64 typedef Bool (*PFNGLXCREATECONTEXTWITHCONFIGPROC)( Display*, int, int, void *,
65 drmContextPtr );
66
67 static PFNGLXCREATECONTEXTWITHCONFIGPROC create_context_with_config;
68
69 /**
70 * Cached copy of the internal API version used by libGL and the client-side
71 * DRI driver.
72 */
73 static int api_ver = 0;
74
75 /* forward declarations */
76 static int driQueryFrameTracking( Display * dpy, void * priv,
77 int64_t * sbc, int64_t * missedFrames, float * lastMissedUsage,
78 float * usage );
79
80 static void *driCreateNewDrawable(Display *dpy, const __GLcontextModes *modes,
81 GLXDrawable draw, __DRIdrawable *pdraw, int renderType, const int *attrs);
82
83 static void driDestroyDrawable(Display *dpy, void *drawablePrivate);
84
85
86
87
88 #ifdef not_defined
89 static Bool driFeatureOn(const char *name)
90 {
91 char *env = getenv(name);
92
93 if (!env) return GL_FALSE;
94 if (!strcasecmp(env, "enable")) return GL_TRUE;
95 if (!strcasecmp(env, "1")) return GL_TRUE;
96 if (!strcasecmp(env, "on")) return GL_TRUE;
97 if (!strcasecmp(env, "true")) return GL_TRUE;
98 if (!strcasecmp(env, "t")) return GL_TRUE;
99 if (!strcasecmp(env, "yes")) return GL_TRUE;
100 if (!strcasecmp(env, "y")) return GL_TRUE;
101
102 return GL_FALSE;
103 }
104 #endif /* not_defined */
105
106
107 /**
108 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
109 * is set.
110 *
111 * Is called from the drivers.
112 *
113 * \param f \c printf like format string.
114 */
115 void
116 __driUtilMessage(const char *f, ...)
117 {
118 va_list args;
119
120 if (getenv("LIBGL_DEBUG")) {
121 fprintf(stderr, "libGL error: \n");
122 va_start(args, f);
123 vfprintf(stderr, f, args);
124 va_end(args);
125 fprintf(stderr, "\n");
126 }
127 }
128
129
130 /*****************************************************************/
131 /** \name Visual utility functions */
132 /*****************************************************************/
133 /*@{*/
134
135 #ifndef DRI_NEW_INTERFACE_ONLY
136 /**
137 * Find a \c __GLcontextModes structure matching the given visual ID.
138 *
139 * \param dpy Display to search for a matching configuration.
140 * \param scrn Screen number on \c dpy to be searched.
141 * \param vid Desired \c VisualID to find.
142 *
143 * \returns A pointer to a \c __GLcontextModes structure that matches \c vid,
144 * if found, or \c NULL if no match is found.
145 */
146 static const __GLcontextModes *
147 findConfigMode(Display *dpy, int scrn, VisualID vid,
148 const __DRIscreen * pDRIScreen)
149 {
150 if ( (pDRIScreen != NULL) && (pDRIScreen->private != NULL) ) {
151 const __DRIscreenPrivate * const psp =
152 (const __DRIscreenPrivate *) pDRIScreen->private;
153
154 return _gl_context_modes_find_visual( psp->modes, vid );
155 }
156
157 return NULL;
158 }
159
160
161 /**
162 * This function is a hack to work-around old versions of libGL.so that
163 * do not export \c XF86DRICreateContextWithConfig. I would modify the
164 * code to just use this function, but the stand-alone driver (i.e., DRI
165 * drivers that are built to work without XFree86) shouldn't have to know
166 * about X structures like a \c Visual.
167 */
168 static Bool
169 fake_XF86DRICreateContextWithConfig( Display* dpy, int screen, int configID,
170 XID* context, drmContextPtr hHWContext )
171 {
172 Visual vis;
173
174 vis.visualid = configID;
175 return XF86DRICreateContext( dpy, screen, & vis, context, hHWContext );
176 }
177 #endif /* DRI_NEW_INTERFACE_ONLY */
178
179 /*@}*/
180
181
182 /*****************************************************************/
183 /** \name Drawable list management */
184 /*****************************************************************/
185 /*@{*/
186
187 static Bool __driAddDrawable(void *drawHash, __DRIdrawable *pdraw)
188 {
189 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
190
191 if (drmHashInsert(drawHash, pdp->draw, pdraw))
192 return GL_FALSE;
193
194 return GL_TRUE;
195 }
196
197 static __DRIdrawable *__driFindDrawable(void *drawHash, GLXDrawable draw)
198 {
199 int retcode;
200 __DRIdrawable *pdraw;
201
202 retcode = drmHashLookup(drawHash, draw, (void **)&pdraw);
203 if (retcode)
204 return NULL;
205
206 return pdraw;
207 }
208
209 static void __driRemoveDrawable(void *drawHash, __DRIdrawable *pdraw)
210 {
211 int retcode;
212 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
213
214 retcode = drmHashLookup(drawHash, pdp->draw, (void **)&pdraw);
215 if (!retcode) { /* Found */
216 drmHashDelete(drawHash, pdp->draw);
217 }
218 }
219
220 #ifndef DRI_NEW_INTERFACE_ONLY
221 static Bool __driWindowExistsFlag;
222
223 static int __driWindowExistsErrorHandler(Display *dpy, XErrorEvent *xerr)
224 {
225 if (xerr->error_code == BadWindow) {
226 __driWindowExistsFlag = GL_FALSE;
227 }
228 return 0;
229 }
230
231 /**
232 * Determine if a window associated with a \c GLXDrawable exists on the
233 * X-server.
234 *
235 * \param dpy Display associated with the drawable to be queried.
236 * \param draw \c GLXDrawable to test.
237 *
238 * \returns \c GL_TRUE if a window exists that is associated with \c draw,
239 * otherwise \c GL_FALSE is returned.
240 *
241 * \warning This function is not currently thread-safe.
242 *
243 * \deprecated
244 * \c __glXWindowExists (from libGL) is prefered over this function. Starting
245 * with the next major release of XFree86, this function will be removed.
246 * Even now this function is no longer directly called. Instead it is called
247 * via a function pointer if and only if \c __glXWindowExists does not exist.
248 *
249 * \sa __glXWindowExists glXGetProcAddress window_exists
250 */
251 static Bool __driWindowExists(Display *dpy, GLXDrawable draw)
252 {
253 XWindowAttributes xwa;
254 int (*oldXErrorHandler)(Display *, XErrorEvent *);
255
256 XSync(dpy, GL_FALSE);
257 __driWindowExistsFlag = GL_TRUE;
258 oldXErrorHandler = XSetErrorHandler(__driWindowExistsErrorHandler);
259 XGetWindowAttributes(dpy, draw, &xwa); /* dummy request */
260 XSetErrorHandler(oldXErrorHandler);
261 return __driWindowExistsFlag;
262 }
263 #endif /* DRI_NEW_INTERFACE_ONLY */
264
265 /**
266 * Find drawables in the local hash that have been destroyed on the
267 * server.
268 *
269 * \param drawHash Hash-table containing all know drawables.
270 */
271 static void __driGarbageCollectDrawables(void *drawHash)
272 {
273 GLXDrawable draw;
274 __DRIdrawable *pdraw;
275 Display *dpy;
276
277 if (drmHashFirst(drawHash, &draw, (void **)&pdraw)) {
278 do {
279 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
280 dpy = pdp->driScreenPriv->display;
281 if (! (*window_exists)(dpy, draw)) {
282 /* Destroy the local drawable data in the hash table, if the
283 drawable no longer exists in the Xserver */
284 __driRemoveDrawable(drawHash, pdraw);
285 (*pdraw->destroyDrawable)(dpy, pdraw->private);
286 Xfree(pdraw);
287 }
288 } while (drmHashNext(drawHash, &draw, (void **)&pdraw));
289 }
290 }
291
292 /*@}*/
293
294
295 /*****************************************************************/
296 /** \name Context (un)binding functions */
297 /*****************************************************************/
298 /*@{*/
299
300 /**
301 * Unbind context.
302 *
303 * \param dpy the display handle.
304 * \param scrn the screen number.
305 * \param draw drawable.
306 * \param read Current reading drawable.
307 * \param gc context.
308 *
309 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
310 *
311 * \internal
312 * This function calls __DriverAPIRec::UnbindContext, and then decrements
313 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
314 * return.
315 *
316 * While casting the opaque private pointers associated with the parameters
317 * into their respective real types it also assures they are not \c NULL.
318 */
319 static Bool driUnbindContext3(Display *dpy, int scrn,
320 GLXDrawable draw, GLXDrawable read,
321 __DRIcontext *ctx)
322 {
323 __DRIscreen *pDRIScreen;
324 __DRIdrawable *pdraw;
325 __DRIdrawable *pread;
326 __DRIcontextPrivate *pcp;
327 __DRIscreenPrivate *psp;
328 __DRIdrawablePrivate *pdp;
329 __DRIdrawablePrivate *prp;
330
331 /*
332 ** Assume error checking is done properly in glXMakeCurrent before
333 ** calling driUnbindContext3.
334 */
335
336 if (ctx == NULL || draw == None || read == None) {
337 /* ERROR!!! */
338 return GL_FALSE;
339 }
340
341 pDRIScreen = __glXFindDRIScreen(dpy, scrn);
342 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
343 /* ERROR!!! */
344 return GL_FALSE;
345 }
346
347 psp = (__DRIscreenPrivate *)pDRIScreen->private;
348 pcp = (__DRIcontextPrivate *)ctx->private;
349
350 pdraw = __driFindDrawable(psp->drawHash, draw);
351 if (!pdraw) {
352 /* ERROR!!! */
353 return GL_FALSE;
354 }
355 pdp = (__DRIdrawablePrivate *)pdraw->private;
356
357 pread = __driFindDrawable(psp->drawHash, read);
358 if (!pread) {
359 /* ERROR!!! */
360 return GL_FALSE;
361 }
362 prp = (__DRIdrawablePrivate *)pread->private;
363
364
365 /* Let driver unbind drawable from context */
366 (*psp->DriverAPI.UnbindContext)(pcp);
367
368
369 if (pdp->refcount == 0) {
370 /* ERROR!!! */
371 return GL_FALSE;
372 }
373
374 pdp->refcount--;
375
376 if (prp != pdp) {
377 if (prp->refcount == 0) {
378 /* ERROR!!! */
379 return GL_FALSE;
380 }
381
382 prp->refcount--;
383 }
384
385
386 /* XXX this is disabled so that if we call SwapBuffers on an unbound
387 * window we can determine the last context bound to the window and
388 * use that context's lock. (BrianP, 2-Dec-2000)
389 */
390 #if 0
391 /* Unbind the drawable */
392 pcp->driDrawablePriv = NULL;
393 pdp->driContextPriv = &psp->dummyContextPriv;
394 #endif
395
396 return GL_TRUE;
397 }
398
399
400 /**
401 * This function takes both a read buffer and a draw buffer. This is needed
402 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
403 * function.
404 *
405 * \bug This function calls \c driCreateNewDrawable in two places with the
406 * \c renderType hard-coded to \c GLX_WINDOW_BIT. Some checking might
407 * be needed in those places when support for pbuffers and / or pixmaps
408 * is added. Is it safe to assume that the drawable is a window?
409 */
410 static Bool DoBindContext(Display *dpy,
411 GLXDrawable draw, GLXDrawable read,
412 __DRIcontext *ctx, const __GLcontextModes * modes,
413 __DRIscreenPrivate *psp)
414 {
415 __DRIdrawable *pdraw;
416 __DRIdrawablePrivate *pdp;
417 __DRIdrawable *pread;
418 __DRIdrawablePrivate *prp;
419 __DRIcontextPrivate * const pcp = ctx->private;
420
421
422 /* Find the _DRIdrawable which corresponds to the writing GLXDrawable */
423 pdraw = __driFindDrawable(psp->drawHash, draw);
424 if (!pdraw) {
425 /* Allocate a new drawable */
426 pdraw = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable));
427 if (!pdraw) {
428 /* ERROR!!! */
429 return GL_FALSE;
430 }
431
432 /* Create a new drawable */
433 driCreateNewDrawable(dpy, modes, draw, pdraw, GLX_WINDOW_BIT,
434 empty_attribute_list);
435 if (!pdraw->private) {
436 /* ERROR!!! */
437 Xfree(pdraw);
438 return GL_FALSE;
439 }
440
441 }
442 pdp = (__DRIdrawablePrivate *) pdraw->private;
443
444 /* Find the _DRIdrawable which corresponds to the reading GLXDrawable */
445 if (read == draw) {
446 /* read buffer == draw buffer */
447 prp = pdp;
448 }
449 else {
450 pread = __driFindDrawable(psp->drawHash, read);
451 if (!pread) {
452 /* Allocate a new drawable */
453 pread = (__DRIdrawable *)Xmalloc(sizeof(__DRIdrawable));
454 if (!pread) {
455 /* ERROR!!! */
456 return GL_FALSE;
457 }
458
459 /* Create a new drawable */
460 driCreateNewDrawable(dpy, modes, read, pread, GLX_WINDOW_BIT,
461 empty_attribute_list);
462 if (!pread->private) {
463 /* ERROR!!! */
464 Xfree(pread);
465 return GL_FALSE;
466 }
467 }
468 prp = (__DRIdrawablePrivate *) pread->private;
469 }
470
471 /* Bind the drawable to the context */
472 pcp->driDrawablePriv = pdp;
473 pdp->driContextPriv = pcp;
474 pdp->refcount++;
475 if ( pdp != prp ) {
476 prp->refcount++;
477 }
478
479 /*
480 ** Now that we have a context associated with this drawable, we can
481 ** initialize the drawable information if has not been done before.
482 */
483 if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) {
484 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
485 __driUtilUpdateDrawableInfo(pdp);
486 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
487 }
488
489 /* Call device-specific MakeCurrent */
490 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
491
492 return GL_TRUE;
493 }
494
495
496 /**
497 * This function takes both a read buffer and a draw buffer. This is needed
498 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
499 * function.
500 */
501 static Bool driBindContext3(Display *dpy, int scrn,
502 GLXDrawable draw, GLXDrawable read,
503 __DRIcontext * ctx)
504 {
505 __DRIscreen *pDRIScreen;
506
507 /*
508 ** Assume error checking is done properly in glXMakeCurrent before
509 ** calling driBindContext.
510 */
511
512 if (ctx == NULL || draw == None || read == None) {
513 /* ERROR!!! */
514 return GL_FALSE;
515 }
516
517 pDRIScreen = __glXFindDRIScreen(dpy, scrn);
518 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
519 /* ERROR!!! */
520 return GL_FALSE;
521 }
522
523 return DoBindContext( dpy, draw, read, ctx, ctx->mode,
524 (__DRIscreenPrivate *)pDRIScreen->private );
525 }
526
527
528 #ifndef DRI_NEW_INTERFACE_ONLY
529 /**
530 * This function takes both a read buffer and a draw buffer. This is needed
531 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
532 * function.
533 */
534 static Bool driBindContext2(Display *dpy, int scrn,
535 GLXDrawable draw, GLXDrawable read,
536 GLXContext gc)
537 {
538 __DRIscreen *pDRIScreen;
539 const __GLcontextModes *modes;
540
541 /*
542 ** Assume error checking is done properly in glXMakeCurrent before
543 ** calling driBindContext.
544 */
545
546 if (gc == NULL || draw == None || read == None) {
547 /* ERROR!!! */
548 return GL_FALSE;
549 }
550
551 pDRIScreen = __glXFindDRIScreen(dpy, scrn);
552 modes = (driCompareGLXAPIVersion( 20040317 ) >= 0)
553 ? gc->driContext.mode
554 : findConfigMode( dpy, scrn, gc->vid, pDRIScreen );
555
556 if ( modes == NULL ) {
557 /* ERROR!!! */
558 return GL_FALSE;
559 }
560
561 /* findConfigMode will return NULL if the DRI screen or screen private
562 * are NULL.
563 */
564 assert( (pDRIScreen != NULL) && (pDRIScreen->private != NULL) );
565
566 return DoBindContext( dpy, draw, read, & gc->driContext, modes,
567 (__DRIscreenPrivate *)pDRIScreen->private );
568 }
569
570 static Bool driUnbindContext2(Display *dpy, int scrn,
571 GLXDrawable draw, GLXDrawable read,
572 GLXContext gc)
573 {
574 return driUnbindContext3(dpy, scrn, draw, read, & gc->driContext);
575 }
576
577 /*
578 * Simply call bind with the same GLXDrawable for the read and draw buffers.
579 */
580 static Bool driBindContext(Display *dpy, int scrn,
581 GLXDrawable draw, GLXContext gc)
582 {
583 return driBindContext2(dpy, scrn, draw, draw, gc);
584 }
585
586
587 /*
588 * Simply call bind with the same GLXDrawable for the read and draw buffers.
589 */
590 static Bool driUnbindContext(Display *dpy, int scrn,
591 GLXDrawable draw, GLXContext gc,
592 int will_rebind)
593 {
594 (void) will_rebind;
595 return driUnbindContext2( dpy, scrn, draw, draw, gc );
596 }
597 #endif /* DRI_NEW_INTERFACE_ONLY */
598
599 /*@}*/
600
601
602 /*****************************************************************/
603 /** \name Drawable handling functions */
604 /*****************************************************************/
605 /*@{*/
606
607 /**
608 * Update private drawable information.
609 *
610 * \param pdp pointer to the private drawable information to update.
611 *
612 * This function basically updates the __DRIdrawablePrivate struct's
613 * cliprect information by calling \c __DRIDrawablePrivate::getInfo. This is
614 * usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
615 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
616 * the values are different that means we have to update the clipping
617 * info.
618 */
619 void
620 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
621 {
622 __DRIscreenPrivate *psp;
623 __DRIcontextPrivate *pcp = pdp->driContextPriv;
624
625 if (!pcp || (pdp != pcp->driDrawablePriv)) {
626 /* ERROR!!! */
627 return;
628 }
629
630 psp = pdp->driScreenPriv;
631 if (!psp) {
632 /* ERROR!!! */
633 return;
634 }
635
636 if (pdp->pClipRects) {
637 Xfree(pdp->pClipRects);
638 }
639
640 if (pdp->pBackClipRects) {
641 Xfree(pdp->pBackClipRects);
642 }
643
644 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
645
646 if (!__driFindDrawable(psp->drawHash, pdp->draw) ||
647 ! (*pdp->getInfo)(pdp->display, pdp->screen, pdp->draw,
648 &pdp->index, &pdp->lastStamp,
649 &pdp->x, &pdp->y, &pdp->w, &pdp->h,
650 &pdp->numClipRects, &pdp->pClipRects,
651 &pdp->backX,
652 &pdp->backY,
653 &pdp->numBackClipRects,
654 &pdp->pBackClipRects )) {
655 /* Error -- eg the window may have been destroyed. Keep going
656 * with no cliprects.
657 */
658 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */
659 pdp->numClipRects = 0;
660 pdp->pClipRects = NULL;
661 pdp->numBackClipRects = 0;
662 pdp->pBackClipRects = NULL;
663 }
664 else
665 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
666
667 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
668
669 }
670
671 /*@}*/
672
673 /*****************************************************************/
674 /** \name GLX callbacks */
675 /*****************************************************************/
676 /*@{*/
677
678 /**
679 * Swap buffers.
680 *
681 * \param dpy the display handle.
682 * \param drawablePrivate opaque pointer to the per-drawable private info.
683 *
684 * \internal
685 * This function calls __DRIdrawablePrivate::swapBuffers.
686 *
687 * Is called directly from glXSwapBuffers().
688 */
689 static void driSwapBuffers( Display *dpy, void *drawablePrivate )
690 {
691 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
692 dPriv->swapBuffers(dPriv);
693 (void) dpy;
694 }
695
696 /**
697 * Called directly from a number of higher-level GLX functions.
698 */
699 static int driGetMSC( void *screenPrivate, int64_t *msc )
700 {
701 __DRIscreenPrivate *sPriv = (__DRIscreenPrivate *) screenPrivate;
702
703 return sPriv->DriverAPI.GetMSC( sPriv, msc );
704 }
705
706 /**
707 * Called directly from a number of higher-level GLX functions.
708 */
709 static int driGetSBC( Display *dpy, void *drawablePrivate, int64_t *sbc )
710 {
711 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
712 __DRIswapInfo sInfo;
713 int status;
714
715
716 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
717 *sbc = sInfo.swap_count;
718
719 return status;
720 }
721
722 static int driWaitForSBC( Display * dpy, void *drawablePriv,
723 int64_t target_sbc,
724 int64_t * msc, int64_t * sbc )
725 {
726 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
727
728 return dPriv->driScreenPriv->DriverAPI.WaitForSBC( dPriv, target_sbc,
729 msc, sbc );
730 }
731
732 static int driWaitForMSC( Display * dpy, void *drawablePriv,
733 int64_t target_msc,
734 int64_t divisor, int64_t remainder,
735 int64_t * msc, int64_t * sbc )
736 {
737 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
738 __DRIswapInfo sInfo;
739 int status;
740
741
742 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc,
743 divisor, remainder,
744 msc );
745
746 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
747 * is supported but GLX_OML_sync_control is not. Therefore, don't return
748 * an error value if GetSwapInfo() is not implemented.
749 */
750 if ( status == 0
751 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) {
752 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
753 *sbc = sInfo.swap_count;
754 }
755
756 return status;
757 }
758
759 static int64_t driSwapBuffersMSC( Display * dpy, void *drawablePriv,
760 int64_t target_msc,
761 int64_t divisor, int64_t remainder )
762 {
763 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
764
765 return dPriv->driScreenPriv->DriverAPI.SwapBuffersMSC( dPriv, target_msc,
766 divisor,
767 remainder );
768 }
769
770
771 /**
772 * This is called via __DRIscreenRec's createNewDrawable pointer.
773 */
774 static void *driCreateNewDrawable(Display *dpy,
775 const __GLcontextModes *modes,
776 GLXDrawable draw,
777 __DRIdrawable *pdraw,
778 int renderType,
779 const int *attrs)
780 {
781 __DRIscreen * const pDRIScreen = __glXFindDRIScreen(dpy, modes->screen);
782 __DRIscreenPrivate *psp;
783 __DRIdrawablePrivate *pdp;
784
785
786 /* Since pbuffers are not yet supported, no drawable attributes are
787 * supported either.
788 */
789 (void) attrs;
790
791 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
792 return NULL;
793 }
794
795 pdp = (__DRIdrawablePrivate *)Xmalloc(sizeof(__DRIdrawablePrivate));
796 if (!pdp) {
797 return NULL;
798 }
799
800 if (!XF86DRICreateDrawable(dpy, modes->screen, draw, &pdp->hHWDrawable)) {
801 Xfree(pdp);
802 return NULL;
803 }
804
805 pdp->draw = draw;
806 pdp->pdraw = pdraw;
807 pdp->refcount = 0;
808 pdp->pStamp = NULL;
809 pdp->lastStamp = 0;
810 pdp->index = 0;
811 pdp->x = 0;
812 pdp->y = 0;
813 pdp->w = 0;
814 pdp->h = 0;
815 pdp->numClipRects = 0;
816 pdp->numBackClipRects = 0;
817 pdp->pClipRects = NULL;
818 pdp->pBackClipRects = NULL;
819 pdp->display = dpy;
820 pdp->screen = modes->screen;
821
822 psp = (__DRIscreenPrivate *)pDRIScreen->private;
823 pdp->driScreenPriv = psp;
824 pdp->driContextPriv = &psp->dummyContextPriv;
825
826 pdp->getInfo = (GetDrawableInfo *)
827 glXGetProcAddress( (const GLubyte *) "__glXGetDrawableInfo" );
828 if ( pdp->getInfo == NULL ) {
829 pdp->getInfo = XF86DRIGetDrawableInfo;
830 }
831
832 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, modes,
833 renderType == GLX_PIXMAP_BIT)) {
834 (void)XF86DRIDestroyDrawable(dpy, modes->screen, pdp->draw);
835 Xfree(pdp);
836 return NULL;
837 }
838
839 pdraw->private = pdp;
840 pdraw->destroyDrawable = driDestroyDrawable;
841 pdraw->swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
842
843 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
844 pdraw->getSBC = driGetSBC;
845 pdraw->waitForSBC = driWaitForSBC;
846 pdraw->waitForMSC = driWaitForMSC;
847 pdraw->swapBuffersMSC = driSwapBuffersMSC;
848 pdraw->frameTracking = NULL;
849 pdraw->queryFrameTracking = driQueryFrameTracking;
850
851 /* This special default value is replaced with the configured
852 * default value when the drawable is first bound to a direct
853 * rendering context. */
854 pdraw->swap_interval = (unsigned)-1;
855 }
856
857 pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
858
859 /* Add pdraw to drawable list */
860 if (!__driAddDrawable(psp->drawHash, pdraw)) {
861 /* ERROR!!! */
862 (*pdraw->destroyDrawable)(dpy, pdp);
863 Xfree(pdp);
864 pdp = NULL;
865 pdraw->private = NULL;
866 }
867
868 return (void *) pdp;
869 }
870
871 static __DRIdrawable *driGetDrawable(Display *dpy, GLXDrawable draw,
872 void *screenPrivate)
873 {
874 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
875
876 /*
877 ** Make sure this routine returns NULL if the drawable is not bound
878 ** to a direct rendering context!
879 */
880 return __driFindDrawable(psp->drawHash, draw);
881 }
882
883 static void driDestroyDrawable(Display *dpy, void *drawablePrivate)
884 {
885 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *) drawablePrivate;
886 __DRIscreenPrivate *psp = pdp->driScreenPriv;
887 int scrn = psp->myNum;
888
889 if (pdp) {
890 (*psp->DriverAPI.DestroyBuffer)(pdp);
891 if ((*window_exists)(dpy, pdp->draw))
892 (void)XF86DRIDestroyDrawable(dpy, scrn, pdp->draw);
893 if (pdp->pClipRects) {
894 Xfree(pdp->pClipRects);
895 pdp->pClipRects = NULL;
896 }
897 if (pdp->pBackClipRects) {
898 Xfree(pdp->pBackClipRects);
899 pdp->pBackClipRects = NULL;
900 }
901 Xfree(pdp);
902 }
903 }
904
905 /*@}*/
906
907
908 /*****************************************************************/
909 /** \name Context handling functions */
910 /*****************************************************************/
911 /*@{*/
912
913 /**
914 * Destroy the per-context private information.
915 *
916 * \param dpy the display handle.
917 * \param scrn the screen number.
918 * \param contextPrivate opaque pointer to the per-drawable private info.
919 *
920 * \internal
921 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
922 * drmDestroyContext(), and finally frees \p contextPrivate.
923 */
924 static void driDestroyContext(Display *dpy, int scrn, void *contextPrivate)
925 {
926 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *) contextPrivate;
927
928 if (pcp) {
929 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
930 __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
931 (void)XF86DRIDestroyContext(dpy, scrn, pcp->contextID);
932 Xfree(pcp);
933 }
934 }
935
936
937 /**
938 * Create the per-drawable private driver information.
939 *
940 * \param dpy The display handle.
941 * \param modes Mode used to create the new context.
942 * \param render_type Type of rendering target. \c GLX_RGBA is the only
943 * type likely to ever be supported for direct-rendering.
944 * \param sharedPrivate The shared context dependent methods or \c NULL if
945 * non-existent.
946 * \param pctx DRI context to receive the context dependent methods.
947 *
948 * \returns An opaque pointer to the per-context private information on
949 * success, or \c NULL on failure.
950 *
951 * \internal
952 * This function allocates and fills a __DRIcontextPrivateRec structure. It
953 * performs some device independent initialization and passes all the
954 * relevent information to __DriverAPIRec::CreateContext to create the
955 * context.
956 *
957 */
958 static void *
959 driCreateNewContext(Display *dpy, const __GLcontextModes *modes,
960 int render_type, void *sharedPrivate, __DRIcontext *pctx)
961 {
962 __DRIscreen *pDRIScreen;
963 __DRIcontextPrivate *pcp;
964 __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
965 __DRIscreenPrivate *psp;
966 void * const shareCtx = (pshare != NULL) ? pshare->driverPrivate : NULL;
967
968 pDRIScreen = __glXFindDRIScreen(dpy, modes->screen);
969 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
970 /* ERROR!!! */
971 return NULL;
972 }
973
974 psp = (__DRIscreenPrivate *)pDRIScreen->private;
975
976 pcp = (__DRIcontextPrivate *)Xmalloc(sizeof(__DRIcontextPrivate));
977 if (!pcp) {
978 return NULL;
979 }
980
981 if (! (*create_context_with_config)(dpy, modes->screen, modes->fbconfigID,
982 &pcp->contextID, &pcp->hHWContext)) {
983 Xfree(pcp);
984 return NULL;
985 }
986
987 pcp->display = dpy;
988 pcp->driScreenPriv = psp;
989 pcp->driDrawablePriv = NULL;
990
991 /* When the first context is created for a screen, initialize a "dummy"
992 * context.
993 */
994
995 if (!psp->dummyContextPriv.driScreenPriv) {
996 psp->dummyContextPriv.contextID = 0;
997 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context;
998 psp->dummyContextPriv.driScreenPriv = psp;
999 psp->dummyContextPriv.driDrawablePriv = NULL;
1000 psp->dummyContextPriv.driverPrivate = NULL;
1001 /* No other fields should be used! */
1002 }
1003
1004 pctx->destroyContext = driDestroyContext;
1005 #ifdef DRI_NEW_INTERFACE_ONLY
1006 pctx->bindContext = NULL;
1007 pctx->unbindContext = NULL;
1008 pctx->bindContext2 = NULL;
1009 pctx->unbindContext2 = NULL;
1010 pctx->bindContex3 = driBindContext3;
1011 pctx->unbindContext3 = driUnbindContext3;
1012 #else
1013 pctx->bindContext = driBindContext;
1014 pctx->unbindContext = driUnbindContext;
1015 if ( driCompareGLXAPIVersion( 20030606 ) >= 0 ) {
1016 pctx->bindContext2 = driBindContext2;
1017 pctx->unbindContext2 = driUnbindContext2;
1018 }
1019
1020 if ( driCompareGLXAPIVersion( 20040415 ) >= 0 ) {
1021 pctx->bindContext3 = driBindContext3;
1022 pctx->unbindContext3 = driUnbindContext3;
1023 }
1024 #endif
1025
1026 if ( !(*psp->DriverAPI.CreateContext)(modes, pcp, shareCtx) ) {
1027 (void)XF86DRIDestroyContext(dpy, modes->screen, pcp->contextID);
1028 Xfree(pcp);
1029 return NULL;
1030 }
1031
1032 __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
1033
1034 return pcp;
1035 }
1036
1037
1038 #ifndef DRI_NEW_INTERFACE_ONLY
1039 /**
1040 * Create the per-drawable private driver information.
1041 *
1042 * \param dpy the display handle.
1043 * \param vis the visual information.
1044 * \param sharedPrivate the shared context dependent methods or \c NULL if
1045 * non-existent.
1046 * \param pctx will receive the context dependent methods.
1047 *
1048 * \returns a opaque pointer to the per-context private information on success, or \c NULL
1049 * on failure.
1050 *
1051 * \deprecated
1052 * This function has been replaced by \c driCreateNewContext. In drivers
1053 * built to work with XFree86, this function will continue to exist to support
1054 * older versions of libGL. Starting with the next major relelase of XFree86,
1055 * this function will be removed.
1056 *
1057 * \internal
1058 * This function allocates and fills a __DRIcontextPrivateRec structure. It
1059 * gets the visual, converts it into a __GLcontextModesRec and passes it
1060 * to __DriverAPIRec::CreateContext to create the context.
1061 */
1062 static void *driCreateContext(Display *dpy, XVisualInfo *vis,
1063 void *sharedPrivate, __DRIcontext *pctx)
1064 {
1065 __DRIscreen *pDRIScreen;
1066 const __GLcontextModes *modes;
1067
1068 pDRIScreen = __glXFindDRIScreen(dpy, vis->screen);
1069 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
1070 /* ERROR!!! */
1071 return NULL;
1072 }
1073
1074
1075 /* Setup a __GLcontextModes struct corresponding to vis->visualid
1076 * and create the rendering context.
1077 */
1078
1079 modes = findConfigMode(dpy, vis->screen, vis->visualid, pDRIScreen);
1080 return (modes == NULL)
1081 ? NULL
1082 : driCreateNewContext( dpy, modes, GLX_RGBA_TYPE,
1083 sharedPrivate, pctx );
1084 }
1085 #endif /* DRI_NEW_INTERFACE_ONLY */
1086
1087 /*@}*/
1088
1089
1090 /*****************************************************************/
1091 /** \name Screen handling functions */
1092 /*****************************************************************/
1093 /*@{*/
1094
1095 /**
1096 * Destroy the per-screen private information.
1097 *
1098 * \param dpy the display handle.
1099 * \param scrn the screen number.
1100 * \param screenPrivate opaque pointer to the per-screen private information.
1101 *
1102 * \internal
1103 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
1104 * drmClose(), and finally frees \p screenPrivate.
1105 */
1106 static void driDestroyScreen(Display *dpy, int scrn, void *screenPrivate)
1107 {
1108 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
1109
1110 if (psp) {
1111 /* No interaction with the X-server is possible at this point. This
1112 * routine is called after XCloseDisplay, so there is no protocol
1113 * stream open to the X-server anymore.
1114 */
1115
1116 if (psp->DriverAPI.DestroyScreen)
1117 (*psp->DriverAPI.DestroyScreen)(psp);
1118
1119 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
1120 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
1121 Xfree(psp->pDevPriv);
1122 (void)drmClose(psp->fd);
1123 if ( psp->modes != NULL ) {
1124 _gl_context_modes_destroy( psp->modes );
1125 }
1126 Xfree(psp);
1127 }
1128 }
1129
1130
1131 /**
1132 * Utility function used to create a new driver-private screen structure.
1133 *
1134 * \param dpy Display pointer
1135 * \param scrn Index of the screen
1136 * \param psc DRI screen data (not driver private)
1137 * \param modes Linked list of known display modes. This list is, at a
1138 * minimum, a list of modes based on the current display mode.
1139 * These roughly match the set of available X11 visuals, but it
1140 * need not be limited to X11! The calling libGL should create
1141 * a list that will inform the driver of the current display
1142 * mode (i.e., color buffer depth, depth buffer depth, etc.).
1143 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
1144 * all drivers.
1145 * \param dri_version Version of the "server-side" DRI.
1146 * \param drm_version Version of the kernel DRM.
1147 * \param frame_buffer Data describing the location and layout of the
1148 * framebuffer.
1149 * \param pSAREA Pointer the the SAREA.
1150 * \param fd Device handle for the DRM.
1151 * \param internal_api_version Version of the internal interface between the
1152 * driver and libGL.
1153 * \param driverAPI Driver API functions used by other routines in dri_util.c.
1154 */
1155 __DRIscreenPrivate *
1156 __driUtilCreateNewScreen(Display *dpy, int scrn, __DRIscreen *psc,
1157 __GLcontextModes * modes,
1158 const __DRIversion * ddx_version,
1159 const __DRIversion * dri_version,
1160 const __DRIversion * drm_version,
1161 const __DRIframebuffer * frame_buffer,
1162 drmAddress pSAREA,
1163 int fd,
1164 int internal_api_version,
1165 const struct __DriverAPIRec *driverAPI)
1166 {
1167 __DRIscreenPrivate *psp;
1168
1169
1170 #ifdef DRI_NEW_INTERFACE_ONLY
1171 if ( internal_api_version < 20040415 ) {
1172 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. "
1173 "20040415 or later is required.\n", internal_api_version );
1174 return NULL;
1175 }
1176 #else
1177 if ( internal_api_version == 20031201 ) {
1178 fprintf( stderr, "libGL error: libGL version 20031201 has critical "
1179 "binary compatilibity bugs.\nlibGL error: You must upgrade "
1180 "to use direct-rendering!\n" );
1181 return NULL;
1182 }
1183 #endif /* DRI_NEW_INTERFACE_ONLY */
1184
1185
1186 window_exists = (PFNGLXWINDOWEXISTSPROC)
1187 glXGetProcAddress( (const GLubyte *) "__glXWindowExists" );
1188
1189 if ( window_exists == NULL ) {
1190 #ifdef DRI_NEW_INTERFACE_ONLY
1191 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. "
1192 "20021128 or later is required.\n", internal_api_version );
1193 return NULL;
1194 #else
1195 window_exists = (PFNGLXWINDOWEXISTSPROC) __driWindowExists;
1196 #endif /* DRI_NEW_INTERFACE_ONLY */
1197 }
1198
1199 create_context_with_config = (PFNGLXCREATECONTEXTWITHCONFIGPROC)
1200 glXGetProcAddress( (const GLubyte *) "__glXCreateContextWithConfig" );
1201 if ( create_context_with_config == NULL ) {
1202 #ifdef DRI_NEW_INTERFACE_ONLY
1203 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. "
1204 "20031201 or later is required.\n", internal_api_version );
1205 return NULL;
1206 #else
1207 create_context_with_config = (PFNGLXCREATECONTEXTWITHCONFIGPROC)
1208 fake_XF86DRICreateContextWithConfig;
1209 #endif /* DRI_NEW_INTERFACE_ONLY */
1210 }
1211
1212 api_ver = internal_api_version;
1213
1214 psp = (__DRIscreenPrivate *)Xmalloc(sizeof(__DRIscreenPrivate));
1215 if (!psp) {
1216 return NULL;
1217 }
1218
1219 /* Create the hash table */
1220 psp->drawHash = drmHashCreate();
1221 if ( psp->drawHash == NULL ) {
1222 Xfree( psp );
1223 return NULL;
1224 }
1225
1226 psp->display = dpy;
1227 psp->myNum = scrn;
1228 psp->psc = psc;
1229 psp->modes = modes;
1230
1231 /*
1232 ** NOT_DONE: This is used by the X server to detect when the client
1233 ** has died while holding the drawable lock. The client sets the
1234 ** drawable lock to this value.
1235 */
1236 psp->drawLockID = 1;
1237
1238 psp->drmMajor = drm_version->major;
1239 psp->drmMinor = drm_version->minor;
1240 psp->drmPatch = drm_version->patch;
1241 psp->ddxMajor = ddx_version->major;
1242 psp->ddxMinor = ddx_version->minor;
1243 psp->ddxPatch = ddx_version->patch;
1244 psp->driMajor = dri_version->major;
1245 psp->driMinor = dri_version->minor;
1246 psp->driPatch = dri_version->patch;
1247
1248 /* install driver's callback functions */
1249 memcpy( &psp->DriverAPI, driverAPI, sizeof(struct __DriverAPIRec) );
1250
1251 psp->pSAREA = pSAREA;
1252
1253 psp->pFB = frame_buffer->base;
1254 psp->fbSize = frame_buffer->size;
1255 psp->fbStride = frame_buffer->stride;
1256 psp->fbWidth = frame_buffer->width;
1257 psp->fbHeight = frame_buffer->height;
1258 psp->devPrivSize = frame_buffer->dev_priv_size;
1259 psp->pDevPriv = frame_buffer->dev_priv;
1260
1261 psp->fd = fd;
1262
1263 /*
1264 ** Do not init dummy context here; actual initialization will be
1265 ** done when the first DRI context is created. Init screen priv ptr
1266 ** to NULL to let CreateContext routine that it needs to be inited.
1267 */
1268 psp->dummyContextPriv.driScreenPriv = NULL;
1269
1270 psc->destroyScreen = driDestroyScreen;
1271 #ifndef DRI_NEW_INTERFACE_ONLY
1272 psc->createContext = driCreateContext;
1273 #else
1274 psc->createConteext = NULL;
1275 #endif
1276 psc->createNewDrawable = driCreateNewDrawable;
1277 psc->getDrawable = driGetDrawable;
1278 #ifdef DRI_NEW_INTERFACE_ONLY
1279 psc->getMSC = driGetMSC;
1280 psc->createNewContext = driCreateNewContext;
1281 #else
1282 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) {
1283 psc->getMSC = driGetMSC;
1284
1285 if ( driCompareGLXAPIVersion( 20030824 ) >= 0 ) {
1286 psc->createNewContext = driCreateNewContext;
1287 }
1288 }
1289 #endif
1290
1291 if ( (psp->DriverAPI.InitDriver != NULL)
1292 && !(*psp->DriverAPI.InitDriver)(psp) ) {
1293 Xfree( psp );
1294 return NULL;
1295 }
1296
1297
1298 return psp;
1299 }
1300
1301
1302 #ifndef DRI_NEW_INTERFACE_ONLY
1303 /**
1304 * Utility function used to create a new driver-private screen structure.
1305 *
1306 * \param dpy Display pointer.
1307 * \param scrn Index of the screen.
1308 * \param psc DRI screen data (not driver private)
1309 * \param numConfigs Number of visual configs pointed to by \c configs.
1310 * \param configs Array of GLXvisualConfigs exported by the 2D driver.
1311 * \param driverAPI Driver API functions used by other routines in dri_util.c.
1312 *
1313 * \deprecated
1314 * This function has been replaced by \c __driUtilCreateNewScreen. In drivers
1315 * built to work with XFree86, this function will continue to exist to support
1316 * older versions of libGL. Starting with the next major relelase of XFree86,
1317 * this function will be removed.
1318 */
1319 __DRIscreenPrivate *
1320 __driUtilCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
1321 int numConfigs, __GLXvisualConfig *configs,
1322 const struct __DriverAPIRec *driverAPI)
1323 {
1324 int directCapable;
1325 __DRIscreenPrivate *psp = NULL;
1326 drmHandle hSAREA;
1327 drmAddress pSAREA;
1328 char *BusID;
1329 __GLcontextModes *modes;
1330 __GLcontextModes *temp;
1331 int i;
1332 __DRIversion ddx_version;
1333 __DRIversion dri_version;
1334 __DRIversion drm_version;
1335 __DRIframebuffer framebuffer;
1336 int fd = -1;
1337 int status;
1338 const char * err_msg;
1339 const char * err_extra;
1340
1341
1342 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrn, &directCapable)
1343 || !directCapable) {
1344 return NULL;
1345 }
1346
1347
1348 /* Create the linked list of context modes, and populate it with the
1349 * GLX visual information passed in by libGL.
1350 */
1351
1352 modes = _gl_context_modes_create( numConfigs, sizeof(__GLcontextModes) );
1353 if ( modes == NULL ) {
1354 return NULL;
1355 }
1356
1357 temp = modes;
1358 for ( i = 0 ; i < numConfigs ; i++ ) {
1359 assert( temp != NULL );
1360 _gl_copy_visual_to_context_mode( temp, & configs[i] );
1361 temp->screen = scrn;
1362
1363 temp = temp->next;
1364 }
1365
1366 err_msg = "XF86DRIOpenConnection";
1367 err_extra = NULL;
1368
1369 if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
1370 fd = drmOpen(NULL,BusID);
1371 Xfree(BusID); /* No longer needed */
1372
1373 err_msg = "open DRM";
1374 err_extra = strerror( -fd );
1375
1376 if (fd >= 0) {
1377 drmMagic magic;
1378
1379 err_msg = "drmGetMagic";
1380 err_extra = NULL;
1381
1382 if (!drmGetMagic(fd, &magic)) {
1383 drmVersionPtr version = drmGetVersion(fd);
1384 if (version) {
1385 drm_version.major = version->version_major;
1386 drm_version.minor = version->version_minor;
1387 drm_version.patch = version->version_patchlevel;
1388 drmFreeVersion(version);
1389 }
1390 else {
1391 drm_version.major = -1;
1392 drm_version.minor = -1;
1393 drm_version.patch = -1;
1394 }
1395
1396 err_msg = "XF86DRIAuthConnection";
1397 if (XF86DRIAuthConnection(dpy, scrn, magic)) {
1398 char *driverName;
1399
1400 /*
1401 * Get device name (like "tdfx") and the ddx version numbers.
1402 * We'll check the version in each DRI driver's "createScreen"
1403 * function.
1404 */
1405 err_msg = "XF86DRIGetClientDriverName";
1406 if (XF86DRIGetClientDriverName(dpy, scrn,
1407 &ddx_version.major,
1408 &ddx_version.minor,
1409 &ddx_version.patch,
1410 &driverName)) {
1411
1412 /* No longer needed. */
1413 Xfree( driverName );
1414
1415 /*
1416 * Get the DRI X extension version.
1417 */
1418 err_msg = "XF86DRIQueryVersion";
1419 if (XF86DRIQueryVersion(dpy,
1420 &dri_version.major,
1421 &dri_version.minor,
1422 &dri_version.patch)) {
1423 drmHandle hFB;
1424 int junk;
1425
1426 /*
1427 * Get device-specific info. pDevPriv will point to a struct
1428 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
1429 * that has information about the screen size, depth, pitch,
1430 * ancilliary buffers, DRM mmap handles, etc.
1431 */
1432 err_msg = "XF86DRIGetDeviceInfo";
1433 if (XF86DRIGetDeviceInfo(dpy, scrn,
1434 &hFB,
1435 &junk,
1436 &framebuffer.size,
1437 &framebuffer.stride,
1438 &framebuffer.dev_priv_size,
1439 &framebuffer.dev_priv)) {
1440 framebuffer.width = DisplayWidth(dpy, scrn);
1441 framebuffer.height = DisplayHeight(dpy, scrn);
1442
1443 /*
1444 * Map the framebuffer region.
1445 */
1446 status = drmMap(fd, hFB, framebuffer.size,
1447 (drmAddressPtr)&framebuffer.base);
1448
1449 err_msg = "drmMap of framebuffer";
1450 err_extra = strerror( -status );
1451
1452 if ( status == 0 ) {
1453 /*
1454 * Map the SAREA region. Further mmap regions may be setup in
1455 * each DRI driver's "createScreen" function.
1456 */
1457 status = drmMap(fd, hSAREA, SAREA_MAX,
1458 &pSAREA);
1459
1460 err_msg = "drmMap of sarea";
1461 err_extra = strerror( -status );
1462
1463 if ( status == 0 ) {
1464 PFNGLXGETINTERNALVERSIONPROC get_ver;
1465
1466 get_ver = (PFNGLXGETINTERNALVERSIONPROC)
1467 glXGetProcAddress( (const GLubyte *) "__glXGetInternalVersion" );
1468
1469 err_msg = "InitDriver";
1470 err_extra = NULL;
1471 psp = __driUtilCreateNewScreen( dpy, scrn, psc, modes,
1472 & ddx_version,
1473 & dri_version,
1474 & drm_version,
1475 & framebuffer,
1476 pSAREA,
1477 fd,
1478 (get_ver != NULL) ? (*get_ver)() : 1,
1479 driverAPI );
1480 }
1481 }
1482 }
1483 }
1484 }
1485 }
1486 }
1487 }
1488 }
1489
1490 if ( psp == NULL ) {
1491 if ( pSAREA != MAP_FAILED ) {
1492 (void)drmUnmap(pSAREA, SAREA_MAX);
1493 }
1494
1495 if ( framebuffer.base != MAP_FAILED ) {
1496 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
1497 }
1498
1499 if ( framebuffer.dev_priv != NULL ) {
1500 Xfree(framebuffer.dev_priv);
1501 }
1502
1503 if ( fd >= 0 ) {
1504 (void)drmClose(fd);
1505 }
1506
1507 if ( modes != NULL ) {
1508 _gl_context_modes_destroy( modes );
1509 }
1510
1511 (void)XF86DRICloseConnection(dpy, scrn);
1512
1513 if ( err_extra != NULL ) {
1514 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
1515 err_extra);
1516 }
1517 else {
1518 fprintf(stderr, "libGL error: %s failed\n", err_msg );
1519 }
1520
1521 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
1522 }
1523
1524 return psp;
1525 }
1526 #endif /* DRI_NEW_INTERFACE_ONLY */
1527
1528
1529 /**
1530 * Compare the current GLX API version with a driver supplied required version.
1531 *
1532 * The minimum required version is compared with the API version exported by
1533 * the \c __glXGetInternalVersion function (in libGL.so).
1534 *
1535 * \param required_version Minimum required internal GLX API version.
1536 * \return A tri-value return, as from strcmp is returned. A value less
1537 * than, equal to, or greater than zero will be returned if the
1538 * internal GLX API version is less than, equal to, or greater
1539 * than \c required_version.
1540 *
1541 * \sa __glXGetInternalVersion().
1542 */
1543 int driCompareGLXAPIVersion( GLuint required_version )
1544 {
1545 if ( api_ver > required_version ) {
1546 return 1;
1547 }
1548 else if ( api_ver == required_version ) {
1549 return 0;
1550 }
1551
1552 return -1;
1553 }
1554
1555
1556 static int
1557 driQueryFrameTracking( Display * dpy, void * priv,
1558 int64_t * sbc, int64_t * missedFrames,
1559 float * lastMissedUsage, float * usage )
1560 {
1561 static PFNGLXGETUSTPROC get_ust;
1562 __DRIswapInfo sInfo;
1563 int status;
1564 int64_t ust;
1565 __DRIdrawablePrivate * dpriv = (__DRIdrawablePrivate *) priv;
1566
1567 if ( get_ust == NULL ) {
1568 get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( (const GLubyte *) "__glXGetUST" );
1569 }
1570
1571 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo );
1572 if ( status == 0 ) {
1573 *sbc = sInfo.swap_count;
1574 *missedFrames = sInfo.swap_missed_count;
1575 *lastMissedUsage = sInfo.swap_missed_usage;
1576
1577 (*get_ust)( & ust );
1578 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust );
1579 }
1580
1581 return status;
1582 }
1583
1584
1585 /**
1586 * Calculate amount of swap interval used between GLX buffer swaps.
1587 *
1588 * The usage value, on the range [0,max], is the fraction of total swap
1589 * interval time used between GLX buffer swaps is calculated.
1590 *
1591 * \f$p = t_d / (i * t_r)\f$
1592 *
1593 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
1594 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
1595 * required for a single vertical refresh period (as returned by \c
1596 * glXGetMscRateOML).
1597 *
1598 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
1599 * details.
1600 *
1601 * \param dPriv Pointer to the private drawable structure.
1602 * \return If less than a single swap interval time period was required
1603 * between GLX buffer swaps, a number greater than 0 and less than
1604 * 1.0 is returned. If exactly one swap interval time period is
1605 * required, 1.0 is returned, and if more than one is required then
1606 * a number greater than 1.0 will be returned.
1607 *
1608 * \sa glXSwapIntervalSGI glXGetMscRateOML
1609 *
1610 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
1611 * be possible to cache the sync rate?
1612 */
1613 float
1614 driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
1615 int64_t current_ust )
1616 {
1617 static PFNGLXGETMSCRATEOMLPROC get_msc_rate = NULL;
1618 int32_t n;
1619 int32_t d;
1620 int interval;
1621 float usage = 1.0;
1622
1623
1624 if ( get_msc_rate == NULL ) {
1625 get_msc_rate = (PFNGLXGETMSCRATEOMLPROC)
1626 glXGetProcAddress( (const GLubyte *) "glXGetMscRateOML" );
1627 }
1628
1629 if ( (get_msc_rate != NULL)
1630 && get_msc_rate( dPriv->display, dPriv->draw, &n, &d ) ) {
1631 interval = (dPriv->pdraw->swap_interval != 0)
1632 ? dPriv->pdraw->swap_interval : 1;
1633
1634
1635 /* We want to calculate
1636 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
1637 * current_UST by calling __glXGetUST. last_swap_UST is stored in
1638 * dPriv->swap_ust. interval has already been calculated.
1639 *
1640 * The only tricky part is us_per_refresh. us_per_refresh is
1641 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
1642 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
1643 * the denominator of the final calculation, we calculate
1644 * (interval * 1000000 * d) and move n into the numerator.
1645 */
1646
1647 usage = (current_ust - last_swap_ust);
1648 usage *= n;
1649 usage /= (interval * d);
1650 usage /= 1000000.0;
1651 }
1652
1653 return usage;
1654 }
1655
1656 /*@}*/
1657
1658 #endif /* GLX_DIRECT_RENDERING */