3 * 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
25 #define MAP_FAILED ((void *)-1)
28 #include "main/imports.h"
32 #include "drm_sarea.h"
35 #include "../glsl/glsl_parser_extras.h"
37 PUBLIC const char __dri2ConfigOptions[] =
39 DRI_CONF_SECTION_PERFORMANCE
40 DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
44 static const uint __dri2NConfigOptions = 1;
46 #ifndef GLX_OML_sync_control
47 typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator);
50 static void dri_get_drawable(__DRIdrawable *pdp);
51 static void dri_put_drawable(__DRIdrawable *pdp);
54 driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 )
56 if (rect2.x1 > rect1.x1) rect1.x1 = rect2.x1;
57 if (rect2.x2 < rect1.x2) rect1.x2 = rect2.x2;
58 if (rect2.y1 > rect1.y1) rect1.y1 = rect2.y1;
59 if (rect2.y2 < rect1.y2) rect1.y2 = rect2.y2;
61 if (rect1.x1 > rect1.x2 || rect1.y1 > rect1.y2) return 0;
63 return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1);
66 /*****************************************************************/
67 /** \name Context (un)binding functions */
68 /*****************************************************************/
74 * \param scrn the screen.
77 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
80 * This function calls __DriverAPIRec::UnbindContext, and then decrements
81 * __DRIdrawableRec::refcount which must be non-zero for a successful
84 * While casting the opaque private pointers associated with the parameters
85 * into their respective real types it also assures they are not \c NULL.
87 static int driUnbindContext(__DRIcontext *pcp)
94 ** Assume error checking is done properly in glXMakeCurrent before
95 ** calling driUnbindContext.
101 psp = pcp->driScreenPriv;
102 pdp = pcp->driDrawablePriv;
103 prp = pcp->driReadablePriv;
105 /* already unbound */
108 /* Let driver unbind drawable from context */
109 (*psp->DriverAPI.UnbindContext)(pcp);
112 if (pdp->refcount == 0) {
117 dri_put_drawable(pdp);
120 if (prp->refcount == 0) {
125 dri_put_drawable(prp);
129 /* XXX this is disabled so that if we call SwapBuffers on an unbound
130 * window we can determine the last context bound to the window and
131 * use that context's lock. (BrianP, 2-Dec-2000)
133 pcp->driDrawablePriv = pcp->driReadablePriv = NULL;
139 * This function takes both a read buffer and a draw buffer. This is needed
140 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
143 static int driBindContext(__DRIcontext *pcp,
147 __DRIscreen *psp = NULL;
150 ** Assume error checking is done properly in glXMakeCurrent before
151 ** calling driUnbindContext.
157 /* Bind the drawable to the context */
158 psp = pcp->driScreenPriv;
159 pcp->driDrawablePriv = pdp;
160 pcp->driReadablePriv = prp;
162 pdp->driContextPriv = pcp;
163 dri_get_drawable(pdp);
165 if (prp && pdp != prp) {
166 dri_get_drawable(prp);
170 ** Now that we have a context associated with this drawable, we can
171 ** initialize the drawable information if has not been done before.
174 if (!psp->dri2.enabled) {
175 if (pdp && !pdp->pStamp) {
176 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
177 __driUtilUpdateDrawableInfo(pdp);
178 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
180 if (prp && pdp != prp && !prp->pStamp) {
181 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
182 __driUtilUpdateDrawableInfo(prp);
183 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
187 /* Call device-specific MakeCurrent */
188 return (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
194 /*****************************************************************/
195 /** \name Drawable handling functions */
196 /*****************************************************************/
200 * Update private drawable information.
202 * \param pdp pointer to the private drawable information to update.
204 * This function basically updates the __DRIdrawable struct's
205 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
206 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
207 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
208 * the values are different that means we have to update the clipping
212 __driUtilUpdateDrawableInfo(__DRIdrawable *pdp)
214 __DRIscreen *psp = pdp->driScreenPriv;
215 __DRIcontext *pcp = pdp->driContextPriv;
218 || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) {
220 * ...but we must ignore it. There can be many contexts bound to a
225 if (pdp->pClipRects) {
226 free(pdp->pClipRects);
227 pdp->pClipRects = NULL;
230 if (pdp->pBackClipRects) {
231 free(pdp->pBackClipRects);
232 pdp->pBackClipRects = NULL;
235 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
237 if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp,
238 &pdp->index, &pdp->lastStamp,
239 &pdp->x, &pdp->y, &pdp->w, &pdp->h,
240 &pdp->numClipRects, &pdp->pClipRects,
243 &pdp->numBackClipRects,
244 &pdp->pBackClipRects,
245 pdp->loaderPrivate)) {
246 /* Error -- eg the window may have been destroyed. Keep going
249 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */
250 pdp->numClipRects = 0;
251 pdp->pClipRects = NULL;
252 pdp->numBackClipRects = 0;
253 pdp->pBackClipRects = NULL;
256 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
258 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
261 static __DRIdrawable *
262 dri2CreateNewDrawable(__DRIscreen *screen,
263 const __DRIconfig *config,
266 __DRIdrawable *pdraw;
268 pdraw = malloc(sizeof *pdraw);
272 pdraw->driContextPriv = NULL;
273 pdraw->loaderPrivate = loaderPrivate;
274 pdraw->hHWDrawable = 0;
276 pdraw->pStamp = NULL;
277 pdraw->lastStamp = 0;
283 pdraw->numClipRects = 0;
284 pdraw->numBackClipRects = 0;
285 pdraw->pClipRects = NULL;
286 pdraw->pBackClipRects = NULL;
290 pdraw->driScreenPriv = screen;
292 if (!(*screen->DriverAPI.CreateBuffer)(screen, pdraw, &config->modes, 0)) {
299 /* This special default value is replaced with the configured
300 * default value when the drawable is first bound to a direct
303 pdraw->swap_interval = (unsigned)-1;
305 pdraw->pClipRects = &pdraw->dri2.clipRect;
306 pdraw->pBackClipRects = &pdraw->dri2.clipRect;
308 pdraw->pStamp = &pdraw->dri2.stamp;
309 *pdraw->pStamp = pdraw->lastStamp + 1;
315 dri2AllocateBuffer(__DRIscreen *screen,
316 unsigned int attachment, unsigned int format,
317 int width, int height)
319 return (*screen->DriverAPI.AllocateBuffer)(screen, attachment, format,
324 dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
326 (*screen->DriverAPI.ReleaseBuffer)(screen, buffer);
331 dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val)
333 if (!driCheckOption(&screen->optionCache, var, DRI_BOOL))
336 *val = driQueryOptionb(&screen->optionCache, var);
342 dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val)
344 if (!driCheckOption(&screen->optionCache, var, DRI_INT) &&
345 !driCheckOption(&screen->optionCache, var, DRI_ENUM))
348 *val = driQueryOptioni(&screen->optionCache, var);
354 dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val)
356 if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT))
359 *val = driQueryOptionf(&screen->optionCache, var);
365 static void dri_get_drawable(__DRIdrawable *pdp)
370 static void dri_put_drawable(__DRIdrawable *pdp)
379 psp = pdp->driScreenPriv;
380 (*psp->DriverAPI.DestroyBuffer)(pdp);
381 if (pdp->pClipRects && pdp->pClipRects != &pdp->dri2.clipRect) {
382 free(pdp->pClipRects);
383 pdp->pClipRects = NULL;
385 if (pdp->pBackClipRects && pdp->pClipRects != &pdp->dri2.clipRect) {
386 free(pdp->pBackClipRects);
387 pdp->pBackClipRects = NULL;
394 driDestroyDrawable(__DRIdrawable *pdp)
396 dri_put_drawable(pdp);
402 /*****************************************************************/
403 /** \name Context handling functions */
404 /*****************************************************************/
408 * Destroy the per-context private information.
411 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
412 * drmDestroyContext(), and finally frees \p contextPrivate.
415 driDestroyContext(__DRIcontext *pcp)
418 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
424 dri2GetAPIMask(__DRIscreen *screen)
426 return screen->api_mask;
429 static __DRIcontext *
430 dri2CreateNewContextForAPI(__DRIscreen *screen, int api,
431 const __DRIconfig *config,
432 __DRIcontext *shared, void *data)
434 __DRIcontext *context;
435 const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
436 void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
439 if (!(screen->api_mask & (1 << api)))
443 case __DRI_API_OPENGL:
444 mesa_api = API_OPENGL;
447 mesa_api = API_OPENGLES;
449 case __DRI_API_GLES2:
450 mesa_api = API_OPENGLES2;
456 context = malloc(sizeof *context);
460 context->driScreenPriv = screen;
461 context->driDrawablePriv = NULL;
462 context->loaderPrivate = data;
464 if (!(*screen->DriverAPI.CreateContext)(mesa_api, modes,
465 context, shareCtx) ) {
474 static __DRIcontext *
475 dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
476 __DRIcontext *shared, void *data)
478 return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL,
479 config, shared, data);
483 driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
494 /*****************************************************************/
495 /** \name Screen handling functions */
496 /*****************************************************************/
500 * Destroy the per-screen private information.
503 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
504 * drmClose(), and finally frees \p screenPrivate.
506 static void driDestroyScreen(__DRIscreen *psp)
509 /* No interaction with the X-server is possible at this point. This
510 * routine is called after XCloseDisplay, so there is no protocol
511 * stream open to the X-server anymore.
514 _mesa_destroy_shader_compiler();
516 if (psp->DriverAPI.DestroyScreen)
517 (*psp->DriverAPI.DestroyScreen)(psp);
519 if (!psp->dri2.enabled) {
520 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
521 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
522 (void)drmCloseOnce(psp->fd);
524 driDestroyOptionCache(&psp->optionCache);
525 driDestroyOptionInfo(&psp->optionInfo);
533 setupLoaderExtensions(__DRIscreen *psp,
534 const __DRIextension **extensions)
538 for (i = 0; extensions[i]; i++) {
539 if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0)
540 psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i];
541 if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0)
542 psp->damage = (__DRIdamageExtension *) extensions[i];
543 if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0)
544 psp->systemTime = (__DRIsystemTimeExtension *) extensions[i];
545 if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
546 psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
547 if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0)
548 psp->dri2.image = (__DRIimageLookupExtension *) extensions[i];
549 if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0)
550 psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i];
558 dri2CreateNewScreen(int scrn, int fd,
559 const __DRIextension **extensions,
560 const __DRIconfig ***driver_configs, void *data)
562 static const __DRIextension *emptyExtensionList[] = { NULL };
564 drmVersionPtr version;
566 if (driDriverAPI.InitScreen2 == NULL)
569 psp = calloc(1, sizeof(*psp));
573 setupLoaderExtensions(psp, extensions);
575 version = drmGetVersion(fd);
577 psp->drm_version.major = version->version_major;
578 psp->drm_version.minor = version->version_minor;
579 psp->drm_version.patch = version->version_patchlevel;
580 drmFreeVersion(version);
583 psp->extensions = emptyExtensionList;
586 psp->dri2.enabled = GL_TRUE;
588 psp->DriverAPI = driDriverAPI;
589 psp->api_mask = (1 << __DRI_API_OPENGL);
590 *driver_configs = driDriverAPI.InitScreen2(psp);
591 if (*driver_configs == NULL) {
596 psp->DriverAPI = driDriverAPI;
597 psp->loaderPrivate = data;
599 driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions,
600 __dri2NConfigOptions);
601 driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum,
607 static const __DRIextension **driGetExtensions(__DRIscreen *psp)
609 return psp->extensions;
612 /** Core interface */
613 const __DRIcoreExtension driCoreExtension = {
614 { __DRI_CORE, __DRI_CORE_VERSION },
619 driIndexConfigAttrib,
630 /** DRI2 interface */
631 const __DRIdri2Extension driDRI2Extension = {
632 { __DRI_DRI2, __DRI_DRI2_VERSION },
634 dri2CreateNewDrawable,
635 dri2CreateNewContext,
637 dri2CreateNewContextForAPI,
642 const __DRI2configQueryExtension dri2ConfigQueryExtension = {
643 { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION },
650 * Calculate amount of swap interval used between GLX buffer swaps.
652 * The usage value, on the range [0,max], is the fraction of total swap
653 * interval time used between GLX buffer swaps is calculated.
655 * \f$p = t_d / (i * t_r)\f$
657 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
658 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
659 * required for a single vertical refresh period (as returned by \c
662 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
665 * \param dPriv Pointer to the private drawable structure.
666 * \return If less than a single swap interval time period was required
667 * between GLX buffer swaps, a number greater than 0 and less than
668 * 1.0 is returned. If exactly one swap interval time period is
669 * required, 1.0 is returned, and if more than one is required then
670 * a number greater than 1.0 will be returned.
672 * \sa glXSwapIntervalSGI glXGetMscRateOML
674 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
675 * be possible to cache the sync rate?
678 driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust,
679 int64_t current_ust )
685 __DRIscreen *psp = dPriv->driScreenPriv;
687 if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) {
688 interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1;
691 /* We want to calculate
692 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
693 * current_UST by calling __glXGetUST. last_swap_UST is stored in
694 * dPriv->swap_ust. interval has already been calculated.
696 * The only tricky part is us_per_refresh. us_per_refresh is
697 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
698 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
699 * the denominator of the final calculation, we calculate
700 * (interval * 1000000 * d) and move n into the numerator.
703 usage = (current_ust - last_swap_ust);
705 usage /= (interval * d);
713 dri2InvalidateDrawable(__DRIdrawable *drawable)
715 drawable->dri2.stamp++;