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>
34 * \brief Print message to \c stderr if the \c LIBGL_DEBUG environment variable
37 * Is called from the drivers.
39 * \param f \e printf like format.
42 * This function is a wrapper around vfprintf().
45 __driUtilMessage(const char *f
, ...)
49 if (getenv("LIBGL_DEBUG")) {
50 fprintf(stderr
, "libGL error: \n");
52 vfprintf(stderr
, f
, args
);
54 fprintf(stderr
, "\n");
59 /*****************************************************************/
60 /** \name Visual utility functions */
61 /*****************************************************************/
68 /*****************************************************************/
69 /** \name Context (un)binding functions */
70 /*****************************************************************/
75 * \brief Unbind context.
77 * \param drawable __DRIdrawable
78 * \param context __DRIcontext
79 * \param will_rebind not used.
81 * \return GL_TRUE on success, or GL_FALSE on failure.
84 * This function calls __DriverAPIRec::UnbindContext, and then decrements
85 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
88 * While casting the opaque private pointers associated with the parameters into their
89 * respective real types it also assures they are not null.
91 static GLboolean
driUnbindContext(__DRIdrawable
*drawable
,
92 __DRIcontext
*context
)
94 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)drawable
;
95 __DRIcontextPrivate
*pcp
= (__DRIcontextPrivate
*)context
;
96 __DRIscreenPrivate
*psp
;
98 if (pdp
== NULL
|| pcp
== NULL
)
101 if (!(psp
= (__DRIscreenPrivate
*)pdp
->driScreenPriv
))
104 /* Let driver unbind drawable from context */
105 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
107 if (pdp
->refcount
== 0)
117 * \brief Unbind context.
119 * \param pDRIScreen __DRIscreen
120 * \param drawable __DRIdrawable
121 * \param context __DRIcontext
124 * This function and increments __DRIdrawablePrivateRec::refcount and calls
125 * __DriverAPIRec::MakeCurrent to binds the drawable.
127 * While casting the opaque private pointers into their
128 * respective real types it also assures they are not null.
130 static GLboolean
driBindContext(__DRIscreen
*screen
, __DRIdrawable
*drawable
,
131 __DRIcontext
*context
)
133 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*)screen
;
134 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)drawable
;
135 __DRIcontextPrivate
*pcp
= (__DRIcontextPrivate
*)context
;
140 if (pdp
== NULL
|| pcp
== NULL
) {
141 (*psp
->DriverAPI
.MakeCurrent
)(0, 0, 0);
145 /* Bind the drawable to the context */
146 pcp
->driDrawablePriv
= pdp
;
147 pdp
->driContextPriv
= pcp
;
150 /* Call device-specific MakeCurrent */
151 (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, pdp
);
159 /*****************************************************************/
160 /** \name Drawable handling functions */
161 /*****************************************************************/
166 * \brief Update private drawable information.
168 * \param pdp pointer to the private drawable information to update.
171 * This function is a no-op. Should never be called but is referenced as an
172 * external symbol from client drivers.
174 void __driUtilUpdateDrawableInfo(__DRIdrawablePrivate
*pdp
)
176 __DRIscreenPrivate
*psp
= pdp
->driScreenPriv
;
178 pdp
->numClipRects
= psp
->pSAREA
->drawableTable
[pdp
->index
].flags
? 1 : 0;
179 pdp
->lastStamp
= *(pdp
->pStamp
);
184 * \brief Swap buffers.
186 * \param pDRIscreen __DRIscreen
187 * \param drawablePrivate opaque pointer to the per-drawable private info.
190 * This function calls __DRIdrawablePrivate::swapBuffers.
192 * Is called directly from glXSwapBuffers().
194 static void driSwapBuffers(__DRIdrawable
*drawable
)
196 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)drawable
;
198 pdp
->swapBuffers(pdp
);
203 * \brief Destroy per-drawable private information.
205 * \param pDRIscreen __DRIscreen
206 * \param drawablePrivate opaque pointer to the per-drawable private info.
209 * This function calls __DriverAPIRec::DestroyBuffer on \p drawablePrivate,
210 * frees the clip rects if any, and finally frees \p drawablePrivate itself.
212 static void driDestroyDrawable(__DRIdrawable
*drawable
)
214 __DRIdrawablePrivate
*pdp
= (__DRIdrawablePrivate
*)drawable
;
215 __DRIscreenPrivate
*psp
;
218 psp
= pdp
->driScreenPriv
;
219 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
221 free(pdp
->pClipRects
);
228 * \brief Create the per-drawable private driver information.
230 * \param dpy the display handle.
231 * \param scrn the screen number.
232 * \param draw the GLX drawable info.
233 * \param vid visual ID.
234 * \param pdraw will receive the drawable dependent methods.
237 * \returns a opaque pointer to the per-drawable private info on success, or NULL
241 * This function allocates and fills a __DRIdrawablePrivateRec structure,
242 * initializing the invariant window dimensions and clip rects. It obtains the
243 * visual config, converts it into a __GLcontextModesRec and passes it to
244 * __DriverAPIRec::CreateBuffer to create a buffer.
246 static void *driCreateDrawable(__DRIscreen
*screen
,
247 int width
, int height
, int index
,
248 const __GLcontextModes
*glVisual
)
250 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*)screen
;
251 __DRIdrawablePrivate
*pdp
;
256 if (!(pdp
= (__DRIdrawablePrivate
*)malloc(sizeof(__DRIdrawablePrivate
))))
262 pdp
->numBackClipRects
= 0;
263 pdp
->pBackClipRects
= NULL
;
265 /* Initialize with the invariant window dimensions and clip rects here.
271 pdp
->numClipRects
= 0;
272 pdp
->pClipRects
= (drm_clip_rect_t
*) malloc(sizeof(drm_clip_rect_t
));
273 (pdp
->pClipRects
)[0].x1
= 0;
274 (pdp
->pClipRects
)[0].y1
= 0;
275 (pdp
->pClipRects
)[0].x2
= width
;
276 (pdp
->pClipRects
)[0].y2
= height
;
278 pdp
->driScreenPriv
= psp
;
279 pdp
->driContextPriv
= 0;
281 pdp
->frontBuffer
= psp
->pFB
;
282 pdp
->currentBuffer
= pdp
->frontBuffer
;
283 pdp
->currentPitch
= psp
->fbStride
;
284 pdp
->backBuffer
= psp
->pFB
+ psp
->fbStride
* psp
->fbHeight
;
286 if (!(*psp
->DriverAPI
.CreateBuffer
)(psp
, pdp
, glVisual
, GL_FALSE
)) {
291 pdp
->entry
.destroyDrawable
= driDestroyDrawable
;
292 pdp
->entry
.swapBuffers
= driSwapBuffers
; /* called by glXSwapBuffers() */
293 pdp
->swapBuffers
= psp
->DriverAPI
.SwapBuffers
;
295 pdp
->pStamp
= &(psp
->pSAREA
->drawableTable
[pdp
->index
].stamp
);
302 /*****************************************************************/
303 /** \name Context handling functions */
304 /*****************************************************************/
309 * \brief Destroy the per-context private information.
311 * \param contextPrivate opaque pointer to the per-drawable private info.
314 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
315 * drmDestroyContext(), and finally frees \p contextPrivate.
317 static void driDestroyContext(__DRIcontext
*context
)
319 __DRIcontextPrivate
*pcp
= (__DRIcontextPrivate
*)context
;
320 __DRIscreenPrivate
*psp
= NULL
;
323 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
324 psp
= pcp
->driDrawablePriv
->driScreenPriv
;
326 printf(">>> drmDestroyContext(0x%x)\n", (int) pcp
->hHWContext
);
327 drmDestroyContext(psp
->fd
, pcp
->hHWContext
);
334 * \brief Create the per-drawable private driver information.
336 * \param dpy the display handle.
337 * \param vis the visual information.
338 * \param sharedPrivate the shared context dependent methods or NULL if non-existent.
339 * \param pctx will receive the context dependent methods.
341 * \returns a opaque pointer to the per-context private information on success, or NULL
345 * This function allocates and fills a __DRIcontextPrivateRec structure. It
346 * gets the visual, converts it into a __GLcontextModesRec and passes it
347 * to __DriverAPIRec::CreateContext to create the context.
349 static void *driCreateContext(__DRIscreen
*screen
,
350 const __GLcontextModes
*glVisual
,
353 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*)screen
;
354 __DRIcontextPrivate
*pcp
;
355 __DRIcontextPrivate
*pshare
= (__DRIcontextPrivate
*) sharedPrivate
;
361 if (!(pcp
= (__DRIcontextPrivate
*)malloc(sizeof(__DRIcontextPrivate
))))
364 pcp
->driScreenPriv
= psp
;
365 pcp
->driDrawablePriv
= NULL
;
368 if (drmCreateContext(psp
->fd
, &pcp
->hHWContext
)) {
369 fprintf(stderr
, ">>> drmCreateContext failed\n");
375 shareCtx
= pshare
? pshare
->driverPrivate
: NULL
;
377 if (!(*psp
->DriverAPI
.CreateContext
)(glVisual
, pcp
, shareCtx
)) {
379 (void) drmDestroyContext(psp
->fd
, pcp
->hHWContext
);
384 pcp
->entry
.destroyContext
= driDestroyContext
;
385 pcp
->entry
.bindContext
= driBindContext
;
386 pcp
->entry
.unbindContext
= driUnbindContext
;
394 /*****************************************************************/
395 /** \name Screen handling functions */
396 /*****************************************************************/
401 * \brief Destroy the per-screen private information.
403 * \param pDRIscreen __DRIscreen
406 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
407 * drmClose(), and finally frees \p screenPrivate.
409 static void driDestroyScreen(__DRIscreen
*screen
)
411 __DRIscreenPrivate
*psp
= (__DRIscreenPrivate
*)screen
;
413 if (psp
->DriverAPI
.DestroyScreen
)
414 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
417 (void)drmClose(psp
->fd
);
426 * \brief Create the per-screen private information.
428 * \param dpy the display handle.
429 * \param scrn the screen number.
430 * \param psc will receive the screen dependent methods.
431 * \param numConfigs number of visuals.
432 * \param config visuals.
433 * \param driverAPI driver callbacks structure.
435 * \return a pointer to the per-screen private information.
438 * This function allocates and fills a __DRIscreenPrivateRec structure. It
439 * opens the DRM device verifying that the exported version matches the
440 * expected. It copies the driver callback functions and calls
441 * __DriverAPIRec::InitDriver.
443 * If a client maps the framebuffer and SAREA regions.
446 __driUtilCreateScreen(struct DRIDriverRec
*driver
,
447 struct DRIDriverContextRec
*driverContext
,
448 const struct __DriverAPIRec
*driverAPI
)
450 __DRIscreenPrivate
*psp
;
452 if(!(psp
= (__DRIscreenPrivate
*)malloc(sizeof(__DRIscreenPrivate
))))
455 psp
->fd
= drmOpen(NULL
, driverContext
->pciBusID
);
457 fprintf(stderr
, "libGL error: failed to open DRM: %s\n",
464 drmVersionPtr version
= drmGetVersion(psp
->fd
);
466 psp
->drmMajor
= version
->version_major
;
467 psp
->drmMinor
= version
->version_minor
;
468 psp
->drmPatch
= version
->version_patchlevel
;
469 drmFreeVersion(version
);
472 fprintf(stderr
, "libGL error: failed to get drm version: %s\n",
479 /* install driver's callback functions */
480 psp
->DriverAPI
= *driverAPI
;
483 * Get device-specific info. pDevPriv will point to a struct
484 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
485 * that has information about the screen size, depth, pitch,
486 * ancilliary buffers, DRM mmap handles, etc.
488 psp
->fbOrigin
= driverContext
->shared
.fbOrigin
;
489 psp
->fbSize
= driverContext
->shared
.fbSize
;
490 psp
->fbStride
= driverContext
->shared
.fbStride
;
491 psp
->devPrivSize
= driverContext
->driverClientMsgSize
;
492 psp
->pDevPriv
= driverContext
->driverClientMsg
;
493 psp
->fbWidth
= driverContext
->shared
.virtualWidth
;
494 psp
->fbHeight
= driverContext
->shared
.virtualHeight
;
495 psp
->fbBPP
= driverContext
->bpp
;
497 if ((driverContext
->FBAddress
!= NULL
) && (driverContext
->pSAREA
!= NULL
)) {
498 /* Already mapped in server */
499 psp
->pFB
= driverContext
->FBAddress
;
500 psp
->pSAREA
= driverContext
->pSAREA
;
503 * Map the framebuffer region.
505 if (drmMap(psp
->fd
, driverContext
->shared
.hFrameBuffer
, psp
->fbSize
,
506 (drmAddressPtr
)&psp
->pFB
)) {
507 fprintf(stderr
, "libGL error: drmMap of framebuffer failed\n");
508 (void)drmClose(psp
->fd
);
514 * Map the SAREA region. Further mmap regions may be setup in
515 * each DRI driver's "createScreen" function.
517 if (drmMap(psp
->fd
, driverContext
->shared
.hSAREA
,
518 driverContext
->shared
.SAREASize
,
519 (drmAddressPtr
)&psp
->pSAREA
)) {
520 fprintf(stderr
, "libGL error: drmMap of sarea failed\n");
521 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
522 (void)drmClose(psp
->fd
);
528 mprotect(psp
->pSAREA
, driverContext
->shared
.SAREASize
, PROT_READ
);
533 /* Initialize the screen specific GLX driver */
534 if (psp
->DriverAPI
.InitDriver
) {
535 if (!(*psp
->DriverAPI
.InitDriver
)(psp
)) {
536 fprintf(stderr
, "libGL error: InitDriver failed\n");
538 (void)drmClose(psp
->fd
);
544 psp
->entry
.destroyScreen
= driDestroyScreen
;
545 psp
->entry
.createContext
= driCreateContext
;
546 psp
->entry
.createDrawable
= driCreateDrawable
;
554 * \brief Create the per-screen private information.
556 * Version for drivers without a DRM module.
558 * \param dpy the display handle.
559 * \param scrn the screen number.
560 * \param numConfigs number of visuals.
561 * \param config visuals.
562 * \param driverAPI driver callbacks structure.
565 * Same as __driUtilCreateScreen() but without opening the DRM device.
568 __driUtilCreateScreenNoDRM(struct DRIDriverRec
*driver
,
569 struct DRIDriverContextRec
*driverContext
,
570 const struct __DriverAPIRec
*driverAPI
)
572 __DRIscreenPrivate
*psp
;
574 psp
= (__DRIscreenPrivate
*)calloc(1, sizeof(__DRIscreenPrivate
));
586 psp
->fbOrigin
= driverContext
->shared
.fbOrigin
;
587 psp
->fbSize
= driverContext
->shared
.fbSize
;
588 psp
->fbStride
= driverContext
->shared
.fbStride
;
589 psp
->devPrivSize
= driverContext
->driverClientMsgSize
;
590 psp
->pDevPriv
= driverContext
->driverClientMsg
;
591 psp
->fbWidth
= driverContext
->shared
.virtualWidth
;
592 psp
->fbHeight
= driverContext
->shared
.virtualHeight
;
593 psp
->fbBPP
= driverContext
->bpp
;
595 psp
->pFB
= driverContext
->FBAddress
;
597 /* install driver's callback functions */
598 psp
->DriverAPI
= *driverAPI
;
600 if ((driverContext
->FBAddress
!= NULL
) && (driverContext
->pSAREA
!= NULL
)) {
601 /* Already mapped in server */
602 psp
->pFB
= driverContext
->FBAddress
;
603 psp
->pSAREA
= driverContext
->pSAREA
;
605 psp
->fd
= open("/dev/mem", O_RDWR
, 0);
607 * Map the framebuffer region.
609 if (drmMap(psp
->fd
, driverContext
->shared
.hFrameBuffer
, psp
->fbSize
,
610 (drmAddressPtr
)&psp
->pFB
)) {
611 fprintf(stderr
, "libGL error: drmMap of framebuffer failed\n");
612 (void)drmClose(psp
->fd
);
616 driverContext
->FBAddress
= psp
->pFB
;
619 * Map the SAREA region. Non-DRM drivers use a shmem SAREA
622 id
= shmget(driverContext
->shared
.hSAREA
, driverContext
->shared
.SAREASize
, 0);
623 driverContext
->pSAREA
= shmat(id
, NULL
, 0);
624 if (!driverContext
->pSAREA
) {
625 fprintf(stderr
, "libGL error: shmget of sarea failed\n");
626 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
627 (void)drmClose(psp
->fd
);
636 /* Initialize the screen specific GLX driver */
637 if (psp
->DriverAPI
.InitDriver
) {
638 if (!(*psp
->DriverAPI
.InitDriver
)(psp
)) {
639 fprintf(stderr
, "libGL error: InitDriver failed\n");
646 psp
->entry
.destroyScreen
= driDestroyScreen
;
647 psp
->entry
.createContext
= driCreateContext
;
648 psp
->entry
.createDrawable
= driCreateDrawable
;
654 * Calculate amount of swap interval used between GLX buffer swaps.
656 * The usage value, on the range [0,max], is the fraction of total swap
657 * interval time used between GLX buffer swaps is calculated.
659 * \f$p = t_d / (i * t_r)\f$
661 * Where \f$t_d\$f is the time since the last GLX buffer swap, \f$i\f$ is the
662 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
663 * required for a single vertical refresh period (as returned by \c
666 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
669 * \param dPriv Pointer to the private drawable structure.
670 * \return If less than a single swap interval time period was required
671 * between GLX buffer swaps, a number greater than 0 and less than
672 * 1.0 is returned. If exactly one swap interval time period is
673 * required, 1.0 is returned, and if more than one is required then
674 * a number greater than 1.0 will be returned.
676 * \sa glXSwapIntervalSGI(), glXGetMscRateOML().
679 driCalculateSwapUsage( __DRIdrawablePrivate
*dPriv
, int64_t last_swap_ust
,
680 int64_t current_ust
)
686 * Compare the current GLX API version with a driver supplied required version.
688 * The minimum required version is compared with the API version exported by
689 * the \c __glXGetInternalVersion function (in libGL.so).
691 * \param required_version Minimum required internal GLX API version.
692 * \return A tri-value return, as from strcmp is returned. A value less
693 * than, equal to, or greater than zero will be returned if the
694 * internal GLX API version is less than, equal to, or greater
695 * than \c required_version.
697 * \sa __glXGetInternalVersion().
699 int driCompareGLXAPIVersion( GLuint required_version
)