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