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
);
53 /*****************************************************************/
54 /** \name Context (un)binding functions */
55 /*****************************************************************/
61 * \param scrn the screen.
64 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
67 * This function calls __DriverAPIRec::UnbindContext, and then decrements
68 * __DRIdrawableRec::refcount which must be non-zero for a successful
71 * While casting the opaque private pointers associated with the parameters
72 * into their respective real types it also assures they are not \c NULL.
74 static int driUnbindContext(__DRIcontext
*pcp
)
81 ** Assume error checking is done properly in glXMakeCurrent before
82 ** calling driUnbindContext.
88 psp
= pcp
->driScreenPriv
;
89 pdp
= pcp
->driDrawablePriv
;
90 prp
= pcp
->driReadablePriv
;
95 /* Let driver unbind drawable from context */
96 (*psp
->DriverAPI
.UnbindContext
)(pcp
);
99 if (pdp
->refcount
== 0) {
104 dri_put_drawable(pdp
);
107 if (prp
->refcount
== 0) {
112 dri_put_drawable(prp
);
116 /* XXX this is disabled so that if we call SwapBuffers on an unbound
117 * window we can determine the last context bound to the window and
118 * use that context's lock. (BrianP, 2-Dec-2000)
120 pcp
->driDrawablePriv
= pcp
->driReadablePriv
= NULL
;
126 * This function takes both a read buffer and a draw buffer. This is needed
127 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
130 static int driBindContext(__DRIcontext
*pcp
,
134 __DRIscreen
*psp
= NULL
;
137 ** Assume error checking is done properly in glXMakeCurrent before
138 ** calling driUnbindContext.
144 /* Bind the drawable to the context */
145 psp
= pcp
->driScreenPriv
;
146 pcp
->driDrawablePriv
= pdp
;
147 pcp
->driReadablePriv
= prp
;
149 pdp
->driContextPriv
= pcp
;
150 dri_get_drawable(pdp
);
152 if (prp
&& pdp
!= prp
) {
153 dri_get_drawable(prp
);
156 /* Call device-specific MakeCurrent */
157 return (*psp
->DriverAPI
.MakeCurrent
)(pcp
, pdp
, prp
);
160 static __DRIdrawable
*
161 dri2CreateNewDrawable(__DRIscreen
*screen
,
162 const __DRIconfig
*config
,
165 __DRIdrawable
*pdraw
;
167 pdraw
= malloc(sizeof *pdraw
);
171 pdraw
->driContextPriv
= NULL
;
172 pdraw
->loaderPrivate
= loaderPrivate
;
173 pdraw
->hHWDrawable
= 0;
175 pdraw
->pStamp
= NULL
;
176 pdraw
->lastStamp
= 0;
182 pdraw
->numClipRects
= 0;
183 pdraw
->numBackClipRects
= 0;
184 pdraw
->pClipRects
= NULL
;
185 pdraw
->pBackClipRects
= NULL
;
189 pdraw
->driScreenPriv
= screen
;
191 if (!(*screen
->DriverAPI
.CreateBuffer
)(screen
, pdraw
, &config
->modes
, 0)) {
198 /* This special default value is replaced with the configured
199 * default value when the drawable is first bound to a direct
202 pdraw
->swap_interval
= (unsigned)-1;
204 pdraw
->pClipRects
= &pdraw
->dri2
.clipRect
;
205 pdraw
->pBackClipRects
= &pdraw
->dri2
.clipRect
;
207 pdraw
->pStamp
= &pdraw
->dri2
.stamp
;
208 *pdraw
->pStamp
= pdraw
->lastStamp
+ 1;
214 dri2AllocateBuffer(__DRIscreen
*screen
,
215 unsigned int attachment
, unsigned int format
,
216 int width
, int height
)
218 return (*screen
->DriverAPI
.AllocateBuffer
)(screen
, attachment
, format
,
223 dri2ReleaseBuffer(__DRIscreen
*screen
, __DRIbuffer
*buffer
)
225 (*screen
->DriverAPI
.ReleaseBuffer
)(screen
, buffer
);
230 dri2ConfigQueryb(__DRIscreen
*screen
, const char *var
, GLboolean
*val
)
232 if (!driCheckOption(&screen
->optionCache
, var
, DRI_BOOL
))
235 *val
= driQueryOptionb(&screen
->optionCache
, var
);
241 dri2ConfigQueryi(__DRIscreen
*screen
, const char *var
, GLint
*val
)
243 if (!driCheckOption(&screen
->optionCache
, var
, DRI_INT
) &&
244 !driCheckOption(&screen
->optionCache
, var
, DRI_ENUM
))
247 *val
= driQueryOptioni(&screen
->optionCache
, var
);
253 dri2ConfigQueryf(__DRIscreen
*screen
, const char *var
, GLfloat
*val
)
255 if (!driCheckOption(&screen
->optionCache
, var
, DRI_FLOAT
))
258 *val
= driQueryOptionf(&screen
->optionCache
, var
);
264 static void dri_get_drawable(__DRIdrawable
*pdp
)
269 static void dri_put_drawable(__DRIdrawable
*pdp
)
278 psp
= pdp
->driScreenPriv
;
279 (*psp
->DriverAPI
.DestroyBuffer
)(pdp
);
280 if (pdp
->pClipRects
&& pdp
->pClipRects
!= &pdp
->dri2
.clipRect
) {
281 free(pdp
->pClipRects
);
282 pdp
->pClipRects
= NULL
;
284 if (pdp
->pBackClipRects
&& pdp
->pClipRects
!= &pdp
->dri2
.clipRect
) {
285 free(pdp
->pBackClipRects
);
286 pdp
->pBackClipRects
= NULL
;
293 driDestroyDrawable(__DRIdrawable
*pdp
)
295 dri_put_drawable(pdp
);
301 /*****************************************************************/
302 /** \name Context handling functions */
303 /*****************************************************************/
307 * Destroy the per-context private information.
310 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
311 * drmDestroyContext(), and finally frees \p contextPrivate.
314 driDestroyContext(__DRIcontext
*pcp
)
317 (*pcp
->driScreenPriv
->DriverAPI
.DestroyContext
)(pcp
);
323 dri2GetAPIMask(__DRIscreen
*screen
)
325 return screen
->api_mask
;
328 static __DRIcontext
*
329 dri2CreateNewContextForAPI(__DRIscreen
*screen
, int api
,
330 const __DRIconfig
*config
,
331 __DRIcontext
*shared
, void *data
)
333 __DRIcontext
*context
;
334 const struct gl_config
*modes
= (config
!= NULL
) ? &config
->modes
: NULL
;
335 void *shareCtx
= (shared
!= NULL
) ? shared
->driverPrivate
: NULL
;
338 if (!(screen
->api_mask
& (1 << api
)))
342 case __DRI_API_OPENGL
:
343 mesa_api
= API_OPENGL
;
346 mesa_api
= API_OPENGLES
;
348 case __DRI_API_GLES2
:
349 mesa_api
= API_OPENGLES2
;
355 context
= malloc(sizeof *context
);
359 context
->driScreenPriv
= screen
;
360 context
->driDrawablePriv
= NULL
;
361 context
->loaderPrivate
= data
;
363 if (!(*screen
->DriverAPI
.CreateContext
)(mesa_api
, modes
,
364 context
, shareCtx
) ) {
373 static __DRIcontext
*
374 dri2CreateNewContext(__DRIscreen
*screen
, const __DRIconfig
*config
,
375 __DRIcontext
*shared
, void *data
)
377 return dri2CreateNewContextForAPI(screen
, __DRI_API_OPENGL
,
378 config
, shared
, data
);
382 driCopyContext(__DRIcontext
*dest
, __DRIcontext
*src
, unsigned long mask
)
393 /*****************************************************************/
394 /** \name Screen handling functions */
395 /*****************************************************************/
399 * Destroy the per-screen private information.
402 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
403 * drmClose(), and finally frees \p screenPrivate.
405 static void driDestroyScreen(__DRIscreen
*psp
)
408 /* No interaction with the X-server is possible at this point. This
409 * routine is called after XCloseDisplay, so there is no protocol
410 * stream open to the X-server anymore.
413 _mesa_destroy_shader_compiler();
415 if (psp
->DriverAPI
.DestroyScreen
)
416 (*psp
->DriverAPI
.DestroyScreen
)(psp
);
418 if (!psp
->dri2
.enabled
) {
419 (void)drmUnmap((drmAddress
)psp
->pSAREA
, SAREA_MAX
);
420 (void)drmUnmap((drmAddress
)psp
->pFB
, psp
->fbSize
);
421 (void)drmCloseOnce(psp
->fd
);
423 driDestroyOptionCache(&psp
->optionCache
);
424 driDestroyOptionInfo(&psp
->optionInfo
);
432 setupLoaderExtensions(__DRIscreen
*psp
,
433 const __DRIextension
**extensions
)
437 for (i
= 0; extensions
[i
]; i
++) {
438 if (strcmp(extensions
[i
]->name
, __DRI_GET_DRAWABLE_INFO
) == 0)
439 psp
->getDrawableInfo
= (__DRIgetDrawableInfoExtension
*) extensions
[i
];
440 if (strcmp(extensions
[i
]->name
, __DRI_DAMAGE
) == 0)
441 psp
->damage
= (__DRIdamageExtension
*) extensions
[i
];
442 if (strcmp(extensions
[i
]->name
, __DRI_SYSTEM_TIME
) == 0)
443 psp
->systemTime
= (__DRIsystemTimeExtension
*) extensions
[i
];
444 if (strcmp(extensions
[i
]->name
, __DRI_DRI2_LOADER
) == 0)
445 psp
->dri2
.loader
= (__DRIdri2LoaderExtension
*) extensions
[i
];
446 if (strcmp(extensions
[i
]->name
, __DRI_IMAGE_LOOKUP
) == 0)
447 psp
->dri2
.image
= (__DRIimageLookupExtension
*) extensions
[i
];
448 if (strcmp(extensions
[i
]->name
, __DRI_USE_INVALIDATE
) == 0)
449 psp
->dri2
.useInvalidate
= (__DRIuseInvalidateExtension
*) extensions
[i
];
457 dri2CreateNewScreen(int scrn
, int fd
,
458 const __DRIextension
**extensions
,
459 const __DRIconfig
***driver_configs
, void *data
)
461 static const __DRIextension
*emptyExtensionList
[] = { NULL
};
463 drmVersionPtr version
;
465 if (driDriverAPI
.InitScreen2
== NULL
)
468 psp
= calloc(1, sizeof(*psp
));
472 setupLoaderExtensions(psp
, extensions
);
474 version
= drmGetVersion(fd
);
476 psp
->drm_version
.major
= version
->version_major
;
477 psp
->drm_version
.minor
= version
->version_minor
;
478 psp
->drm_version
.patch
= version
->version_patchlevel
;
479 drmFreeVersion(version
);
482 psp
->extensions
= emptyExtensionList
;
485 psp
->dri2
.enabled
= GL_TRUE
;
487 psp
->DriverAPI
= driDriverAPI
;
488 psp
->api_mask
= (1 << __DRI_API_OPENGL
);
489 *driver_configs
= driDriverAPI
.InitScreen2(psp
);
490 if (*driver_configs
== NULL
) {
495 psp
->DriverAPI
= driDriverAPI
;
496 psp
->loaderPrivate
= data
;
498 driParseOptionInfo(&psp
->optionInfo
, __dri2ConfigOptions
,
499 __dri2NConfigOptions
);
500 driParseConfigFiles(&psp
->optionCache
, &psp
->optionInfo
, psp
->myNum
,
506 static const __DRIextension
**driGetExtensions(__DRIscreen
*psp
)
508 return psp
->extensions
;
511 /** Core interface */
512 const __DRIcoreExtension driCoreExtension
= {
513 { __DRI_CORE
, __DRI_CORE_VERSION
},
518 driIndexConfigAttrib
,
529 /** DRI2 interface */
530 const __DRIdri2Extension driDRI2Extension
= {
531 { __DRI_DRI2
, __DRI_DRI2_VERSION
},
533 dri2CreateNewDrawable
,
534 dri2CreateNewContext
,
536 dri2CreateNewContextForAPI
,
541 const __DRI2configQueryExtension dri2ConfigQueryExtension
= {
542 { __DRI2_CONFIG_QUERY
, __DRI2_CONFIG_QUERY_VERSION
},
549 * Calculate amount of swap interval used between GLX buffer swaps.
551 * The usage value, on the range [0,max], is the fraction of total swap
552 * interval time used between GLX buffer swaps is calculated.
554 * \f$p = t_d / (i * t_r)\f$
556 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
557 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
558 * required for a single vertical refresh period (as returned by \c
561 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
564 * \param dPriv Pointer to the private drawable structure.
565 * \return If less than a single swap interval time period was required
566 * between GLX buffer swaps, a number greater than 0 and less than
567 * 1.0 is returned. If exactly one swap interval time period is
568 * required, 1.0 is returned, and if more than one is required then
569 * a number greater than 1.0 will be returned.
571 * \sa glXSwapIntervalSGI glXGetMscRateOML
573 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
574 * be possible to cache the sync rate?
577 driCalculateSwapUsage( __DRIdrawable
*dPriv
, int64_t last_swap_ust
,
578 int64_t current_ust
)
584 __DRIscreen
*psp
= dPriv
->driScreenPriv
;
586 if ( (*psp
->systemTime
->getMSCRate
)(dPriv
, &n
, &d
, dPriv
->loaderPrivate
) ) {
587 interval
= (dPriv
->swap_interval
!= 0) ? dPriv
->swap_interval
: 1;
590 /* We want to calculate
591 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
592 * current_UST by calling __glXGetUST. last_swap_UST is stored in
593 * dPriv->swap_ust. interval has already been calculated.
595 * The only tricky part is us_per_refresh. us_per_refresh is
596 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
597 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
598 * the denominator of the final calculation, we calculate
599 * (interval * 1000000 * d) and move n into the numerator.
602 usage
= (current_ust
- last_swap_ust
);
604 usage
/= (interval
* d
);
612 dri2InvalidateDrawable(__DRIdrawable
*drawable
)
614 drawable
->dri2
.stamp
++;