dri_util.c revision fd4f7064e24654c89248be6d76f39c7baf22fce4
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */ 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * \file dri_util.c 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DRI utility functions. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This module acts as glue between GLX and the actual hardware driver. A DRI 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * driver doesn't really \e have to use any of this - it's optional. But, some 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * useful stuff is done here that otherwise would have to be duplicated in most 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * drivers. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Basically, these utility functions take care of some of the dirty details of 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * screen initialization, context creation, context binding, DRM setup, etc. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * These functions are compiled into each DRI driver so libGL.so knows nothing 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * about them. 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * \note 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * When \c DRI_NEW_INTERFACE_ONLY is defined, code is built / not built so 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * that only the "new" libGL-to-driver interfaces are supported. This breaks 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * backwards compatability. However, this may be necessary when DRI drivers 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * are built to be used in non-XFree86 environments. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * \todo There are still some places in the code that need to be wrapped with 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * \c DRI_NEW_INTERFACE_ONLY. 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdarg.h> 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/mman.h> 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef MAP_FAILED 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAP_FAILED ((void *)-1) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef DRI_NEW_INTERFACE_ONLY 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# include <X11/Xlibint.h> 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# include <Xext.h> 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# include <extutil.h> 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# include "xf86dri.h" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define _mesa_malloc(b) Xmalloc(b) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define _mesa_free(m) Xfree(m) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# include "imports.h" 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define None 0 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* DRI_NEW_INTERFACE_ONLY */ 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dri_util.h" 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "drm_sarea.h" 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "glcontextmodes.h" 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef GLX_OML_sync_control 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRInativeDisplay *dpy, __DRIid drawable, int32_t *numerator, int32_t *denominator); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Weak thread-safety dispatch pointer. Older versions of libGL will not have 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this symbol, so a "weak" version is included here so that the driver will 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * dynamically link properly. The value is set to \c NULL. This forces the 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * driver to fall back to the old dispatch interface. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct _glapi_table *_glapi_DispatchTSD __attribute__((weak)) = NULL; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is used in a couple of places that call \c driCreateNewDrawable. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int empty_attribute_list[1] = { None }; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Function used to determine if a drawable (window) still exists. Ideally 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this function comes from libGL. With older versions of libGL from XFree86 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * we can fall-back to an internal version. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * \sa __driWindowExists __glXWindowExists 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PFNGLXWINDOWEXISTSPROC window_exists; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef GLboolean (*PFNGLXCREATECONTEXTWITHCONFIGPROC)( __DRInativeDisplay*, int, int, void *, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) drm_context_t * ); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static PFNGLXCREATECONTEXTWITHCONFIGPROC create_context_with_config; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Cached copy of the internal API version used by libGL and the client-side 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DRI driver. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int api_ver = 0; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* forward declarations */ 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int driQueryFrameTracking( __DRInativeDisplay * dpy, void * priv, 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64_t * sbc, int64_t * missedFrames, float * lastMissedUsage, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float * usage ); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *driCreateNewDrawable(__DRInativeDisplay *dpy, const __GLcontextModes *modes, 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __DRIid draw, __DRIdrawable *pdraw, int renderType, const int *attrs); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void driDestroyDrawable(__DRInativeDisplay *dpy, void *drawablePrivate); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef not_defined 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static GLboolean driFeatureOn(const char *name) 106{ 107 char *env = getenv(name); 108 109 if (!env) return GL_FALSE; 110 if (!strcasecmp(env, "enable")) return GL_TRUE; 111 if (!strcasecmp(env, "1")) return GL_TRUE; 112 if (!strcasecmp(env, "on")) return GL_TRUE; 113 if (!strcasecmp(env, "true")) return GL_TRUE; 114 if (!strcasecmp(env, "t")) return GL_TRUE; 115 if (!strcasecmp(env, "yes")) return GL_TRUE; 116 if (!strcasecmp(env, "y")) return GL_TRUE; 117 118 return GL_FALSE; 119} 120#endif /* not_defined */ 121 122 123/** 124 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable 125 * is set. 126 * 127 * Is called from the drivers. 128 * 129 * \param f \c printf like format string. 130 */ 131void 132__driUtilMessage(const char *f, ...) 133{ 134 va_list args; 135 136 if (getenv("LIBGL_DEBUG")) { 137 fprintf(stderr, "libGL error: \n"); 138 va_start(args, f); 139 vfprintf(stderr, f, args); 140 va_end(args); 141 fprintf(stderr, "\n"); 142 } 143} 144 145/* 146 * fd.o bug #1713: Some rare libGL's have __glXFindDRIScreen defined but do not 147 * export it via glXGetProcAddress. These are not supported anymore, so print 148 * an error message to that effect. - ajax 2004-10-26 149 */ 150typedef __DRIscreen *(*PFNGLXFINDDRISCREEN)(__DRInativeDisplay *, int); 151 152static __DRIscreen *glx_find_dri_screen(__DRInativeDisplay *d, int i) 153{ 154 PFNGLXFINDDRISCREEN findscreen = 155 (PFNGLXFINDDRISCREEN)glXGetProcAddress("__glXFindDRIScreen"); 156 157 if (!findscreen) 158 { 159 __driUtilMessage("glXGetProcAddress(\"__glXFindDRIScreen\") failed!"); 160 __driUtilMessage("Your libGL is too old, please upgrade."); 161 return NULL; 162 } 163 else return findscreen(d, i); 164} 165 166/*****************************************************************/ 167/** \name Visual utility functions */ 168/*****************************************************************/ 169/*@{*/ 170 171#ifndef DRI_NEW_INTERFACE_ONLY 172/** 173 * Find a \c __GLcontextModes structure matching the given visual ID. 174 * 175 * \param dpy Display to search for a matching configuration. 176 * \param scrn Screen number on \c dpy to be searched. 177 * \param vid Desired \c VisualID to find. 178 * 179 * \returns A pointer to a \c __GLcontextModes structure that matches \c vid, 180 * if found, or \c NULL if no match is found. 181 */ 182static const __GLcontextModes * 183findConfigMode(__DRInativeDisplay *dpy, int scrn, VisualID vid, 184 const __DRIscreen * pDRIScreen) 185{ 186 if ( (pDRIScreen != NULL) && (pDRIScreen->private != NULL) ) { 187 const __DRIscreenPrivate * const psp = 188 (const __DRIscreenPrivate *) pDRIScreen->private; 189 190 return _gl_context_modes_find_visual( psp->modes, vid ); 191 } 192 193 return NULL; 194} 195 196 197/** 198 * This function is a hack to work-around old versions of libGL.so that 199 * do not export \c XF86DRICreateContextWithConfig. I would modify the 200 * code to just use this function, but the stand-alone driver (i.e., DRI 201 * drivers that are built to work without XFree86) shouldn't have to know 202 * about X structures like a \c Visual. 203 */ 204static GLboolean 205fake_XF86DRICreateContextWithConfig( __DRInativeDisplay* dpy, int screen, int configID, 206 XID* context, drm_context_t * hHWContext ) 207{ 208 Visual vis; 209 210 vis.visualid = configID; 211 return XF86DRICreateContext( dpy, screen, & vis, context, hHWContext ); 212} 213#endif /* DRI_NEW_INTERFACE_ONLY */ 214 215/*@}*/ 216 217 218/*****************************************************************/ 219/** \name Drawable list management */ 220/*****************************************************************/ 221/*@{*/ 222 223static GLboolean __driAddDrawable(void *drawHash, __DRIdrawable *pdraw) 224{ 225 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private; 226 227 if (drmHashInsert(drawHash, pdp->draw, pdraw)) 228 return GL_FALSE; 229 230 return GL_TRUE; 231} 232 233static __DRIdrawable *__driFindDrawable(void *drawHash, __DRIid draw) 234{ 235 int retcode; 236 __DRIdrawable *pdraw; 237 238 retcode = drmHashLookup(drawHash, draw, (void *)&pdraw); 239 if (retcode) 240 return NULL; 241 242 return pdraw; 243} 244 245#ifndef DRI_NEW_INTERFACE_ONLY 246static GLboolean __driWindowExistsFlag; 247 248static int __driWindowExistsErrorHandler(Display *dpy, XErrorEvent *xerr) 249{ 250 if (xerr->error_code == BadWindow) { 251 __driWindowExistsFlag = GL_FALSE; 252 } 253 return 0; 254} 255 256/** 257 * Determine if a window associated with a \c GLXDrawable exists on the 258 * X-server. 259 * 260 * \param dpy Display associated with the drawable to be queried. 261 * \param draw \c GLXDrawable to test. 262 * 263 * \returns \c GL_TRUE if a window exists that is associated with \c draw, 264 * otherwise \c GL_FALSE is returned. 265 * 266 * \warning This function is not currently thread-safe. 267 * 268 * \deprecated 269 * \c __glXWindowExists (from libGL) is prefered over this function. Starting 270 * with the next major release of XFree86, this function will be removed. 271 * Even now this function is no longer directly called. Instead it is called 272 * via a function pointer if and only if \c __glXWindowExists does not exist. 273 * 274 * \sa __glXWindowExists glXGetProcAddress window_exists 275 */ 276static GLboolean __driWindowExists(Display *dpy, GLXDrawable draw) 277{ 278 XWindowAttributes xwa; 279 int (*oldXErrorHandler)(Display *, XErrorEvent *); 280 281 XSync(dpy, GL_FALSE); 282 __driWindowExistsFlag = GL_TRUE; 283 oldXErrorHandler = XSetErrorHandler(__driWindowExistsErrorHandler); 284 XGetWindowAttributes(dpy, draw, &xwa); /* dummy request */ 285 XSetErrorHandler(oldXErrorHandler); 286 return __driWindowExistsFlag; 287} 288#endif /* DRI_NEW_INTERFACE_ONLY */ 289 290/** 291 * Find drawables in the local hash that have been destroyed on the 292 * server. 293 * 294 * \param drawHash Hash-table containing all know drawables. 295 */ 296static void __driGarbageCollectDrawables(void *drawHash) 297{ 298 __DRIid draw; 299 __DRInativeDisplay *dpy; 300 __DRIdrawable *pdraw; 301 302 if (drmHashFirst(drawHash, &draw, (void *)&pdraw) == 1) { 303 do { 304 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)pdraw->private; 305 dpy = pdp->driScreenPriv->display; 306 if (! (*window_exists)(dpy, draw)) { 307 /* Destroy the local drawable data in the hash table, if the 308 drawable no longer exists in the Xserver */ 309 drmHashDelete(drawHash, draw); 310 (*pdraw->destroyDrawable)(dpy, pdraw->private); 311 _mesa_free(pdraw); 312 } 313 } while (drmHashNext(drawHash, &draw, (void *)&pdraw) == 1); 314 } 315} 316 317/*@}*/ 318 319 320/*****************************************************************/ 321/** \name Context (un)binding functions */ 322/*****************************************************************/ 323/*@{*/ 324 325/** 326 * Unbind context. 327 * 328 * \param dpy the display handle. 329 * \param scrn the screen number. 330 * \param draw drawable. 331 * \param read Current reading drawable. 332 * \param gc context. 333 * 334 * \return \c GL_TRUE on success, or \c GL_FALSE on failure. 335 * 336 * \internal 337 * This function calls __DriverAPIRec::UnbindContext, and then decrements 338 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful 339 * return. 340 * 341 * While casting the opaque private pointers associated with the parameters 342 * into their respective real types it also assures they are not \c NULL. 343 */ 344static GLboolean driUnbindContext3(__DRInativeDisplay *dpy, int scrn, 345 __DRIid draw, __DRIid read, 346 __DRIcontext *ctx) 347{ 348 __DRIscreen *pDRIScreen; 349 __DRIdrawable *pdraw; 350 __DRIdrawable *pread; 351 __DRIcontextPrivate *pcp; 352 __DRIscreenPrivate *psp; 353 __DRIdrawablePrivate *pdp; 354 __DRIdrawablePrivate *prp; 355 356 /* 357 ** Assume error checking is done properly in glXMakeCurrent before 358 ** calling driUnbindContext3. 359 */ 360 361 if (ctx == NULL || draw == None || read == None) { 362 /* ERROR!!! */ 363 return GL_FALSE; 364 } 365 366 pDRIScreen = glx_find_dri_screen(dpy, scrn); 367 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 368 /* ERROR!!! */ 369 return GL_FALSE; 370 } 371 372 psp = (__DRIscreenPrivate *)pDRIScreen->private; 373 pcp = (__DRIcontextPrivate *)ctx->private; 374 375 pdraw = __driFindDrawable(psp->drawHash, draw); 376 if (!pdraw) { 377 /* ERROR!!! */ 378 return GL_FALSE; 379 } 380 pdp = (__DRIdrawablePrivate *)pdraw->private; 381 382 pread = __driFindDrawable(psp->drawHash, read); 383 if (!pread) { 384 /* ERROR!!! */ 385 return GL_FALSE; 386 } 387 prp = (__DRIdrawablePrivate *)pread->private; 388 389 390 /* Let driver unbind drawable from context */ 391 (*psp->DriverAPI.UnbindContext)(pcp); 392 393 394 if (pdp->refcount == 0) { 395 /* ERROR!!! */ 396 return GL_FALSE; 397 } 398 399 pdp->refcount--; 400 401 if (prp != pdp) { 402 if (prp->refcount == 0) { 403 /* ERROR!!! */ 404 return GL_FALSE; 405 } 406 407 prp->refcount--; 408 } 409 410 411 /* XXX this is disabled so that if we call SwapBuffers on an unbound 412 * window we can determine the last context bound to the window and 413 * use that context's lock. (BrianP, 2-Dec-2000) 414 */ 415#if 0 416 /* Unbind the drawable */ 417 pcp->driDrawablePriv = NULL; 418 pdp->driContextPriv = &psp->dummyContextPriv; 419#endif 420 421 return GL_TRUE; 422} 423 424 425/** 426 * This function takes both a read buffer and a draw buffer. This is needed 427 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 428 * function. 429 * 430 * \bug This function calls \c driCreateNewDrawable in two places with the 431 * \c renderType hard-coded to \c GLX_WINDOW_BIT. Some checking might 432 * be needed in those places when support for pbuffers and / or pixmaps 433 * is added. Is it safe to assume that the drawable is a window? 434 */ 435static GLboolean DoBindContext(__DRInativeDisplay *dpy, 436 __DRIid draw, __DRIid read, 437 __DRIcontext *ctx, const __GLcontextModes * modes, 438 __DRIscreenPrivate *psp) 439{ 440 __DRIdrawable *pdraw; 441 __DRIdrawablePrivate *pdp; 442 __DRIdrawable *pread; 443 __DRIdrawablePrivate *prp; 444 __DRIcontextPrivate * const pcp = ctx->private; 445 446 447 /* Find the _DRIdrawable which corresponds to the writing drawable. */ 448 pdraw = __driFindDrawable(psp->drawHash, draw); 449 if (!pdraw) { 450 /* Allocate a new drawable */ 451 pdraw = (__DRIdrawable *)_mesa_malloc(sizeof(__DRIdrawable)); 452 if (!pdraw) { 453 /* ERROR!!! */ 454 return GL_FALSE; 455 } 456 457 /* Create a new drawable */ 458 driCreateNewDrawable(dpy, modes, draw, pdraw, GLX_WINDOW_BIT, 459 empty_attribute_list); 460 if (!pdraw->private) { 461 /* ERROR!!! */ 462 _mesa_free(pdraw); 463 return GL_FALSE; 464 } 465 466 } 467 pdp = (__DRIdrawablePrivate *) pdraw->private; 468 469 /* Find the _DRIdrawable which corresponds to the reading drawable. */ 470 if (read == draw) { 471 /* read buffer == draw buffer */ 472 prp = pdp; 473 } 474 else { 475 pread = __driFindDrawable(psp->drawHash, read); 476 if (!pread) { 477 /* Allocate a new drawable */ 478 pread = (__DRIdrawable *)_mesa_malloc(sizeof(__DRIdrawable)); 479 if (!pread) { 480 /* ERROR!!! */ 481 return GL_FALSE; 482 } 483 484 /* Create a new drawable */ 485 driCreateNewDrawable(dpy, modes, read, pread, GLX_WINDOW_BIT, 486 empty_attribute_list); 487 if (!pread->private) { 488 /* ERROR!!! */ 489 _mesa_free(pread); 490 return GL_FALSE; 491 } 492 } 493 prp = (__DRIdrawablePrivate *) pread->private; 494 } 495 496 /* Bind the drawable to the context */ 497 pcp->driDrawablePriv = pdp; 498 pdp->driContextPriv = pcp; 499 pdp->refcount++; 500 if ( pdp != prp ) { 501 prp->refcount++; 502 } 503 504 /* 505 ** Now that we have a context associated with this drawable, we can 506 ** initialize the drawable information if has not been done before. 507 */ 508 if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) { 509 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 510 __driUtilUpdateDrawableInfo(pdp); 511 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 512 } 513 514 /* Call device-specific MakeCurrent */ 515 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); 516 517 return GL_TRUE; 518} 519 520 521/** 522 * This function takes both a read buffer and a draw buffer. This is needed 523 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 524 * function. 525 */ 526static GLboolean driBindContext3(__DRInativeDisplay *dpy, int scrn, 527 __DRIid draw, __DRIid read, 528 __DRIcontext * ctx) 529{ 530 __DRIscreen *pDRIScreen; 531 532 /* 533 ** Assume error checking is done properly in glXMakeCurrent before 534 ** calling driBindContext. 535 */ 536 537 if (ctx == NULL || draw == None || read == None) { 538 /* ERROR!!! */ 539 return GL_FALSE; 540 } 541 542 pDRIScreen = glx_find_dri_screen(dpy, scrn); 543 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 544 /* ERROR!!! */ 545 return GL_FALSE; 546 } 547 548 return DoBindContext( dpy, draw, read, ctx, ctx->mode, 549 (__DRIscreenPrivate *)pDRIScreen->private ); 550} 551 552 553#ifndef DRI_NEW_INTERFACE_ONLY 554/** 555 * This function takes both a read buffer and a draw buffer. This is needed 556 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 557 * function. 558 */ 559static GLboolean driBindContext2(Display *dpy, int scrn, 560 GLXDrawable draw, GLXDrawable read, 561 GLXContext gc) 562{ 563 __DRIscreen *pDRIScreen; 564 const __GLcontextModes *modes; 565 566 /* 567 ** Assume error checking is done properly in glXMakeCurrent before 568 ** calling driBindContext. 569 */ 570 571 if (gc == NULL || draw == None || read == None) { 572 /* ERROR!!! */ 573 return GL_FALSE; 574 } 575 576 pDRIScreen = glx_find_dri_screen(dpy, scrn); 577 modes = (driCompareGLXAPIVersion( 20040317 ) >= 0) 578 ? gc->driContext.mode 579 : findConfigMode( dpy, scrn, gc->vid, pDRIScreen ); 580 581 if ( modes == NULL ) { 582 /* ERROR!!! */ 583 return GL_FALSE; 584 } 585 586 /* findConfigMode will return NULL if the DRI screen or screen private 587 * are NULL. 588 */ 589 assert( (pDRIScreen != NULL) && (pDRIScreen->private != NULL) ); 590 591 return DoBindContext( dpy, draw, read, & gc->driContext, modes, 592 (__DRIscreenPrivate *)pDRIScreen->private ); 593} 594 595static GLboolean driUnbindContext2(Display *dpy, int scrn, 596 GLXDrawable draw, GLXDrawable read, 597 GLXContext gc) 598{ 599 return driUnbindContext3(dpy, scrn, draw, read, & gc->driContext); 600} 601 602/* 603 * Simply call bind with the same GLXDrawable for the read and draw buffers. 604 */ 605static GLboolean driBindContext(Display *dpy, int scrn, 606 GLXDrawable draw, GLXContext gc) 607{ 608 return driBindContext2(dpy, scrn, draw, draw, gc); 609} 610 611 612/* 613 * Simply call bind with the same GLXDrawable for the read and draw buffers. 614 */ 615static GLboolean driUnbindContext(Display *dpy, int scrn, 616 GLXDrawable draw, GLXContext gc, 617 int will_rebind) 618{ 619 (void) will_rebind; 620 return driUnbindContext2( dpy, scrn, draw, draw, gc ); 621} 622#endif /* DRI_NEW_INTERFACE_ONLY */ 623 624/*@}*/ 625 626 627/*****************************************************************/ 628/** \name Drawable handling functions */ 629/*****************************************************************/ 630/*@{*/ 631 632/** 633 * Update private drawable information. 634 * 635 * \param pdp pointer to the private drawable information to update. 636 * 637 * This function basically updates the __DRIdrawablePrivate struct's 638 * cliprect information by calling \c __DRIDrawablePrivate::getInfo. This is 639 * usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which 640 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If 641 * the values are different that means we have to update the clipping 642 * info. 643 */ 644void 645__driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp) 646{ 647 __DRIscreenPrivate *psp; 648 __DRIcontextPrivate *pcp = pdp->driContextPriv; 649 650 if (!pcp || (pdp != pcp->driDrawablePriv)) { 651 /* ERROR!!! */ 652 return; 653 } 654 655 psp = pdp->driScreenPriv; 656 if (!psp) { 657 /* ERROR!!! */ 658 return; 659 } 660 661 if (pdp->pClipRects) { 662 _mesa_free(pdp->pClipRects); 663 } 664 665 if (pdp->pBackClipRects) { 666 _mesa_free(pdp->pBackClipRects); 667 } 668 669 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 670 671 if (!__driFindDrawable(psp->drawHash, pdp->draw) || 672 ! (*pdp->getInfo)(pdp->display, pdp->screen, pdp->draw, 673 &pdp->index, &pdp->lastStamp, 674 &pdp->x, &pdp->y, &pdp->w, &pdp->h, 675 &pdp->numClipRects, &pdp->pClipRects, 676 &pdp->backX, 677 &pdp->backY, 678 &pdp->numBackClipRects, 679 &pdp->pBackClipRects )) { 680 /* Error -- eg the window may have been destroyed. Keep going 681 * with no cliprects. 682 */ 683 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */ 684 pdp->numClipRects = 0; 685 pdp->pClipRects = NULL; 686 pdp->numBackClipRects = 0; 687 pdp->pBackClipRects = NULL; 688 } 689 else 690 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp); 691 692 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 693 694} 695 696/*@}*/ 697 698/*****************************************************************/ 699/** \name GLX callbacks */ 700/*****************************************************************/ 701/*@{*/ 702 703/** 704 * Swap buffers. 705 * 706 * \param dpy the display handle. 707 * \param drawablePrivate opaque pointer to the per-drawable private info. 708 * 709 * \internal 710 * This function calls __DRIdrawablePrivate::swapBuffers. 711 * 712 * Is called directly from glXSwapBuffers(). 713 */ 714static void driSwapBuffers( __DRInativeDisplay *dpy, void *drawablePrivate ) 715{ 716 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate; 717 dPriv->swapBuffers(dPriv); 718 (void) dpy; 719} 720 721/** 722 * Called directly from a number of higher-level GLX functions. 723 */ 724static int driGetMSC( void *screenPrivate, int64_t *msc ) 725{ 726 __DRIscreenPrivate *sPriv = (__DRIscreenPrivate *) screenPrivate; 727 728 return sPriv->DriverAPI.GetMSC( sPriv, msc ); 729} 730 731/** 732 * Called directly from a number of higher-level GLX functions. 733 */ 734static int driGetSBC( __DRInativeDisplay *dpy, void *drawablePrivate, int64_t *sbc ) 735{ 736 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePrivate; 737 __DRIswapInfo sInfo; 738 int status; 739 740 741 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); 742 *sbc = sInfo.swap_count; 743 744 return status; 745} 746 747static int driWaitForSBC( __DRInativeDisplay * dpy, void *drawablePriv, 748 int64_t target_sbc, 749 int64_t * msc, int64_t * sbc ) 750{ 751 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 752 753 return dPriv->driScreenPriv->DriverAPI.WaitForSBC( dPriv, target_sbc, 754 msc, sbc ); 755} 756 757static int driWaitForMSC( __DRInativeDisplay * dpy, void *drawablePriv, 758 int64_t target_msc, 759 int64_t divisor, int64_t remainder, 760 int64_t * msc, int64_t * sbc ) 761{ 762 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 763 __DRIswapInfo sInfo; 764 int status; 765 766 767 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc, 768 divisor, remainder, 769 msc ); 770 771 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync 772 * is supported but GLX_OML_sync_control is not. Therefore, don't return 773 * an error value if GetSwapInfo() is not implemented. 774 */ 775 if ( status == 0 776 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) { 777 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); 778 *sbc = sInfo.swap_count; 779 } 780 781 return status; 782} 783 784static int64_t driSwapBuffersMSC( __DRInativeDisplay * dpy, void *drawablePriv, 785 int64_t target_msc, 786 int64_t divisor, int64_t remainder ) 787{ 788 __DRIdrawablePrivate *dPriv = (__DRIdrawablePrivate *) drawablePriv; 789 790 return dPriv->driScreenPriv->DriverAPI.SwapBuffersMSC( dPriv, target_msc, 791 divisor, 792 remainder ); 793} 794 795 796/** 797 * This is called via __DRIscreenRec's createNewDrawable pointer. 798 */ 799static void *driCreateNewDrawable(__DRInativeDisplay *dpy, 800 const __GLcontextModes *modes, 801 __DRIid draw, 802 __DRIdrawable *pdraw, 803 int renderType, 804 const int *attrs) 805{ 806 __DRIscreen * const pDRIScreen = glx_find_dri_screen(dpy, modes->screen); 807 __DRIscreenPrivate *psp; 808 __DRIdrawablePrivate *pdp; 809 810 811 pdraw->private = NULL; 812 813 /* Since pbuffers are not yet supported, no drawable attributes are 814 * supported either. 815 */ 816 (void) attrs; 817 818 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 819 return NULL; 820 } 821 822 pdp = (__DRIdrawablePrivate *)_mesa_malloc(sizeof(__DRIdrawablePrivate)); 823 if (!pdp) { 824 return NULL; 825 } 826 827 if (!XF86DRICreateDrawable(dpy, modes->screen, draw, &pdp->hHWDrawable)) { 828 _mesa_free(pdp); 829 return NULL; 830 } 831 832 pdp->draw = draw; 833 pdp->pdraw = pdraw; 834 pdp->refcount = 0; 835 pdp->pStamp = NULL; 836 pdp->lastStamp = 0; 837 pdp->index = 0; 838 pdp->x = 0; 839 pdp->y = 0; 840 pdp->w = 0; 841 pdp->h = 0; 842 pdp->numClipRects = 0; 843 pdp->numBackClipRects = 0; 844 pdp->pClipRects = NULL; 845 pdp->pBackClipRects = NULL; 846 pdp->display = dpy; 847 pdp->screen = modes->screen; 848 849 psp = (__DRIscreenPrivate *)pDRIScreen->private; 850 pdp->driScreenPriv = psp; 851 pdp->driContextPriv = &psp->dummyContextPriv; 852 853 pdp->getInfo = (PFNGLXGETDRAWABLEINFOPROC) 854 glXGetProcAddress( (const GLubyte *) "__glXGetDrawableInfo" ); 855 if ( pdp->getInfo == NULL ) { 856#ifdef DRI_NEW_INTERFACE_ONLY 857 (void)XF86DRIDestroyDrawable(dpy, modes->screen, pdp->draw); 858 _mesa_free(pdp); 859 return NULL; 860#else 861 pdp->getInfo = (PFNGLXGETDRAWABLEINFOPROC) XF86DRIGetDrawableInfo; 862#endif /* DRI_NEW_INTERFACE_ONLY */ 863 } 864 865 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, modes, 866 renderType == GLX_PIXMAP_BIT)) { 867 (void)XF86DRIDestroyDrawable(dpy, modes->screen, pdp->draw); 868 _mesa_free(pdp); 869 return NULL; 870 } 871 872 pdraw->private = pdp; 873 pdraw->destroyDrawable = driDestroyDrawable; 874 pdraw->swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */ 875 876 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) { 877 pdraw->getSBC = driGetSBC; 878 pdraw->waitForSBC = driWaitForSBC; 879 pdraw->waitForMSC = driWaitForMSC; 880 pdraw->swapBuffersMSC = driSwapBuffersMSC; 881 pdraw->frameTracking = NULL; 882 pdraw->queryFrameTracking = driQueryFrameTracking; 883 884 /* This special default value is replaced with the configured 885 * default value when the drawable is first bound to a direct 886 * rendering context. */ 887 pdraw->swap_interval = (unsigned)-1; 888 } 889 890 pdp->swapBuffers = psp->DriverAPI.SwapBuffers; 891 892 /* Add pdraw to drawable list */ 893 if (!__driAddDrawable(psp->drawHash, pdraw)) { 894 /* ERROR!!! */ 895 (*pdraw->destroyDrawable)(dpy, pdp); 896 _mesa_free(pdp); 897 pdp = NULL; 898 pdraw->private = NULL; 899 } 900 901 return (void *) pdp; 902} 903 904static __DRIdrawable *driGetDrawable(__DRInativeDisplay *dpy, __DRIid draw, 905 void *screenPrivate) 906{ 907 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate; 908 909 /* 910 ** Make sure this routine returns NULL if the drawable is not bound 911 ** to a direct rendering context! 912 */ 913 return __driFindDrawable(psp->drawHash, draw); 914} 915 916static void driDestroyDrawable(__DRInativeDisplay *dpy, void *drawablePrivate) 917{ 918 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *) drawablePrivate; 919 __DRIscreenPrivate *psp = pdp->driScreenPriv; 920 int scrn = psp->myNum; 921 922 if (pdp) { 923 (*psp->DriverAPI.DestroyBuffer)(pdp); 924 if ((*window_exists)(dpy, pdp->draw)) 925 (void)XF86DRIDestroyDrawable(dpy, scrn, pdp->draw); 926 if (pdp->pClipRects) { 927 _mesa_free(pdp->pClipRects); 928 pdp->pClipRects = NULL; 929 } 930 if (pdp->pBackClipRects) { 931 _mesa_free(pdp->pBackClipRects); 932 pdp->pBackClipRects = NULL; 933 } 934 _mesa_free(pdp); 935 } 936} 937 938/*@}*/ 939 940 941/*****************************************************************/ 942/** \name Context handling functions */ 943/*****************************************************************/ 944/*@{*/ 945 946/** 947 * Destroy the per-context private information. 948 * 949 * \param dpy the display handle. 950 * \param scrn the screen number. 951 * \param contextPrivate opaque pointer to the per-drawable private info. 952 * 953 * \internal 954 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls 955 * drmDestroyContext(), and finally frees \p contextPrivate. 956 */ 957static void driDestroyContext(__DRInativeDisplay *dpy, int scrn, void *contextPrivate) 958{ 959 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *) contextPrivate; 960 961 if (pcp) { 962 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); 963 __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash); 964 (void)XF86DRIDestroyContext(dpy, scrn, pcp->contextID); 965 _mesa_free(pcp); 966 } 967} 968 969 970/** 971 * Create the per-drawable private driver information. 972 * 973 * \param dpy The display handle. 974 * \param modes Mode used to create the new context. 975 * \param render_type Type of rendering target. \c GLX_RGBA is the only 976 * type likely to ever be supported for direct-rendering. 977 * \param sharedPrivate The shared context dependent methods or \c NULL if 978 * non-existent. 979 * \param pctx DRI context to receive the context dependent methods. 980 * 981 * \returns An opaque pointer to the per-context private information on 982 * success, or \c NULL on failure. 983 * 984 * \internal 985 * This function allocates and fills a __DRIcontextPrivateRec structure. It 986 * performs some device independent initialization and passes all the 987 * relevent information to __DriverAPIRec::CreateContext to create the 988 * context. 989 * 990 */ 991static void * 992driCreateNewContext(__DRInativeDisplay *dpy, const __GLcontextModes *modes, 993 int render_type, void *sharedPrivate, __DRIcontext *pctx) 994{ 995 __DRIscreen *pDRIScreen; 996 __DRIcontextPrivate *pcp; 997 __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate; 998 __DRIscreenPrivate *psp; 999 void * const shareCtx = (pshare != NULL) ? pshare->driverPrivate : NULL; 1000 1001 pDRIScreen = glx_find_dri_screen(dpy, modes->screen); 1002 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 1003 /* ERROR!!! */ 1004 return NULL; 1005 } 1006 1007 psp = (__DRIscreenPrivate *)pDRIScreen->private; 1008 1009 pcp = (__DRIcontextPrivate *)_mesa_malloc(sizeof(__DRIcontextPrivate)); 1010 if (!pcp) { 1011 return NULL; 1012 } 1013 1014 if (! (*create_context_with_config)(dpy, modes->screen, modes->fbconfigID, 1015 &pcp->contextID, &pcp->hHWContext)) { 1016 _mesa_free(pcp); 1017 return NULL; 1018 } 1019 1020 pcp->display = dpy; 1021 pcp->driScreenPriv = psp; 1022 pcp->driDrawablePriv = NULL; 1023 1024 /* When the first context is created for a screen, initialize a "dummy" 1025 * context. 1026 */ 1027 1028 if (!psp->dummyContextPriv.driScreenPriv) { 1029 psp->dummyContextPriv.contextID = 0; 1030 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context; 1031 psp->dummyContextPriv.driScreenPriv = psp; 1032 psp->dummyContextPriv.driDrawablePriv = NULL; 1033 psp->dummyContextPriv.driverPrivate = NULL; 1034 /* No other fields should be used! */ 1035 } 1036 1037 pctx->destroyContext = driDestroyContext; 1038#ifdef DRI_NEW_INTERFACE_ONLY 1039 pctx->bindContext = NULL; 1040 pctx->unbindContext = NULL; 1041 pctx->bindContext2 = NULL; 1042 pctx->unbindContext2 = NULL; 1043 pctx->bindContext3 = driBindContext3; 1044 pctx->unbindContext3 = driUnbindContext3; 1045#else 1046 pctx->bindContext = (void *)driBindContext; 1047 pctx->unbindContext = (void *)driUnbindContext; 1048 if ( driCompareGLXAPIVersion( 20030606 ) >= 0 ) { 1049 pctx->bindContext2 = (void *)driBindContext2; 1050 pctx->unbindContext2 = (void *)driUnbindContext2; 1051 } 1052 1053 if ( driCompareGLXAPIVersion( 20040415 ) >= 0 ) { 1054 pctx->bindContext3 = (void *)driBindContext3; 1055 pctx->unbindContext3 = (void *)driUnbindContext3; 1056 } 1057#endif 1058 1059 if ( !(*psp->DriverAPI.CreateContext)(modes, pcp, shareCtx) ) { 1060 (void)XF86DRIDestroyContext(dpy, modes->screen, pcp->contextID); 1061 _mesa_free(pcp); 1062 return NULL; 1063 } 1064 1065 __driGarbageCollectDrawables(pcp->driScreenPriv->drawHash); 1066 1067 return pcp; 1068} 1069 1070 1071#ifndef DRI_NEW_INTERFACE_ONLY 1072/** 1073 * Create the per-drawable private driver information. 1074 * 1075 * \param dpy the display handle. 1076 * \param vis the visual information. 1077 * \param sharedPrivate the shared context dependent methods or \c NULL if 1078 * non-existent. 1079 * \param pctx will receive the context dependent methods. 1080 * 1081 * \returns a opaque pointer to the per-context private information on success, or \c NULL 1082 * on failure. 1083 * 1084 * \deprecated 1085 * This function has been replaced by \c driCreateNewContext. In drivers 1086 * built to work with XFree86, this function will continue to exist to support 1087 * older versions of libGL. Starting with the next major relelase of XFree86, 1088 * this function will be removed. 1089 * 1090 * \internal 1091 * This function allocates and fills a __DRIcontextPrivateRec structure. It 1092 * gets the visual, converts it into a __GLcontextModesRec and passes it 1093 * to __DriverAPIRec::CreateContext to create the context. 1094 */ 1095static void *driCreateContext(Display *dpy, XVisualInfo *vis, 1096 void *sharedPrivate, __DRIcontext *pctx) 1097{ 1098 __DRIscreen *pDRIScreen; 1099 const __GLcontextModes *modes; 1100 1101 pDRIScreen = glx_find_dri_screen(dpy, vis->screen); 1102 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) { 1103 /* ERROR!!! */ 1104 return NULL; 1105 } 1106 1107 1108 /* Setup a __GLcontextModes struct corresponding to vis->visualid 1109 * and create the rendering context. 1110 */ 1111 1112 modes = findConfigMode(dpy, vis->screen, vis->visualid, pDRIScreen); 1113 return (modes == NULL) 1114 ? NULL 1115 : driCreateNewContext( dpy, modes, GLX_RGBA_TYPE, 1116 sharedPrivate, pctx ); 1117} 1118#endif /* DRI_NEW_INTERFACE_ONLY */ 1119 1120/*@}*/ 1121 1122 1123/*****************************************************************/ 1124/** \name Screen handling functions */ 1125/*****************************************************************/ 1126/*@{*/ 1127 1128/** 1129 * Destroy the per-screen private information. 1130 * 1131 * \param dpy the display handle. 1132 * \param scrn the screen number. 1133 * \param screenPrivate opaque pointer to the per-screen private information. 1134 * 1135 * \internal 1136 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls 1137 * drmClose(), and finally frees \p screenPrivate. 1138 */ 1139static void driDestroyScreen(__DRInativeDisplay *dpy, int scrn, void *screenPrivate) 1140{ 1141 __DRIscreenPrivate *psp = (__DRIscreenPrivate *) screenPrivate; 1142 1143 if (psp) { 1144 /* No interaction with the X-server is possible at this point. This 1145 * routine is called after XCloseDisplay, so there is no protocol 1146 * stream open to the X-server anymore. 1147 */ 1148 1149 if (psp->DriverAPI.DestroyScreen) 1150 (*psp->DriverAPI.DestroyScreen)(psp); 1151 1152 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); 1153 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); 1154 _mesa_free(psp->pDevPriv); 1155 (void)drmClose(psp->fd); 1156 if ( psp->modes != NULL ) { 1157 _gl_context_modes_destroy( psp->modes ); 1158 } 1159 _mesa_free(psp); 1160 } 1161} 1162 1163 1164/** 1165 * Utility function used to create a new driver-private screen structure. 1166 * 1167 * \param dpy Display pointer 1168 * \param scrn Index of the screen 1169 * \param psc DRI screen data (not driver private) 1170 * \param modes Linked list of known display modes. This list is, at a 1171 * minimum, a list of modes based on the current display mode. 1172 * These roughly match the set of available X11 visuals, but it 1173 * need not be limited to X11! The calling libGL should create 1174 * a list that will inform the driver of the current display 1175 * mode (i.e., color buffer depth, depth buffer depth, etc.). 1176 * \param ddx_version Version of the 2D DDX. This may not be meaningful for 1177 * all drivers. 1178 * \param dri_version Version of the "server-side" DRI. 1179 * \param drm_version Version of the kernel DRM. 1180 * \param frame_buffer Data describing the location and layout of the 1181 * framebuffer. 1182 * \param pSAREA Pointer the the SAREA. 1183 * \param fd Device handle for the DRM. 1184 * \param internal_api_version Version of the internal interface between the 1185 * driver and libGL. 1186 * \param driverAPI Driver API functions used by other routines in dri_util.c. 1187 */ 1188__DRIscreenPrivate * 1189__driUtilCreateNewScreen(__DRInativeDisplay *dpy, int scrn, __DRIscreen *psc, 1190 __GLcontextModes * modes, 1191 const __DRIversion * ddx_version, 1192 const __DRIversion * dri_version, 1193 const __DRIversion * drm_version, 1194 const __DRIframebuffer * frame_buffer, 1195 drm_sarea_t *pSAREA, 1196 int fd, 1197 int internal_api_version, 1198 const struct __DriverAPIRec *driverAPI) 1199{ 1200 __DRIscreenPrivate *psp; 1201 1202 1203#ifdef DRI_NEW_INTERFACE_ONLY 1204 if ( internal_api_version < 20040602 ) { 1205 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. " 1206 "20040602 or later is required.\n", internal_api_version ); 1207 return NULL; 1208 } 1209#else 1210 if ( internal_api_version == 20031201 ) { 1211 fprintf( stderr, "libGL error: libGL version 20031201 has critical " 1212 "binary compatilibity bugs.\nlibGL error: You must upgrade " 1213 "to use direct-rendering!\n" ); 1214 return NULL; 1215 } 1216#endif /* DRI_NEW_INTERFACE_ONLY */ 1217 1218 1219 window_exists = (PFNGLXWINDOWEXISTSPROC) 1220 glXGetProcAddress( (const GLubyte *) "__glXWindowExists" ); 1221 1222 if ( window_exists == NULL ) { 1223#ifdef DRI_NEW_INTERFACE_ONLY 1224 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. " 1225 "20021128 or later is required.\n", internal_api_version ); 1226 return NULL; 1227#else 1228 window_exists = (PFNGLXWINDOWEXISTSPROC) __driWindowExists; 1229#endif /* DRI_NEW_INTERFACE_ONLY */ 1230 } 1231 1232 create_context_with_config = (PFNGLXCREATECONTEXTWITHCONFIGPROC) 1233 glXGetProcAddress( (const GLubyte *) "__glXCreateContextWithConfig" ); 1234 if ( create_context_with_config == NULL ) { 1235#ifdef DRI_NEW_INTERFACE_ONLY 1236 fprintf( stderr, "libGL error: libGL.so version (%08u) is too old. " 1237 "20031201 or later is required.\n", internal_api_version ); 1238 return NULL; 1239#else 1240 create_context_with_config = (PFNGLXCREATECONTEXTWITHCONFIGPROC) 1241 fake_XF86DRICreateContextWithConfig; 1242#endif /* DRI_NEW_INTERFACE_ONLY */ 1243 } 1244 1245 api_ver = internal_api_version; 1246 1247 psp = (__DRIscreenPrivate *)_mesa_malloc(sizeof(__DRIscreenPrivate)); 1248 if (!psp) { 1249 return NULL; 1250 } 1251 1252 /* Create the hash table */ 1253 psp->drawHash = drmHashCreate(); 1254 if ( psp->drawHash == NULL ) { 1255 _mesa_free( psp ); 1256 return NULL; 1257 } 1258 1259 psp->display = dpy; 1260 psp->myNum = scrn; 1261 psp->psc = psc; 1262 psp->modes = modes; 1263 1264 /* 1265 ** NOT_DONE: This is used by the X server to detect when the client 1266 ** has died while holding the drawable lock. The client sets the 1267 ** drawable lock to this value. 1268 */ 1269 psp->drawLockID = 1; 1270 1271 psp->drmMajor = drm_version->major; 1272 psp->drmMinor = drm_version->minor; 1273 psp->drmPatch = drm_version->patch; 1274 psp->ddxMajor = ddx_version->major; 1275 psp->ddxMinor = ddx_version->minor; 1276 psp->ddxPatch = ddx_version->patch; 1277 psp->driMajor = dri_version->major; 1278 psp->driMinor = dri_version->minor; 1279 psp->driPatch = dri_version->patch; 1280 1281 /* install driver's callback functions */ 1282 memcpy( &psp->DriverAPI, driverAPI, sizeof(struct __DriverAPIRec) ); 1283 1284 psp->pSAREA = pSAREA; 1285 1286 psp->pFB = frame_buffer->base; 1287 psp->fbSize = frame_buffer->size; 1288 psp->fbStride = frame_buffer->stride; 1289 psp->fbWidth = frame_buffer->width; 1290 psp->fbHeight = frame_buffer->height; 1291 psp->devPrivSize = frame_buffer->dev_priv_size; 1292 psp->pDevPriv = frame_buffer->dev_priv; 1293 psp->fbBPP = psp->fbStride * 8 / frame_buffer->width; 1294 1295 psp->fd = fd; 1296 1297 /* 1298 ** Do not init dummy context here; actual initialization will be 1299 ** done when the first DRI context is created. Init screen priv ptr 1300 ** to NULL to let CreateContext routine that it needs to be inited. 1301 */ 1302 psp->dummyContextPriv.driScreenPriv = NULL; 1303 1304 psc->destroyScreen = driDestroyScreen; 1305#ifndef DRI_NEW_INTERFACE_ONLY 1306 psc->createContext = driCreateContext; 1307#else 1308 psc->createContext = NULL; 1309#endif 1310 psc->createNewDrawable = driCreateNewDrawable; 1311 psc->getDrawable = driGetDrawable; 1312#ifdef DRI_NEW_INTERFACE_ONLY 1313 psc->getMSC = driGetMSC; 1314 psc->createNewContext = driCreateNewContext; 1315#else 1316 if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) { 1317 psc->getMSC = driGetMSC; 1318 1319 if ( driCompareGLXAPIVersion( 20030824 ) >= 0 ) { 1320 psc->createNewContext = driCreateNewContext; 1321 } 1322 } 1323#endif 1324 1325 if ( (psp->DriverAPI.InitDriver != NULL) 1326 && !(*psp->DriverAPI.InitDriver)(psp) ) { 1327 _mesa_free( psp ); 1328 return NULL; 1329 } 1330 1331 1332 return psp; 1333} 1334 1335 1336#ifndef DRI_NEW_INTERFACE_ONLY 1337/** 1338 * Utility function used to create a new driver-private screen structure. 1339 * 1340 * \param dpy Display pointer. 1341 * \param scrn Index of the screen. 1342 * \param psc DRI screen data (not driver private) 1343 * \param numConfigs Number of visual configs pointed to by \c configs. 1344 * \param configs Array of GLXvisualConfigs exported by the 2D driver. 1345 * \param driverAPI Driver API functions used by other routines in dri_util.c. 1346 * 1347 * \deprecated 1348 * This function has been replaced by \c __driUtilCreateNewScreen. In drivers 1349 * built to work with XFree86, this function will continue to exist to support 1350 * older versions of libGL. Starting with the next major relelase of XFree86, 1351 * this function will be removed. 1352 */ 1353__DRIscreenPrivate * 1354__driUtilCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, 1355 int numConfigs, __GLXvisualConfig *configs, 1356 const struct __DriverAPIRec *driverAPI) 1357{ 1358 int directCapable; 1359 __DRIscreenPrivate *psp = NULL; 1360 drm_handle_t hSAREA; 1361 drmAddress pSAREA; 1362 char *BusID; 1363 __GLcontextModes *modes; 1364 __GLcontextModes *temp; 1365 int i; 1366 __DRIversion ddx_version; 1367 __DRIversion dri_version; 1368 __DRIversion drm_version; 1369 __DRIframebuffer framebuffer; 1370 int fd = -1; 1371 int status; 1372 const char * err_msg; 1373 const char * err_extra; 1374 1375 1376 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrn, &directCapable) 1377 || !directCapable) { 1378 return NULL; 1379 } 1380 1381 1382 /* Create the linked list of context modes, and populate it with the 1383 * GLX visual information passed in by libGL. 1384 */ 1385 1386 modes = _gl_context_modes_create( numConfigs, sizeof(__GLcontextModes) ); 1387 if ( modes == NULL ) { 1388 return NULL; 1389 } 1390 1391 temp = modes; 1392 for ( i = 0 ; i < numConfigs ; i++ ) { 1393 assert( temp != NULL ); 1394 _gl_copy_visual_to_context_mode( temp, & configs[i] ); 1395 temp->screen = scrn; 1396 1397 temp = temp->next; 1398 } 1399 1400 err_msg = "XF86DRIOpenConnection"; 1401 err_extra = NULL; 1402 1403 if (XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) { 1404 fd = drmOpen(NULL,BusID); 1405 _mesa_free(BusID); /* No longer needed */ 1406 1407 err_msg = "open DRM"; 1408 err_extra = strerror( -fd ); 1409 1410 if (fd >= 0) { 1411 drm_magic_t magic; 1412 1413 err_msg = "drmGetMagic"; 1414 err_extra = NULL; 1415 1416 if (!drmGetMagic(fd, &magic)) { 1417 drmVersionPtr version = drmGetVersion(fd); 1418 if (version) { 1419 drm_version.major = version->version_major; 1420 drm_version.minor = version->version_minor; 1421 drm_version.patch = version->version_patchlevel; 1422 drmFreeVersion(version); 1423 } 1424 else { 1425 drm_version.major = -1; 1426 drm_version.minor = -1; 1427 drm_version.patch = -1; 1428 } 1429 1430 err_msg = "XF86DRIAuthConnection"; 1431 if (XF86DRIAuthConnection(dpy, scrn, magic)) { 1432 char *driverName; 1433 1434 /* 1435 * Get device name (like "tdfx") and the ddx version numbers. 1436 * We'll check the version in each DRI driver's "createScreen" 1437 * function. 1438 */ 1439 err_msg = "XF86DRIGetClientDriverName"; 1440 if (XF86DRIGetClientDriverName(dpy, scrn, 1441 &ddx_version.major, 1442 &ddx_version.minor, 1443 &ddx_version.patch, 1444 &driverName)) { 1445 1446 /* No longer needed. */ 1447 _mesa_free( driverName ); 1448 1449 /* 1450 * Get the DRI X extension version. 1451 */ 1452 err_msg = "XF86DRIQueryVersion"; 1453 if (XF86DRIQueryVersion(dpy, 1454 &dri_version.major, 1455 &dri_version.minor, 1456 &dri_version.patch)) { 1457 drm_handle_t hFB; 1458 int junk; 1459 1460 /* 1461 * Get device-specific info. pDevPriv will point to a struct 1462 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) 1463 * that has information about the screen size, depth, pitch, 1464 * ancilliary buffers, DRM mmap handles, etc. 1465 */ 1466 err_msg = "XF86DRIGetDeviceInfo"; 1467 if (XF86DRIGetDeviceInfo(dpy, scrn, 1468 &hFB, 1469 &junk, 1470 &framebuffer.size, 1471 &framebuffer.stride, 1472 &framebuffer.dev_priv_size, 1473 &framebuffer.dev_priv)) { 1474 framebuffer.width = DisplayWidth(dpy, scrn); 1475 framebuffer.height = DisplayHeight(dpy, scrn); 1476 1477 /* 1478 * Map the framebuffer region. 1479 */ 1480 status = drmMap(fd, hFB, framebuffer.size, 1481 (drmAddressPtr)&framebuffer.base); 1482 1483 err_msg = "drmMap of framebuffer"; 1484 err_extra = strerror( -status ); 1485 1486 if ( status == 0 ) { 1487 /* 1488 * Map the SAREA region. Further mmap regions may be setup in 1489 * each DRI driver's "createScreen" function. 1490 */ 1491 status = drmMap(fd, hSAREA, SAREA_MAX, 1492 &pSAREA); 1493 1494 err_msg = "drmMap of sarea"; 1495 err_extra = strerror( -status ); 1496 1497 if ( status == 0 ) { 1498 PFNGLXGETINTERNALVERSIONPROC get_ver; 1499 1500 get_ver = (PFNGLXGETINTERNALVERSIONPROC) 1501 glXGetProcAddress( (const GLubyte *) "__glXGetInternalVersion" ); 1502 1503 err_msg = "InitDriver"; 1504 err_extra = NULL; 1505 psp = __driUtilCreateNewScreen( dpy, scrn, psc, modes, 1506 & ddx_version, 1507 & dri_version, 1508 & drm_version, 1509 & framebuffer, 1510 pSAREA, 1511 fd, 1512 (get_ver != NULL) ? (*get_ver)() : 1, 1513 driverAPI ); 1514 } 1515 } 1516 } 1517 } 1518 } 1519 } 1520 } 1521 } 1522 } 1523 1524 if ( psp == NULL ) { 1525 if ( pSAREA != MAP_FAILED ) { 1526 (void)drmUnmap(pSAREA, SAREA_MAX); 1527 } 1528 1529 if ( framebuffer.base != MAP_FAILED ) { 1530 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size); 1531 } 1532 1533 if ( framebuffer.dev_priv != NULL ) { 1534 _mesa_free(framebuffer.dev_priv); 1535 } 1536 1537 if ( fd >= 0 ) { 1538 (void)drmClose(fd); 1539 } 1540 1541 if ( modes != NULL ) { 1542 _gl_context_modes_destroy( modes ); 1543 } 1544 1545 (void)XF86DRICloseConnection(dpy, scrn); 1546 1547 if ( err_extra != NULL ) { 1548 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg, 1549 err_extra); 1550 } 1551 else { 1552 fprintf(stderr, "libGL error: %s failed\n", err_msg ); 1553 } 1554 1555 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n"); 1556 } 1557 1558 return psp; 1559} 1560#endif /* DRI_NEW_INTERFACE_ONLY */ 1561 1562 1563/** 1564 * Compare the current GLX API version with a driver supplied required version. 1565 * 1566 * The minimum required version is compared with the API version exported by 1567 * the \c __glXGetInternalVersion function (in libGL.so). 1568 * 1569 * \param required_version Minimum required internal GLX API version. 1570 * \return A tri-value return, as from strcmp is returned. A value less 1571 * than, equal to, or greater than zero will be returned if the 1572 * internal GLX API version is less than, equal to, or greater 1573 * than \c required_version. 1574 * 1575 * \sa __glXGetInternalVersion(). 1576 */ 1577int driCompareGLXAPIVersion( GLint required_version ) 1578{ 1579 if ( api_ver > required_version ) { 1580 return 1; 1581 } 1582 else if ( api_ver == required_version ) { 1583 return 0; 1584 } 1585 1586 return -1; 1587} 1588 1589 1590static int 1591driQueryFrameTracking( __DRInativeDisplay * dpy, void * priv, 1592 int64_t * sbc, int64_t * missedFrames, 1593 float * lastMissedUsage, float * usage ) 1594{ 1595 static PFNGLXGETUSTPROC get_ust; 1596 __DRIswapInfo sInfo; 1597 int status; 1598 int64_t ust; 1599 __DRIdrawablePrivate * dpriv = (__DRIdrawablePrivate *) priv; 1600 1601 if ( get_ust == NULL ) { 1602 get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( (const GLubyte *) "__glXGetUST" ); 1603 } 1604 1605 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo ); 1606 if ( status == 0 ) { 1607 *sbc = sInfo.swap_count; 1608 *missedFrames = sInfo.swap_missed_count; 1609 *lastMissedUsage = sInfo.swap_missed_usage; 1610 1611 (*get_ust)( & ust ); 1612 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust ); 1613 } 1614 1615 return status; 1616} 1617 1618 1619/** 1620 * Calculate amount of swap interval used between GLX buffer swaps. 1621 * 1622 * The usage value, on the range [0,max], is the fraction of total swap 1623 * interval time used between GLX buffer swaps is calculated. 1624 * 1625 * \f$p = t_d / (i * t_r)\f$ 1626 * 1627 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the 1628 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time 1629 * required for a single vertical refresh period (as returned by \c 1630 * glXGetMscRateOML). 1631 * 1632 * See the documentation for the GLX_MESA_swap_frame_usage extension for more 1633 * details. 1634 * 1635 * \param dPriv Pointer to the private drawable structure. 1636 * \return If less than a single swap interval time period was required 1637 * between GLX buffer swaps, a number greater than 0 and less than 1638 * 1.0 is returned. If exactly one swap interval time period is 1639 * required, 1.0 is returned, and if more than one is required then 1640 * a number greater than 1.0 will be returned. 1641 * 1642 * \sa glXSwapIntervalSGI glXGetMscRateOML 1643 * 1644 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it 1645 * be possible to cache the sync rate? 1646 */ 1647float 1648driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust, 1649 int64_t current_ust ) 1650{ 1651 static PFNGLXGETMSCRATEOMLPROC get_msc_rate = NULL; 1652 int32_t n; 1653 int32_t d; 1654 int interval; 1655 float usage = 1.0; 1656 1657 1658 if ( get_msc_rate == NULL ) { 1659 get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) 1660 glXGetProcAddress( (const GLubyte *) "glXGetMscRateOML" ); 1661 } 1662 1663 if ( (get_msc_rate != NULL) 1664 && get_msc_rate( dPriv->display, dPriv->draw, &n, &d ) ) { 1665 interval = (dPriv->pdraw->swap_interval != 0) 1666 ? dPriv->pdraw->swap_interval : 1; 1667 1668 1669 /* We want to calculate 1670 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get 1671 * current_UST by calling __glXGetUST. last_swap_UST is stored in 1672 * dPriv->swap_ust. interval has already been calculated. 1673 * 1674 * The only tricky part is us_per_refresh. us_per_refresh is 1675 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it 1676 * around and say us_per_refresh = 1000000 * d / n. Since this goes in 1677 * the denominator of the final calculation, we calculate 1678 * (interval * 1000000 * d) and move n into the numerator. 1679 */ 1680 1681 usage = (current_ust - last_swap_ust); 1682 usage *= n; 1683 usage /= (interval * d); 1684 usage /= 1000000.0; 1685 } 1686 1687 return usage; 1688} 1689 1690/*@}*/ 1691