1 /* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */
4 * DRI utility functions.
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
11 * Basically, these utility functions take care of some of the dirty details of
12 * screen initialization, context creation, context binding, DRM setup, etc.
14 * These functions are compiled into each DRI driver so libGL.so knows nothing
27 #define MAP_FAILED ((void *)-1)
34 #include "drm_sarea.h"
36 #ifndef GLX_OML_sync_control
37 typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC
) (__DRIdrawable
*drawable
, int32_t *numerator
, int32_t *denominator
);
40 /* This pointer *must* be set by the driver's __driCreateNewScreen funciton!
42 const __DRIinterfaceMethods
* dri_interface
= NULL
;
45 * This is used in a couple of places that call \c driCreateNewDrawable.
47 static const int empty_attribute_list
[1] = { None
};
51 * This is just a token extension used to signal that the driver
52 * supports setting a read drawable.
54 const __DRIextension driReadDrawableExtension
= {
55 __DRI_READ_DRAWABLE
, __DRI_READ_DRAWABLE_VERSION
59 * Cached copy of the internal API version used by libGL and the client-side
62 static int api_ver
= 0;
64 static void *driCreateNewDrawable(__DRIscreen
*screen
,
65 const __GLcontextModes
*modes
,
67 drm_drawable_t hwDrawable
,
68 int renderType
, const int *attrs
);
70 static void driDestroyDrawable(__DRIdrawable
*drawable
);
74 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
77 * Is called from the drivers.
79 * \param f \c printf like format string.
82 __driUtilMessage(const char *f
, ...)
86 if (getenv("LIBGL_DEBUG")) {
87 fprintf(stderr
, "libGL error: \n");
89 vfprintf(stderr
, f
, args
);
91 fprintf(stderr
, "\n");
96 /*****************************************************************/
97 /** \name Context (un)binding functions */
98 /*****************************************************************/
104 * \param scrn the screen.
107 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
110 * This function calls __DriverAPIRec::UnbindContext, and then decrements
111 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
114 * While casting the opaque private pointers associated with the parameters
115 * into their respective real types it also assures they are not \c NULL.
117 static GLboolean
driUnbindContext(__DRIcontext
*ctx
)
119 __DRIcontextPrivate
*pcp
;
120 __DRIscreenPrivate
*psp
;
121 __DRIdrawablePrivate
*pdp
;
122 __DRIdrawablePrivate
*prp
;
125 ** Assume error checking is done properly in glXMakeCurrent before
126 ** calling driUnbindContext.
132 pcp
= (__DRIcontextPrivate
*)ctx
->private;
133 psp
= (__DRIscreenPrivate
*)pcp
->driScreenPriv
;
134 pdp
= (__DRIdrawablePrivate
*)pcp
->driDrawablePriv
;
135 prp
= (__DRIdrawablePrivate
*)pcp
->driReadablePriv
;
137 /* Let driver unbind drawable from context */
138 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
140 if (pdp
->refcount
== 0) {
148 if (prp
->refcount
== 0) {
157 /* XXX this is disabled so that if we call SwapBuffers on an unbound
158 * window we can determine the last context bound to the window and
159 * use that context's lock. (BrianP, 2-Dec-2000)
162 /* Unbind the drawable */
163 pcp
->driDrawablePriv
= NULL
;
164 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
172 * This function takes both a read buffer and a draw buffer. This is needed
173 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
176 static GLboolean
driBindContext(__DRIcontext
* ctx
,
177 __DRIdrawable
*pdraw
,
178 __DRIdrawable
*pread
)
180 __DRIdrawablePrivate
*pdp
;
181 __DRIdrawablePrivate
*prp
;
182 __DRIcontextPrivate
* const pcp
= ctx
->private;
183 __DRIscreenPrivate
*psp
= pcp
->driScreenPriv
;
186 ** Assume error checking is done properly in glXMakeCurrent before
187 ** calling driBindContext.
190 if (ctx
== NULL
|| pdraw
== None
|| pread
== None
)
193 pdp
= (__DRIdrawablePrivate
*) pdraw
->private;
194 prp
= (__DRIdrawablePrivate
*) pread
->private;
196 /* Bind the drawable to the context */
197 pcp
->driDrawablePriv
= pdp
;
198 pcp
->driReadablePriv
= prp
;
199 pdp
->driContextPriv
= pcp
;
206 ** Now that we have a context associated with this drawable, we can
207 ** initialize the drawable information if has not been done before.
210 if (psp
->dri2
.enabled
) {
211 __driParseEvents(psp
, pdp
);
212 __driParseEvents(psp
, prp
);
214 if (!pdp
->pStamp
|| *pdp
->pStamp
!= pdp
->lastStamp
) {
215 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
216 __driUtilUpdateDrawableInfo(pdp
);
217 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
220 if ((pdp
!= prp
) && (!prp
->pStamp
|| *prp
->pStamp
!= prp
->lastStamp
)) {
221 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
222 __driUtilUpdateDrawableInfo(prp
);
223 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
227 /* Call device-specific MakeCurrent */
228 (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, prp
);
236 /*****************************************************************/
237 /** \name Drawable handling functions */
238 /*****************************************************************/
242 * Update private drawable information.
244 * \param pdp pointer to the private drawable information to update.
246 * This function basically updates the __DRIdrawablePrivate struct's
247 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
248 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
249 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
250 * the values are different that means we have to update the clipping
254 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate
*pdp
)
256 __DRIscreenPrivate
*psp
;
257 __DRIcontextPrivate
*pcp
= pdp
->driContextPriv
;
260 || ((pdp
!= pcp
->driDrawablePriv
) && (pdp
!= pcp
->driReadablePriv
))) {
262 * ...but we must ignore it. There can be many contexts bound to a
267 psp
= pdp
->driScreenPriv
;
270 _mesa_problem(NULL
, "Warning! Possible infinite loop due to bug "
271 "in file %s, line %d\n",
276 if (pdp
->pClipRects
) {
277 _mesa_free(pdp
->pClipRects
);
278 pdp
->pClipRects
= NULL
;
281 if (pdp
->pBackClipRects
) {
282 _mesa_free(pdp
->pBackClipRects
);
283 pdp
->pBackClipRects
= NULL
;
286 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
288 if (! (*dri_interface
->getDrawableInfo
)(pdp
->pdraw
,
289 &pdp
->index
, &pdp
->lastStamp
,
290 &pdp
->x
, &pdp
->y
, &pdp
->w
, &pdp
->h
,
291 &pdp
->numClipRects
, &pdp
->pClipRects
,
294 &pdp
->numBackClipRects
,
295 &pdp
->pBackClipRects
)) {
296 /* Error -- eg the window may have been destroyed. Keep going
299 pdp
->pStamp
= &pdp
->lastStamp
; /* prevent endless loop */
300 pdp
->numClipRects
= 0;
301 pdp
->pClipRects
= NULL
;
302 pdp
->numBackClipRects
= 0;
303 pdp
->pBackClipRects
= NULL
;
306 pdp
->pStamp
= &(psp
->pSAREA
->drawableTable
[pdp
->index
].stamp
);
308 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
313 __driParseEvents(__DRIscreenPrivate
*psp
, __DRIdrawablePrivate
*pdp
)
315 __DRIDrawableConfigEvent
*dc
;
316 __DRIBufferAttachEvent
*ba
;
317 unsigned int tail
, mask
, *p
, end
, total
, size
, changed
;
320 __DRIcontextPrivate
*pcp
= pdp
->driContextPriv
;
325 /* Check for wraparound. */
326 if (psp
->dri2
.buffer
->prealloc
- pdp
->dri2
.tail
> psp
->dri2
.buffer
->size
) {
327 /* If prealloc overlaps into what we just parsed, the
328 * server overwrote it and we have to reset our tail
330 DRM_UNLOCK(psp
->fd
, psp
->lock
, pcp
->hHWContext
);
331 (*dri_interface
->reemitDrawableInfo
)(pdp
->pdraw
);
332 DRM_LIGHT_LOCK(psp
->fd
, psp
->lock
, pcp
->hHWContext
);
335 total
= psp
->dri2
.buffer
->head
- pdp
->dri2
.tail
;
336 mask
= psp
->dri2
.buffer
->size
- 1;
337 tail
= pdp
->dri2
.tail
;
338 end
= psp
->dri2
.buffer
->head
;
339 data
= psp
->dri2
.buffer
->data
;
342 while (tail
!= end
) {
343 p
= (unsigned int *) (data
+ (tail
& mask
));
344 size
= DRI2_EVENT_SIZE(*p
);
345 if (size
> total
|| (tail
& mask
) + size
> psp
->dri2
.buffer
->size
) {
346 /* illegal data, bail out. */
347 fprintf(stderr
, "illegal event size\n");
351 switch (DRI2_EVENT_TYPE(*p
)) {
352 case DRI2_EVENT_DRAWABLE_CONFIG
:
353 dc
= (__DRIDrawableConfigEvent
*) p
;
355 if (dc
->drawable
!= pdp
->hHWDrawable
)
358 if (pdp
->w
!= dc
->width
|| pdp
->h
!= dc
->height
)
368 pdp
->numBackClipRects
= 1;
369 pdp
->pBackClipRects
[0].x1
= 0;
370 pdp
->pBackClipRects
[0].y1
= 0;
371 pdp
->pBackClipRects
[0].x2
= pdp
->w
;
372 pdp
->pBackClipRects
[0].y2
= pdp
->h
;
374 pdp
->numClipRects
= dc
->num_rects
;
375 _mesa_free(pdp
->pClipRects
);
376 rect_size
= dc
->num_rects
* sizeof dc
->rects
[0];
377 pdp
->pClipRects
= _mesa_malloc(rect_size
);
378 memcpy(pdp
->pClipRects
, dc
->rects
, rect_size
);
381 (*psp
->DriverAPI
.UpdateBuffer
)(pdp
, p
);
384 case DRI2_EVENT_BUFFER_ATTACH
:
385 ba
= (__DRIBufferAttachEvent
*) p
;
387 if (ba
->drawable
!= pdp
->hHWDrawable
)
390 (*psp
->DriverAPI
.UpdateBuffer
)(pdp
, p
);
400 pdp
->dri2
.tail
= tail
;
402 /* FIXME: Return whether we changed anything. This check always
403 * returns true if we received events, but we could refine the
404 * check to only return TRUE if the drawable actually changed. */
411 /*****************************************************************/
412 /** \name GLX callbacks */
413 /*****************************************************************/
419 * \param drawablePrivate opaque pointer to the per-drawable private info.
422 * This function calls __DRIdrawablePrivate::swapBuffers.
424 * Is called directly from glXSwapBuffers().
426 static void driSwapBuffers(__DRIdrawable
*drawable
)
428 __DRIdrawablePrivate
*dPriv
= drawable
->private;
429 drm_clip_rect_t rect
;
431 if (!dPriv
->numClipRects
)
434 dPriv
->swapBuffers(dPriv
);
436 /* Check that we actually have the new damage report method */
437 if (api_ver
< 20070105 || dri_interface
->reportDamage
== NULL
)
440 /* Assume it's affecting the whole drawable for now */
443 rect
.x2
= rect
.x1
+ dPriv
->w
;
444 rect
.y2
= rect
.y1
+ dPriv
->h
;
446 /* Report the damage. Currently, all our drivers draw directly to the
447 * front buffer, so we report the damage there rather than to the backing
450 (*dri_interface
->reportDamage
)(dPriv
->pdraw
, dPriv
->x
, dPriv
->y
,
454 static int driDrawableGetMSC( __DRIscreen
*screen
, __DRIdrawable
*drawable
,
457 __DRIscreenPrivate
*sPriv
= screen
->private;
458 __DRIdrawablePrivate
*dPriv
= drawable
->private;
460 return sPriv
->DriverAPI
.GetDrawableMSC(sPriv
, dPriv
, msc
);
463 static int driWaitForMSC(__DRIdrawable
*drawable
, int64_t target_msc
,
464 int64_t divisor
, int64_t remainder
,
465 int64_t * msc
, int64_t * sbc
)
467 __DRIdrawablePrivate
*dPriv
= drawable
->private;
472 status
= dPriv
->driScreenPriv
->DriverAPI
.WaitForMSC( dPriv
, target_msc
,
476 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
477 * is supported but GLX_OML_sync_control is not. Therefore, don't return
478 * an error value if GetSwapInfo() is not implemented.
481 && dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo
) {
482 status
= dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dPriv
, & sInfo
);
483 *sbc
= sInfo
.swap_count
;
489 const __DRImediaStreamCounterExtension driMediaStreamCounterExtension
= {
490 { __DRI_MEDIA_STREAM_COUNTER
, __DRI_MEDIA_STREAM_COUNTER_VERSION
},
495 static void driCopySubBuffer(__DRIdrawable
*drawable
,
496 int x
, int y
, int w
, int h
)
498 __DRIdrawablePrivate
*dPriv
= drawable
->private;
499 dPriv
->driScreenPriv
->DriverAPI
.CopySubBuffer(dPriv
, x
, y
, w
, h
);
502 const __DRIcopySubBufferExtension driCopySubBufferExtension
= {
503 { __DRI_COPY_SUB_BUFFER
, __DRI_COPY_SUB_BUFFER_VERSION
},
507 static void driSetSwapInterval(__DRIdrawable
*drawable
, unsigned int interval
)
509 __DRIdrawablePrivate
*dpriv
= drawable
->private;
511 dpriv
->swap_interval
= interval
;
514 static unsigned int driGetSwapInterval(__DRIdrawable
*drawable
)
516 __DRIdrawablePrivate
*dpriv
= drawable
->private;
518 return dpriv
->swap_interval
;
521 const __DRIswapControlExtension driSwapControlExtension
= {
522 { __DRI_SWAP_CONTROL
, __DRI_SWAP_CONTROL_VERSION
},
529 * This is called via __DRIscreenRec's createNewDrawable pointer.
531 static void *driCreateNewDrawable(__DRIscreen
*screen
,
532 const __GLcontextModes
*modes
,
533 __DRIdrawable
*pdraw
,
534 drm_drawable_t hwDrawable
,
538 __DRIscreenPrivate
*psp
;
539 __DRIdrawablePrivate
*pdp
;
542 pdraw
->private = NULL
;
544 /* Since pbuffers are not yet supported, no drawable attributes are
549 pdp
= (__DRIdrawablePrivate
*)_mesa_malloc(sizeof(__DRIdrawablePrivate
));
554 pdp
->hHWDrawable
= hwDrawable
;
564 pdp
->numClipRects
= 0;
565 pdp
->numBackClipRects
= 0;
566 pdp
->pClipRects
= NULL
;
567 pdp
->pBackClipRects
= NULL
;
571 psp
= (__DRIscreenPrivate
*)screen
->private;
572 pdp
->driScreenPriv
= psp
;
573 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
575 if (!(*psp
->DriverAPI
.CreateBuffer
)(psp
, pdp
, modes
,
576 renderType
== GLX_PIXMAP_BIT
)) {
581 pdraw
->private = pdp
;
582 pdraw
->destroyDrawable
= driDestroyDrawable
;
583 pdraw
->swapBuffers
= driSwapBuffers
; /* called by glXSwapBuffers() */
586 /* This special default value is replaced with the configured
587 * default value when the drawable is first bound to a direct
590 pdp
->swap_interval
= (unsigned)-1;
592 pdp
->swapBuffers
= psp
->DriverAPI
.SwapBuffers
;
594 if (psp
->dri2
.enabled
) {
596 pdp
->pBackClipRects
= _mesa_malloc(sizeof *pdp
->pBackClipRects
);
603 driDestroyDrawable(__DRIdrawable
*drawable
)
605 __DRIdrawablePrivate
*pdp
= drawable
->private;
606 __DRIscreenPrivate
*psp
;
609 psp
= pdp
->driScreenPriv
;
610 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
611 if (pdp
->pClipRects
) {
612 _mesa_free(pdp
->pClipRects
);
613 pdp
->pClipRects
= NULL
;
615 if (pdp
->pBackClipRects
) {
616 _mesa_free(pdp
->pBackClipRects
);
617 pdp
->pBackClipRects
= NULL
;
626 /*****************************************************************/
627 /** \name Context handling functions */
628 /*****************************************************************/
632 * Destroy the per-context private information.
634 * \param contextPrivate opaque pointer to the per-drawable private info.
637 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
638 * drmDestroyContext(), and finally frees \p contextPrivate.
641 driDestroyContext(__DRIcontext
*context
)
643 __DRIcontextPrivate
*pcp
= context
->private;
646 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
653 * Create the per-drawable private driver information.
655 * \param dpy The display handle.
656 * \param modes Mode used to create the new context.
657 * \param render_type Type of rendering target. \c GLX_RGBA is the only
658 * type likely to ever be supported for direct-rendering.
659 * \param shared The shared context dependent methods or \c NULL if
661 * \param pctx DRI context to receive the context dependent methods.
663 * \returns An opaque pointer to the per-context private information on
664 * success, or \c NULL on failure.
667 * This function allocates and fills a __DRIcontextPrivateRec structure. It
668 * performs some device independent initialization and passes all the
669 * relevent information to __DriverAPIRec::CreateContext to create the
674 driCreateNewContext(__DRIscreen
*screen
, const __GLcontextModes
*modes
,
675 int render_type
, __DRIcontext
*shared
,
676 drm_context_t hwContext
, __DRIcontext
*pctx
)
678 __DRIcontextPrivate
*pcp
;
679 __DRIcontextPrivate
*pshare
= (shared
!= NULL
) ? shared
->private : NULL
;
680 __DRIscreenPrivate
*psp
;
681 void * const shareCtx
= (pshare
!= NULL
) ? pshare
->driverPrivate
: NULL
;
683 psp
= (__DRIscreenPrivate
*)screen
->private;
685 pcp
= (__DRIcontextPrivate
*)_mesa_malloc(sizeof(__DRIcontextPrivate
));
690 pcp
->hHWContext
= hwContext
;
691 pcp
->driScreenPriv
= psp
;
692 pcp
->driDrawablePriv
= NULL
;
694 /* When the first context is created for a screen, initialize a "dummy"
698 if (!psp
->dri2
.enabled
&& !psp
->dummyContextPriv
.driScreenPriv
) {
699 psp
->dummyContextPriv
.hHWContext
= psp
->pSAREA
->dummy_context
;
700 psp
->dummyContextPriv
.driScreenPriv
= psp
;
701 psp
->dummyContextPriv
.driDrawablePriv
= NULL
;
702 psp
->dummyContextPriv
.driverPrivate
= NULL
;
703 /* No other fields should be used! */
706 pctx
->destroyContext
= driDestroyContext
;
707 pctx
->bindContext
= driBindContext
;
708 pctx
->unbindContext
= driUnbindContext
;
710 if ( !(*psp
->DriverAPI
.CreateContext
)(modes
, pcp
, shareCtx
) ) {
720 static const __DRIextension
**
721 driGetExtensions(__DRIscreen
*screen
)
723 __DRIscreenPrivate
*psp
= screen
->private;
725 return psp
->extensions
;
728 /*****************************************************************/
729 /** \name Screen handling functions */
730 /*****************************************************************/
734 * Destroy the per-screen private information.
736 * \param dpy the display handle.
737 * \param scrn the screen number.
738 * \param screenPrivate opaque pointer to the per-screen private information.
741 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
742 * drmClose(), and finally frees \p screenPrivate.
744 static void driDestroyScreen(__DRIscreen
*screen
)
746 __DRIscreenPrivate
*psp
= screen
->private;
749 /* No interaction with the X-server is possible at this point. This
750 * routine is called after XCloseDisplay, so there is no protocol
751 * stream open to the X-server anymore.
754 if (psp
->DriverAPI
.DestroyScreen
)
755 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
757 if (psp
->dri2
.enabled
) {
758 drmBOUnmap(psp
->fd
, &psp
->dri2
.sareaBO
);
759 drmBOUnreference(psp
->fd
, &psp
->dri2
.sareaBO
);
761 (void)drmUnmap((drmAddress
)psp
->pSAREA
, SAREA_MAX
);
762 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
763 (void)drmCloseOnce(psp
->fd
);
771 * This is the bootstrap function for the driver. libGL supplies all of the
772 * requisite information about the system, and the driver initializes itself.
773 * This routine also fills in the linked list pointed to by \c driver_modes
774 * with the \c __GLcontextModes that the driver can support for windows or
777 * \param scrn Index of the screen
778 * \param psc DRI screen data (not driver private)
779 * \param modes Linked list of known display modes. This list is, at a
780 * minimum, a list of modes based on the current display mode.
781 * These roughly match the set of available X11 visuals, but it
782 * need not be limited to X11! The calling libGL should create
783 * a list that will inform the driver of the current display
784 * mode (i.e., color buffer depth, depth buffer depth, etc.).
785 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
787 * \param dri_version Version of the "server-side" DRI.
788 * \param drm_version Version of the kernel DRM.
789 * \param frame_buffer Data describing the location and layout of the
791 * \param pSAREA Pointer the the SAREA.
792 * \param fd Device handle for the DRM.
793 * \param internal_api_version Version of the internal interface between the
795 * \param driverAPI Driver API functions used by other routines in dri_util.c.
797 * \note There is no need to check the minimum API version in this
798 * function. Since the name of this function is versioned, it is
799 * impossible for a loader that is too old to even load this driver.
802 void * __DRI_CREATE_NEW_SCREEN( int scrn
, __DRIscreen
*psc
,
803 const __DRIversion
* ddx_version
,
804 const __DRIversion
* dri_version
,
805 const __DRIversion
* drm_version
,
806 const __DRIframebuffer
* frame_buffer
,
807 drmAddress pSAREA
, int fd
,
808 int internal_api_version
,
809 const __DRIinterfaceMethods
* interface
,
810 __GLcontextModes
** driver_modes
)
813 __DRIscreenPrivate
*psp
;
814 static const __DRIextension
*emptyExtensionList
[] = { NULL
};
815 dri_interface
= interface
;
816 api_ver
= internal_api_version
;
818 psp
= _mesa_malloc(sizeof(*psp
));
825 ** NOT_DONE: This is used by the X server to detect when the client
826 ** has died while holding the drawable lock. The client sets the
827 ** drawable lock to this value.
831 psp
->drm_version
= *drm_version
;
832 psp
->ddx_version
= *ddx_version
;
833 psp
->dri_version
= *dri_version
;
835 psp
->pSAREA
= pSAREA
;
836 psp
->lock
= (drmLock
*) &psp
->pSAREA
->lock
;
838 psp
->pFB
= frame_buffer
->base
;
839 psp
->fbSize
= frame_buffer
->size
;
840 psp
->fbStride
= frame_buffer
->stride
;
841 psp
->fbWidth
= frame_buffer
->width
;
842 psp
->fbHeight
= frame_buffer
->height
;
843 psp
->devPrivSize
= frame_buffer
->dev_priv_size
;
844 psp
->pDevPriv
= frame_buffer
->dev_priv
;
845 psp
->fbBPP
= psp
->fbStride
* 8 / frame_buffer
->width
;
847 psp
->extensions
= emptyExtensionList
;
850 psp
->dri2
.enabled
= GL_FALSE
;
853 ** Do not init dummy context here; actual initialization will be
854 ** done when the first DRI context is created. Init screen priv ptr
855 ** to NULL to let CreateContext routine that it needs to be inited.
857 psp
->dummyContextPriv
.driScreenPriv
= NULL
;
859 psc
->destroyScreen
= driDestroyScreen
;
860 psc
->getExtensions
= driGetExtensions
;
861 psc
->createNewDrawable
= driCreateNewDrawable
;
862 psc
->createNewContext
= driCreateNewContext
;
864 *driver_modes
= __driDriverInitScreen(psp
);
865 if (*driver_modes
== NULL
) {
874 __DRI2_CREATE_NEW_SCREEN(int scrn
, __DRIscreen
*psc
,
875 const __DRIversion
* ddx_version
,
876 const __DRIversion
* dri_version
,
877 const __DRIversion
* drm_version
,
879 unsigned int sarea_handle
,
880 const __DRIinterfaceMethods
* interface
,
881 __GLcontextModes
** driver_modes
)
883 __DRIscreenPrivate
*psp
;
884 static const __DRIextension
*emptyExtensionList
[] = { NULL
};
885 dri_interface
= interface
;
887 __GLcontextModes
*(*initScreen
)(__DRIscreenPrivate
*psc
);
889 initScreen
= dlsym(NULL
, "__dri2DriverInitScreen");
890 if (initScreen
== NULL
)
893 psp
= _mesa_malloc(sizeof(*psp
));
899 psp
->drm_version
= *drm_version
;
900 psp
->ddx_version
= *ddx_version
;
901 psp
->dri_version
= *dri_version
;
902 psp
->extensions
= emptyExtensionList
;
905 psp
->dri2
.enabled
= GL_TRUE
;
907 if (drmBOReference(psp
->fd
, sarea_handle
, &psp
->dri2
.sareaBO
)) {
908 fprintf(stderr
, "Failed to reference DRI2 sarea BO\n");
913 if (drmBOMap(psp
->fd
, &psp
->dri2
.sareaBO
,
914 DRM_BO_FLAG_READ
| DRM_BO_FLAG_WRITE
, 0, &psp
->dri2
.sarea
)) {
915 drmBOUnreference(psp
->fd
, &psp
->dri2
.sareaBO
);
921 while (DRI2_SAREA_BLOCK_TYPE(*p
)) {
922 switch (DRI2_SAREA_BLOCK_TYPE(*p
)) {
923 case DRI2_SAREA_BLOCK_LOCK
:
924 psp
->dri2
.lock
= (__DRILock
*) p
;
926 case DRI2_SAREA_BLOCK_EVENT_BUFFER
:
927 psp
->dri2
.buffer
= (__DRIEventBuffer
*) p
;
930 p
= DRI2_SAREA_BLOCK_NEXT(p
);
933 psp
->lock
= (drmLock
*) &psp
->dri2
.lock
->lock
;
935 psc
->destroyScreen
= driDestroyScreen
;
936 psc
->getExtensions
= driGetExtensions
;
937 psc
->createNewDrawable
= driCreateNewDrawable
;
938 psc
->createNewContext
= driCreateNewContext
;
940 *driver_modes
= initScreen(psp
);
941 if (*driver_modes
== NULL
) {
942 drmBOUnmap(psp
->fd
, &psp
->dri2
.sareaBO
);
943 drmBOUnreference(psp
->fd
, &psp
->dri2
.sareaBO
);
952 * Compare the current GLX API version with a driver supplied required version.
954 * The minimum required version is compared with the API version exported by
955 * the \c __glXGetInternalVersion function (in libGL.so).
957 * \param required_version Minimum required internal GLX API version.
958 * \return A tri-value return, as from strcmp is returned. A value less
959 * than, equal to, or greater than zero will be returned if the
960 * internal GLX API version is less than, equal to, or greater
961 * than \c required_version.
963 * \sa __glXGetInternalVersion().
965 int driCompareGLXAPIVersion( GLint required_version
)
967 if ( api_ver
> required_version
) {
970 else if ( api_ver
== required_version
) {
979 driFrameTracking(__DRIdrawable
*drawable
, GLboolean enable
)
981 return GLX_BAD_CONTEXT
;
985 driQueryFrameTracking(__DRIdrawable
*drawable
,
986 int64_t * sbc
, int64_t * missedFrames
,
987 float * lastMissedUsage
, float * usage
)
992 __DRIdrawablePrivate
* dpriv
= drawable
->private;
995 status
= dpriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dpriv
, & sInfo
);
997 *sbc
= sInfo
.swap_count
;
998 *missedFrames
= sInfo
.swap_missed_count
;
999 *lastMissedUsage
= sInfo
.swap_missed_usage
;
1001 (*dri_interface
->getUST
)( & ust
);
1002 *usage
= driCalculateSwapUsage( dpriv
, sInfo
.swap_ust
, ust
);
1008 const __DRIframeTrackingExtension driFrameTrackingExtension
= {
1009 { __DRI_FRAME_TRACKING
, __DRI_FRAME_TRACKING_VERSION
},
1011 driQueryFrameTracking
1015 * Calculate amount of swap interval used between GLX buffer swaps.
1017 * The usage value, on the range [0,max], is the fraction of total swap
1018 * interval time used between GLX buffer swaps is calculated.
1020 * \f$p = t_d / (i * t_r)\f$
1022 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
1023 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
1024 * required for a single vertical refresh period (as returned by \c
1025 * glXGetMscRateOML).
1027 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
1030 * \param dPriv Pointer to the private drawable structure.
1031 * \return If less than a single swap interval time period was required
1032 * between GLX buffer swaps, a number greater than 0 and less than
1033 * 1.0 is returned. If exactly one swap interval time period is
1034 * required, 1.0 is returned, and if more than one is required then
1035 * a number greater than 1.0 will be returned.
1037 * \sa glXSwapIntervalSGI glXGetMscRateOML
1039 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
1040 * be possible to cache the sync rate?
1043 driCalculateSwapUsage( __DRIdrawablePrivate
*dPriv
, int64_t last_swap_ust
,
1044 int64_t current_ust
)
1052 if ( (*dri_interface
->getMSCRate
)(dPriv
->pdraw
, &n
, &d
) ) {
1053 interval
= (dPriv
->swap_interval
!= 0) ? dPriv
->swap_interval
: 1;
1056 /* We want to calculate
1057 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
1058 * current_UST by calling __glXGetUST. last_swap_UST is stored in
1059 * dPriv->swap_ust. interval has already been calculated.
1061 * The only tricky part is us_per_refresh. us_per_refresh is
1062 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
1063 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
1064 * the denominator of the final calculation, we calculate
1065 * (interval * 1000000 * d) and move n into the numerator.
1068 usage
= (current_ust
- last_swap_ust
);
1070 usage
/= (interval
* d
);