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);
263 /*****************************************************************/
264 /** \name GLX callbacks */
265 /*****************************************************************/
268 static void driReportDamage(__DRIdrawable *pdp,
269 struct drm_clip_rect *pClipRects, int numClipRects)
271 __DRIscreen *psp = pdp->driScreenPriv;
273 /* Check that we actually have the new damage report method */
275 /* Report the damage. Currently, all our drivers draw
276 * directly to the front buffer, so we report the damage there
277 * rather than to the backing storein (if any).
279 (*psp->damage->reportDamage)(pdp,
281 pClipRects, numClipRects,
282 GL_TRUE, pdp->loaderPrivate);
290 * \param drawablePrivate opaque pointer to the per-drawable private info.
293 * This function calls __DRIdrawable::swapBuffers.
295 * Is called directly from glXSwapBuffers().
297 static void driSwapBuffers(__DRIdrawable *dPriv)
299 __DRIscreen *psp = dPriv->driScreenPriv;
300 drm_clip_rect_t *rects;
303 psp->DriverAPI.SwapBuffers(dPriv);
305 if (!dPriv->numClipRects)
308 rects = malloc(sizeof(*rects) * dPriv->numClipRects);
313 for (i = 0; i < dPriv->numClipRects; i++) {
314 rects[i].x1 = dPriv->pClipRects[i].x1 - dPriv->x;
315 rects[i].y1 = dPriv->pClipRects[i].y1 - dPriv->y;
316 rects[i].x2 = dPriv->pClipRects[i].x2 - dPriv->x;
317 rects[i].y2 = dPriv->pClipRects[i].y2 - dPriv->y;
320 driReportDamage(dPriv, rects, dPriv->numClipRects);
324 static __DRIdrawable *
325 dri2CreateNewDrawable(__DRIscreen *screen,
326 const __DRIconfig *config,
329 __DRIdrawable *pdraw;
331 pdraw = malloc(sizeof *pdraw);
335 pdraw->driContextPriv = NULL;
336 pdraw->loaderPrivate = loaderPrivate;
337 pdraw->hHWDrawable = 0;
339 pdraw->pStamp = NULL;
340 pdraw->lastStamp = 0;
346 pdraw->numClipRects = 0;
347 pdraw->numBackClipRects = 0;
348 pdraw->pClipRects = NULL;
349 pdraw->pBackClipRects = NULL;
353 pdraw->driScreenPriv = screen;
355 if (!(*screen->DriverAPI.CreateBuffer)(screen, pdraw, &config->modes, 0)) {
362 /* This special default value is replaced with the configured
363 * default value when the drawable is first bound to a direct
366 pdraw->swap_interval = (unsigned)-1;
368 pdraw->pClipRects = &pdraw->dri2.clipRect;
369 pdraw->pBackClipRects = &pdraw->dri2.clipRect;
371 pdraw->pStamp = &pdraw->dri2.stamp;
372 *pdraw->pStamp = pdraw->lastStamp + 1;
378 dri2AllocateBuffer(__DRIscreen *screen,
379 unsigned int attachment, unsigned int format,
380 int width, int height)
382 return (*screen->DriverAPI.AllocateBuffer)(screen, attachment, format,
387 dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
389 (*screen->DriverAPI.ReleaseBuffer)(screen, buffer);
394 dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val)
396 if (!driCheckOption(&screen->optionCache, var, DRI_BOOL))
399 *val = driQueryOptionb(&screen->optionCache, var);
405 dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val)
407 if (!driCheckOption(&screen->optionCache, var, DRI_INT) &&
408 !driCheckOption(&screen->optionCache, var, DRI_ENUM))
411 *val = driQueryOptioni(&screen->optionCache, var);
417 dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val)
419 if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT))
422 *val = driQueryOptionf(&screen->optionCache, var);
428 static void dri_get_drawable(__DRIdrawable *pdp)
433 static void dri_put_drawable(__DRIdrawable *pdp)
442 psp = pdp->driScreenPriv;
443 (*psp->DriverAPI.DestroyBuffer)(pdp);
444 if (pdp->pClipRects && pdp->pClipRects != &pdp->dri2.clipRect) {
445 free(pdp->pClipRects);
446 pdp->pClipRects = NULL;
448 if (pdp->pBackClipRects && pdp->pClipRects != &pdp->dri2.clipRect) {
449 free(pdp->pBackClipRects);
450 pdp->pBackClipRects = NULL;
457 driDestroyDrawable(__DRIdrawable *pdp)
459 dri_put_drawable(pdp);
465 /*****************************************************************/
466 /** \name Context handling functions */
467 /*****************************************************************/
471 * Destroy the per-context private information.
474 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
475 * drmDestroyContext(), and finally frees \p contextPrivate.
478 driDestroyContext(__DRIcontext *pcp)
481 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
487 dri2GetAPIMask(__DRIscreen *screen)
489 return screen->api_mask;
492 static __DRIcontext *
493 dri2CreateNewContextForAPI(__DRIscreen *screen, int api,
494 const __DRIconfig *config,
495 __DRIcontext *shared, void *data)
497 __DRIcontext *context;
498 const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
499 void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
502 if (!(screen->api_mask & (1 << api)))
506 case __DRI_API_OPENGL:
507 mesa_api = API_OPENGL;
510 mesa_api = API_OPENGLES;
512 case __DRI_API_GLES2:
513 mesa_api = API_OPENGLES2;
519 context = malloc(sizeof *context);
523 context->driScreenPriv = screen;
524 context->driDrawablePriv = NULL;
525 context->loaderPrivate = data;
527 if (!(*screen->DriverAPI.CreateContext)(mesa_api, modes,
528 context, shareCtx) ) {
537 static __DRIcontext *
538 dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
539 __DRIcontext *shared, void *data)
541 return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL,
542 config, shared, data);
546 driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
557 /*****************************************************************/
558 /** \name Screen handling functions */
559 /*****************************************************************/
563 * Destroy the per-screen private information.
566 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
567 * drmClose(), and finally frees \p screenPrivate.
569 static void driDestroyScreen(__DRIscreen *psp)
572 /* No interaction with the X-server is possible at this point. This
573 * routine is called after XCloseDisplay, so there is no protocol
574 * stream open to the X-server anymore.
577 _mesa_destroy_shader_compiler();
579 if (psp->DriverAPI.DestroyScreen)
580 (*psp->DriverAPI.DestroyScreen)(psp);
582 if (!psp->dri2.enabled) {
583 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
584 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
585 (void)drmCloseOnce(psp->fd);
587 driDestroyOptionCache(&psp->optionCache);
588 driDestroyOptionInfo(&psp->optionInfo);
596 setupLoaderExtensions(__DRIscreen *psp,
597 const __DRIextension **extensions)
601 for (i = 0; extensions[i]; i++) {
602 if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0)
603 psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i];
604 if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0)
605 psp->damage = (__DRIdamageExtension *) extensions[i];
606 if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0)
607 psp->systemTime = (__DRIsystemTimeExtension *) extensions[i];
608 if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
609 psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
610 if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0)
611 psp->dri2.image = (__DRIimageLookupExtension *) extensions[i];
612 if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0)
613 psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i];
621 dri2CreateNewScreen(int scrn, int fd,
622 const __DRIextension **extensions,
623 const __DRIconfig ***driver_configs, void *data)
625 static const __DRIextension *emptyExtensionList[] = { NULL };
627 drmVersionPtr version;
629 if (driDriverAPI.InitScreen2 == NULL)
632 psp = calloc(1, sizeof(*psp));
636 setupLoaderExtensions(psp, extensions);
638 version = drmGetVersion(fd);
640 psp->drm_version.major = version->version_major;
641 psp->drm_version.minor = version->version_minor;
642 psp->drm_version.patch = version->version_patchlevel;
643 drmFreeVersion(version);
646 psp->extensions = emptyExtensionList;
649 psp->dri2.enabled = GL_TRUE;
651 psp->DriverAPI = driDriverAPI;
652 psp->api_mask = (1 << __DRI_API_OPENGL);
653 *driver_configs = driDriverAPI.InitScreen2(psp);
654 if (*driver_configs == NULL) {
659 psp->DriverAPI = driDriverAPI;
660 psp->loaderPrivate = data;
662 driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions,
663 __dri2NConfigOptions);
664 driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum,
670 static const __DRIextension **driGetExtensions(__DRIscreen *psp)
672 return psp->extensions;
675 /** Core interface */
676 const __DRIcoreExtension driCoreExtension = {
677 { __DRI_CORE, __DRI_CORE_VERSION },
682 driIndexConfigAttrib,
693 /** DRI2 interface */
694 const __DRIdri2Extension driDRI2Extension = {
695 { __DRI_DRI2, __DRI_DRI2_VERSION },
697 dri2CreateNewDrawable,
698 dri2CreateNewContext,
700 dri2CreateNewContextForAPI,
705 const __DRI2configQueryExtension dri2ConfigQueryExtension = {
706 { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION },
713 * Calculate amount of swap interval used between GLX buffer swaps.
715 * The usage value, on the range [0,max], is the fraction of total swap
716 * interval time used between GLX buffer swaps is calculated.
718 * \f$p = t_d / (i * t_r)\f$
720 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
721 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
722 * required for a single vertical refresh period (as returned by \c
725 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
728 * \param dPriv Pointer to the private drawable structure.
729 * \return If less than a single swap interval time period was required
730 * between GLX buffer swaps, a number greater than 0 and less than
731 * 1.0 is returned. If exactly one swap interval time period is
732 * required, 1.0 is returned, and if more than one is required then
733 * a number greater than 1.0 will be returned.
735 * \sa glXSwapIntervalSGI glXGetMscRateOML
737 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
738 * be possible to cache the sync rate?
741 driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust,
742 int64_t current_ust )
748 __DRIscreen *psp = dPriv->driScreenPriv;
750 if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) {
751 interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1;
754 /* We want to calculate
755 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
756 * current_UST by calling __glXGetUST. last_swap_UST is stored in
757 * dPriv->swap_ust. interval has already been calculated.
759 * The only tricky part is us_per_refresh. us_per_refresh is
760 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
761 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
762 * the denominator of the final calculation, we calculate
763 * (interval * 1000000 * d) and move n into the numerator.
766 usage = (current_ust - last_swap_ust);
768 usage /= (interval * d);
776 dri2InvalidateDrawable(__DRIdrawable *drawable)
778 drawable->dri2.stamp++;