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