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
);
41 * This is just a token extension used to signal that the driver
42 * supports setting a read drawable.
44 const __DRIextension driReadDrawableExtension
= {
45 __DRI_READ_DRAWABLE
, __DRI_READ_DRAWABLE_VERSION
48 static void *driCreateNewDrawable(__DRIscreen
*screen
,
49 const __GLcontextModes
*modes
,
51 drm_drawable_t hwDrawable
,
53 int renderType
, const int *attrs
);
55 static void driDestroyDrawable(__DRIdrawable
*drawable
);
59 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
62 * Is called from the drivers.
64 * \param f \c printf like format string.
67 __driUtilMessage(const char *f
, ...)
71 if (getenv("LIBGL_DEBUG")) {
72 fprintf(stderr
, "libGL error: \n");
74 vfprintf(stderr
, f
, args
);
76 fprintf(stderr
, "\n");
81 /*****************************************************************/
82 /** \name Context (un)binding functions */
83 /*****************************************************************/
89 * \param scrn the screen.
92 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
95 * This function calls __DriverAPIRec::UnbindContext, and then decrements
96 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
99 * While casting the opaque private pointers associated with the parameters
100 * into their respective real types it also assures they are not \c NULL.
102 static GLboolean
driUnbindContext(__DRIcontext
*ctx
)
104 __DRIcontextPrivate
*pcp
;
105 __DRIscreenPrivate
*psp
;
106 __DRIdrawablePrivate
*pdp
;
107 __DRIdrawablePrivate
*prp
;
110 ** Assume error checking is done properly in glXMakeCurrent before
111 ** calling driUnbindContext.
117 pcp
= (__DRIcontextPrivate
*)ctx
->private;
118 psp
= (__DRIscreenPrivate
*)pcp
->driScreenPriv
;
119 pdp
= (__DRIdrawablePrivate
*)pcp
->driDrawablePriv
;
120 prp
= (__DRIdrawablePrivate
*)pcp
->driReadablePriv
;
122 /* Let driver unbind drawable from context */
123 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
125 if (pdp
->refcount
== 0) {
133 if (prp
->refcount
== 0) {
142 /* XXX this is disabled so that if we call SwapBuffers on an unbound
143 * window we can determine the last context bound to the window and
144 * use that context's lock. (BrianP, 2-Dec-2000)
147 /* Unbind the drawable */
148 pcp
->driDrawablePriv
= NULL
;
149 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
157 * This function takes both a read buffer and a draw buffer. This is needed
158 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
161 static GLboolean
driBindContext(__DRIcontext
* ctx
,
162 __DRIdrawable
*pdraw
,
163 __DRIdrawable
*pread
)
165 __DRIdrawablePrivate
*pdp
;
166 __DRIdrawablePrivate
*prp
;
167 __DRIcontextPrivate
* const pcp
= ctx
->private;
168 __DRIscreenPrivate
*psp
= pcp
->driScreenPriv
;
171 ** Assume error checking is done properly in glXMakeCurrent before
172 ** calling driBindContext.
175 if (ctx
== NULL
|| pdraw
== None
|| pread
== None
)
178 pdp
= (__DRIdrawablePrivate
*) pdraw
->private;
179 prp
= (__DRIdrawablePrivate
*) pread
->private;
181 /* Bind the drawable to the context */
182 pcp
->driDrawablePriv
= pdp
;
183 pcp
->driReadablePriv
= prp
;
184 pdp
->driContextPriv
= pcp
;
191 ** Now that we have a context associated with this drawable, we can
192 ** initialize the drawable information if has not been done before.
195 if (psp
->dri2
.enabled
) {
196 __driParseEvents(pcp
, pdp
);
197 __driParseEvents(pcp
, prp
);
199 if (!pdp
->pStamp
|| *pdp
->pStamp
!= pdp
->lastStamp
) {
200 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
201 __driUtilUpdateDrawableInfo(pdp
);
202 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
205 if ((pdp
!= prp
) && (!prp
->pStamp
|| *prp
->pStamp
!= prp
->lastStamp
)) {
206 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
207 __driUtilUpdateDrawableInfo(prp
);
208 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
212 /* Call device-specific MakeCurrent */
213 (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, prp
);
221 /*****************************************************************/
222 /** \name Drawable handling functions */
223 /*****************************************************************/
227 * Update private drawable information.
229 * \param pdp pointer to the private drawable information to update.
231 * This function basically updates the __DRIdrawablePrivate struct's
232 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
233 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
234 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
235 * the values are different that means we have to update the clipping
239 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate
*pdp
)
241 __DRIscreenPrivate
*psp
= pdp
->driScreenPriv
;
242 __DRIcontextPrivate
*pcp
= pdp
->driContextPriv
;
245 || ((pdp
!= pcp
->driDrawablePriv
) && (pdp
!= pcp
->driReadablePriv
))) {
247 * ...but we must ignore it. There can be many contexts bound to a
252 if (pdp
->pClipRects
) {
253 _mesa_free(pdp
->pClipRects
);
254 pdp
->pClipRects
= NULL
;
257 if (pdp
->pBackClipRects
) {
258 _mesa_free(pdp
->pBackClipRects
);
259 pdp
->pBackClipRects
= NULL
;
262 DRM_SPINUNLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
264 if (! (*psp
->getDrawableInfo
->getDrawableInfo
)(pdp
->pdraw
,
265 &pdp
->index
, &pdp
->lastStamp
,
266 &pdp
->x
, &pdp
->y
, &pdp
->w
, &pdp
->h
,
267 &pdp
->numClipRects
, &pdp
->pClipRects
,
270 &pdp
->numBackClipRects
,
271 &pdp
->pBackClipRects
)) {
272 /* Error -- eg the window may have been destroyed. Keep going
275 pdp
->pStamp
= &pdp
->lastStamp
; /* prevent endless loop */
276 pdp
->numClipRects
= 0;
277 pdp
->pClipRects
= NULL
;
278 pdp
->numBackClipRects
= 0;
279 pdp
->pBackClipRects
= NULL
;
282 pdp
->pStamp
= &(psp
->pSAREA
->drawableTable
[pdp
->index
].stamp
);
284 DRM_SPINLOCK(&psp
->pSAREA
->drawable_lock
, psp
->drawLockID
);
289 __driParseEvents(__DRIcontextPrivate
*pcp
, __DRIdrawablePrivate
*pdp
)
291 __DRIscreenPrivate
*psp
= pcp
->driScreenPriv
;
292 __DRIDrawableConfigEvent
*dc
, *last_dc
;
293 __DRIBufferAttachEvent
*ba
, *last_ba
;
294 unsigned int tail
, mask
, *p
, end
, total
, size
, changed
;
298 /* Check for wraparound. */
299 if (psp
->dri2
.buffer
->prealloc
- pdp
->dri2
.tail
> psp
->dri2
.buffer
->size
) {
300 /* If prealloc overlaps into what we just parsed, the
301 * server overwrote it and we have to reset our tail
303 DRM_UNLOCK(psp
->fd
, psp
->lock
, pcp
->hHWContext
);
304 (*psp
->dri2
.core
->reemitDrawableInfo
)(pdp
->pdraw
, &pdp
->dri2
.tail
);
305 DRM_LIGHT_LOCK(psp
->fd
, psp
->lock
, pcp
->hHWContext
);
308 total
= psp
->dri2
.buffer
->head
- pdp
->dri2
.tail
;
309 mask
= psp
->dri2
.buffer
->size
- 1;
310 end
= psp
->dri2
.buffer
->head
;
311 data
= psp
->dri2
.buffer
->data
;
317 for (tail
= pdp
->dri2
.tail
; tail
!= end
; tail
+= size
) {
318 p
= (unsigned int *) (data
+ (tail
& mask
));
319 size
= DRI2_EVENT_SIZE(*p
);
320 if (size
> total
|| (tail
& mask
) + size
> psp
->dri2
.buffer
->size
) {
321 /* illegal data, bail out. */
322 fprintf(stderr
, "illegal event size\n");
326 switch (DRI2_EVENT_TYPE(*p
)) {
327 case DRI2_EVENT_DRAWABLE_CONFIG
:
328 dc
= (__DRIDrawableConfigEvent
*) p
;
329 if (dc
->drawable
== pdp
->hHWDrawable
)
333 case DRI2_EVENT_BUFFER_ATTACH
:
334 ba
= (__DRIBufferAttachEvent
*) p
;
335 if (ba
->drawable
== pdp
->hHWDrawable
&&
336 ba
->buffer
.attachment
== DRI_DRAWABLE_BUFFER_FRONT_LEFT
)
343 if (pdp
->w
!= last_dc
->width
|| pdp
->h
!= last_dc
->height
)
348 pdp
->w
= last_dc
->width
;
349 pdp
->h
= last_dc
->height
;
353 pdp
->numBackClipRects
= 1;
354 pdp
->pBackClipRects
[0].x1
= 0;
355 pdp
->pBackClipRects
[0].y1
= 0;
356 pdp
->pBackClipRects
[0].x2
= pdp
->w
;
357 pdp
->pBackClipRects
[0].y2
= pdp
->h
;
359 pdp
->numClipRects
= last_dc
->num_rects
;
360 _mesa_free(pdp
->pClipRects
);
361 rect_size
= last_dc
->num_rects
* sizeof last_dc
->rects
[0];
362 pdp
->pClipRects
= _mesa_malloc(rect_size
);
363 memcpy(pdp
->pClipRects
, last_dc
->rects
, rect_size
);
366 (*psp
->DriverAPI
.HandleDrawableConfig
)(pdp
, pcp
, last_dc
);
369 /* Front buffer attachments are special, they typically mean that
370 * we're rendering to a redirected window (or a child window of a
371 * redirected window) and that it got resized. Resizing the root
372 * window on randr events is a special case of this. Other causes
373 * may be a window transitioning between redirected and
374 * non-redirected, or a window getting reparented between parents
375 * with different window pixmaps (eg two redirected windows).
376 * These events are special in that the X server allocates the
377 * buffer and that the buffer may be shared by other child
378 * windows. When our window share the window pixmap with its
379 * parent, drawable config events doesn't affect the front buffer.
380 * We only care about the last such event in the buffer; in fact,
381 * older events will refer to invalid buffer objects.*/
383 (*psp
->DriverAPI
.HandleBufferAttach
)(pdp
, pcp
, last_ba
);
385 /* Like for buffer attachments, we only care about the most recent
386 * drawable config. */
388 (*psp
->DriverAPI
.HandleDrawableConfig
)(pdp
, pcp
, last_dc
);
390 /* If there was a drawable config event in the buffer and it
391 * changed the size of the window, all buffer auxillary buffer
392 * attachments prior to that are invalid (as opposed to the front
393 * buffer case discussed above). In that case we can start
394 * looking for buffer attachment after the last drawable config
395 * event. If there is no drawable config event in this batch of
396 * events, we have to assume that the last batch might have had
397 * one and process all buffer attach events.*/
398 if (last_dc
&& changed
)
399 tail
= (unsigned char *) last_dc
- data
;
401 tail
= pdp
->dri2
.tail
;
403 for ( ; tail
!= end
; tail
+= size
) {
404 ba
= (__DRIBufferAttachEvent
*) (data
+ (tail
& mask
));
405 size
= DRI2_EVENT_SIZE(ba
->event_header
);
407 if (DRI2_EVENT_TYPE(ba
->event_header
) != DRI2_EVENT_BUFFER_ATTACH
)
409 if (ba
->drawable
!= pdp
->hHWDrawable
)
414 (*psp
->DriverAPI
.HandleBufferAttach
)(pdp
, pcp
, ba
);
417 pdp
->dri2
.tail
= tail
;
419 /* FIXME: Return whether we changed anything. This check always
420 * returns true if we received events, but we could refine the
421 * check to only return TRUE if the drawable actually changed. */
428 /*****************************************************************/
429 /** \name GLX callbacks */
430 /*****************************************************************/
436 * \param drawablePrivate opaque pointer to the per-drawable private info.
439 * This function calls __DRIdrawablePrivate::swapBuffers.
441 * Is called directly from glXSwapBuffers().
443 static void driSwapBuffers(__DRIdrawable
*drawable
)
445 __DRIdrawablePrivate
*dPriv
= drawable
->private;
446 __DRIscreenPrivate
*psp
= dPriv
->driScreenPriv
;
447 drm_clip_rect_t rect
;
449 if (!dPriv
->numClipRects
)
452 dPriv
->swapBuffers(dPriv
);
454 /* Check that we actually have the new damage report method */
455 if (psp
->damage
== NULL
)
458 /* Assume it's affecting the whole drawable for now */
461 rect
.x2
= rect
.x1
+ dPriv
->w
;
462 rect
.y2
= rect
.y1
+ dPriv
->h
;
464 /* Report the damage. Currently, all our drivers draw directly to the
465 * front buffer, so we report the damage there rather than to the backing
468 (*psp
->damage
->reportDamage
)(dPriv
->pdraw
,
469 dPriv
->x
, dPriv
->y
, &rect
, 1, GL_TRUE
);
472 static int driDrawableGetMSC( __DRIscreen
*screen
, __DRIdrawable
*drawable
,
475 __DRIscreenPrivate
*sPriv
= screen
->private;
476 __DRIdrawablePrivate
*dPriv
= drawable
->private;
478 return sPriv
->DriverAPI
.GetDrawableMSC(sPriv
, dPriv
, msc
);
481 static int driWaitForMSC(__DRIdrawable
*drawable
, int64_t target_msc
,
482 int64_t divisor
, int64_t remainder
,
483 int64_t * msc
, int64_t * sbc
)
485 __DRIdrawablePrivate
*dPriv
= drawable
->private;
490 status
= dPriv
->driScreenPriv
->DriverAPI
.WaitForMSC( dPriv
, target_msc
,
494 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
495 * is supported but GLX_OML_sync_control is not. Therefore, don't return
496 * an error value if GetSwapInfo() is not implemented.
499 && dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo
) {
500 status
= dPriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dPriv
, & sInfo
);
501 *sbc
= sInfo
.swap_count
;
507 const __DRImediaStreamCounterExtension driMediaStreamCounterExtension
= {
508 { __DRI_MEDIA_STREAM_COUNTER
, __DRI_MEDIA_STREAM_COUNTER_VERSION
},
513 static void driCopySubBuffer(__DRIdrawable
*drawable
,
514 int x
, int y
, int w
, int h
)
516 __DRIdrawablePrivate
*dPriv
= drawable
->private;
517 dPriv
->driScreenPriv
->DriverAPI
.CopySubBuffer(dPriv
, x
, y
, w
, h
);
520 const __DRIcopySubBufferExtension driCopySubBufferExtension
= {
521 { __DRI_COPY_SUB_BUFFER
, __DRI_COPY_SUB_BUFFER_VERSION
},
525 static void driSetSwapInterval(__DRIdrawable
*drawable
, unsigned int interval
)
527 __DRIdrawablePrivate
*dpriv
= drawable
->private;
529 dpriv
->swap_interval
= interval
;
532 static unsigned int driGetSwapInterval(__DRIdrawable
*drawable
)
534 __DRIdrawablePrivate
*dpriv
= drawable
->private;
536 return dpriv
->swap_interval
;
539 const __DRIswapControlExtension driSwapControlExtension
= {
540 { __DRI_SWAP_CONTROL
, __DRI_SWAP_CONTROL_VERSION
},
547 * This is called via __DRIscreenRec's createNewDrawable pointer.
549 static void *driCreateNewDrawable(__DRIscreen
*screen
,
550 const __GLcontextModes
*modes
,
551 __DRIdrawable
*pdraw
,
552 drm_drawable_t hwDrawable
,
557 __DRIscreenPrivate
*psp
;
558 __DRIdrawablePrivate
*pdp
;
560 pdraw
->private = NULL
;
562 /* Since pbuffers are not yet supported, no drawable attributes are
567 pdp
= (__DRIdrawablePrivate
*)_mesa_malloc(sizeof(__DRIdrawablePrivate
));
572 pdp
->hHWDrawable
= hwDrawable
;
582 pdp
->numClipRects
= 0;
583 pdp
->numBackClipRects
= 0;
584 pdp
->pClipRects
= NULL
;
585 pdp
->pBackClipRects
= NULL
;
589 psp
= (__DRIscreenPrivate
*)screen
->private;
590 pdp
->driScreenPriv
= psp
;
591 pdp
->driContextPriv
= &psp
->dummyContextPriv
;
593 if (!(*psp
->DriverAPI
.CreateBuffer
)(psp
, pdp
, modes
,
594 renderType
== GLX_PIXMAP_BIT
)) {
599 pdraw
->private = pdp
;
600 pdraw
->destroyDrawable
= driDestroyDrawable
;
601 pdraw
->swapBuffers
= driSwapBuffers
; /* called by glXSwapBuffers() */
604 /* This special default value is replaced with the configured
605 * default value when the drawable is first bound to a direct
608 pdp
->swap_interval
= (unsigned)-1;
610 pdp
->swapBuffers
= psp
->DriverAPI
.SwapBuffers
;
612 if (psp
->dri2
.enabled
) {
613 pdp
->dri2
.tail
= head
;
614 pdp
->pBackClipRects
= _mesa_malloc(sizeof *pdp
->pBackClipRects
);
621 driDestroyDrawable(__DRIdrawable
*drawable
)
623 __DRIdrawablePrivate
*pdp
= drawable
->private;
624 __DRIscreenPrivate
*psp
;
627 psp
= pdp
->driScreenPriv
;
628 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
629 if (pdp
->pClipRects
) {
630 _mesa_free(pdp
->pClipRects
);
631 pdp
->pClipRects
= NULL
;
633 if (pdp
->pBackClipRects
) {
634 _mesa_free(pdp
->pBackClipRects
);
635 pdp
->pBackClipRects
= NULL
;
644 /*****************************************************************/
645 /** \name Context handling functions */
646 /*****************************************************************/
650 * Destroy the per-context private information.
652 * \param contextPrivate opaque pointer to the per-drawable private info.
655 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
656 * drmDestroyContext(), and finally frees \p contextPrivate.
659 driDestroyContext(__DRIcontext
*context
)
661 __DRIcontextPrivate
*pcp
= context
->private;
664 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
671 * Create the per-drawable private driver information.
673 * \param dpy The display handle.
674 * \param modes Mode used to create the new context.
675 * \param render_type Type of rendering target. \c GLX_RGBA is the only
676 * type likely to ever be supported for direct-rendering.
677 * \param shared The shared context dependent methods or \c NULL if
679 * \param pctx DRI context to receive the context dependent methods.
681 * \returns An opaque pointer to the per-context private information on
682 * success, or \c NULL on failure.
685 * This function allocates and fills a __DRIcontextPrivateRec structure. It
686 * performs some device independent initialization and passes all the
687 * relevent information to __DriverAPIRec::CreateContext to create the
692 driCreateNewContext(__DRIscreen
*screen
, const __GLcontextModes
*modes
,
693 int render_type
, __DRIcontext
*shared
,
694 drm_context_t hwContext
, __DRIcontext
*pctx
)
696 __DRIcontextPrivate
*pcp
;
697 __DRIcontextPrivate
*pshare
= (shared
!= NULL
) ? shared
->private : NULL
;
698 __DRIscreenPrivate
*psp
;
699 void * const shareCtx
= (pshare
!= NULL
) ? pshare
->driverPrivate
: NULL
;
701 psp
= (__DRIscreenPrivate
*)screen
->private;
703 pcp
= (__DRIcontextPrivate
*)_mesa_malloc(sizeof(__DRIcontextPrivate
));
708 pcp
->hHWContext
= hwContext
;
709 pcp
->driScreenPriv
= psp
;
710 pcp
->driDrawablePriv
= NULL
;
712 /* When the first context is created for a screen, initialize a "dummy"
716 if (!psp
->dri2
.enabled
&& !psp
->dummyContextPriv
.driScreenPriv
) {
717 psp
->dummyContextPriv
.hHWContext
= psp
->pSAREA
->dummy_context
;
718 psp
->dummyContextPriv
.driScreenPriv
= psp
;
719 psp
->dummyContextPriv
.driDrawablePriv
= NULL
;
720 psp
->dummyContextPriv
.driverPrivate
= NULL
;
721 /* No other fields should be used! */
724 pctx
->destroyContext
= driDestroyContext
;
725 pctx
->bindContext
= driBindContext
;
726 pctx
->unbindContext
= driUnbindContext
;
728 if ( !(*psp
->DriverAPI
.CreateContext
)(modes
, pcp
, shareCtx
) ) {
738 static const __DRIextension
**
739 driGetExtensions(__DRIscreen
*screen
)
741 __DRIscreenPrivate
*psp
= screen
->private;
743 return psp
->extensions
;
746 /*****************************************************************/
747 /** \name Screen handling functions */
748 /*****************************************************************/
752 * Destroy the per-screen private information.
754 * \param dpy the display handle.
755 * \param scrn the screen number.
756 * \param screenPrivate opaque pointer to the per-screen private information.
759 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
760 * drmClose(), and finally frees \p screenPrivate.
762 static void driDestroyScreen(__DRIscreen
*screen
)
764 __DRIscreenPrivate
*psp
= screen
->private;
767 /* No interaction with the X-server is possible at this point. This
768 * routine is called after XCloseDisplay, so there is no protocol
769 * stream open to the X-server anymore.
772 if (psp
->DriverAPI
.DestroyScreen
)
773 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
775 if (psp
->dri2
.enabled
) {
776 drmBOUnmap(psp
->fd
, &psp
->dri2
.sareaBO
);
777 drmBOUnreference(psp
->fd
, &psp
->dri2
.sareaBO
);
779 (void)drmUnmap((drmAddress
)psp
->pSAREA
, SAREA_MAX
);
780 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
781 (void)drmCloseOnce(psp
->fd
);
789 setupLoaderExtensions(__DRIscreenPrivate
*psp
,
790 const __DRIextension
**extensions
)
794 for (i
= 0; extensions
[i
]; i
++) {
795 if (strcmp(extensions
[i
]->name
, __DRI_CONTEXT_MODES
) == 0)
796 psp
->contextModes
= (__DRIcontextModesExtension
*) extensions
[i
];
797 if (strcmp(extensions
[i
]->name
, __DRI_GET_DRAWABLE_INFO
) == 0)
798 psp
->getDrawableInfo
= (__DRIgetDrawableInfoExtension
*) extensions
[i
];
799 if (strcmp(extensions
[i
]->name
, __DRI_DAMAGE
) == 0)
800 psp
->damage
= (__DRIdamageExtension
*) extensions
[i
];
801 if (strcmp(extensions
[i
]->name
, __DRI_SYSTEM_TIME
) == 0)
802 psp
->systemTime
= (__DRIsystemTimeExtension
*) extensions
[i
];
803 if (strcmp(extensions
[i
]->name
, __DRI_CORE_DRI2
) == 0)
804 psp
->dri2
.core
= (__DRIcoreDRI2Extension
*) extensions
[i
];
809 * This is the bootstrap function for the driver. libGL supplies all of the
810 * requisite information about the system, and the driver initializes itself.
811 * This routine also fills in the linked list pointed to by \c driver_modes
812 * with the \c __GLcontextModes that the driver can support for windows or
815 * \param scrn Index of the screen
816 * \param psc DRI screen data (not driver private)
817 * \param modes Linked list of known display modes. This list is, at a
818 * minimum, a list of modes based on the current display mode.
819 * These roughly match the set of available X11 visuals, but it
820 * need not be limited to X11! The calling libGL should create
821 * a list that will inform the driver of the current display
822 * mode (i.e., color buffer depth, depth buffer depth, etc.).
823 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
825 * \param dri_version Version of the "server-side" DRI.
826 * \param drm_version Version of the kernel DRM.
827 * \param frame_buffer Data describing the location and layout of the
829 * \param pSAREA Pointer the the SAREA.
830 * \param fd Device handle for the DRM.
831 * \param internal_api_version Version of the internal interface between the
833 * \param driverAPI Driver API functions used by other routines in dri_util.c.
835 * \note There is no need to check the minimum API version in this
836 * function. Since the name of this function is versioned, it is
837 * impossible for a loader that is too old to even load this driver.
840 void * __DRI_CREATE_NEW_SCREEN( int scrn
, __DRIscreen
*psc
,
841 const __DRIversion
* ddx_version
,
842 const __DRIversion
* dri_version
,
843 const __DRIversion
* drm_version
,
844 const __DRIframebuffer
* frame_buffer
,
845 drmAddress pSAREA
, int fd
,
846 const __DRIextension
** extensions
,
847 __GLcontextModes
** driver_modes
)
850 __DRIscreenPrivate
*psp
;
851 static const __DRIextension
*emptyExtensionList
[] = { NULL
};
853 psp
= _mesa_malloc(sizeof(*psp
));
859 setupLoaderExtensions(psp
, extensions
);
862 ** NOT_DONE: This is used by the X server to detect when the client
863 ** has died while holding the drawable lock. The client sets the
864 ** drawable lock to this value.
868 psp
->drm_version
= *drm_version
;
869 psp
->ddx_version
= *ddx_version
;
870 psp
->dri_version
= *dri_version
;
872 psp
->pSAREA
= pSAREA
;
873 psp
->lock
= (drmLock
*) &psp
->pSAREA
->lock
;
875 psp
->pFB
= frame_buffer
->base
;
876 psp
->fbSize
= frame_buffer
->size
;
877 psp
->fbStride
= frame_buffer
->stride
;
878 psp
->fbWidth
= frame_buffer
->width
;
879 psp
->fbHeight
= frame_buffer
->height
;
880 psp
->devPrivSize
= frame_buffer
->dev_priv_size
;
881 psp
->pDevPriv
= frame_buffer
->dev_priv
;
882 psp
->fbBPP
= psp
->fbStride
* 8 / frame_buffer
->width
;
884 psp
->extensions
= emptyExtensionList
;
887 psp
->dri2
.enabled
= GL_FALSE
;
890 ** Do not init dummy context here; actual initialization will be
891 ** done when the first DRI context is created. Init screen priv ptr
892 ** to NULL to let CreateContext routine that it needs to be inited.
894 psp
->dummyContextPriv
.driScreenPriv
= NULL
;
896 psc
->destroyScreen
= driDestroyScreen
;
897 psc
->getExtensions
= driGetExtensions
;
898 psc
->createNewDrawable
= driCreateNewDrawable
;
899 psc
->createNewContext
= driCreateNewContext
;
901 *driver_modes
= __driDriverInitScreen(psp
);
902 if (*driver_modes
== NULL
) {
911 __DRI2_CREATE_NEW_SCREEN(int scrn
, __DRIscreen
*psc
,
912 int fd
, unsigned int sarea_handle
,
913 const __DRIextension
**extensions
,
914 __GLcontextModes
**driver_modes
)
916 __DRIscreenPrivate
*psp
;
917 static const __DRIextension
*emptyExtensionList
[] = { NULL
};
919 drmVersionPtr version
;
920 __GLcontextModes
*(*initScreen
)(__DRIscreenPrivate
*psc
);
922 initScreen
= dlsym(NULL
, "__dri2DriverInitScreen");
923 if (initScreen
== NULL
)
926 psp
= _mesa_malloc(sizeof(*psp
));
930 setupLoaderExtensions(psp
, extensions
);
934 version
= drmGetVersion(fd
);
936 psp
->drm_version
.major
= version
->version_major
;
937 psp
->drm_version
.minor
= version
->version_minor
;
938 psp
->drm_version
.patch
= version
->version_patchlevel
;
939 drmFreeVersion(version
);
942 psp
->extensions
= emptyExtensionList
;
945 psp
->dri2
.enabled
= GL_TRUE
;
947 if (drmBOReference(psp
->fd
, sarea_handle
, &psp
->dri2
.sareaBO
)) {
948 fprintf(stderr
, "Failed to reference DRI2 sarea BO\n");
953 if (drmBOMap(psp
->fd
, &psp
->dri2
.sareaBO
,
954 DRM_BO_FLAG_READ
| DRM_BO_FLAG_WRITE
, 0, &psp
->dri2
.sarea
)) {
955 drmBOUnreference(psp
->fd
, &psp
->dri2
.sareaBO
);
961 while (DRI2_SAREA_BLOCK_TYPE(*p
)) {
962 switch (DRI2_SAREA_BLOCK_TYPE(*p
)) {
963 case DRI2_SAREA_BLOCK_LOCK
:
964 psp
->dri2
.lock
= (__DRILock
*) p
;
966 case DRI2_SAREA_BLOCK_EVENT_BUFFER
:
967 psp
->dri2
.buffer
= (__DRIEventBuffer
*) p
;
970 p
= DRI2_SAREA_BLOCK_NEXT(p
);
973 psp
->lock
= (drmLock
*) &psp
->dri2
.lock
->lock
;
975 psc
->destroyScreen
= driDestroyScreen
;
976 psc
->getExtensions
= driGetExtensions
;
977 psc
->createNewDrawable
= driCreateNewDrawable
;
978 psc
->createNewContext
= driCreateNewContext
;
980 *driver_modes
= initScreen(psp
);
981 if (*driver_modes
== NULL
) {
982 drmBOUnmap(psp
->fd
, &psp
->dri2
.sareaBO
);
983 drmBOUnreference(psp
->fd
, &psp
->dri2
.sareaBO
);
992 driFrameTracking(__DRIdrawable
*drawable
, GLboolean enable
)
994 return GLX_BAD_CONTEXT
;
998 driQueryFrameTracking(__DRIdrawable
*drawable
,
999 int64_t * sbc
, int64_t * missedFrames
,
1000 float * lastMissedUsage
, float * usage
)
1002 __DRIswapInfo sInfo
;
1005 __DRIdrawablePrivate
* dpriv
= drawable
->private;
1006 __DRIscreenPrivate
*psp
= dpriv
->driScreenPriv
;
1008 status
= dpriv
->driScreenPriv
->DriverAPI
.GetSwapInfo( dpriv
, & sInfo
);
1009 if ( status
== 0 ) {
1010 *sbc
= sInfo
.swap_count
;
1011 *missedFrames
= sInfo
.swap_missed_count
;
1012 *lastMissedUsage
= sInfo
.swap_missed_usage
;
1014 (*psp
->systemTime
->getUST
)( & ust
);
1015 *usage
= driCalculateSwapUsage( dpriv
, sInfo
.swap_ust
, ust
);
1021 const __DRIframeTrackingExtension driFrameTrackingExtension
= {
1022 { __DRI_FRAME_TRACKING
, __DRI_FRAME_TRACKING_VERSION
},
1024 driQueryFrameTracking
1028 * Calculate amount of swap interval used between GLX buffer swaps.
1030 * The usage value, on the range [0,max], is the fraction of total swap
1031 * interval time used between GLX buffer swaps is calculated.
1033 * \f$p = t_d / (i * t_r)\f$
1035 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
1036 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
1037 * required for a single vertical refresh period (as returned by \c
1038 * glXGetMscRateOML).
1040 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
1043 * \param dPriv Pointer to the private drawable structure.
1044 * \return If less than a single swap interval time period was required
1045 * between GLX buffer swaps, a number greater than 0 and less than
1046 * 1.0 is returned. If exactly one swap interval time period is
1047 * required, 1.0 is returned, and if more than one is required then
1048 * a number greater than 1.0 will be returned.
1050 * \sa glXSwapIntervalSGI glXGetMscRateOML
1052 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
1053 * be possible to cache the sync rate?
1056 driCalculateSwapUsage( __DRIdrawablePrivate
*dPriv
, int64_t last_swap_ust
,
1057 int64_t current_ust
)
1063 __DRIscreenPrivate
*psp
= dPriv
->driScreenPriv
;
1065 if ( (*psp
->systemTime
->getMSCRate
)(dPriv
->pdraw
, &n
, &d
) ) {
1066 interval
= (dPriv
->swap_interval
!= 0) ? dPriv
->swap_interval
: 1;
1069 /* We want to calculate
1070 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
1071 * current_UST by calling __glXGetUST. last_swap_UST is stored in
1072 * dPriv->swap_ust. interval has already been calculated.
1074 * The only tricky part is us_per_refresh. us_per_refresh is
1075 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
1076 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
1077 * the denominator of the final calculation, we calculate
1078 * (interval * 1000000 * d) and move n into the numerator.
1081 usage
= (current_ust
- last_swap_ust
);
1083 usage
/= (interval
* d
);