Move media stream counter entry points to new extension.
[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
35 #ifndef GLX_OML_sync_control
36 typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator);
37 #endif
38
39 /* This pointer *must* be set by the driver's __driCreateNewScreen funciton!
40 */
41 const __DRIinterfaceMethods * dri_interface = NULL;
42
43 /**
44 * This is used in a couple of places that call \c driCreateNewDrawable.
45 */
46 static const int empty_attribute_list[1] = { None };
47
48
49 /**
50 * Cached copy of the internal API version used by libGL and the client-side
51 * DRI driver.
52 */
53 static int api_ver = 0;
54
55 static void *driCreateNewDrawable(__DRIscreen *screen,
56 const __GLcontextModes *modes,
57 __DRIdrawable *pdraw,
58 drm_drawable_t hwDrawable,
59 int renderType, const int *attrs);
60
61 static void driDestroyDrawable(__DRIdrawable *drawable);
62
63
64 /**
65 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
66 * is set.
67 *
68 * Is called from the drivers.
69 *
70 * \param f \c printf like format string.
71 */
72 void
73 __driUtilMessage(const char *f, ...)
74 {
75 va_list args;
76
77 if (getenv("LIBGL_DEBUG")) {
78 fprintf(stderr, "libGL error: \n");
79 va_start(args, f);
80 vfprintf(stderr, f, args);
81 va_end(args);
82 fprintf(stderr, "\n");
83 }
84 }
85
86
87 /*****************************************************************/
88 /** \name Context (un)binding functions */
89 /*****************************************************************/
90 /*@{*/
91
92 /**
93 * Unbind context.
94 *
95 * \param scrn the screen.
96 * \param gc context.
97 *
98 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
99 *
100 * \internal
101 * This function calls __DriverAPIRec::UnbindContext, and then decrements
102 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
103 * return.
104 *
105 * While casting the opaque private pointers associated with the parameters
106 * into their respective real types it also assures they are not \c NULL.
107 */
108 static GLboolean driUnbindContext(__DRIcontext *ctx)
109 {
110 __DRIcontextPrivate *pcp;
111 __DRIscreenPrivate *psp;
112 __DRIdrawablePrivate *pdp;
113 __DRIdrawablePrivate *prp;
114
115 /*
116 ** Assume error checking is done properly in glXMakeCurrent before
117 ** calling driUnbindContext.
118 */
119
120 if (ctx == NULL)
121 return GL_FALSE;
122
123 pcp = (__DRIcontextPrivate *)ctx->private;
124 psp = (__DRIscreenPrivate *)pcp->driScreenPriv;
125 pdp = (__DRIdrawablePrivate *)pcp->driDrawablePriv;
126 prp = (__DRIdrawablePrivate *)pcp->driReadablePriv;
127
128 /* Let driver unbind drawable from context */
129 (*psp->DriverAPI.UnbindContext)(pcp);
130
131 if (pdp->refcount == 0) {
132 /* ERROR!!! */
133 return GL_FALSE;
134 }
135
136 pdp->refcount--;
137
138 if (prp != pdp) {
139 if (prp->refcount == 0) {
140 /* ERROR!!! */
141 return GL_FALSE;
142 }
143
144 prp->refcount--;
145 }
146
147
148 /* XXX this is disabled so that if we call SwapBuffers on an unbound
149 * window we can determine the last context bound to the window and
150 * use that context's lock. (BrianP, 2-Dec-2000)
151 */
152 #if 0
153 /* Unbind the drawable */
154 pcp->driDrawablePriv = NULL;
155 pdp->driContextPriv = &psp->dummyContextPriv;
156 #endif
157
158 return GL_TRUE;
159 }
160
161
162 /**
163 * This function takes both a read buffer and a draw buffer. This is needed
164 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
165 * function.
166 */
167 static GLboolean DoBindContext(__DRIcontext *ctx,
168 __DRIdrawable *pdraw,
169 __DRIdrawable *pread)
170 {
171 __DRIdrawablePrivate *pdp;
172 __DRIdrawablePrivate *prp;
173 __DRIcontextPrivate * const pcp = ctx->private;
174 __DRIscreenPrivate *psp = pcp->driScreenPriv;
175
176 pdp = (__DRIdrawablePrivate *) pdraw->private;
177 prp = (__DRIdrawablePrivate *) pread->private;
178
179 /* Bind the drawable to the context */
180 pcp->driDrawablePriv = pdp;
181 pcp->driReadablePriv = prp;
182 pdp->driContextPriv = pcp;
183 pdp->refcount++;
184 if ( pdp != prp ) {
185 prp->refcount++;
186 }
187
188 /*
189 ** Now that we have a context associated with this drawable, we can
190 ** initialize the drawable information if has not been done before.
191 */
192 if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) {
193 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
194 __driUtilUpdateDrawableInfo(pdp);
195 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
196 }
197
198 if ((pdp != prp) && (!prp->pStamp || *prp->pStamp != prp->lastStamp)) {
199 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
200 __driUtilUpdateDrawableInfo(prp);
201 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
202 }
203
204 /* Call device-specific MakeCurrent */
205 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
206
207 return GL_TRUE;
208 }
209
210
211 /**
212 * This function takes both a read buffer and a draw buffer. This is needed
213 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
214 * function.
215 */
216 static GLboolean driBindContext(__DRIcontext * ctx,
217 __DRIdrawable *pdraw,
218 __DRIdrawable *pread)
219 {
220 /*
221 ** Assume error checking is done properly in glXMakeCurrent before
222 ** calling driBindContext.
223 */
224
225 if (ctx == NULL || pdraw == None || pread == None)
226 return GL_FALSE;
227
228 return DoBindContext( ctx, pdraw, pread );
229 }
230 /*@}*/
231
232
233 /*****************************************************************/
234 /** \name Drawable handling functions */
235 /*****************************************************************/
236 /*@{*/
237
238 /**
239 * Update private drawable information.
240 *
241 * \param pdp pointer to the private drawable information to update.
242 *
243 * This function basically updates the __DRIdrawablePrivate struct's
244 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
245 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
246 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
247 * the values are different that means we have to update the clipping
248 * info.
249 */
250 void
251 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
252 {
253 __DRIscreenPrivate *psp;
254 __DRIcontextPrivate *pcp = pdp->driContextPriv;
255
256 if (!pcp
257 || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) {
258 /* ERROR!!!
259 * ...but we must ignore it. There can be many contexts bound to a
260 * drawable.
261 */
262 }
263
264 psp = pdp->driScreenPriv;
265 if (!psp) {
266 /* ERROR!!! */
267 _mesa_problem(NULL, "Warning! Possible infinite loop due to bug "
268 "in file %s, line %d\n",
269 __FILE__, __LINE__);
270 return;
271 }
272
273 if (pdp->pClipRects) {
274 _mesa_free(pdp->pClipRects);
275 pdp->pClipRects = NULL;
276 }
277
278 if (pdp->pBackClipRects) {
279 _mesa_free(pdp->pBackClipRects);
280 pdp->pBackClipRects = NULL;
281 }
282
283 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
284
285 if (! (*dri_interface->getDrawableInfo)(pdp->pdraw,
286 &pdp->index, &pdp->lastStamp,
287 &pdp->x, &pdp->y, &pdp->w, &pdp->h,
288 &pdp->numClipRects, &pdp->pClipRects,
289 &pdp->backX,
290 &pdp->backY,
291 &pdp->numBackClipRects,
292 &pdp->pBackClipRects )) {
293 /* Error -- eg the window may have been destroyed. Keep going
294 * with no cliprects.
295 */
296 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */
297 pdp->numClipRects = 0;
298 pdp->pClipRects = NULL;
299 pdp->numBackClipRects = 0;
300 pdp->pBackClipRects = NULL;
301 }
302 else
303 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
304
305 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
306
307 }
308
309 /*@}*/
310
311 /*****************************************************************/
312 /** \name GLX callbacks */
313 /*****************************************************************/
314 /*@{*/
315
316 /**
317 * Swap buffers.
318 *
319 * \param drawablePrivate opaque pointer to the per-drawable private info.
320 *
321 * \internal
322 * This function calls __DRIdrawablePrivate::swapBuffers.
323 *
324 * Is called directly from glXSwapBuffers().
325 */
326 static void driSwapBuffers(__DRIdrawable *drawable)
327 {
328 __DRIdrawablePrivate *dPriv = drawable->private;
329 drm_clip_rect_t rect;
330
331 dPriv->swapBuffers(dPriv);
332
333 /* Check that we actually have the new damage report method */
334 if (api_ver < 20070105 || dri_interface->reportDamage == NULL)
335 return;
336
337 /* Assume it's affecting the whole drawable for now */
338 rect.x1 = 0;
339 rect.y1 = 0;
340 rect.x2 = rect.x1 + dPriv->w;
341 rect.y2 = rect.y1 + dPriv->h;
342
343 /* Report the damage. Currently, all our drivers draw directly to the
344 * front buffer, so we report the damage there rather than to the backing
345 * store (if any).
346 */
347 (*dri_interface->reportDamage)(dPriv->pdraw, dPriv->x, dPriv->y,
348 &rect, 1, GL_TRUE);
349 }
350
351 /**
352 * Called directly from a number of higher-level GLX functions.
353 */
354 static int driGetMSC( __DRIscreen *screen, int64_t *msc )
355 {
356 __DRIscreenPrivate *sPriv = screen->private;
357
358 return sPriv->DriverAPI.GetMSC( sPriv, msc );
359 }
360
361 static int driWaitForMSC(__DRIdrawable *drawable, int64_t target_msc,
362 int64_t divisor, int64_t remainder,
363 int64_t * msc, int64_t * sbc)
364 {
365 __DRIdrawablePrivate *dPriv = drawable->private;
366 __DRIswapInfo sInfo;
367 int status;
368
369
370 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc,
371 divisor, remainder,
372 msc );
373
374 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
375 * is supported but GLX_OML_sync_control is not. Therefore, don't return
376 * an error value if GetSwapInfo() is not implemented.
377 */
378 if ( status == 0
379 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) {
380 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
381 *sbc = sInfo.swap_count;
382 }
383
384 return status;
385 }
386
387 const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = {
388 { __DRI_MEDIA_STREAM_COUNTER },
389 driGetMSC,
390 driWaitForMSC,
391 };
392
393 static void driCopySubBuffer(__DRIdrawable *drawable,
394 int x, int y, int w, int h)
395 {
396 __DRIdrawablePrivate *dPriv = drawable->private;
397 dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h);
398 }
399
400 const __DRIcopySubBufferExtension driCopySubBufferExtension = {
401 { __DRI_COPY_SUB_BUFFER }, driCopySubBuffer
402 };
403
404 static void driSetSwapInterval(__DRIdrawable *drawable, unsigned int interval)
405 {
406 __DRIdrawablePrivate *dpriv = drawable->private;
407
408 dpriv->swap_interval = interval;
409 }
410
411 static unsigned int driGetSwapInterval(__DRIdrawable *drawable)
412 {
413 __DRIdrawablePrivate *dpriv = drawable->private;
414
415 return dpriv->swap_interval;
416 }
417
418 const __DRIswapControlExtension driSwapControlExtension = {
419 { __DRI_SWAP_CONTROL },
420 driSetSwapInterval,
421 driGetSwapInterval
422 };
423
424
425 /**
426 * This is called via __DRIscreenRec's createNewDrawable pointer.
427 */
428 static void *driCreateNewDrawable(__DRIscreen *screen,
429 const __GLcontextModes *modes,
430 __DRIdrawable *pdraw,
431 drm_drawable_t hwDrawable,
432 int renderType,
433 const int *attrs)
434 {
435 __DRIscreenPrivate *psp;
436 __DRIdrawablePrivate *pdp;
437
438
439 pdraw->private = NULL;
440
441 /* Since pbuffers are not yet supported, no drawable attributes are
442 * supported either.
443 */
444 (void) attrs;
445
446 pdp = (__DRIdrawablePrivate *)_mesa_malloc(sizeof(__DRIdrawablePrivate));
447 if (!pdp) {
448 return NULL;
449 }
450
451 pdp->hHWDrawable = hwDrawable;
452 pdp->pdraw = pdraw;
453 pdp->refcount = 0;
454 pdp->pStamp = NULL;
455 pdp->lastStamp = 0;
456 pdp->index = 0;
457 pdp->x = 0;
458 pdp->y = 0;
459 pdp->w = 0;
460 pdp->h = 0;
461 pdp->numClipRects = 0;
462 pdp->numBackClipRects = 0;
463 pdp->pClipRects = NULL;
464 pdp->pBackClipRects = NULL;
465
466 psp = (__DRIscreenPrivate *)screen->private;
467 pdp->driScreenPriv = psp;
468 pdp->driContextPriv = &psp->dummyContextPriv;
469
470 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, modes,
471 renderType == GLX_PIXMAP_BIT)) {
472 _mesa_free(pdp);
473 return NULL;
474 }
475
476 pdraw->private = pdp;
477 pdraw->destroyDrawable = driDestroyDrawable;
478 pdraw->swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
479
480 /* This special default value is replaced with the configured
481 * default value when the drawable is first bound to a direct
482 * rendering context.
483 */
484 pdp->swap_interval = (unsigned)-1;
485
486 pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
487
488 return (void *) pdp;
489 }
490
491 static void
492 driDestroyDrawable(__DRIdrawable *drawable)
493 {
494 __DRIdrawablePrivate *pdp = drawable->private;
495 __DRIscreenPrivate *psp;
496
497 if (pdp) {
498 psp = pdp->driScreenPriv;
499 (*psp->DriverAPI.DestroyBuffer)(pdp);
500 if (pdp->pClipRects) {
501 _mesa_free(pdp->pClipRects);
502 pdp->pClipRects = NULL;
503 }
504 if (pdp->pBackClipRects) {
505 _mesa_free(pdp->pBackClipRects);
506 pdp->pBackClipRects = NULL;
507 }
508 _mesa_free(pdp);
509 }
510 }
511
512 /*@}*/
513
514
515 /*****************************************************************/
516 /** \name Context handling functions */
517 /*****************************************************************/
518 /*@{*/
519
520 /**
521 * Destroy the per-context private information.
522 *
523 * \param contextPrivate opaque pointer to the per-drawable private info.
524 *
525 * \internal
526 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
527 * drmDestroyContext(), and finally frees \p contextPrivate.
528 */
529 static void
530 driDestroyContext(__DRIcontext *context)
531 {
532 __DRIcontextPrivate *pcp = context->private;
533
534 if (pcp) {
535 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
536 _mesa_free(pcp);
537 }
538 }
539
540
541 /**
542 * Create the per-drawable private driver information.
543 *
544 * \param dpy The display handle.
545 * \param modes Mode used to create the new context.
546 * \param render_type Type of rendering target. \c GLX_RGBA is the only
547 * type likely to ever be supported for direct-rendering.
548 * \param sharedPrivate The shared context dependent methods or \c NULL if
549 * non-existent.
550 * \param pctx DRI context to receive the context dependent methods.
551 *
552 * \returns An opaque pointer to the per-context private information on
553 * success, or \c NULL on failure.
554 *
555 * \internal
556 * This function allocates and fills a __DRIcontextPrivateRec structure. It
557 * performs some device independent initialization and passes all the
558 * relevent information to __DriverAPIRec::CreateContext to create the
559 * context.
560 *
561 */
562 static void *
563 driCreateNewContext(__DRIscreen *screen, const __GLcontextModes *modes,
564 int render_type, void *sharedPrivate,
565 drm_context_t hwContext, __DRIcontext *pctx)
566 {
567 __DRIcontextPrivate *pcp;
568 __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
569 __DRIscreenPrivate *psp;
570 void * const shareCtx = (pshare != NULL) ? pshare->driverPrivate : NULL;
571
572 psp = (__DRIscreenPrivate *)screen->private;
573
574 pcp = (__DRIcontextPrivate *)_mesa_malloc(sizeof(__DRIcontextPrivate));
575 if (!pcp) {
576 return NULL;
577 }
578
579 pcp->hHWContext = hwContext;
580 pcp->driScreenPriv = psp;
581 pcp->driDrawablePriv = NULL;
582
583 /* When the first context is created for a screen, initialize a "dummy"
584 * context.
585 */
586
587 if (!psp->dummyContextPriv.driScreenPriv) {
588 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context;
589 psp->dummyContextPriv.driScreenPriv = psp;
590 psp->dummyContextPriv.driDrawablePriv = NULL;
591 psp->dummyContextPriv.driverPrivate = NULL;
592 /* No other fields should be used! */
593 }
594
595 pctx->destroyContext = driDestroyContext;
596 pctx->bindContext = driBindContext;
597 pctx->unbindContext = driUnbindContext;
598
599 if ( !(*psp->DriverAPI.CreateContext)(modes, pcp, shareCtx) ) {
600 _mesa_free(pcp);
601 return NULL;
602 }
603
604 return pcp;
605 }
606 /*@}*/
607
608
609 static const __DRIextension **
610 driGetExtensions(__DRIscreen *screen)
611 {
612 __DRIscreenPrivate *psp = screen->private;
613
614 return psp->extensions;
615 }
616
617 /*****************************************************************/
618 /** \name Screen handling functions */
619 /*****************************************************************/
620 /*@{*/
621
622 /**
623 * Destroy the per-screen private information.
624 *
625 * \param dpy the display handle.
626 * \param scrn the screen number.
627 * \param screenPrivate opaque pointer to the per-screen private information.
628 *
629 * \internal
630 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
631 * drmClose(), and finally frees \p screenPrivate.
632 */
633 static void driDestroyScreen(__DRIscreen *screen)
634 {
635 __DRIscreenPrivate *psp = screen->private;
636
637 if (psp) {
638 /* No interaction with the X-server is possible at this point. This
639 * routine is called after XCloseDisplay, so there is no protocol
640 * stream open to the X-server anymore.
641 */
642
643 if (psp->DriverAPI.DestroyScreen)
644 (*psp->DriverAPI.DestroyScreen)(psp);
645
646 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
647 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
648 (void)drmCloseOnce(psp->fd);
649
650 _mesa_free(psp);
651 }
652 }
653
654
655 /**
656 * This is the bootstrap function for the driver. libGL supplies all of the
657 * requisite information about the system, and the driver initializes itself.
658 * This routine also fills in the linked list pointed to by \c driver_modes
659 * with the \c __GLcontextModes that the driver can support for windows or
660 * pbuffers.
661 *
662 * \param scrn Index of the screen
663 * \param psc DRI screen data (not driver private)
664 * \param modes Linked list of known display modes. This list is, at a
665 * minimum, a list of modes based on the current display mode.
666 * These roughly match the set of available X11 visuals, but it
667 * need not be limited to X11! The calling libGL should create
668 * a list that will inform the driver of the current display
669 * mode (i.e., color buffer depth, depth buffer depth, etc.).
670 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
671 * all drivers.
672 * \param dri_version Version of the "server-side" DRI.
673 * \param drm_version Version of the kernel DRM.
674 * \param frame_buffer Data describing the location and layout of the
675 * framebuffer.
676 * \param pSAREA Pointer the the SAREA.
677 * \param fd Device handle for the DRM.
678 * \param internal_api_version Version of the internal interface between the
679 * driver and libGL.
680 * \param driverAPI Driver API functions used by other routines in dri_util.c.
681 *
682 * \note There is no need to check the minimum API version in this
683 * function. Since the name of this function is versioned, it is
684 * impossible for a loader that is too old to even load this driver.
685 */
686 PUBLIC
687 void * __DRI_CREATE_NEW_SCREEN( int scrn, __DRIscreen *psc,
688 const __DRIversion * ddx_version,
689 const __DRIversion * dri_version,
690 const __DRIversion * drm_version,
691 const __DRIframebuffer * frame_buffer,
692 drmAddress pSAREA, int fd,
693 int internal_api_version,
694 const __DRIinterfaceMethods * interface,
695 __GLcontextModes ** driver_modes )
696
697 {
698 __DRIscreenPrivate *psp;
699 static const __DRIextension *emptyExtensionList[] = { NULL };
700 dri_interface = interface;
701 api_ver = internal_api_version;
702
703 psp = _mesa_malloc(sizeof(*psp));
704 if (!psp)
705 return NULL;
706
707 psp->psc = psc;
708
709 /*
710 ** NOT_DONE: This is used by the X server to detect when the client
711 ** has died while holding the drawable lock. The client sets the
712 ** drawable lock to this value.
713 */
714 psp->drawLockID = 1;
715
716 psp->drm_version = *drm_version;
717 psp->ddx_version = *ddx_version;
718 psp->dri_version = *dri_version;
719
720 psp->pSAREA = pSAREA;
721
722 psp->pFB = frame_buffer->base;
723 psp->fbSize = frame_buffer->size;
724 psp->fbStride = frame_buffer->stride;
725 psp->fbWidth = frame_buffer->width;
726 psp->fbHeight = frame_buffer->height;
727 psp->devPrivSize = frame_buffer->dev_priv_size;
728 psp->pDevPriv = frame_buffer->dev_priv;
729 psp->fbBPP = psp->fbStride * 8 / frame_buffer->width;
730
731 psp->extensions = emptyExtensionList;
732 psp->fd = fd;
733 psp->myNum = scrn;
734
735 /*
736 ** Do not init dummy context here; actual initialization will be
737 ** done when the first DRI context is created. Init screen priv ptr
738 ** to NULL to let CreateContext routine that it needs to be inited.
739 */
740 psp->dummyContextPriv.driScreenPriv = NULL;
741
742 psc->destroyScreen = driDestroyScreen;
743 psc->getExtensions = driGetExtensions;
744 psc->createNewDrawable = driCreateNewDrawable;
745 psc->createNewContext = driCreateNewContext;
746
747 if (internal_api_version >= 20070121)
748 psc->setTexOffset = psp->DriverAPI.setTexOffset;
749
750 *driver_modes = __driDriverInitScreen(psp);
751 if (*driver_modes == NULL) {
752 _mesa_free(psp);
753 return NULL;
754 }
755
756 return psp;
757 }
758
759 /**
760 * Compare the current GLX API version with a driver supplied required version.
761 *
762 * The minimum required version is compared with the API version exported by
763 * the \c __glXGetInternalVersion function (in libGL.so).
764 *
765 * \param required_version Minimum required internal GLX API version.
766 * \return A tri-value return, as from strcmp is returned. A value less
767 * than, equal to, or greater than zero will be returned if the
768 * internal GLX API version is less than, equal to, or greater
769 * than \c required_version.
770 *
771 * \sa __glXGetInternalVersion().
772 */
773 int driCompareGLXAPIVersion( GLint required_version )
774 {
775 if ( api_ver > required_version ) {
776 return 1;
777 }
778 else if ( api_ver == required_version ) {
779 return 0;
780 }
781
782 return -1;
783 }
784
785
786 static int
787 driFrameTracking(__DRIdrawable *drawable, GLboolean enable)
788 {
789 return GLX_BAD_CONTEXT;
790 }
791
792 static int
793 driQueryFrameTracking(__DRIdrawable *drawable,
794 int64_t * sbc, int64_t * missedFrames,
795 float * lastMissedUsage, float * usage)
796 {
797 __DRIswapInfo sInfo;
798 int status;
799 int64_t ust;
800 __DRIdrawablePrivate * dpriv = drawable->private;
801
802
803 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo );
804 if ( status == 0 ) {
805 *sbc = sInfo.swap_count;
806 *missedFrames = sInfo.swap_missed_count;
807 *lastMissedUsage = sInfo.swap_missed_usage;
808
809 (*dri_interface->getUST)( & ust );
810 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust );
811 }
812
813 return status;
814 }
815
816 const __DRIframeTrackingExtension driFrameTrackingExtension = {
817 { __DRI_FRAME_TRACKING },
818 driFrameTracking,
819 driQueryFrameTracking
820 };
821
822 /**
823 * Calculate amount of swap interval used between GLX buffer swaps.
824 *
825 * The usage value, on the range [0,max], is the fraction of total swap
826 * interval time used between GLX buffer swaps is calculated.
827 *
828 * \f$p = t_d / (i * t_r)\f$
829 *
830 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
831 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
832 * required for a single vertical refresh period (as returned by \c
833 * glXGetMscRateOML).
834 *
835 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
836 * details.
837 *
838 * \param dPriv Pointer to the private drawable structure.
839 * \return If less than a single swap interval time period was required
840 * between GLX buffer swaps, a number greater than 0 and less than
841 * 1.0 is returned. If exactly one swap interval time period is
842 * required, 1.0 is returned, and if more than one is required then
843 * a number greater than 1.0 will be returned.
844 *
845 * \sa glXSwapIntervalSGI glXGetMscRateOML
846 *
847 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
848 * be possible to cache the sync rate?
849 */
850 float
851 driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
852 int64_t current_ust )
853 {
854 int32_t n;
855 int32_t d;
856 int interval;
857 float usage = 1.0;
858
859
860 if ( (*dri_interface->getMSCRate)(dPriv->pdraw, &n, &d) ) {
861 interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1;
862
863
864 /* We want to calculate
865 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
866 * current_UST by calling __glXGetUST. last_swap_UST is stored in
867 * dPriv->swap_ust. interval has already been calculated.
868 *
869 * The only tricky part is us_per_refresh. us_per_refresh is
870 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
871 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
872 * the denominator of the final calculation, we calculate
873 * (interval * 1000000 * d) and move n into the numerator.
874 */
875
876 usage = (current_ust - last_swap_ust);
877 usage *= n;
878 usage /= (interval * d);
879 usage /= 1000000.0;
880 }
881
882 return usage;
883 }
884
885 /*@}*/