Fixes the glXGetProcAddress portion of the interface. Most of the functions
[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
18
19 #include <assert.h>
20 #include <stdarg.h>
21 #include <unistd.h>
22 #include <sys/mman.h>
23 #include <stdio.h>
24
25 #ifndef MAP_FAILED
26 #define MAP_FAILED ((void *)-1)
27 #endif
28
29 #include "imports.h"
30 #define None 0
31
32 #include "dri_util.h"
33 #include "drm_sarea.h"
34 #include "glcontextmodes.h"
35
36 #ifndef GLX_OML_sync_control
37 typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRInativeDisplay *dpy, __DRIid drawable, int32_t *numerator, int32_t *denominator);
38 #endif
39
40 /* This pointer *must* be set by the driver's __driCreateNewScreen funciton!
41 */
42 const __DRIinterfaceMethods * dri_interface = NULL;
43
44 /**
45 * Weak thread-safety dispatch pointer. Older versions of libGL will not have
46 * this symbol, so a "weak" version is included here so that the driver will
47 * dynamically link properly. The value is set to \c NULL. This forces the
48 * driver to fall back to the old dispatch interface.
49 */
50 struct _glapi_table *_glapi_DispatchTSD __attribute__((weak)) = NULL;
51
52 /**
53 * This is used in a couple of places that call \c driCreateNewDrawable.
54 */
55 static const int empty_attribute_list[1] = { None };
56
57
58 /**
59 * Cached copy of the internal API version used by libGL and the client-side
60 * DRI driver.
61 */
62 static int api_ver = 0;
63
64 /* forward declarations */
65 static int driQueryFrameTracking( __DRInativeDisplay * dpy, void * priv,
66 int64_t * sbc, int64_t * missedFrames, float * lastMissedUsage,
67 float * usage );
68
69 static void *driCreateNewDrawable(__DRInativeDisplay *dpy, const __GLcontextModes *modes,
70 __DRIid draw, __DRIdrawable *pdraw, int renderType, const int *attrs);
71
72 static void driDestroyDrawable(__DRInativeDisplay *dpy, void *drawablePrivate);
73
74
75 /**
76 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
77 * is set.
78 *
79 * Is called from the drivers.
80 *
81 * \param f \c printf like format string.
82 */
83 void
84 __driUtilMessage(const char *f, ...)
85 {
86 va_list args;
87
88 if (getenv("LIBGL_DEBUG")) {
89 fprintf(stderr, "libGL error: \n");
90 va_start(args, f);
91 vfprintf(stderr, f, args);
92 va_end(args);
93 fprintf(stderr, "\n");
94 }
95 }
96
97
98 /*****************************************************************/
99 /** \name Drawable list management */
100 /*****************************************************************/
101 /*@{*/
102
103 static GLboolean __driAddDrawable(void *drawHash, __DRIdrawable *pdraw)
104 {
105 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
106
107 if (drmHashInsert(drawHash, pdp->draw, pdraw))
108 return GL_FALSE;
109
110 return GL_TRUE;
111 }
112
113 static __DRIdrawable *__driFindDrawable(void *drawHash, __DRIid draw)
114 {
115 int retcode;
116 __DRIdrawable *pdraw;
117
118 retcode = drmHashLookup(drawHash, draw, (void *)&pdraw);
119 if (retcode)
120 return NULL;
121
122 return pdraw;
123 }
124
125
126 /**
127 * Find drawables in the local hash that have been destroyed on the
128 * server.
129 *
130 * \param drawHash Hash-table containing all know drawables.
131 */
132 static void __driGarbageCollectDrawables(void *drawHash)
133 {
134 __DRIid draw;
135 __DRInativeDisplay *dpy;
136 __DRIdrawable *pdraw;
137
138 if (drmHashFirst(drawHash, &draw, (void *)&pdraw) == 1) {
139 do {
140 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private;
141 dpy = pdp->driScreenPriv->display;
142 if (! (*dri_interface->windowExists)(dpy, draw)) {
143 /* Destroy the local drawable data in the hash table, if the
144 drawable no longer exists in the Xserver */
145 drmHashDelete(drawHash, draw);
146 (*pdraw->destroyDrawable)(dpy, pdraw->private);
147 _mesa_free(pdraw);
148 }
149 } while (drmHashNext(drawHash, &draw, (void *)&pdraw) == 1);
150 }
151 }
152
153 /*@}*/
154
155
156 /*****************************************************************/
157 /** \name Context (un)binding functions */
158 /*****************************************************************/
159 /*@{*/
160
161 /**
162 * Unbind context.
163 *
164 * \param dpy the display handle.
165 * \param scrn the screen number.
166 * \param draw drawable.
167 * \param read Current reading drawable.
168 * \param gc context.
169 *
170 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
171 *
172 * \internal
173 * This function calls __DriverAPIRec::UnbindContext, and then decrements
174 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
175 * return.
176 *
177 * While casting the opaque private pointers associated with the parameters
178 * into their respective real types it also assures they are not \c NULL.
179 */
180 static GLboolean driUnbindContext(__DRInativeDisplay *dpy, int scrn,
181 __DRIid draw, __DRIid read,
182 __DRIcontext *ctx)
183 {
184 __DRIscreen *pDRIScreen;
185 __DRIdrawable *pdraw;
186 __DRIdrawable *pread;
187 __DRIcontextPrivate *pcp;
188 __DRIscreenPrivate *psp;
189 __DRIdrawablePrivate *pdp;
190 __DRIdrawablePrivate *prp;
191
192 /*
193 ** Assume error checking is done properly in glXMakeCurrent before
194 ** calling driUnbindContext.
195 */
196
197 if (ctx == NULL || draw == None || read == None) {
198 /* ERROR!!! */
199 return GL_FALSE;
200 }
201
202 pDRIScreen = (*dri_interface->getScreen)(dpy, scrn);
203 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
204 /* ERROR!!! */
205 return GL_FALSE;
206 }
207
208 psp = (__DRIscreenPrivate *)pDRIScreen->private;
209 pcp = (__DRIcontextPrivate *)ctx->private;
210
211 pdraw = __driFindDrawable(psp->drawHash, draw);
212 if (!pdraw) {
213 /* ERROR!!! */
214 return GL_FALSE;
215 }
216 pdp = (__DRIdrawablePrivate *)pdraw->private;
217
218 pread = __driFindDrawable(psp->drawHash, read);
219 if (!pread) {
220 /* ERROR!!! */
221 return GL_FALSE;
222 }
223 prp = (__DRIdrawablePrivate *)pread->private;
224
225
226 /* Let driver unbind drawable from context */
227 (*psp->DriverAPI.UnbindContext)(pcp);
228
229
230 if (pdp->refcount == 0) {
231 /* ERROR!!! */
232 return GL_FALSE;
233 }
234
235 pdp->refcount--;
236
237 if (prp != pdp) {
238 if (prp->refcount == 0) {
239 /* ERROR!!! */
240 return GL_FALSE;
241 }
242
243 prp->refcount--;
244 }
245
246
247 /* XXX this is disabled so that if we call SwapBuffers on an unbound
248 * window we can determine the last context bound to the window and
249 * use that context's lock. (BrianP, 2-Dec-2000)
250 */
251 #if 0
252 /* Unbind the drawable */
253 pcp->driDrawablePriv = NULL;
254 pdp->driContextPriv = &psp->dummyContextPriv;
255 #endif
256
257 return GL_TRUE;
258 }
259
260
261 /**
262 * This function takes both a read buffer and a draw buffer. This is needed
263 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
264 * function.
265 *
266 * \bug This function calls \c driCreateNewDrawable in two places with the
267 * \c renderType hard-coded to \c GLX_WINDOW_BIT. Some checking might
268 * be needed in those places when support for pbuffers and / or pixmaps
269 * is added. Is it safe to assume that the drawable is a window?
270 */
271 static GLboolean DoBindContext(__DRInativeDisplay *dpy,
272 __DRIid draw, __DRIid read,
273 __DRIcontext *ctx, const __GLcontextModes * modes,
274 __DRIscreenPrivate *psp)
275 {
276 __DRIdrawable *pdraw;
277 __DRIdrawablePrivate *pdp;
278 __DRIdrawable *pread;
279 __DRIdrawablePrivate *prp;
280 __DRIcontextPrivate * const pcp = ctx->private;
281
282
283 /* Find the _DRIdrawable which corresponds to the writing drawable. */
284 pdraw = __driFindDrawable(psp->drawHash, draw);
285 if (!pdraw) {
286 /* Allocate a new drawable */
287 pdraw = (__DRIdrawable *)_mesa_malloc(sizeof(__DRIdrawable));
288 if (!pdraw) {
289 /* ERROR!!! */
290 return GL_FALSE;
291 }
292
293 /* Create a new drawable */
294 driCreateNewDrawable(dpy, modes, draw, pdraw, GLX_WINDOW_BIT,
295 empty_attribute_list);
296 if (!pdraw->private) {
297 /* ERROR!!! */
298 _mesa_free(pdraw);
299 return GL_FALSE;
300 }
301
302 }
303 pdp = (__DRIdrawablePrivate *) pdraw->private;
304
305 /* Find the _DRIdrawable which corresponds to the reading drawable. */
306 if (read == draw) {
307 /* read buffer == draw buffer */
308 prp = pdp;
309 }
310 else {
311 pread = __driFindDrawable(psp->drawHash, read);
312 if (!pread) {
313 /* Allocate a new drawable */
314 pread = (__DRIdrawable *)_mesa_malloc(sizeof(__DRIdrawable));
315 if (!pread) {
316 /* ERROR!!! */
317 return GL_FALSE;
318 }
319
320 /* Create a new drawable */
321 driCreateNewDrawable(dpy, modes, read, pread, GLX_WINDOW_BIT,
322 empty_attribute_list);
323 if (!pread->private) {
324 /* ERROR!!! */
325 _mesa_free(pread);
326 return GL_FALSE;
327 }
328 }
329 prp = (__DRIdrawablePrivate *) pread->private;
330 }
331
332 /* Bind the drawable to the context */
333 pcp->driDrawablePriv = pdp;
334 pdp->driContextPriv = pcp;
335 pdp->refcount++;
336 if ( pdp != prp ) {
337 prp->refcount++;
338 }
339
340 /*
341 ** Now that we have a context associated with this drawable, we can
342 ** initialize the drawable information if has not been done before.
343 */
344 if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) {
345 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
346 __driUtilUpdateDrawableInfo(pdp);
347 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
348 }
349
350 /* Call device-specific MakeCurrent */
351 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
352
353 return GL_TRUE;
354 }
355
356
357 /**
358 * This function takes both a read buffer and a draw buffer. This is needed
359 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
360 * function.
361 */
362 static GLboolean driBindContext(__DRInativeDisplay *dpy, int scrn,
363 __DRIid draw, __DRIid read,
364 __DRIcontext * ctx)
365 {
366 __DRIscreen *pDRIScreen;
367
368 /*
369 ** Assume error checking is done properly in glXMakeCurrent before
370 ** calling driBindContext.
371 */
372
373 if (ctx == NULL || draw == None || read == None) {
374 /* ERROR!!! */
375 return GL_FALSE;
376 }
377
378 pDRIScreen = (*dri_interface->getScreen)(dpy, scrn);
379 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
380 /* ERROR!!! */
381 return GL_FALSE;
382 }
383
384 return DoBindContext( dpy, draw, read, ctx, ctx->mode,
385 (__DRIscreenPrivate *)pDRIScreen->private );
386 }
387 /*@}*/
388
389
390 /*****************************************************************/
391 /** \name Drawable handling functions */
392 /*****************************************************************/
393 /*@{*/
394
395 /**
396 * Update private drawable information.
397 *
398 * \param pdp pointer to the private drawable information to update.
399 *
400 * This function basically updates the __DRIdrawablePrivate struct's
401 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
402 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
403 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
404 * the values are different that means we have to update the clipping
405 * info.
406 */
407 void
408 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
409 {
410 __DRIscreenPrivate *psp;
411 __DRIcontextPrivate *pcp = pdp->driContextPriv;
412
413 if (!pcp || (pdp != pcp->driDrawablePriv)) {
414 /* ERROR!!! */
415 return;
416 }
417
418 psp = pdp->driScreenPriv;
419 if (!psp) {
420 /* ERROR!!! */
421 return;
422 }
423
424 if (pdp->pClipRects) {
425 _mesa_free(pdp->pClipRects);
426 }
427
428 if (pdp->pBackClipRects) {
429 _mesa_free(pdp->pBackClipRects);
430 }
431
432 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
433
434 if (!__driFindDrawable(psp->drawHash, pdp->draw) ||
435 ! (*dri_interface->getDrawableInfo)(pdp->display, pdp->screen, pdp->draw,
436 &pdp->index, &pdp->lastStamp,
437 &pdp->x, &pdp->y, &pdp->w, &pdp->h,
438 &pdp->numClipRects, &pdp->pClipRects,
439 &pdp->backX,
440 &pdp->backY,
441 &pdp->numBackClipRects,
442 &pdp->pBackClipRects )) {
443 /* Error -- eg the window may have been destroyed. Keep going
444 * with no cliprects.
445 */
446 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */
447 pdp->numClipRects = 0;
448 pdp->pClipRects = NULL;
449 pdp->numBackClipRects = 0;
450 pdp->pBackClipRects = NULL;
451 }
452 else
453 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
454
455 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
456
457 }
458
459 /*@}*/
460
461 /*****************************************************************/
462 /** \name GLX callbacks */
463 /*****************************************************************/
464 /*@{*/
465
466 /**
467 * Swap buffers.
468 *
469 * \param dpy the display handle.
470 * \param drawablePrivate opaque pointer to the per-drawable private info.
471 *
472 * \internal
473 * This function calls __DRIdrawablePrivate::swapBuffers.
474 *
475 * Is called directly from glXSwapBuffers().
476 */
477 static void driSwapBuffers( __DRInativeDisplay *dpy, void *drawablePrivate )
478 {
479 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
480 dPriv->swapBuffers(dPriv);
481 (void) dpy;
482 }
483
484 /**
485 * Called directly from a number of higher-level GLX functions.
486 */
487 static int driGetMSC( void *screenPrivate, int64_t *msc )
488 {
489 __DRIscreenPrivate *sPriv = (__DRIscreenPrivate *) screenPrivate;
490
491 return sPriv->DriverAPI.GetMSC( sPriv, msc );
492 }
493
494 /**
495 * Called directly from a number of higher-level GLX functions.
496 */
497 static int driGetSBC( __DRInativeDisplay *dpy, void *drawablePrivate, int64_t *sbc )
498 {
499 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate;
500 __DRIswapInfo sInfo;
501 int status;
502
503
504 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
505 *sbc = sInfo.swap_count;
506
507 return status;
508 }
509
510 static int driWaitForSBC( __DRInativeDisplay * dpy, void *drawablePriv,
511 int64_t target_sbc,
512 int64_t * msc, int64_t * sbc )
513 {
514 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
515
516 return dPriv->driScreenPriv->DriverAPI.WaitForSBC( dPriv, target_sbc,
517 msc, sbc );
518 }
519
520 static int driWaitForMSC( __DRInativeDisplay * dpy, void *drawablePriv,
521 int64_t target_msc,
522 int64_t divisor, int64_t remainder,
523 int64_t * msc, int64_t * sbc )
524 {
525 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
526 __DRIswapInfo sInfo;
527 int status;
528
529
530 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc,
531 divisor, remainder,
532 msc );
533
534 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
535 * is supported but GLX_OML_sync_control is not. Therefore, don't return
536 * an error value if GetSwapInfo() is not implemented.
537 */
538 if ( status == 0
539 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) {
540 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
541 *sbc = sInfo.swap_count;
542 }
543
544 return status;
545 }
546
547 static int64_t driSwapBuffersMSC( __DRInativeDisplay * dpy, void *drawablePriv,
548 int64_t target_msc,
549 int64_t divisor, int64_t remainder )
550 {
551 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv;
552
553 return dPriv->driScreenPriv->DriverAPI.SwapBuffersMSC( dPriv, target_msc,
554 divisor,
555 remainder );
556 }
557
558
559 /**
560 * This is called via __DRIscreenRec's createNewDrawable pointer.
561 */
562 static void *driCreateNewDrawable(__DRInativeDisplay *dpy,
563 const __GLcontextModes *modes,
564 __DRIid draw,
565 __DRIdrawable *pdraw,
566 int renderType,
567 const int *attrs)
568 {
569 __DRIscreen * const pDRIScreen = (*dri_interface->getScreen)(dpy, modes->screen);
570 __DRIscreenPrivate *psp;
571 __DRIdrawablePrivate *pdp;
572
573
574 pdraw->private = NULL;
575
576 /* Since pbuffers are not yet supported, no drawable attributes are
577 * supported either.
578 */
579 (void) attrs;
580
581 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
582 return NULL;
583 }
584
585 pdp = (__DRIdrawablePrivate *)_mesa_malloc(sizeof(__DRIdrawablePrivate));
586 if (!pdp) {
587 return NULL;
588 }
589
590 if (!(*dri_interface->createDrawable)(dpy, modes->screen, draw, &pdp->hHWDrawable)) {
591 _mesa_free(pdp);
592 return NULL;
593 }
594
595 pdp->draw = draw;
596 pdp->pdraw = pdraw;
597 pdp->refcount = 0;
598 pdp->pStamp = NULL;
599 pdp->lastStamp = 0;
600 pdp->index = 0;
601 pdp->x = 0;
602 pdp->y = 0;
603 pdp->w = 0;
604 pdp->h = 0;
605 pdp->numClipRects = 0;
606 pdp->numBackClipRects = 0;
607 pdp->pClipRects = NULL;
608 pdp->pBackClipRects = NULL;
609 pdp->display = dpy;
610 pdp->screen = modes->screen;
611
612 psp = (__DRIscreenPrivate *)pDRIScreen->private;
613 pdp->driScreenPriv = psp;
614 pdp->driContextPriv = &psp->dummyContextPriv;
615
616 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, modes,
617 renderType == GLX_PIXMAP_BIT)) {
618 (void)(*dri_interface->destroyDrawable)(dpy, modes->screen, pdp->draw);
619 _mesa_free(pdp);
620 return NULL;
621 }
622
623 pdraw->private = pdp;
624 pdraw->destroyDrawable = driDestroyDrawable;
625 pdraw->swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
626
627 pdraw->getSBC = driGetSBC;
628 pdraw->waitForSBC = driWaitForSBC;
629 pdraw->waitForMSC = driWaitForMSC;
630 pdraw->swapBuffersMSC = driSwapBuffersMSC;
631 pdraw->frameTracking = NULL;
632 pdraw->queryFrameTracking = driQueryFrameTracking;
633
634 /* This special default value is replaced with the configured
635 * default value when the drawable is first bound to a direct
636 * rendering context.
637 */
638 pdraw->swap_interval = (unsigned)-1;
639
640 pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
641
642 /* Add pdraw to drawable list */
643 if (!__driAddDrawable(psp->drawHash, pdraw)) {
644 /* ERROR!!! */
645 (*pdraw->destroyDrawable)(dpy, pdp);
646 _mesa_free(pdp);
647 pdp = NULL;
648 pdraw->private = NULL;
649 }
650
651 return (void *) pdp;
652 }
653
654 static __DRIdrawable *driGetDrawable(__DRInativeDisplay *dpy, __DRIid draw,
655 void *screenPrivate)
656 {
657 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
658
659 /*
660 ** Make sure this routine returns NULL if the drawable is not bound
661 ** to a direct rendering context!
662 */
663 return __driFindDrawable(psp->drawHash, draw);
664 }
665
666 static void driDestroyDrawable(__DRInativeDisplay *dpy, void *drawablePrivate)
667 {
668 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *) drawablePrivate;
669 __DRIscreenPrivate *psp = pdp->driScreenPriv;
670 int scrn = psp->myNum;
671
672 if (pdp) {
673 (*psp->DriverAPI.DestroyBuffer)(pdp);
674 if ((*dri_interface->windowExists)(dpy, pdp->draw))
675 (void)(*dri_interface->destroyDrawable)(dpy, scrn, pdp->draw);
676 if (pdp->pClipRects) {
677 _mesa_free(pdp->pClipRects);
678 pdp->pClipRects = NULL;
679 }
680 if (pdp->pBackClipRects) {
681 _mesa_free(pdp->pBackClipRects);
682 pdp->pBackClipRects = NULL;
683 }
684 _mesa_free(pdp);
685 }
686 }
687
688 /*@}*/
689
690
691 /*****************************************************************/
692 /** \name Context handling functions */
693 /*****************************************************************/
694 /*@{*/
695
696 /**
697 * Destroy the per-context private information.
698 *
699 * \param dpy the display handle.
700 * \param scrn the screen number.
701 * \param contextPrivate opaque pointer to the per-drawable private info.
702 *
703 * \internal
704 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
705 * drmDestroyContext(), and finally frees \p contextPrivate.
706 */
707 static void driDestroyContext(__DRInativeDisplay *dpy, int scrn, void *contextPrivate)
708 {
709 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *) contextPrivate;
710
711 if (pcp) {
712 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
713 __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
714 (void) (*dri_interface->destroyContext)(dpy, scrn, pcp->contextID);
715 _mesa_free(pcp);
716 }
717 }
718
719
720 /**
721 * Create the per-drawable private driver information.
722 *
723 * \param dpy The display handle.
724 * \param modes Mode used to create the new context.
725 * \param render_type Type of rendering target. \c GLX_RGBA is the only
726 * type likely to ever be supported for direct-rendering.
727 * \param sharedPrivate The shared context dependent methods or \c NULL if
728 * non-existent.
729 * \param pctx DRI context to receive the context dependent methods.
730 *
731 * \returns An opaque pointer to the per-context private information on
732 * success, or \c NULL on failure.
733 *
734 * \internal
735 * This function allocates and fills a __DRIcontextPrivateRec structure. It
736 * performs some device independent initialization and passes all the
737 * relevent information to __DriverAPIRec::CreateContext to create the
738 * context.
739 *
740 */
741 static void *
742 driCreateNewContext(__DRInativeDisplay *dpy, const __GLcontextModes *modes,
743 int render_type, void *sharedPrivate, __DRIcontext *pctx)
744 {
745 __DRIscreen *pDRIScreen;
746 __DRIcontextPrivate *pcp;
747 __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
748 __DRIscreenPrivate *psp;
749 void * const shareCtx = (pshare != NULL) ? pshare->driverPrivate : NULL;
750
751 pDRIScreen = (*dri_interface->getScreen)(dpy, modes->screen);
752 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
753 /* ERROR!!! */
754 return NULL;
755 }
756
757 psp = (__DRIscreenPrivate *)pDRIScreen->private;
758
759 pcp = (__DRIcontextPrivate *)_mesa_malloc(sizeof(__DRIcontextPrivate));
760 if (!pcp) {
761 return NULL;
762 }
763
764 if (! (*dri_interface->createContext)(dpy, modes->screen, modes->fbconfigID,
765 &pcp->contextID, &pcp->hHWContext)) {
766 _mesa_free(pcp);
767 return NULL;
768 }
769
770 pcp->display = dpy;
771 pcp->driScreenPriv = psp;
772 pcp->driDrawablePriv = NULL;
773
774 /* When the first context is created for a screen, initialize a "dummy"
775 * context.
776 */
777
778 if (!psp->dummyContextPriv.driScreenPriv) {
779 psp->dummyContextPriv.contextID = 0;
780 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context;
781 psp->dummyContextPriv.driScreenPriv = psp;
782 psp->dummyContextPriv.driDrawablePriv = NULL;
783 psp->dummyContextPriv.driverPrivate = NULL;
784 /* No other fields should be used! */
785 }
786
787 pctx->destroyContext = driDestroyContext;
788 pctx->bindContext = driBindContext;
789 pctx->unbindContext = driUnbindContext;
790
791 if ( !(*psp->DriverAPI.CreateContext)(modes, pcp, shareCtx) ) {
792 (void) (*dri_interface->destroyContext)(dpy, modes->screen,
793 pcp->contextID);
794 _mesa_free(pcp);
795 return NULL;
796 }
797
798 __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash);
799
800 return pcp;
801 }
802 /*@}*/
803
804
805 /*****************************************************************/
806 /** \name Screen handling functions */
807 /*****************************************************************/
808 /*@{*/
809
810 /**
811 * Destroy the per-screen private information.
812 *
813 * \param dpy the display handle.
814 * \param scrn the screen number.
815 * \param screenPrivate opaque pointer to the per-screen private information.
816 *
817 * \internal
818 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
819 * drmClose(), and finally frees \p screenPrivate.
820 */
821 static void driDestroyScreen(__DRInativeDisplay *dpy, int scrn, void *screenPrivate)
822 {
823 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate;
824
825 if (psp) {
826 /* No interaction with the X-server is possible at this point. This
827 * routine is called after XCloseDisplay, so there is no protocol
828 * stream open to the X-server anymore.
829 */
830
831 if (psp->DriverAPI.DestroyScreen)
832 (*psp->DriverAPI.DestroyScreen)(psp);
833
834 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
835 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
836 _mesa_free(psp->pDevPriv);
837 (void)drmClose(psp->fd);
838 if ( psp->modes != NULL ) {
839 _gl_context_modes_destroy( psp->modes );
840 }
841 _mesa_free(psp);
842 }
843 }
844
845
846 /**
847 * Utility function used to create a new driver-private screen structure.
848 *
849 * \param dpy Display pointer
850 * \param scrn Index of the screen
851 * \param psc DRI screen data (not driver private)
852 * \param modes Linked list of known display modes. This list is, at a
853 * minimum, a list of modes based on the current display mode.
854 * These roughly match the set of available X11 visuals, but it
855 * need not be limited to X11! The calling libGL should create
856 * a list that will inform the driver of the current display
857 * mode (i.e., color buffer depth, depth buffer depth, etc.).
858 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
859 * all drivers.
860 * \param dri_version Version of the "server-side" DRI.
861 * \param drm_version Version of the kernel DRM.
862 * \param frame_buffer Data describing the location and layout of the
863 * framebuffer.
864 * \param pSAREA Pointer the the SAREA.
865 * \param fd Device handle for the DRM.
866 * \param internal_api_version Version of the internal interface between the
867 * driver and libGL.
868 * \param driverAPI Driver API functions used by other routines in dri_util.c.
869 *
870 * \note
871 * There is no need to check the minimum API version in this function. Since
872 * the \c __driCreateNewScreen function is versioned, it is impossible for a
873 * loader that is too old to even load this driver.
874 */
875 __DRIscreenPrivate *
876 __driUtilCreateNewScreen(__DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
877 __GLcontextModes * modes,
878 const __DRIversion * ddx_version,
879 const __DRIversion * dri_version,
880 const __DRIversion * drm_version,
881 const __DRIframebuffer * frame_buffer,
882 drm_sarea_t *pSAREA,
883 int fd,
884 int internal_api_version,
885 const struct __DriverAPIRec *driverAPI)
886 {
887 __DRIscreenPrivate *psp;
888
889
890 api_ver = internal_api_version;
891
892 psp = (__DRIscreenPrivate *)_mesa_malloc(sizeof(__DRIscreenPrivate));
893 if (!psp) {
894 return NULL;
895 }
896
897 /* Create the hash table */
898 psp->drawHash = drmHashCreate();
899 if ( psp->drawHash == NULL ) {
900 _mesa_free( psp );
901 return NULL;
902 }
903
904 psp->display = dpy;
905 psp->myNum = scrn;
906 psp->psc = psc;
907 psp->modes = modes;
908
909 /*
910 ** NOT_DONE: This is used by the X server to detect when the client
911 ** has died while holding the drawable lock. The client sets the
912 ** drawable lock to this value.
913 */
914 psp->drawLockID = 1;
915
916 psp->drmMajor = drm_version->major;
917 psp->drmMinor = drm_version->minor;
918 psp->drmPatch = drm_version->patch;
919 psp->ddxMajor = ddx_version->major;
920 psp->ddxMinor = ddx_version->minor;
921 psp->ddxPatch = ddx_version->patch;
922 psp->driMajor = dri_version->major;
923 psp->driMinor = dri_version->minor;
924 psp->driPatch = dri_version->patch;
925
926 /* install driver's callback functions */
927 memcpy( &psp->DriverAPI, driverAPI, sizeof(struct __DriverAPIRec) );
928
929 psp->pSAREA = pSAREA;
930
931 psp->pFB = frame_buffer->base;
932 psp->fbSize = frame_buffer->size;
933 psp->fbStride = frame_buffer->stride;
934 psp->fbWidth = frame_buffer->width;
935 psp->fbHeight = frame_buffer->height;
936 psp->devPrivSize = frame_buffer->dev_priv_size;
937 psp->pDevPriv = frame_buffer->dev_priv;
938 psp->fbBPP = psp->fbStride * 8 / frame_buffer->width;
939
940 psp->fd = fd;
941
942 /*
943 ** Do not init dummy context here; actual initialization will be
944 ** done when the first DRI context is created. Init screen priv ptr
945 ** to NULL to let CreateContext routine that it needs to be inited.
946 */
947 psp->dummyContextPriv.driScreenPriv = NULL;
948
949 psc->destroyScreen = driDestroyScreen;
950 psc->createNewDrawable = driCreateNewDrawable;
951 psc->getDrawable = driGetDrawable;
952 psc->getMSC = driGetMSC;
953 psc->createNewContext = driCreateNewContext;
954
955 if ( (psp->DriverAPI.InitDriver != NULL)
956 && !(*psp->DriverAPI.InitDriver)(psp) ) {
957 _mesa_free( psp );
958 return NULL;
959 }
960
961
962 return psp;
963 }
964
965
966 /**
967 * Compare the current GLX API version with a driver supplied required version.
968 *
969 * The minimum required version is compared with the API version exported by
970 * the \c __glXGetInternalVersion function (in libGL.so).
971 *
972 * \param required_version Minimum required internal GLX API version.
973 * \return A tri-value return, as from strcmp is returned. A value less
974 * than, equal to, or greater than zero will be returned if the
975 * internal GLX API version is less than, equal to, or greater
976 * than \c required_version.
977 *
978 * \sa __glXGetInternalVersion().
979 */
980 int driCompareGLXAPIVersion( GLint required_version )
981 {
982 if ( api_ver > required_version ) {
983 return 1;
984 }
985 else if ( api_ver == required_version ) {
986 return 0;
987 }
988
989 return -1;
990 }
991
992
993 static int
994 driQueryFrameTracking( __DRInativeDisplay * dpy, void * priv,
995 int64_t * sbc, int64_t * missedFrames,
996 float * lastMissedUsage, float * usage )
997 {
998 __DRIswapInfo sInfo;
999 int status;
1000 int64_t ust;
1001 __DRIdrawablePrivate * dpriv = (__DRIdrawablePrivate *) priv;
1002
1003
1004 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo );
1005 if ( status == 0 ) {
1006 *sbc = sInfo.swap_count;
1007 *missedFrames = sInfo.swap_missed_count;
1008 *lastMissedUsage = sInfo.swap_missed_usage;
1009
1010 (*dri_interface->getUST)( & ust );
1011 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust );
1012 }
1013
1014 return status;
1015 }
1016
1017
1018 /**
1019 * Calculate amount of swap interval used between GLX buffer swaps.
1020 *
1021 * The usage value, on the range [0,max], is the fraction of total swap
1022 * interval time used between GLX buffer swaps is calculated.
1023 *
1024 * \f$p = t_d / (i * t_r)\f$
1025 *
1026 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
1027 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
1028 * required for a single vertical refresh period (as returned by \c
1029 * glXGetMscRateOML).
1030 *
1031 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
1032 * details.
1033 *
1034 * \param dPriv Pointer to the private drawable structure.
1035 * \return If less than a single swap interval time period was required
1036 * between GLX buffer swaps, a number greater than 0 and less than
1037 * 1.0 is returned. If exactly one swap interval time period is
1038 * required, 1.0 is returned, and if more than one is required then
1039 * a number greater than 1.0 will be returned.
1040 *
1041 * \sa glXSwapIntervalSGI glXGetMscRateOML
1042 *
1043 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
1044 * be possible to cache the sync rate?
1045 */
1046 float
1047 driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
1048 int64_t current_ust )
1049 {
1050 int32_t n;
1051 int32_t d;
1052 int interval;
1053 float usage = 1.0;
1054
1055
1056 if ( (*dri_interface->getMSCRate)( dPriv->display, dPriv->draw, &n, &d ) ) {
1057 interval = (dPriv->pdraw->swap_interval != 0)
1058 ? dPriv->pdraw->swap_interval : 1;
1059
1060
1061 /* We want to calculate
1062 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
1063 * current_UST by calling __glXGetUST. last_swap_UST is stored in
1064 * dPriv->swap_ust. interval has already been calculated.
1065 *
1066 * The only tricky part is us_per_refresh. us_per_refresh is
1067 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
1068 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
1069 * the denominator of the final calculation, we calculate
1070 * (interval * 1000000 * d) and move n into the numerator.
1071 */
1072
1073 usage = (current_ust - last_swap_ust);
1074 usage *= n;
1075 usage /= (interval * d);
1076 usage /= 1000000.0;
1077 }
1078
1079 return usage;
1080 }
1081
1082 /*@}*/