dri_util.c revision 45e2b51c853471b79004a954ce3092a253b20b77
1/** 2 * \file dri_util.c 3 * DRI utility functions. 4 * 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 8 * drivers. 9 * 10 * Basically, these utility functions take care of some of the dirty details of 11 * screen initialization, context creation, context binding, DRM setup, etc. 12 * 13 * These functions are compiled into each DRI driver so libGL.so knows nothing 14 * about them. 15 */ 16 17 18#include <assert.h> 19#include <stdarg.h> 20#include <unistd.h> 21#include <sys/mman.h> 22#include <stdio.h> 23 24#ifndef MAP_FAILED 25#define MAP_FAILED ((void *)-1) 26#endif 27 28#include "main/imports.h" 29#define None 0 30 31#include "dri_util.h" 32#include "drm_sarea.h" 33#include "utils.h" 34#include "vblank.h" 35#include "xmlpool.h" 36 37PUBLIC const char __dri2ConfigOptions[] = 38 DRI_CONF_BEGIN 39 DRI_CONF_SECTION_PERFORMANCE 40 DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1) 41 DRI_CONF_SECTION_END 42 DRI_CONF_END; 43 44static const uint __dri2NConfigOptions = 1; 45 46#ifndef GLX_OML_sync_control 47typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator); 48#endif 49 50static void dri_get_drawable(__DRIdrawable *pdp); 51static void dri_put_drawable(__DRIdrawable *pdp); 52 53/** 54 * This is just a token extension used to signal that the driver 55 * supports setting a read drawable. 56 */ 57const __DRIextension driReadDrawableExtension = { 58 __DRI_READ_DRAWABLE, __DRI_READ_DRAWABLE_VERSION 59}; 60 61GLint 62driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 ) 63{ 64 if (rect2.x1 > rect1.x1) rect1.x1 = rect2.x1; 65 if (rect2.x2 < rect1.x2) rect1.x2 = rect2.x2; 66 if (rect2.y1 > rect1.y1) rect1.y1 = rect2.y1; 67 if (rect2.y2 < rect1.y2) rect1.y2 = rect2.y2; 68 69 if (rect1.x1 > rect1.x2 || rect1.y1 > rect1.y2) return 0; 70 71 return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1); 72} 73 74/*****************************************************************/ 75/** \name Context (un)binding functions */ 76/*****************************************************************/ 77/*@{*/ 78 79/** 80 * Unbind context. 81 * 82 * \param scrn the screen. 83 * \param gc context. 84 * 85 * \return \c GL_TRUE on success, or \c GL_FALSE on failure. 86 * 87 * \internal 88 * This function calls __DriverAPIRec::UnbindContext, and then decrements 89 * __DRIdrawableRec::refcount which must be non-zero for a successful 90 * return. 91 * 92 * While casting the opaque private pointers associated with the parameters 93 * into their respective real types it also assures they are not \c NULL. 94 */ 95static int driUnbindContext(__DRIcontext *pcp) 96{ 97 __DRIscreen *psp; 98 __DRIdrawable *pdp; 99 __DRIdrawable *prp; 100 101 /* 102 ** Assume error checking is done properly in glXMakeCurrent before 103 ** calling driUnbindContext. 104 */ 105 106 if (pcp == NULL) 107 return GL_FALSE; 108 109 psp = pcp->driScreenPriv; 110 pdp = pcp->driDrawablePriv; 111 prp = pcp->driReadablePriv; 112 113 /* already unbound */ 114 if (!pdp && !prp) 115 return GL_TRUE; 116 /* Let driver unbind drawable from context */ 117 (*psp->DriverAPI.UnbindContext)(pcp); 118 119 assert(pdp); 120 if (pdp->refcount == 0) { 121 /* ERROR!!! */ 122 return GL_FALSE; 123 } 124 125 dri_put_drawable(pdp); 126 127 if (prp != pdp) { 128 if (prp->refcount == 0) { 129 /* ERROR!!! */ 130 return GL_FALSE; 131 } 132 133 dri_put_drawable(prp); 134 } 135 136 137 /* XXX this is disabled so that if we call SwapBuffers on an unbound 138 * window we can determine the last context bound to the window and 139 * use that context's lock. (BrianP, 2-Dec-2000) 140 */ 141 pcp->driDrawablePriv = pcp->driReadablePriv = NULL; 142 143 return GL_TRUE; 144} 145 146/** 147 * This function takes both a read buffer and a draw buffer. This is needed 148 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent 149 * function. 150 */ 151static int driBindContext(__DRIcontext *pcp, 152 __DRIdrawable *pdp, 153 __DRIdrawable *prp) 154{ 155 __DRIscreen *psp = NULL; 156 157 /* Bind the drawable to the context */ 158 159 if (pcp) { 160 psp = pcp->driScreenPriv; 161 pcp->driDrawablePriv = pdp; 162 pcp->driReadablePriv = prp; 163 if (pdp) { 164 pdp->driContextPriv = pcp; 165 dri_get_drawable(pdp); 166 } 167 if ( prp && pdp != prp ) { 168 dri_get_drawable(prp); 169 } 170 } 171 172 /* 173 ** Now that we have a context associated with this drawable, we can 174 ** initialize the drawable information if has not been done before. 175 */ 176 177 assert(psp); 178 if (!psp->dri2.enabled) { 179 if (pdp && !pdp->pStamp) { 180 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 181 __driUtilUpdateDrawableInfo(pdp); 182 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 183 } 184 if (prp && pdp != prp && !prp->pStamp) { 185 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 186 __driUtilUpdateDrawableInfo(prp); 187 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 188 } 189 } 190 191 /* Call device-specific MakeCurrent */ 192 193 return (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); 194} 195 196/*@}*/ 197 198 199/*****************************************************************/ 200/** \name Drawable handling functions */ 201/*****************************************************************/ 202/*@{*/ 203 204/** 205 * Update private drawable information. 206 * 207 * \param pdp pointer to the private drawable information to update. 208 * 209 * This function basically updates the __DRIdrawable struct's 210 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo. 211 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which 212 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If 213 * the values are different that means we have to update the clipping 214 * info. 215 */ 216void 217__driUtilUpdateDrawableInfo(__DRIdrawable *pdp) 218{ 219 __DRIscreen *psp = pdp->driScreenPriv; 220 __DRIcontext *pcp = pdp->driContextPriv; 221 222 if (!pcp 223 || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) { 224 /* ERROR!!! 225 * ...but we must ignore it. There can be many contexts bound to a 226 * drawable. 227 */ 228 } 229 230 if (pdp->pClipRects) { 231 free(pdp->pClipRects); 232 pdp->pClipRects = NULL; 233 } 234 235 if (pdp->pBackClipRects) { 236 free(pdp->pBackClipRects); 237 pdp->pBackClipRects = NULL; 238 } 239 240 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 241 242 if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp, 243 &pdp->index, &pdp->lastStamp, 244 &pdp->x, &pdp->y, &pdp->w, &pdp->h, 245 &pdp->numClipRects, &pdp->pClipRects, 246 &pdp->backX, 247 &pdp->backY, 248 &pdp->numBackClipRects, 249 &pdp->pBackClipRects, 250 pdp->loaderPrivate)) { 251 /* Error -- eg the window may have been destroyed. Keep going 252 * with no cliprects. 253 */ 254 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */ 255 pdp->numClipRects = 0; 256 pdp->pClipRects = NULL; 257 pdp->numBackClipRects = 0; 258 pdp->pBackClipRects = NULL; 259 } 260 else 261 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp); 262 263 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID); 264} 265 266/*@}*/ 267 268/*****************************************************************/ 269/** \name GLX callbacks */ 270/*****************************************************************/ 271/*@{*/ 272 273static void driReportDamage(__DRIdrawable *pdp, 274 struct drm_clip_rect *pClipRects, int numClipRects) 275{ 276 __DRIscreen *psp = pdp->driScreenPriv; 277 278 /* Check that we actually have the new damage report method */ 279 if (psp->damage) { 280 /* Report the damage. Currently, all our drivers draw 281 * directly to the front buffer, so we report the damage there 282 * rather than to the backing storein (if any). 283 */ 284 (*psp->damage->reportDamage)(pdp, 285 pdp->x, pdp->y, 286 pClipRects, numClipRects, 287 GL_TRUE, pdp->loaderPrivate); 288 } 289} 290 291 292/** 293 * Swap buffers. 294 * 295 * \param drawablePrivate opaque pointer to the per-drawable private info. 296 * 297 * \internal 298 * This function calls __DRIdrawable::swapBuffers. 299 * 300 * Is called directly from glXSwapBuffers(). 301 */ 302static void driSwapBuffers(__DRIdrawable *dPriv) 303{ 304 __DRIscreen *psp = dPriv->driScreenPriv; 305 drm_clip_rect_t *rects; 306 int i; 307 308 psp->DriverAPI.SwapBuffers(dPriv); 309 310 if (!dPriv->numClipRects) 311 return; 312 313 rects = malloc(sizeof(*rects) * dPriv->numClipRects); 314 315 if (!rects) 316 return; 317 318 for (i = 0; i < dPriv->numClipRects; i++) { 319 rects[i].x1 = dPriv->pClipRects[i].x1 - dPriv->x; 320 rects[i].y1 = dPriv->pClipRects[i].y1 - dPriv->y; 321 rects[i].x2 = dPriv->pClipRects[i].x2 - dPriv->x; 322 rects[i].y2 = dPriv->pClipRects[i].y2 - dPriv->y; 323 } 324 325 driReportDamage(dPriv, rects, dPriv->numClipRects); 326 free(rects); 327} 328 329static int driDrawableGetMSC( __DRIscreen *sPriv, __DRIdrawable *dPriv, 330 int64_t *msc ) 331{ 332 return sPriv->DriverAPI.GetDrawableMSC(sPriv, dPriv, msc); 333} 334 335 336static int driWaitForMSC(__DRIdrawable *dPriv, int64_t target_msc, 337 int64_t divisor, int64_t remainder, 338 int64_t * msc, int64_t * sbc) 339{ 340 __DRIswapInfo sInfo; 341 int status; 342 343 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc, 344 divisor, remainder, 345 msc ); 346 347 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync 348 * is supported but GLX_OML_sync_control is not. Therefore, don't return 349 * an error value if GetSwapInfo() is not implemented. 350 */ 351 if ( status == 0 352 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) { 353 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo ); 354 *sbc = sInfo.swap_count; 355 } 356 357 return status; 358} 359 360 361const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = { 362 { __DRI_MEDIA_STREAM_COUNTER, __DRI_MEDIA_STREAM_COUNTER_VERSION }, 363 driWaitForMSC, 364 driDrawableGetMSC, 365}; 366 367 368static void driCopySubBuffer(__DRIdrawable *dPriv, 369 int x, int y, int w, int h) 370{ 371 drm_clip_rect_t rect; 372 373 rect.x1 = x; 374 rect.y1 = dPriv->h - y - h; 375 rect.x2 = x + w; 376 rect.y2 = rect.y1 + h; 377 driReportDamage(dPriv, &rect, 1); 378 379 dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h); 380} 381 382const __DRIcopySubBufferExtension driCopySubBufferExtension = { 383 { __DRI_COPY_SUB_BUFFER, __DRI_COPY_SUB_BUFFER_VERSION }, 384 driCopySubBuffer 385}; 386 387static void driSetSwapInterval(__DRIdrawable *dPriv, unsigned int interval) 388{ 389 dPriv->swap_interval = interval; 390} 391 392static unsigned int driGetSwapInterval(__DRIdrawable *dPriv) 393{ 394 return dPriv->swap_interval; 395} 396 397const __DRIswapControlExtension driSwapControlExtension = { 398 { __DRI_SWAP_CONTROL, __DRI_SWAP_CONTROL_VERSION }, 399 driSetSwapInterval, 400 driGetSwapInterval 401}; 402 403 404/** 405 * This is called via __DRIscreenRec's createNewDrawable pointer. 406 */ 407static __DRIdrawable * 408driCreateNewDrawable(__DRIscreen *psp, const __DRIconfig *config, 409 drm_drawable_t hwDrawable, int renderType, 410 const int *attrs, void *data) 411{ 412 __DRIdrawable *pdp; 413 414 /* Since pbuffers are not yet supported, no drawable attributes are 415 * supported either. 416 */ 417 (void) attrs; 418 419 pdp = malloc(sizeof *pdp); 420 if (!pdp) { 421 return NULL; 422 } 423 424 pdp->loaderPrivate = data; 425 pdp->hHWDrawable = hwDrawable; 426 pdp->refcount = 1; 427 pdp->pStamp = NULL; 428 pdp->lastStamp = 0; 429 pdp->index = 0; 430 pdp->x = 0; 431 pdp->y = 0; 432 pdp->w = 0; 433 pdp->h = 0; 434 pdp->numClipRects = 0; 435 pdp->numBackClipRects = 0; 436 pdp->pClipRects = NULL; 437 pdp->pBackClipRects = NULL; 438 pdp->vblSeq = 0; 439 pdp->vblFlags = 0; 440 441 pdp->driScreenPriv = psp; 442 443 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, &config->modes, 444 renderType == GLX_PIXMAP_BIT)) { 445 free(pdp); 446 return NULL; 447 } 448 449 pdp->msc_base = 0; 450 451 /* This special default value is replaced with the configured 452 * default value when the drawable is first bound to a direct 453 * rendering context. 454 */ 455 pdp->swap_interval = (unsigned)-1; 456 457 return pdp; 458} 459 460 461static __DRIdrawable * 462dri2CreateNewDrawable(__DRIscreen *screen, 463 const __DRIconfig *config, 464 void *loaderPrivate) 465{ 466 __DRIdrawable *pdraw; 467 468 pdraw = driCreateNewDrawable(screen, config, 0, 0, NULL, loaderPrivate); 469 if (!pdraw) 470 return NULL; 471 472 pdraw->pClipRects = &pdraw->dri2.clipRect; 473 pdraw->pBackClipRects = &pdraw->dri2.clipRect; 474 475 pdraw->pStamp = &pdraw->dri2.stamp; 476 *pdraw->pStamp = pdraw->lastStamp + 1; 477 478 return pdraw; 479} 480 481static int 482dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val) 483{ 484 if (!driCheckOption(&screen->optionCache, var, DRI_BOOL)) 485 return -1; 486 487 *val = driQueryOptionb(&screen->optionCache, var); 488 489 return 0; 490} 491 492static int 493dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val) 494{ 495 if (!driCheckOption(&screen->optionCache, var, DRI_INT) && 496 !driCheckOption(&screen->optionCache, var, DRI_ENUM)) 497 return -1; 498 499 *val = driQueryOptioni(&screen->optionCache, var); 500 501 return 0; 502} 503 504static int 505dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val) 506{ 507 if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT)) 508 return -1; 509 510 *val = driQueryOptionf(&screen->optionCache, var); 511 512 return 0; 513} 514 515 516static void dri_get_drawable(__DRIdrawable *pdp) 517{ 518 pdp->refcount++; 519} 520 521static void dri_put_drawable(__DRIdrawable *pdp) 522{ 523 __DRIscreen *psp; 524 525 if (pdp) { 526 pdp->refcount--; 527 if (pdp->refcount) 528 return; 529 530 psp = pdp->driScreenPriv; 531 (*psp->DriverAPI.DestroyBuffer)(pdp); 532 if (pdp->pClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { 533 free(pdp->pClipRects); 534 pdp->pClipRects = NULL; 535 } 536 if (pdp->pBackClipRects && pdp->pClipRects != &pdp->dri2.clipRect) { 537 free(pdp->pBackClipRects); 538 pdp->pBackClipRects = NULL; 539 } 540 free(pdp); 541 } 542} 543 544static void 545driDestroyDrawable(__DRIdrawable *pdp) 546{ 547 dri_put_drawable(pdp); 548} 549 550/*@}*/ 551 552 553/*****************************************************************/ 554/** \name Context handling functions */ 555/*****************************************************************/ 556/*@{*/ 557 558/** 559 * Destroy the per-context private information. 560 * 561 * \internal 562 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls 563 * drmDestroyContext(), and finally frees \p contextPrivate. 564 */ 565static void 566driDestroyContext(__DRIcontext *pcp) 567{ 568 if (pcp) { 569 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); 570 free(pcp); 571 } 572} 573 574 575/** 576 * Create the per-drawable private driver information. 577 * 578 * \param render_type Type of rendering target. \c GLX_RGBA is the only 579 * type likely to ever be supported for direct-rendering. 580 * \param shared Context with which to share textures, etc. or NULL 581 * 582 * \returns An opaque pointer to the per-context private information on 583 * success, or \c NULL on failure. 584 * 585 * \internal 586 * This function allocates and fills a __DRIcontextRec structure. It 587 * performs some device independent initialization and passes all the 588 * relevent information to __DriverAPIRec::CreateContext to create the 589 * context. 590 * 591 */ 592static __DRIcontext * 593driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config, 594 int render_type, __DRIcontext *shared, 595 drm_context_t hwContext, void *data) 596{ 597 __DRIcontext *pcp; 598 void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; 599 600 pcp = malloc(sizeof *pcp); 601 if (!pcp) 602 return NULL; 603 604 pcp->driScreenPriv = psp; 605 pcp->driDrawablePriv = NULL; 606 pcp->loaderPrivate = data; 607 608 pcp->dri2.draw_stamp = 0; 609 pcp->dri2.read_stamp = 0; 610 611 pcp->hHWContext = hwContext; 612 613 if ( !(*psp->DriverAPI.CreateContext)(&config->modes, pcp, shareCtx) ) { 614 free(pcp); 615 return NULL; 616 } 617 618 return pcp; 619} 620 621 622static __DRIcontext * 623dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config, 624 __DRIcontext *shared, void *data) 625{ 626 return driCreateNewContext(screen, config, 0, shared, 0, data); 627} 628 629 630static int 631driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask) 632{ 633 return GL_FALSE; 634} 635 636/*@}*/ 637 638 639/*****************************************************************/ 640/** \name Screen handling functions */ 641/*****************************************************************/ 642/*@{*/ 643 644/** 645 * Destroy the per-screen private information. 646 * 647 * \internal 648 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls 649 * drmClose(), and finally frees \p screenPrivate. 650 */ 651static void driDestroyScreen(__DRIscreen *psp) 652{ 653 if (psp) { 654 /* No interaction with the X-server is possible at this point. This 655 * routine is called after XCloseDisplay, so there is no protocol 656 * stream open to the X-server anymore. 657 */ 658 659 if (psp->DriverAPI.DestroyScreen) 660 (*psp->DriverAPI.DestroyScreen)(psp); 661 662 if (!psp->dri2.enabled) { 663 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX); 664 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize); 665 (void)drmCloseOnce(psp->fd); 666 } 667 668 free(psp); 669 } 670} 671 672static void 673setupLoaderExtensions(__DRIscreen *psp, 674 const __DRIextension **extensions) 675{ 676 int i; 677 678 for (i = 0; extensions[i]; i++) { 679 if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0) 680 psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i]; 681 if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0) 682 psp->damage = (__DRIdamageExtension *) extensions[i]; 683 if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0) 684 psp->systemTime = (__DRIsystemTimeExtension *) extensions[i]; 685 if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0) 686 psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i]; 687 if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0) 688 psp->dri2.image = (__DRIimageLookupExtension *) extensions[i]; 689 } 690} 691 692/** 693 * This is the bootstrap function for the driver. libGL supplies all of the 694 * requisite information about the system, and the driver initializes itself. 695 * This routine also fills in the linked list pointed to by \c driver_modes 696 * with the \c __GLcontextModes that the driver can support for windows or 697 * pbuffers. 698 * 699 * For legacy DRI. 700 * 701 * \param scrn Index of the screen 702 * \param ddx_version Version of the 2D DDX. This may not be meaningful for 703 * all drivers. 704 * \param dri_version Version of the "server-side" DRI. 705 * \param drm_version Version of the kernel DRM. 706 * \param frame_buffer Data describing the location and layout of the 707 * framebuffer. 708 * \param pSAREA Pointer to the SAREA. 709 * \param fd Device handle for the DRM. 710 * \param extensions ?? 711 * \param driver_modes Returns modes suppoted by the driver 712 * \param loaderPrivate ?? 713 * 714 * \note There is no need to check the minimum API version in this 715 * function. Since the name of this function is versioned, it is 716 * impossible for a loader that is too old to even load this driver. 717 */ 718static __DRIscreen * 719driCreateNewScreen(int scrn, 720 const __DRIversion *ddx_version, 721 const __DRIversion *dri_version, 722 const __DRIversion *drm_version, 723 const __DRIframebuffer *frame_buffer, 724 drmAddress pSAREA, int fd, 725 const __DRIextension **extensions, 726 const __DRIconfig ***driver_modes, 727 void *loaderPrivate) 728{ 729 static const __DRIextension *emptyExtensionList[] = { NULL }; 730 __DRIscreen *psp; 731 732 psp = calloc(1, sizeof *psp); 733 if (!psp) 734 return NULL; 735 736 setupLoaderExtensions(psp, extensions); 737 738 /* 739 ** NOT_DONE: This is used by the X server to detect when the client 740 ** has died while holding the drawable lock. The client sets the 741 ** drawable lock to this value. 742 */ 743 psp->drawLockID = 1; 744 745 psp->drm_version = *drm_version; 746 psp->ddx_version = *ddx_version; 747 psp->dri_version = *dri_version; 748 749 psp->pSAREA = pSAREA; 750 psp->lock = (drmLock *) &psp->pSAREA->lock; 751 752 psp->pFB = frame_buffer->base; 753 psp->fbSize = frame_buffer->size; 754 psp->fbStride = frame_buffer->stride; 755 psp->fbWidth = frame_buffer->width; 756 psp->fbHeight = frame_buffer->height; 757 psp->devPrivSize = frame_buffer->dev_priv_size; 758 psp->pDevPriv = frame_buffer->dev_priv; 759 psp->fbBPP = psp->fbStride * 8 / frame_buffer->width; 760 761 psp->extensions = emptyExtensionList; 762 psp->fd = fd; 763 psp->myNum = scrn; 764 psp->dri2.enabled = GL_FALSE; 765 766 psp->DriverAPI = driDriverAPI; 767 768 *driver_modes = driDriverAPI.InitScreen(psp); 769 if (*driver_modes == NULL) { 770 free(psp); 771 return NULL; 772 } 773 774 return psp; 775} 776 777/** 778 * DRI2 779 */ 780static __DRIscreen * 781dri2CreateNewScreen(int scrn, int fd, 782 const __DRIextension **extensions, 783 const __DRIconfig ***driver_configs, void *data) 784{ 785 static const __DRIextension *emptyExtensionList[] = { NULL }; 786 __DRIscreen *psp; 787 drmVersionPtr version; 788 driOptionCache options; 789 790 if (driDriverAPI.InitScreen2 == NULL) 791 return NULL; 792 793 psp = calloc(1, sizeof(*psp)); 794 if (!psp) 795 return NULL; 796 797 setupLoaderExtensions(psp, extensions); 798 799 version = drmGetVersion(fd); 800 if (version) { 801 psp->drm_version.major = version->version_major; 802 psp->drm_version.minor = version->version_minor; 803 psp->drm_version.patch = version->version_patchlevel; 804 drmFreeVersion(version); 805 } 806 807 psp->extensions = emptyExtensionList; 808 psp->fd = fd; 809 psp->myNum = scrn; 810 psp->dri2.enabled = GL_TRUE; 811 812 psp->DriverAPI = driDriverAPI; 813 *driver_configs = driDriverAPI.InitScreen2(psp); 814 if (*driver_configs == NULL) { 815 free(psp); 816 return NULL; 817 } 818 819 psp->DriverAPI = driDriverAPI; 820 821 driParseOptionInfo(&options, __dri2ConfigOptions, __dri2NConfigOptions); 822 driParseConfigFiles(&psp->optionCache, &options, psp->myNum, "dri2"); 823 824 return psp; 825} 826 827static const __DRIextension **driGetExtensions(__DRIscreen *psp) 828{ 829 return psp->extensions; 830} 831 832/** Core interface */ 833const __DRIcoreExtension driCoreExtension = { 834 { __DRI_CORE, __DRI_CORE_VERSION }, 835 NULL, 836 driDestroyScreen, 837 driGetExtensions, 838 driGetConfigAttrib, 839 driIndexConfigAttrib, 840 NULL, 841 driDestroyDrawable, 842 driSwapBuffers, 843 NULL, 844 driCopyContext, 845 driDestroyContext, 846 driBindContext, 847 driUnbindContext 848}; 849 850/** Legacy DRI interface */ 851const __DRIlegacyExtension driLegacyExtension = { 852 { __DRI_LEGACY, __DRI_LEGACY_VERSION }, 853 driCreateNewScreen, 854 driCreateNewDrawable, 855 driCreateNewContext, 856}; 857 858/** DRI2 interface */ 859const __DRIdri2Extension driDRI2Extension = { 860 { __DRI_DRI2, __DRI_DRI2_VERSION }, 861 dri2CreateNewScreen, 862 dri2CreateNewDrawable, 863 dri2CreateNewContext, 864}; 865 866const __DRI2configQueryExtension dri2ConfigQueryExtension = { 867 { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION }, 868 dri2ConfigQueryb, 869 dri2ConfigQueryi, 870 dri2ConfigQueryf, 871}; 872 873static int 874driFrameTracking(__DRIdrawable *drawable, GLboolean enable) 875{ 876 return GLX_BAD_CONTEXT; 877} 878 879static int 880driQueryFrameTracking(__DRIdrawable *dpriv, 881 int64_t * sbc, int64_t * missedFrames, 882 float * lastMissedUsage, float * usage) 883{ 884 __DRIswapInfo sInfo; 885 int status; 886 int64_t ust; 887 __DRIscreen *psp = dpriv->driScreenPriv; 888 889 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo ); 890 if ( status == 0 ) { 891 *sbc = sInfo.swap_count; 892 *missedFrames = sInfo.swap_missed_count; 893 *lastMissedUsage = sInfo.swap_missed_usage; 894 895 (*psp->systemTime->getUST)( & ust ); 896 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust ); 897 } 898 899 return status; 900} 901 902const __DRIframeTrackingExtension driFrameTrackingExtension = { 903 { __DRI_FRAME_TRACKING, __DRI_FRAME_TRACKING_VERSION }, 904 driFrameTracking, 905 driQueryFrameTracking 906}; 907 908/** 909 * Calculate amount of swap interval used between GLX buffer swaps. 910 * 911 * The usage value, on the range [0,max], is the fraction of total swap 912 * interval time used between GLX buffer swaps is calculated. 913 * 914 * \f$p = t_d / (i * t_r)\f$ 915 * 916 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the 917 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time 918 * required for a single vertical refresh period (as returned by \c 919 * glXGetMscRateOML). 920 * 921 * See the documentation for the GLX_MESA_swap_frame_usage extension for more 922 * details. 923 * 924 * \param dPriv Pointer to the private drawable structure. 925 * \return If less than a single swap interval time period was required 926 * between GLX buffer swaps, a number greater than 0 and less than 927 * 1.0 is returned. If exactly one swap interval time period is 928 * required, 1.0 is returned, and if more than one is required then 929 * a number greater than 1.0 will be returned. 930 * 931 * \sa glXSwapIntervalSGI glXGetMscRateOML 932 * 933 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it 934 * be possible to cache the sync rate? 935 */ 936float 937driCalculateSwapUsage( __DRIdrawable *dPriv, int64_t last_swap_ust, 938 int64_t current_ust ) 939{ 940 int32_t n; 941 int32_t d; 942 int interval; 943 float usage = 1.0; 944 __DRIscreen *psp = dPriv->driScreenPriv; 945 946 if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) { 947 interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1; 948 949 950 /* We want to calculate 951 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get 952 * current_UST by calling __glXGetUST. last_swap_UST is stored in 953 * dPriv->swap_ust. interval has already been calculated. 954 * 955 * The only tricky part is us_per_refresh. us_per_refresh is 956 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it 957 * around and say us_per_refresh = 1000000 * d / n. Since this goes in 958 * the denominator of the final calculation, we calculate 959 * (interval * 1000000 * d) and move n into the numerator. 960 */ 961 962 usage = (current_ust - last_swap_ust); 963 usage *= n; 964 usage /= (interval * d); 965 usage /= 1000000.0; 966 } 967 968 return usage; 969} 970 971void 972dri2InvalidateDrawable(__DRIdrawable *drawable) 973{ 974 drawable->dri2.stamp++; 975} 976 977/*@}*/ 978