3 * \brief DRI utility functions.
5 * This module acts as glue between GLX and the actual hardware driver. A DRI
6 * driver doesn't really \e have to use any of this - it's optional. But, some
7 * useful stuff is done here that otherwise would have to be duplicated in most
10 * Basically, these utility functions take care of some of the dirty details of
11 * screen initialization, context creation, context binding, DRM setup, etc.
13 * These functions are compiled into each DRI driver so libGL.so knows nothing
27 #include <sys/ioctl.h>
35 * \brief Print message to \c stderr if the \c LIBGL_DEBUG environment variable
38 * Is called from the drivers.
40 * \param f \e printf like format.
43 * This function is a wrapper around vfprintf().
46 __driUtilMessage(const char *f
, ...)
50 if (getenv("LIBGL_DEBUG")) {
51 fprintf(stderr
, "libGL error: \n");
53 vfprintf(stderr
, f
, args
);
55 fprintf(stderr
, "\n");
60 /*****************************************************************/
61 /** \name Visual utility functions */
62 /*****************************************************************/
69 /*****************************************************************/
70 /** \name Context (un)binding functions */
71 /*****************************************************************/
76 * \brief Unbind context.
78 * \param drawable __DRIdrawable
79 * \param context __DRIcontext
80 * \param will_rebind not used.
82 * \return GL_TRUE on success, or GL_FALSE on failure.
85 * This function calls __DriverAPIRec::UnbindContext, and then decrements
86 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
89 * While casting the opaque private pointers associated with the parameters into their
90 * respective real types it also assures they are not null.
92 static GLboolean
driUnbindContext(__DRIdrawable
*drawable
,
93 __DRIcontext
*context
)
95 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)drawable
;
96 __DRIcontextPrivate
*pcp
= (__DRIcontextPrivate
*)context
;
97 __DRIscreenPrivate
*psp
;
99 if (pdp
== NULL
|| pcp
== NULL
)
102 if (!(psp
= (__DRIscreenPrivate
*)pdp
->driScreenPriv
))
105 /* Let driver unbind drawable from context */
106 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
108 if (pdp
->refcount
== 0)
118 * \brief Unbind context.
120 * \param pDRIScreen __DRIscreen
121 * \param drawable __DRIdrawable
122 * \param context __DRIcontext
125 * This function and increments __DRIdrawablePrivateRec::refcount and calls
126 * __DriverAPIRec::MakeCurrent to binds the drawable.
128 * While casting the opaque private pointers into their
129 * respective real types it also assures they are not null.
131 static GLboolean
driBindContext(__DRIscreen
*screen
, __DRIdrawable
*drawable
,
132 __DRIcontext
*context
)
134 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*)screen
;
135 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)drawable
;
136 __DRIcontextPrivate
*pcp
= (__DRIcontextPrivate
*)context
;
141 if (pdp
== NULL
|| pcp
== NULL
) {
142 (*psp
->DriverAPI
.MakeCurrent
)(0, 0, 0);
146 /* Bind the drawable to the context */
147 pcp
->driDrawablePriv
= pdp
;
148 pdp
->driContextPriv
= pcp
;
151 /* Call device-specific MakeCurrent */
152 (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, pdp
);
160 /*****************************************************************/
161 /** \name Drawable handling functions */
162 /*****************************************************************/
167 * \brief Update private drawable information.
169 * \param pdp pointer to the private drawable information to update.
172 * This function is a no-op. Should never be called but is referenced as an
173 * external symbol from client drivers.
175 void __driUtilUpdateDrawableInfo(__DRIdrawablePrivate
*pdp
)
177 __DRIscreenPrivate
*psp
= pdp
->driScreenPriv
;
179 pdp
->numClipRects
= psp
->pSAREA
->drawableTable
[pdp
->index
].flags
? 1 : 0;
180 pdp
->lastStamp
= *(pdp
->pStamp
);
185 * \brief Swap buffers.
187 * \param pDRIscreen __DRIscreen
188 * \param drawablePrivate opaque pointer to the per-drawable private info.
191 * This function calls __DRIdrawablePrivate::swapBuffers.
193 * Is called directly from glXSwapBuffers().
195 static void driSwapBuffers(__DRIdrawable
*drawable
)
197 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)drawable
;
199 pdp
->swapBuffers(pdp
);
204 * \brief Destroy per-drawable private information.
206 * \param pDRIscreen __DRIscreen
207 * \param drawablePrivate opaque pointer to the per-drawable private info.
210 * This function calls __DriverAPIRec::DestroyBuffer on \p drawablePrivate,
211 * frees the clip rects if any, and finally frees \p drawablePrivate itself.
213 static void driDestroyDrawable(__DRIdrawable
*drawable
)
215 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)drawable
;
216 __DRIscreenPrivate
*psp
;
219 psp
= pdp
->driScreenPriv
;
220 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
222 free(pdp
->pClipRects
);
229 * \brief Create the per-drawable private driver information.
231 * \param dpy the display handle.
232 * \param scrn the screen number.
233 * \param draw the GLX drawable info.
234 * \param vid visual ID.
235 * \param pdraw will receive the drawable dependent methods.
238 * \returns a opaque pointer to the per-drawable private info on success, or NULL
242 * This function allocates and fills a __DRIdrawablePrivateRec structure,
243 * initializing the invariant window dimensions and clip rects. It obtains the
244 * visual config, converts it into a __GLcontextModesRec and passes it to
245 * __DriverAPIRec::CreateBuffer to create a buffer.
247 static void *driCreateDrawable(__DRIscreen
*screen
,
248 int width
, int height
, int index
,
249 const __GLcontextModes
*glVisual
)
251 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*)screen
;
252 __DRIdrawablePrivate
*pdp
;
257 if (!(pdp
= (__DRIdrawablePrivate
*)malloc(sizeof(__DRIdrawablePrivate
))))
263 pdp
->numBackClipRects
= 0;
264 pdp
->pBackClipRects
= NULL
;
266 /* Initialize with the invariant window dimensions and clip rects here.
272 pdp
->numClipRects
= 0;
273 pdp
->pClipRects
= (XF86DRIClipRectPtr
) malloc(sizeof(XF86DRIClipRectRec
));
274 (pdp
->pClipRects
)[0].x1
= 0;
275 (pdp
->pClipRects
)[0].y1
= 0;
276 (pdp
->pClipRects
)[0].x2
= width
;
277 (pdp
->pClipRects
)[0].y2
= height
;
279 pdp
->driScreenPriv
= psp
;
280 pdp
->driContextPriv
= 0;
282 pdp
->frontBuffer
= psp
->pFB
;
283 pdp
->currentBuffer
= pdp
->frontBuffer
;
284 pdp
->currentPitch
= psp
->fbStride
;
285 pdp
->backBuffer
= psp
->pFB
+ psp
->fbStride
* psp
->fbHeight
;
287 if (!(*psp
->DriverAPI
.CreateBuffer
)(psp
, pdp
, glVisual
, GL_FALSE
)) {
292 pdp
->entry
.destroyDrawable
= driDestroyDrawable
;
293 pdp
->entry
.swapBuffers
= driSwapBuffers
; /* called by glXSwapBuffers() */
294 pdp
->swapBuffers
= psp
->DriverAPI
.SwapBuffers
;
296 pdp
->pStamp
= &(psp
->pSAREA
->drawableTable
[pdp
->index
].stamp
);
303 /*****************************************************************/
304 /** \name Context handling functions */
305 /*****************************************************************/
310 * \brief Destroy the per-context private information.
312 * \param contextPrivate opaque pointer to the per-drawable private info.
315 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
316 * drmDestroyContext(), and finally frees \p contextPrivate.
318 static void driDestroyContext(__DRIcontext
*context
)
320 __DRIcontextPrivate
*pcp
= (__DRIcontextPrivate
*)context
;
321 __DRIscreenPrivate
*psp
= NULL
;
324 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
325 psp
= pcp
->driDrawablePriv
->driScreenPriv
;
327 printf(">>> drmDestroyContext(0x%x)\n", (int) pcp
->hHWContext
);
328 drmDestroyContext(psp
->fd
, pcp
->hHWContext
);
335 * \brief Create the per-drawable private driver information.
337 * \param dpy the display handle.
338 * \param vis the visual information.
339 * \param sharedPrivate the shared context dependent methods or NULL if non-existent.
340 * \param pctx will receive the context dependent methods.
342 * \returns a opaque pointer to the per-context private information on success, or NULL
346 * This function allocates and fills a __DRIcontextPrivateRec structure. It
347 * gets the visual, converts it into a __GLcontextModesRec and passes it
348 * to __DriverAPIRec::CreateContext to create the context.
350 static void *driCreateContext(__DRIscreen
*screen
,
351 const __GLcontextModes
*glVisual
,
354 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*)screen
;
355 __DRIcontextPrivate
*pcp
;
356 __DRIcontextPrivate
*pshare
= (__DRIcontextPrivate
*) sharedPrivate
;
362 if (!(pcp
= (__DRIcontextPrivate
*)malloc(sizeof(__DRIcontextPrivate
))))
365 pcp
->driScreenPriv
= psp
;
366 pcp
->driDrawablePriv
= NULL
;
369 if (drmCreateContext(psp
->fd
, &pcp
->hHWContext
)) {
370 fprintf(stderr
, ">>> drmCreateContext failed\n");
376 shareCtx
= pshare
? pshare
->driverPrivate
: NULL
;
378 if (!(*psp
->DriverAPI
.CreateContext
)(glVisual
, pcp
, shareCtx
)) {
380 (void) drmDestroyContext(psp
->fd
, pcp
->hHWContext
);
385 pcp
->entry
.destroyContext
= driDestroyContext
;
386 pcp
->entry
.bindContext
= driBindContext
;
387 pcp
->entry
.unbindContext
= driUnbindContext
;
395 /*****************************************************************/
396 /** \name Screen handling functions */
397 /*****************************************************************/
402 * \brief Destroy the per-screen private information.
404 * \param pDRIscreen __DRIscreen
407 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
408 * drmClose(), and finally frees \p screenPrivate.
410 static void driDestroyScreen(__DRIscreen
*screen
)
412 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*)screen
;
414 if (psp
->DriverAPI
.DestroyScreen
)
415 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
418 (void)drmClose(psp
->fd
);
427 * \brief Create the per-screen private information.
429 * \param dpy the display handle.
430 * \param scrn the screen number.
431 * \param psc will receive the screen dependent methods.
432 * \param numConfigs number of visuals.
433 * \param config visuals.
434 * \param driverAPI driver callbacks structure.
436 * \return a pointer to the per-screen private information.
439 * This function allocates and fills a __DRIscreenPrivateRec structure. It
440 * opens the DRM device verifying that the exported version matches the
441 * expected. It copies the driver callback functions and calls
442 * __DriverAPIRec::InitDriver.
444 * If a client maps the framebuffer and SAREA regions.
447 __driUtilCreateScreen(struct DRIDriverRec
*driver
,
448 struct DRIDriverContextRec
*driverContext
,
449 const struct __DriverAPIRec
*driverAPI
)
451 __DRIscreenPrivate
*psp
;
453 if(!(psp
= (__DRIscreenPrivate
*)malloc(sizeof(__DRIscreenPrivate
))))
456 psp
->fd
= drmOpen(NULL
, driverContext
->pciBusID
);
458 fprintf(stderr
, "libGL error: failed to open DRM: %s\n",
465 drmVersionPtr version
= drmGetVersion(psp
->fd
);
467 psp
->drmMajor
= version
->version_major
;
468 psp
->drmMinor
= version
->version_minor
;
469 psp
->drmPatch
= version
->version_patchlevel
;
470 drmFreeVersion(version
);
473 fprintf(stderr
, "libGL error: failed to get drm version: %s\n",
481 * Fake various version numbers.
490 /* install driver's callback functions */
491 psp
->DriverAPI
= *driverAPI
;
494 * Get device-specific info. pDevPriv will point to a struct
495 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
496 * that has information about the screen size, depth, pitch,
497 * ancilliary buffers, DRM mmap handles, etc.
499 psp
->fbOrigin
= driverContext
->shared
.fbOrigin
;
500 psp
->fbSize
= driverContext
->shared
.fbSize
;
501 psp
->fbStride
= driverContext
->shared
.fbStride
;
502 psp
->devPrivSize
= driverContext
->driverClientMsgSize
;
503 psp
->pDevPriv
= driverContext
->driverClientMsg
;
504 psp
->fbWidth
= driverContext
->shared
.virtualWidth
;
505 psp
->fbHeight
= driverContext
->shared
.virtualHeight
;
506 psp
->fbBPP
= driverContext
->bpp
;
508 if ((driverContext
->FBAddress
!= NULL
) && (driverContext
->pSAREA
!= NULL
)) {
509 /* Already mapped in server */
510 psp
->pFB
= driverContext
->FBAddress
;
511 psp
->pSAREA
= driverContext
->pSAREA
;
514 * Map the framebuffer region.
516 if (drmMap(psp
->fd
, driverContext
->shared
.hFrameBuffer
, psp
->fbSize
,
517 (drmAddressPtr
)&psp
->pFB
)) {
518 fprintf(stderr
, "libGL error: drmMap of framebuffer failed\n");
519 (void)drmClose(psp
->fd
);
525 * Map the SAREA region. Further mmap regions may be setup in
526 * each DRI driver's "createScreen" function.
528 if (drmMap(psp
->fd
, driverContext
->shared
.hSAREA
,
529 driverContext
->shared
.SAREASize
,
530 (drmAddressPtr
)&psp
->pSAREA
)) {
531 fprintf(stderr
, "libGL error: drmMap of sarea failed\n");
532 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
533 (void)drmClose(psp
->fd
);
539 mprotect(psp
->pSAREA
, driverContext
->shared
.SAREASize
, PROT_READ
);
544 /* Initialize the screen specific GLX driver */
545 if (psp
->DriverAPI
.InitDriver
) {
546 if (!(*psp
->DriverAPI
.InitDriver
)(psp
)) {
547 fprintf(stderr
, "libGL error: InitDriver failed\n");
549 (void)drmClose(psp
->fd
);
555 psp
->entry
.destroyScreen
= driDestroyScreen
;
556 psp
->entry
.createContext
= driCreateContext
;
557 psp
->entry
.createDrawable
= driCreateDrawable
;
565 * \brief Create the per-screen private information.
567 * Version for drivers without a DRM module.
569 * \param dpy the display handle.
570 * \param scrn the screen number.
571 * \param numConfigs number of visuals.
572 * \param config visuals.
573 * \param driverAPI driver callbacks structure.
576 * Same as __driUtilCreateScreen() but without opening the DRM device.
579 __driUtilCreateScreenNoDRM(struct DRIDriverRec
*driver
,
580 struct DRIDriverContextRec
*driverContext
,
581 const struct __DriverAPIRec
*driverAPI
)
583 __DRIscreenPrivate
*psp
;
585 psp
= (__DRIscreenPrivate
*)calloc(1, sizeof(__DRIscreenPrivate
));
597 psp
->fbOrigin
= driverContext
->shared
.fbOrigin
;
598 psp
->fbSize
= driverContext
->shared
.fbSize
;
599 psp
->fbStride
= driverContext
->shared
.fbStride
;
600 psp
->devPrivSize
= driverContext
->driverClientMsgSize
;
601 psp
->pDevPriv
= driverContext
->driverClientMsg
;
602 psp
->fbWidth
= driverContext
->shared
.virtualWidth
;
603 psp
->fbHeight
= driverContext
->shared
.virtualHeight
;
604 psp
->fbBPP
= driverContext
->bpp
;
606 psp
->pFB
= driverContext
->FBAddress
;
608 /* install driver's callback functions */
609 psp
->DriverAPI
= *driverAPI
;
611 if ((driverContext
->FBAddress
!= NULL
) && (driverContext
->pSAREA
!= NULL
)) {
612 /* Already mapped in server */
613 psp
->pFB
= driverContext
->FBAddress
;
614 psp
->pSAREA
= driverContext
->pSAREA
;
616 psp
->fd
= open("/dev/mem", O_RDWR
, 0);
618 * Map the framebuffer region.
620 if (drmMap(psp
->fd
, driverContext
->shared
.hFrameBuffer
, psp
->fbSize
,
621 (drmAddressPtr
)&psp
->pFB
)) {
622 fprintf(stderr
, "libGL error: drmMap of framebuffer failed\n");
623 (void)drmClose(psp
->fd
);
627 driverContext
->FBAddress
= psp
->pFB
;
630 * Map the SAREA region. Non-DRM drivers use a shmem SAREA
633 id
= shmget(driverContext
->shared
.hSAREA
, driverContext
->shared
.SAREASize
, 0);
634 driverContext
->pSAREA
= shmat(id
, NULL
, 0);
635 if (!driverContext
->pSAREA
) {
636 fprintf(stderr
, "libGL error: shmget of sarea failed\n");
637 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
638 (void)drmClose(psp
->fd
);
647 /* Initialize the screen specific GLX driver */
648 if (psp
->DriverAPI
.InitDriver
) {
649 if (!(*psp
->DriverAPI
.InitDriver
)(psp
)) {
650 fprintf(stderr
, "libGL error: InitDriver failed\n");
657 psp
->entry
.destroyScreen
= driDestroyScreen
;
658 psp
->entry
.createContext
= driCreateContext
;
659 psp
->entry
.createDrawable
= driCreateDrawable
;
665 * Calculate amount of swap interval used between GLX buffer swaps.
667 * The usage value, on the range [0,max], is the fraction of total swap
668 * interval time used between GLX buffer swaps is calculated.
670 * \f$p = t_d / (i * t_r)\f$
672 * Where \f$t_d\$f is the time since the last GLX buffer swap, \f$i\f$ is the
673 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
674 * required for a single vertical refresh period (as returned by \c
677 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
680 * \param dPriv Pointer to the private drawable structure.
681 * \return If less than a single swap interval time period was required
682 * between GLX buffer swaps, a number greater than 0 and less than
683 * 1.0 is returned. If exactly one swap interval time period is
684 * required, 1.0 is returned, and if more than one is required then
685 * a number greater than 1.0 will be returned.
687 * \sa glXSwapIntervalSGI(), glXGetMscRateOML().
690 driCalculateSwapUsage( __DRIdrawablePrivate
*dPriv
, int64_t last_swap_ust
,
691 int64_t current_ust
)
697 * Compare the current GLX API version with a driver supplied required version.
699 * The minimum required version is compared with the API version exported by
700 * the \c __glXGetInternalVersion function (in libGL.so).
702 * \param required_version Minimum required internal GLX API version.
703 * \return A tri-value return, as from strcmp is returned. A value less
704 * than, equal to, or greater than zero will be returned if the
705 * internal GLX API version is less than, equal to, or greater
706 * than \c required_version.
708 * \sa __glXGetInternalVersion().
710 int driCompareGLXAPIVersion( GLuint required_version
)