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