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