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