radeon_dri2.c revision 0974d292
1/* 2 * Copyright 2008 Kristian Høgsberg 3 * Copyright 2008 Jérôme Glisse 4 * 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation on the rights to use, copy, modify, merge, 11 * publish, distribute, sublicense, and/or sell copies of the Software, 12 * and to permit persons to whom the Software is furnished to do so, 13 * subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial 17 * portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR 23 * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 * DEALINGS IN THE SOFTWARE. 27 */ 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <sys/types.h> 33#include <sys/stat.h> 34#include <fcntl.h> 35#include <errno.h> 36 37#include "radeon.h" 38#include "radeon_dri2.h" 39#include "radeon_version.h" 40 41#ifdef RADEON_DRI2 42 43#include "radeon_bo_gem.h" 44 45#if DRI2INFOREC_VERSION >= 1 46#define USE_DRI2_1_1_0 47#endif 48 49#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0, 0) 50typedef DRI2BufferPtr BufferPtr; 51#else 52typedef DRI2Buffer2Ptr BufferPtr; 53#endif 54 55struct dri2_buffer_priv { 56 PixmapPtr pixmap; 57 unsigned int attachment; 58 unsigned int refcnt; 59}; 60 61 62#ifndef USE_DRI2_1_1_0 63static BufferPtr 64radeon_dri2_create_buffers(DrawablePtr drawable, 65 unsigned int *attachments, 66 int count) 67{ 68 ScreenPtr pScreen = drawable->pScreen; 69 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 70 RADEONInfoPtr info = RADEONPTR(pScrn); 71 BufferPtr buffers; 72 struct dri2_buffer_priv *privates; 73 PixmapPtr pixmap, depth_pixmap; 74 struct radeon_exa_pixmap_priv *driver_priv; 75 int i, r; 76 int flags = 0; 77 78 buffers = calloc(count, sizeof *buffers); 79 if (buffers == NULL) { 80 return NULL; 81 } 82 privates = calloc(count, sizeof(struct dri2_buffer_priv)); 83 if (privates == NULL) { 84 free(buffers); 85 return NULL; 86 } 87 88 depth_pixmap = NULL; 89 for (i = 0; i < count; i++) { 90 if (attachments[i] == DRI2BufferFrontLeft) { 91 if (drawable->type == DRAWABLE_PIXMAP) { 92 pixmap = (Pixmap*)drawable; 93 } else { 94 pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable); 95 } 96 pixmap->refcnt++; 97 } else if (attachments[i] == DRI2BufferStencil && depth_pixmap) { 98 pixmap = depth_pixmap; 99 pixmap->refcnt++; 100 } else { 101 /* tile the back buffer */ 102 switch(attachments[i]) { 103 case DRI2BufferDepth: 104 case DRI2BufferDepthStencil: 105 if (info->ChipFamily >= CHIP_FAMILY_R600) 106 /* macro is the preferred setting, but the 2D detiling for software 107 * fallbacks in mesa still has issues on some configurations 108 */ 109 flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 110 else 111 flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 112 break; 113 case DRI2BufferBackLeft: 114 case DRI2BufferBackRight: 115 case DRI2BufferFakeFrontLeft: 116 case DRI2BufferFakeFrontRight: 117 if (info->ChipFamily >= CHIP_FAMILY_R600) 118 /* macro is the preferred setting, but the 2D detiling for software 119 * fallbacks in mesa still has issues on some configurations 120 */ 121 flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 122 else 123 flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 124 break; 125 default: 126 flags = 0; 127 } 128 pixmap = (*pScreen->CreatePixmap)(pScreen, 129 drawable->width, 130 drawable->height, 131 drawable->depth, 132 flags); 133 } 134 135 if (attachments[i] == DRI2BufferDepth) { 136 depth_pixmap = pixmap; 137 } 138 info->exa_force_create = TRUE; 139 exaMoveInPixmap(pixmap); 140 info->exa_force_create = FALSE; 141 driver_priv = exaGetPixmapDriverPrivate(pixmap); 142 r = radeon_gem_get_kernel_name(driver_priv->bo, &buffers[i].name); 143 if (r) 144 return r; 145 146 buffers[i].attachment = attachments[i]; 147 buffers[i].pitch = pixmap->devKind; 148 buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8; 149 buffers[i].driverPrivate = &privates[i]; 150 buffers[i].flags = 0; 151 privates[i].pixmap = pixmap; 152 privates[i].attachment = attachments[i]; 153 } 154 return buffers; 155} 156#else 157static BufferPtr 158radeon_dri2_create_buffer(DrawablePtr drawable, 159 unsigned int attachment, 160 unsigned int format) 161{ 162 ScreenPtr pScreen = drawable->pScreen; 163 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 164 RADEONInfoPtr info = RADEONPTR(pScrn); 165 BufferPtr buffers; 166 struct dri2_buffer_priv *privates; 167 PixmapPtr pixmap, depth_pixmap; 168 struct radeon_exa_pixmap_priv *driver_priv; 169 int r; 170 int flags; 171 172 buffers = calloc(1, sizeof *buffers); 173 if (buffers == NULL) { 174 return NULL; 175 } 176 privates = calloc(1, sizeof(struct dri2_buffer_priv)); 177 if (privates == NULL) { 178 free(buffers); 179 return NULL; 180 } 181 182 depth_pixmap = NULL; 183 184 if (attachment == DRI2BufferFrontLeft) { 185 if (drawable->type == DRAWABLE_PIXMAP) { 186 pixmap = (PixmapPtr)drawable; 187 } else { 188 pixmap = (*pScreen->GetWindowPixmap)((WindowPtr)drawable); 189 } 190 pixmap->refcnt++; 191 } else if (attachment == DRI2BufferStencil && depth_pixmap) { 192 pixmap = depth_pixmap; 193 pixmap->refcnt++; 194 } else { 195 /* tile the back buffer */ 196 switch(attachment) { 197 case DRI2BufferDepth: 198 case DRI2BufferDepthStencil: 199 /* macro is the preferred setting, but the 2D detiling for software 200 * fallbacks in mesa still has issues on some configurations 201 */ 202 if (info->ChipFamily >= CHIP_FAMILY_R600) 203 flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 204 else 205 flags = RADEON_CREATE_PIXMAP_TILING_MACRO | RADEON_CREATE_PIXMAP_TILING_MICRO; 206 break; 207 case DRI2BufferBackLeft: 208 case DRI2BufferBackRight: 209 case DRI2BufferFakeFrontLeft: 210 case DRI2BufferFakeFrontRight: 211 if (info->ChipFamily >= CHIP_FAMILY_R600) 212 /* macro is the preferred setting, but the 2D detiling for software 213 * fallbacks in mesa still has issues on some configurations 214 */ 215 flags = RADEON_CREATE_PIXMAP_TILING_MICRO; 216 else 217 flags = RADEON_CREATE_PIXMAP_TILING_MACRO; 218 break; 219 default: 220 flags = 0; 221 } 222 pixmap = (*pScreen->CreatePixmap)(pScreen, 223 drawable->width, 224 drawable->height, 225 (format != 0)?format:drawable->depth, 226 flags); 227 } 228 229 if (attachment == DRI2BufferDepth) { 230 depth_pixmap = pixmap; 231 } 232 info->exa_force_create = TRUE; 233 exaMoveInPixmap(pixmap); 234 info->exa_force_create = FALSE; 235 driver_priv = exaGetPixmapDriverPrivate(pixmap); 236 r = radeon_gem_get_kernel_name(driver_priv->bo, &buffers->name); 237 if (r) 238 return NULL; 239 240 buffers->attachment = attachment; 241 buffers->pitch = pixmap->devKind; 242 buffers->cpp = pixmap->drawable.bitsPerPixel / 8; 243 buffers->driverPrivate = privates; 244 buffers->format = format; 245 buffers->flags = 0; /* not tiled */ 246 privates->pixmap = pixmap; 247 privates->attachment = attachment; 248 privates->refcnt = 1; 249 250 return buffers; 251} 252#endif 253 254#ifndef USE_DRI2_1_1_0 255static void 256radeon_dri2_destroy_buffers(DrawablePtr drawable, 257 BufferPtr buffers, 258 int count) 259{ 260 ScreenPtr pScreen = drawable->pScreen; 261 struct dri2_buffer_priv *private; 262 int i; 263 264 for (i = 0; i < count; i++) { 265 private = buffers[i].driverPrivate; 266 (*pScreen->DestroyPixmap)(private->pixmap); 267 } 268 if (buffers) { 269 free(buffers[0].driverPrivate); 270 free(buffers); 271 } 272} 273#else 274static void 275radeon_dri2_destroy_buffer(DrawablePtr drawable, BufferPtr buffers) 276{ 277 if(buffers) 278 { 279 ScreenPtr pScreen = drawable->pScreen; 280 struct dri2_buffer_priv *private = buffers->driverPrivate; 281 282 /* Trying to free an already freed buffer is unlikely to end well */ 283 if (private->refcnt == 0) { 284 ScrnInfoPtr scrn = xf86Screens[pScreen->myNum]; 285 286 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 287 "Attempted to destroy previously destroyed buffer.\ 288 This is a programming error\n"); 289 return; 290 } 291 292 private->refcnt--; 293 if (private->refcnt == 0) 294 { 295 (*pScreen->DestroyPixmap)(private->pixmap); 296 297 free(buffers->driverPrivate); 298 free(buffers); 299 } 300 } 301} 302#endif 303 304static void 305radeon_dri2_copy_region(DrawablePtr drawable, 306 RegionPtr region, 307 BufferPtr dest_buffer, 308 BufferPtr src_buffer) 309{ 310 struct dri2_buffer_priv *src_private = src_buffer->driverPrivate; 311 struct dri2_buffer_priv *dst_private = dest_buffer->driverPrivate; 312 ScreenPtr pScreen = drawable->pScreen; 313 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 314 DrawablePtr src_drawable; 315 DrawablePtr dst_drawable; 316 RegionPtr copy_clip; 317 GCPtr gc; 318 RADEONInfoPtr info = RADEONPTR(pScrn); 319 Bool vsync; 320 321 if (src_private->attachment == DRI2BufferFrontLeft) { 322 src_drawable = drawable; 323 } else { 324 src_drawable = &src_private->pixmap->drawable; 325 } 326 if (dst_private->attachment == DRI2BufferFrontLeft) { 327 dst_drawable = drawable; 328 } else { 329 dst_drawable = &dst_private->pixmap->drawable; 330 } 331 gc = GetScratchGC(dst_drawable->depth, pScreen); 332 copy_clip = REGION_CREATE(pScreen, NULL, 0); 333 REGION_COPY(pScreen, copy_clip, region); 334 (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 335 ValidateGC(dst_drawable, gc); 336 337 /* If this is a full buffer swap or frontbuffer flush, throttle on the 338 * previous one 339 */ 340 if (dst_private->attachment == DRI2BufferFrontLeft) { 341 if (REGION_NUM_RECTS(region) == 1) { 342 BoxPtr extents = REGION_EXTENTS(pScreen, region); 343 344 if (extents->x1 == 0 && extents->y1 == 0 && 345 extents->x2 == drawable->width && 346 extents->y2 == drawable->height) { 347 struct radeon_exa_pixmap_priv *exa_priv = 348 exaGetPixmapDriverPrivate(dst_private->pixmap); 349 350 if (exa_priv && exa_priv->bo) 351 radeon_bo_wait(exa_priv->bo); 352 } 353 } 354 } 355 356 vsync = info->accel_state->vsync; 357 info->accel_state->vsync = TRUE; 358 359 (*gc->ops->CopyArea)(src_drawable, dst_drawable, gc, 360 0, 0, drawable->width, drawable->height, 0, 0); 361 362 info->accel_state->vsync = vsync; 363 364 FreeScratchGC(gc); 365} 366 367 368#if DRI2INFOREC_VERSION >= 4 369 370enum DRI2FrameEventType { 371 DRI2_SWAP, 372 DRI2_FLIP, 373 DRI2_WAITMSC, 374}; 375 376typedef struct _DRI2FrameEvent { 377 XID drawable_id; 378 ClientPtr client; 379 int client_index; 380 enum DRI2FrameEventType type; 381 int frame; 382 383 /* for swaps & flips only */ 384 DRI2SwapEventPtr event_complete; 385 void *event_data; 386 DRI2BufferPtr front; 387 DRI2BufferPtr back; 388} DRI2FrameEventRec, *DRI2FrameEventPtr; 389 390static void 391radeon_dri2_ref_buffer(BufferPtr buffer) 392{ 393 struct dri2_buffer_priv *private = buffer->driverPrivate; 394 private->refcnt++; 395} 396 397static void 398radeon_dri2_unref_buffer(BufferPtr buffer) 399{ 400 if (buffer) { 401 struct dri2_buffer_priv *private = buffer->driverPrivate; 402 radeon_dri2_destroy_buffer(&(private->pixmap->drawable), buffer); 403 } 404} 405 406void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, 407 unsigned int tv_usec, void *event_data) 408{ 409 DRI2FrameEventPtr event = event_data; 410 DrawablePtr drawable; 411 ClientPtr client; 412 ScreenPtr screen; 413 ScrnInfoPtr scrn; 414 int status; 415 int swap_type; 416 BoxRec box; 417 RegionRec region; 418 419 status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, 420 M_ANY, DixWriteAccess); 421 if (status != Success) { 422 radeon_dri2_unref_buffer(event->front); 423 radeon_dri2_unref_buffer(event->back); 424 free(event); 425 return; 426 } 427 428 screen = drawable->pScreen; 429 scrn = xf86Screens[screen->myNum]; 430 431 /* event->client may have quit between submitting a request 432 * and this callback being triggered. 433 * 434 * Check our saved client pointer against the client in the saved client 435 * slot. This will catch almost all cases where the client that requested 436 * SwapBuffers has gone away, and will guarantee that there is at least a 437 * valid client to write the BufferSwapComplete event to. 438 */ 439 client = event->client == clients[event->client_index] ? 440 event->client : NULL; 441 442 switch (event->type) { 443 case DRI2_FLIP: 444 case DRI2_SWAP: 445 box.x1 = 0; 446 box.y1 = 0; 447 box.x2 = drawable->width; 448 box.y2 = drawable->height; 449 REGION_INIT(pScreen, ®ion, &box, 0); 450 radeon_dri2_copy_region(drawable, ®ion, event->front, event->back); 451 swap_type = DRI2_BLIT_COMPLETE; 452 453 DRI2SwapComplete(client, drawable, frame, tv_sec, tv_usec, 454 swap_type, event->event_complete, event->event_data); 455 456 radeon_dri2_unref_buffer(event->front); 457 radeon_dri2_unref_buffer(event->back); 458 break; 459 case DRI2_WAITMSC: 460 DRI2WaitMSCComplete(client, drawable, frame, tv_sec, tv_usec); 461 break; 462 default: 463 /* Unknown type */ 464 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 465 "%s: unknown vblank event received\n", __func__); 466 break; 467 } 468 469 free(event); 470} 471 472static int radeon_dri2_drawable_crtc(DrawablePtr pDraw) 473{ 474 ScreenPtr pScreen = pDraw->pScreen; 475 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 476 xf86CrtcPtr crtc; 477 int crtc_id = -1; 478 479 crtc = radeon_pick_best_crtc(pScrn, 480 pDraw->x, 481 pDraw->x + pDraw->width, 482 pDraw->y, 483 pDraw->y + pDraw->height); 484 485 /* Make sure the CRTC is valid and this is the real front buffer */ 486 if (crtc != NULL && !crtc->rotatedData) { 487 crtc_id = drmmode_get_crtc_id(crtc); 488 } 489 return crtc_id; 490} 491 492/* 493 * Get current frame count and frame count timestamp, based on drawable's 494 * crtc. 495 */ 496static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 497{ 498 ScreenPtr screen = draw->pScreen; 499 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 500 RADEONInfoPtr info = RADEONPTR(scrn); 501 drmVBlank vbl; 502 int ret; 503 int crtc= radeon_dri2_drawable_crtc(draw); 504 505 /* Drawable not displayed, make up a value */ 506 if (crtc == -1) { 507 *ust = 0; 508 *msc = 0; 509 return TRUE; 510 } 511 vbl.request.type = DRM_VBLANK_RELATIVE; 512 if (crtc > 0) 513 vbl.request.type |= DRM_VBLANK_SECONDARY; 514 vbl.request.sequence = 0; 515 516 ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 517 if (ret) { 518 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 519 "get vblank counter failed: %s\n", strerror(errno)); 520 return FALSE; 521 } 522 523 *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; 524 *msc = vbl.reply.sequence; 525 526 return TRUE; 527} 528 529/* 530 * Request a DRM event when the requested conditions will be satisfied. 531 * 532 * We need to handle the event and ask the server to wake up the client when 533 * we receive it. 534 */ 535static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, 536 CARD64 target_msc, CARD64 divisor, 537 CARD64 remainder) 538{ 539 ScreenPtr screen = draw->pScreen; 540 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 541 RADEONInfoPtr info = RADEONPTR(scrn); 542 DRI2FrameEventPtr wait_info; 543 drmVBlank vbl; 544 int ret, crtc = radeon_dri2_drawable_crtc(draw); 545 CARD64 current_msc; 546 547 /* Truncate to match kernel interfaces; means occasional overflow 548 * misses, but that's generally not a big deal */ 549 target_msc &= 0xffffffff; 550 divisor &= 0xffffffff; 551 remainder &= 0xffffffff; 552 553 /* Drawable not visible, return immediately */ 554 if (crtc == -1) 555 goto out_complete; 556 557 wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 558 if (!wait_info) 559 goto out_complete; 560 561 wait_info->drawable_id = draw->id; 562 wait_info->client = client; 563 wait_info->client_index = client->index; 564 wait_info->type = DRI2_WAITMSC; 565 566 /* Get current count */ 567 vbl.request.type = DRM_VBLANK_RELATIVE; 568 if (crtc > 0) 569 vbl.request.type |= DRM_VBLANK_SECONDARY; 570 vbl.request.sequence = 0; 571 ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 572 if (ret) { 573 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 574 "get vblank counter failed: %s\n", strerror(errno)); 575 goto out_complete; 576 } 577 578 current_msc = vbl.reply.sequence; 579 580 /* 581 * If divisor is zero, or current_msc is smaller than target_msc, 582 * we just need to make sure target_msc passes before waking up the 583 * client. 584 */ 585 if (divisor == 0 || current_msc < target_msc) { 586 /* If target_msc already reached or passed, set it to 587 * current_msc to ensure we return a reasonable value back 588 * to the caller. This keeps the client from continually 589 * sending us MSC targets from the past by forcibly updating 590 * their count on this call. 591 */ 592 if (current_msc >= target_msc) 593 target_msc = current_msc; 594 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 595 if (crtc > 0) 596 vbl.request.type |= DRM_VBLANK_SECONDARY; 597 vbl.request.sequence = target_msc; 598 vbl.request.signal = (unsigned long)wait_info; 599 ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 600 if (ret) { 601 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 602 "get vblank counter failed: %s\n", strerror(errno)); 603 goto out_complete; 604 } 605 606 wait_info->frame = vbl.reply.sequence; 607 DRI2BlockClient(client, draw); 608 return TRUE; 609 } 610 611 /* 612 * If we get here, target_msc has already passed or we don't have one, 613 * so we queue an event that will satisfy the divisor/remainder equation. 614 */ 615 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 616 if (crtc > 0) 617 vbl.request.type |= DRM_VBLANK_SECONDARY; 618 619 vbl.request.sequence = current_msc - (current_msc % divisor) + 620 remainder; 621 622 /* 623 * If calculated remainder is larger than requested remainder, 624 * it means we've passed the last point where 625 * seq % divisor == remainder, so we need to wait for the next time 626 * that will happen. 627 */ 628 if ((current_msc % divisor) >= remainder) 629 vbl.request.sequence += divisor; 630 631 vbl.request.signal = (unsigned long)wait_info; 632 ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 633 if (ret) { 634 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 635 "get vblank counter failed: %s\n", strerror(errno)); 636 goto out_complete; 637 } 638 639 wait_info->frame = vbl.reply.sequence; 640 DRI2BlockClient(client, draw); 641 642 return TRUE; 643 644out_complete: 645 DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); 646 return TRUE; 647} 648 649/* 650 * ScheduleSwap is responsible for requesting a DRM vblank event for the 651 * appropriate frame. 652 * 653 * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 654 * the vblank requested can simply be the last queued swap frame + the swap 655 * interval for the drawable. 656 * 657 * In the case of a page flip, we request an event for the last queued swap 658 * frame + swap interval - 1, since we'll need to queue the flip for the frame 659 * immediately following the received event. 660 * 661 * The client will be blocked if it tries to perform further GL commands 662 * after queueing a swap, though in the Intel case after queueing a flip, the 663 * client is free to queue more commands; they'll block in the kernel if 664 * they access buffers busy with the flip. 665 * 666 * When the swap is complete, the driver should call into the server so it 667 * can send any swap complete events that have been requested. 668 */ 669static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, 670 DRI2BufferPtr front, DRI2BufferPtr back, 671 CARD64 *target_msc, CARD64 divisor, 672 CARD64 remainder, DRI2SwapEventPtr func, 673 void *data) 674{ 675 ScreenPtr screen = draw->pScreen; 676 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 677 RADEONInfoPtr info = RADEONPTR(scrn); 678 drmVBlank vbl; 679 int ret, crtc= radeon_dri2_drawable_crtc(draw), flip = 0; 680 DRI2FrameEventPtr swap_info; 681 enum DRI2FrameEventType swap_type = DRI2_SWAP; 682 CARD64 current_msc; 683 BoxRec box; 684 RegionRec region; 685 686 /* Truncate to match kernel interfaces; means occasional overflow 687 * misses, but that's generally not a big deal */ 688 *target_msc &= 0xffffffff; 689 divisor &= 0xffffffff; 690 remainder &= 0xffffffff; 691 692 swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 693 694 /* radeon_dri2_frame_event_handler will get called some unknown time in the 695 * future with these buffers. Take a reference to ensure that they won't 696 * get destroyed before then. 697 */ 698 radeon_dri2_ref_buffer(front); 699 radeon_dri2_ref_buffer(back); 700 701 /* Drawable not displayed... just complete the swap */ 702 if (crtc == -1 || !swap_info) 703 goto blit_fallback; 704 705 swap_info->drawable_id = draw->id; 706 swap_info->client = client; 707 swap_info->client_index = client->index; 708 swap_info->event_complete = func; 709 swap_info->event_data = data; 710 swap_info->front = front; 711 swap_info->back = back; 712 713 /* Get current count */ 714 vbl.request.type = DRM_VBLANK_RELATIVE; 715 if (crtc > 0) 716 vbl.request.type |= DRM_VBLANK_SECONDARY; 717 vbl.request.sequence = 0; 718 ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 719 if (ret) { 720 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 721 "first get vblank counter failed: %s\n", 722 strerror(errno)); 723 goto blit_fallback; 724 } 725 726 current_msc = vbl.reply.sequence; 727 swap_info->type = swap_type; 728 729 /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. 730 * Do it early, so handling of different timing constraints 731 * for divisor, remainder and msc vs. target_msc works. 732 */ 733 if (*target_msc > 0) 734 *target_msc -= flip; 735 736 /* 737 * If divisor is zero, or current_msc is smaller than target_msc 738 * we just need to make sure target_msc passes before initiating 739 * the swap. 740 */ 741 if (divisor == 0 || current_msc < *target_msc) { 742 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 743 if (crtc > 0) 744 vbl.request.type |= DRM_VBLANK_SECONDARY; 745 746 /* If non-pageflipping, but blitting/exchanging, we need to use 747 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 748 * on. 749 */ 750 if (flip == 0) 751 vbl.request.type |= DRM_VBLANK_NEXTONMISS; 752 if (crtc > 0) 753 vbl.request.type |= DRM_VBLANK_SECONDARY; 754 755 /* If target_msc already reached or passed, set it to 756 * current_msc to ensure we return a reasonable value back 757 * to the caller. This makes swap_interval logic more robust. 758 */ 759 if (current_msc >= *target_msc) 760 *target_msc = current_msc; 761 762 vbl.request.sequence = *target_msc; 763 vbl.request.signal = (unsigned long)swap_info; 764 ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 765 if (ret) { 766 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 767 "divisor 0 get vblank counter failed: %s\n", 768 strerror(errno)); 769 goto blit_fallback; 770 } 771 772 *target_msc = vbl.reply.sequence + flip; 773 swap_info->frame = *target_msc; 774 775 return TRUE; 776 } 777 778 /* 779 * If we get here, target_msc has already passed or we don't have one, 780 * and we need to queue an event that will satisfy the divisor/remainder 781 * equation. 782 */ 783 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; 784 if (flip == 0) 785 vbl.request.type |= DRM_VBLANK_NEXTONMISS; 786 if (crtc > 0) 787 vbl.request.type |= DRM_VBLANK_SECONDARY; 788 789 vbl.request.sequence = current_msc - (current_msc % divisor) + 790 remainder; 791 792 /* 793 * If the calculated deadline vbl.request.sequence is smaller than 794 * or equal to current_msc, it means we've passed the last point 795 * when effective onset frame seq could satisfy 796 * seq % divisor == remainder, so we need to wait for the next time 797 * this will happen. 798 799 * This comparison takes the 1 frame swap delay in pageflipping mode 800 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 801 * if we are blitting/exchanging instead of flipping. 802 */ 803 if (vbl.request.sequence <= current_msc) 804 vbl.request.sequence += divisor; 805 806 /* Account for 1 frame extra pageflip delay if flip > 0 */ 807 vbl.request.sequence -= flip; 808 809 vbl.request.signal = (unsigned long)swap_info; 810 ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); 811 if (ret) { 812 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 813 "final get vblank counter failed: %s\n", 814 strerror(errno)); 815 goto blit_fallback; 816 } 817 818 /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 819 *target_msc = vbl.reply.sequence + flip; 820 swap_info->frame = *target_msc; 821 822 return TRUE; 823 824blit_fallback: 825 box.x1 = 0; 826 box.y1 = 0; 827 box.x2 = draw->width; 828 box.y2 = draw->height; 829 REGION_INIT(pScreen, ®ion, &box, 0); 830 831 radeon_dri2_copy_region(draw, ®ion, front, back); 832 833 DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 834 if (swap_info) 835 free(swap_info); 836 837 radeon_dri2_unref_buffer(front); 838 radeon_dri2_unref_buffer(back); 839 840 *target_msc = 0; /* offscreen, so zero out target vblank count */ 841 return TRUE; 842} 843 844#endif /* DRI2INFOREC_VERSION >= 4 */ 845 846 847Bool 848radeon_dri2_screen_init(ScreenPtr pScreen) 849{ 850 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 851 RADEONInfoPtr info = RADEONPTR(pScrn); 852 DRI2InfoRec dri2_info = { 0 }; 853#if DRI2INFOREC_VERSION >= 4 854 const char *driverNames[1]; 855#endif 856 857 if (!info->useEXA) { 858 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requires EXA\n"); 859 return FALSE; 860 } 861 862 info->dri2.device_name = drmGetDeviceNameFromFd(info->dri2.drm_fd); 863 864 if ( (info->ChipFamily >= CHIP_FAMILY_R600) ) { 865 dri2_info.driverName = R600_DRIVER_NAME; 866 } else if ( (info->ChipFamily >= CHIP_FAMILY_R300) ) { 867 dri2_info.driverName = R300_DRIVER_NAME; 868 } else if ( info->ChipFamily >= CHIP_FAMILY_R200 ) { 869 dri2_info.driverName = R200_DRIVER_NAME; 870 } else { 871 dri2_info.driverName = RADEON_DRIVER_NAME; 872 } 873 dri2_info.fd = info->dri2.drm_fd; 874 dri2_info.deviceName = info->dri2.device_name; 875#ifndef USE_DRI2_1_1_0 876 dri2_info.version = 1; 877 dri2_info.CreateBuffers = radeon_dri2_create_buffers; 878 dri2_info.DestroyBuffers = radeon_dri2_destroy_buffers; 879#else 880 dri2_info.version = DRI2INFOREC_VERSION; 881 dri2_info.CreateBuffer = radeon_dri2_create_buffer; 882 dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer; 883#endif 884 dri2_info.CopyRegion = radeon_dri2_copy_region; 885 886#if DRI2INFOREC_VERSION >= 4 887 if (info->dri->pKernelDRMVersion->version_minor >= 4) { 888 dri2_info.version = 4; 889 dri2_info.ScheduleSwap = radeon_dri2_schedule_swap; 890 dri2_info.GetMSC = radeon_dri2_get_msc; 891 dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc; 892 dri2_info.numDrivers = 1; 893 dri2_info.driverNames = driverNames; 894 driverNames[0] = dri2_info.driverName; 895 } else { 896 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for sync extension\n"); 897 } 898#endif 899 900 info->dri2.enabled = DRI2ScreenInit(pScreen, &dri2_info); 901 return info->dri2.enabled; 902} 903 904void radeon_dri2_close_screen(ScreenPtr pScreen) 905{ 906 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 907 RADEONInfoPtr info = RADEONPTR(pScrn); 908 909 DRI2CloseScreen(pScreen); 910 drmFree(info->dri2.device_name); 911} 912 913#endif 914