intel_dri.c revision 03b705cf
1/************************************************************************** 2 3Copyright 2001 VA Linux Systems Inc., Fremont, California. 4Copyright © 2002 by David Dawes 5 6All Rights Reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a 9copy of this software and associated documentation files (the "Software"), 10to deal in the Software without restriction, including without limitation 11on the rights to use, copy, modify, merge, publish, distribute, sub 12license, and/or sell copies of the Software, and to permit persons to whom 13the Software is furnished to do so, subject to the following conditions: 14 15The above copyright notice and this permission notice (including the next 16paragraph) shall be included in all copies or substantial portions of the 17Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 23DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25USE OR OTHER DEALINGS IN THE SOFTWARE. 26 27**************************************************************************/ 28 29/* 30 * Authors: Jeff Hartmann <jhartmann@valinux.com> 31 * David Dawes <dawes@xfree86.org> 32 * Keith Whitwell <keith@tungstengraphics.com> 33 */ 34 35#ifdef HAVE_CONFIG_H 36#include "config.h" 37#endif 38 39#include <stdio.h> 40#include <string.h> 41#include <assert.h> 42#include <sys/types.h> 43#include <sys/stat.h> 44#include <sys/ioctl.h> 45#include <unistd.h> 46#include <fcntl.h> 47#include <sys/time.h> 48#include <time.h> 49#include <errno.h> 50 51#include "xf86.h" 52#include "xf86_OSproc.h" 53 54#include "xf86Pci.h" 55#include "xf86drm.h" 56 57#include "windowstr.h" 58#include "shadow.h" 59#include "fb.h" 60 61#include "intel.h" 62#include "i830_reg.h" 63 64#include "i915_drm.h" 65 66#include "dri2.h" 67 68#include "intel_glamor.h" 69#include "uxa.h" 70 71typedef struct { 72 int refcnt; 73 PixmapPtr pixmap; 74} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr; 75 76#if HAS_DEVPRIVATEKEYREC 77static DevPrivateKeyRec i830_client_key; 78#else 79static int i830_client_key; 80#endif 81 82static uint32_t pixmap_flink(PixmapPtr pixmap) 83{ 84 struct intel_pixmap *priv = intel_get_pixmap_private(pixmap); 85 uint32_t name; 86 87 if (priv == NULL || priv->bo == NULL) 88 return 0; 89 90 if (dri_bo_flink(priv->bo, &name) != 0) 91 return 0; 92 93 priv->pinned |= PIN_DRI; 94 return name; 95} 96 97static PixmapPtr get_front_buffer(DrawablePtr drawable) 98{ 99 PixmapPtr pixmap; 100 101 pixmap = get_drawable_pixmap(drawable); 102 if (!intel_get_pixmap_bo(pixmap)) 103 return NULL; 104 105 pixmap->refcnt++; 106 return pixmap; 107} 108 109static PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap) 110{ 111 ScreenPtr screen = drawable->pScreen; 112 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 113 intel_screen_private *intel = intel_get_screen_private(scrn); 114 PixmapPtr old = get_drawable_pixmap(drawable); 115 struct intel_pixmap *priv = intel_get_pixmap_private(pixmap); 116 GCPtr gc; 117 118 /* With a glamor pixmap, 2D pixmaps are created in texture 119 * and without a static BO attached to it. To support DRI, 120 * we need to create a new textured-drm pixmap and 121 * need to copy the original content to this new textured-drm 122 * pixmap, and then convert the old pixmap to a coherent 123 * textured-drm pixmap which has a valid BO attached to it 124 * and also has a valid texture, thus both glamor and DRI2 125 * can access it. 126 * 127 */ 128 129 /* Copy the current contents of the pixmap to the bo. */ 130 gc = GetScratchGC(drawable->depth, screen); 131 if (gc) { 132 ValidateGC(&pixmap->drawable, gc); 133 gc->ops->CopyArea(drawable, &pixmap->drawable, 134 gc, 135 0, 0, 136 drawable->width, 137 drawable->height, 138 0, 0); 139 FreeScratchGC(gc); 140 } 141 142 intel_set_pixmap_private(pixmap, NULL); 143 144 /* Exchange the underlying texture/image. */ 145 intel_glamor_exchange_buffers(intel, old, pixmap); 146 /* And redirect the pixmap to the new bo (for 3D). */ 147 intel_set_pixmap_private(old, priv); 148 old->refcnt++; 149 150 screen->ModifyPixmapHeader(old, 151 drawable->width, 152 drawable->height, 153 0, 0, 154 priv->stride, 155 NULL); 156 screen->DestroyPixmap(pixmap); 157 intel_get_screen_private(xf86ScreenToScrn(screen))->needs_flush = TRUE; 158 return old; 159} 160 161#if DRI2INFOREC_VERSION < 2 162static DRI2BufferPtr 163I830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments, 164 int count) 165{ 166 ScreenPtr screen = drawable->pScreen; 167 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 168 intel_screen_private *intel = intel_get_screen_private(scrn); 169 DRI2BufferPtr buffers; 170 I830DRI2BufferPrivatePtr privates; 171 PixmapPtr pixmap, pDepthPixmap; 172 Bool is_glamor_pixmap = FALSE; 173 int i; 174 175 buffers = calloc(count, sizeof *buffers); 176 if (buffers == NULL) 177 return NULL; 178 privates = calloc(count, sizeof *privates); 179 if (privates == NULL) { 180 free(buffers); 181 return NULL; 182 } 183 184 pDepthPixmap = NULL; 185 for (i = 0; i < count; i++) { 186 pixmap = NULL; 187 if (attachments[i] == DRI2BufferFrontLeft) { 188 pixmap = get_front_buffer(drawable); 189 190 if (pixmap == NULL) { 191 drawable = &(get_drawable_pixmap(drawable)->drawable); 192 is_glamor_pixmap = TRUE; 193 } 194 } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) { 195 pixmap = pDepthPixmap; 196 pixmap->refcnt++; 197 } 198 199 if (pixmap == NULL) { 200 unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 201 202 if (intel->tiling & INTEL_TILING_3D) { 203 switch (attachments[i]) { 204 case DRI2BufferDepth: 205 if (SUPPORTS_YTILING(intel)) 206 hint |= INTEL_CREATE_PIXMAP_TILING_Y; 207 else 208 hint |= INTEL_CREATE_PIXMAP_TILING_X; 209 break; 210 case DRI2BufferFakeFrontLeft: 211 case DRI2BufferFakeFrontRight: 212 case DRI2BufferBackLeft: 213 case DRI2BufferBackRight: 214 hint |= INTEL_CREATE_PIXMAP_TILING_X; 215 break; 216 } 217 } 218 219 pixmap = screen->CreatePixmap(screen, 220 drawable->width, 221 drawable->height, 222 drawable->depth, 223 hint); 224 if (pixmap == NULL || 225 intel_get_pixmap_bo(pixmap) == NULL) 226 { 227 if (pixmap) 228 screen->DestroyPixmap(pixmap); 229 goto unwind; 230 } 231 232 if (is_glamor_pixmap) 233 pixmap = fixup_glamor(drawable, pixmap); 234 } 235 236 if (attachments[i] == DRI2BufferDepth) 237 pDepthPixmap = pixmap; 238 239 buffers[i].attachment = attachments[i]; 240 buffers[i].pitch = pixmap->devKind; 241 buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8; 242 buffers[i].driverPrivate = &privates[i]; 243 buffers[i].flags = 0; /* not tiled */ 244 privates[i].refcnt = 1; 245 privates[i].pixmap = pixmap; 246 247 if ((buffers[i].name = pixmap_flink(pixmap)) == 0) { 248 /* failed to name buffer */ 249 screen->DestroyPixmap(pixmap); 250 goto unwind; 251 } 252 } 253 254 return buffers; 255 256unwind: 257 while (i--) 258 screen->DestroyPixmap(privates[i].pixmap); 259 free(privates); 260 free(buffers); 261 return NULL; 262} 263 264static void 265I830DRI2DestroyBuffers(DrawablePtr drawable, DRI2BufferPtr buffers, int count) 266{ 267 ScreenPtr screen = drawable->pScreen; 268 I830DRI2BufferPrivatePtr private; 269 int i; 270 271 for (i = 0; i < count; i++) { 272 private = buffers[i].driverPrivate; 273 screen->DestroyPixmap(private->pixmap); 274 } 275 276 if (buffers) { 277 free(buffers[0].driverPrivate); 278 free(buffers); 279 } 280} 281 282#else 283 284static DRI2Buffer2Ptr 285I830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment, 286 unsigned int format) 287{ 288 ScreenPtr screen = drawable->pScreen; 289 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 290 intel_screen_private *intel = intel_get_screen_private(scrn); 291 DRI2Buffer2Ptr buffer; 292 I830DRI2BufferPrivatePtr privates; 293 PixmapPtr pixmap; 294 Bool is_glamor_pixmap = FALSE; 295 296 buffer = calloc(1, sizeof *buffer); 297 if (buffer == NULL) 298 return NULL; 299 privates = calloc(1, sizeof *privates); 300 if (privates == NULL) { 301 free(buffer); 302 return NULL; 303 } 304 305 pixmap = NULL; 306 if (attachment == DRI2BufferFrontLeft) { 307 pixmap = get_front_buffer(drawable); 308 309 if (pixmap == NULL) { 310 drawable = &(get_drawable_pixmap(drawable)->drawable); 311 is_glamor_pixmap = TRUE; 312 } 313 } 314 315 if (pixmap == NULL) { 316 unsigned int hint = INTEL_CREATE_PIXMAP_DRI2; 317 int pixmap_width = drawable->width; 318 int pixmap_height = drawable->height; 319 int pixmap_cpp = (format != 0) ? format : drawable->depth; 320 321 if (intel->tiling & INTEL_TILING_3D) { 322 switch (attachment) { 323 case DRI2BufferDepth: 324 case DRI2BufferDepthStencil: 325 case DRI2BufferHiz: 326 if (SUPPORTS_YTILING(intel)) { 327 hint |= INTEL_CREATE_PIXMAP_TILING_Y; 328 break; 329 } 330 case DRI2BufferAccum: 331 case DRI2BufferBackLeft: 332 case DRI2BufferBackRight: 333 case DRI2BufferFakeFrontLeft: 334 case DRI2BufferFakeFrontRight: 335 case DRI2BufferFrontLeft: 336 case DRI2BufferFrontRight: 337 hint |= INTEL_CREATE_PIXMAP_TILING_X; 338 break; 339 case DRI2BufferStencil: 340 /* 341 * The stencil buffer is W tiled. However, we 342 * request from the kernel a non-tiled buffer 343 * because the GTT is incapable of W fencing. 344 */ 345 hint |= INTEL_CREATE_PIXMAP_TILING_NONE; 346 break; 347 default: 348 free(privates); 349 free(buffer); 350 return NULL; 351 } 352 } 353 354 /* 355 * The stencil buffer has quirky pitch requirements. From Vol 356 * 2a, 11.5.6.2.1 3DSTATE_STENCIL_BUFFER, field "Surface 357 * Pitch": 358 * The pitch must be set to 2x the value computed based on 359 * width, as the stencil buffer is stored with two rows 360 * interleaved. 361 * To accomplish this, we resort to the nasty hack of doubling 362 * the drm region's cpp and halving its height. 363 * 364 * If we neglect to double the pitch, then render corruption 365 * occurs. 366 */ 367 if (attachment == DRI2BufferStencil) { 368 pixmap_width = ALIGN(pixmap_width, 64); 369 pixmap_height = ALIGN((pixmap_height + 1) / 2, 64); 370 pixmap_cpp *= 2; 371 } 372 373 pixmap = screen->CreatePixmap(screen, 374 pixmap_width, 375 pixmap_height, 376 pixmap_cpp, 377 hint); 378 if (pixmap == NULL || intel_get_pixmap_bo(pixmap) == NULL) { 379 if (pixmap) 380 screen->DestroyPixmap(pixmap); 381 free(privates); 382 free(buffer); 383 return NULL; 384 } 385 if (is_glamor_pixmap) 386 pixmap = fixup_glamor(drawable, pixmap); 387 } 388 389 buffer->attachment = attachment; 390 buffer->pitch = pixmap->devKind; 391 buffer->cpp = pixmap->drawable.bitsPerPixel / 8; 392 buffer->driverPrivate = privates; 393 buffer->format = format; 394 buffer->flags = 0; /* not tiled */ 395 privates->refcnt = 1; 396 privates->pixmap = pixmap; 397 398 if ((buffer->name = pixmap_flink(pixmap)) == 0) { 399 /* failed to name buffer */ 400 screen->DestroyPixmap(pixmap); 401 free(privates); 402 free(buffer); 403 return NULL; 404 } 405 406 return buffer; 407} 408 409static void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer) 410{ 411 if (buffer && buffer->driverPrivate) { 412 I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 413 if (--private->refcnt == 0) { 414 ScreenPtr screen = private->pixmap->drawable.pScreen; 415 screen->DestroyPixmap(private->pixmap); 416 417 free(private); 418 free(buffer); 419 } 420 } else 421 free(buffer); 422} 423 424#endif 425 426static void 427I830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion, 428 DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer) 429{ 430 I830DRI2BufferPrivatePtr srcPrivate = sourceBuffer->driverPrivate; 431 I830DRI2BufferPrivatePtr dstPrivate = destBuffer->driverPrivate; 432 ScreenPtr screen = drawable->pScreen; 433 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 434 intel_screen_private *intel = intel_get_screen_private(scrn); 435 DrawablePtr src = (sourceBuffer->attachment == DRI2BufferFrontLeft) 436 ? drawable : &srcPrivate->pixmap->drawable; 437 DrawablePtr dst = (destBuffer->attachment == DRI2BufferFrontLeft) 438 ? drawable : &dstPrivate->pixmap->drawable; 439 RegionPtr pCopyClip; 440 GCPtr gc; 441 442 gc = GetScratchGC(dst->depth, screen); 443 if (!gc) 444 return; 445 446 pCopyClip = REGION_CREATE(screen, NULL, 0); 447 REGION_COPY(screen, pCopyClip, pRegion); 448 (*gc->funcs->ChangeClip) (gc, CT_REGION, pCopyClip, 0); 449 ValidateGC(dst, gc); 450 451 /* Wait for the scanline to be outside the region to be copied */ 452 if (scrn->vtSema && 453 pixmap_is_scanout(get_drawable_pixmap(dst)) && 454 intel->swapbuffers_wait && INTEL_INFO(intel)->gen < 060) { 455 BoxPtr box; 456 BoxRec crtcbox; 457 int y1, y2; 458 int event, load_scan_lines_pipe; 459 xf86CrtcPtr crtc; 460 Bool full_height = FALSE; 461 462 box = REGION_EXTENTS(unused, gc->pCompositeClip); 463 crtc = intel_covering_crtc(scrn, box, NULL, &crtcbox); 464 465 /* 466 * Make sure the CRTC is valid and this is the real front 467 * buffer 468 */ 469 if (crtc != NULL && !crtc->rotatedData) { 470 int pipe = intel_crtc_to_pipe(crtc); 471 472 /* 473 * Make sure we don't wait for a scanline that will 474 * never occur 475 */ 476 y1 = (crtcbox.y1 <= box->y1) ? box->y1 - crtcbox.y1 : 0; 477 y2 = (box->y2 <= crtcbox.y2) ? 478 box->y2 - crtcbox.y1 : crtcbox.y2 - crtcbox.y1; 479 480 if (y1 == 0 && y2 == (crtcbox.y2 - crtcbox.y1)) 481 full_height = TRUE; 482 483 /* 484 * Pre-965 doesn't have SVBLANK, so we need a bit 485 * of extra time for the blitter to start up and 486 * do its job for a full height blit 487 */ 488 if (full_height && INTEL_INFO(intel)->gen < 040) 489 y2 -= 2; 490 491 if (pipe == 0) { 492 event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 493 load_scan_lines_pipe = 494 MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 495 if (full_height && INTEL_INFO(intel)->gen >= 040) 496 event = MI_WAIT_FOR_PIPEA_SVBLANK; 497 } else { 498 event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 499 load_scan_lines_pipe = 500 MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 501 if (full_height && INTEL_INFO(intel)->gen >= 040) 502 event = MI_WAIT_FOR_PIPEB_SVBLANK; 503 } 504 505 if (crtc->mode.Flags & V_INTERLACE) { 506 /* DSL count field lines */ 507 y1 /= 2; 508 y2 /= 2; 509 } 510 511 BEGIN_BATCH(5); 512 /* 513 * The documentation says that the LOAD_SCAN_LINES 514 * command always comes in pairs. Don't ask me why. 515 */ 516 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 517 load_scan_lines_pipe); 518 OUT_BATCH((y1 << 16) | (y2-1)); 519 OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | 520 load_scan_lines_pipe); 521 OUT_BATCH((y1 << 16) | (y2-1)); 522 OUT_BATCH(MI_WAIT_FOR_EVENT | event); 523 ADVANCE_BATCH(); 524 } 525 } 526 527 /* It's important that this copy gets submitted before the 528 * direct rendering client submits rendering for the next 529 * frame, but we don't actually need to submit right now. The 530 * client will wait for the DRI2CopyRegion reply or the swap 531 * buffer event before rendering, and we'll hit the flush 532 * callback chain before those messages are sent. We submit 533 * our batch buffers from the flush callback chain so we know 534 * that will happen before the client tries to render 535 * again. */ 536 537 gc->ops->CopyArea(src, dst, gc, 538 0, 0, 539 drawable->width, drawable->height, 540 0, 0); 541 542 FreeScratchGC(gc); 543 544 /* And make sure the WAIT_FOR_EVENT is queued before any 545 * modesetting/dpms operations on the pipe. 546 */ 547 intel_batch_submit(scrn); 548} 549 550static void 551I830DRI2FallbackBlitSwap(DrawablePtr drawable, 552 DRI2BufferPtr dst, 553 DRI2BufferPtr src) 554{ 555 BoxRec box; 556 RegionRec region; 557 558 box.x1 = 0; 559 box.y1 = 0; 560 box.x2 = drawable->width; 561 box.y2 = drawable->height; 562 REGION_INIT(pScreen, ®ion, &box, 0); 563 564 I830DRI2CopyRegion(drawable, ®ion, dst, src); 565} 566 567#if DRI2INFOREC_VERSION >= 4 568 569static void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer) 570{ 571 if (buffer) { 572 I830DRI2BufferPrivatePtr private = buffer->driverPrivate; 573 private->refcnt++; 574 } 575} 576 577static int 578I830DRI2DrawablePipe(DrawablePtr pDraw) 579{ 580 ScreenPtr pScreen = pDraw->pScreen; 581 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 582 BoxRec box, crtcbox; 583 xf86CrtcPtr crtc; 584 int pipe = -1; 585 586 box.x1 = pDraw->x; 587 box.y1 = pDraw->y; 588 box.x2 = box.x1 + pDraw->width; 589 box.y2 = box.y1 + pDraw->height; 590 591 crtc = intel_covering_crtc(pScrn, &box, NULL, &crtcbox); 592 593 /* Make sure the CRTC is valid and this is the real front buffer */ 594 if (crtc != NULL && !crtc->rotatedData) 595 pipe = intel_crtc_to_pipe(crtc); 596 597 return pipe; 598} 599 600static RESTYPE frame_event_client_type, frame_event_drawable_type; 601 602struct i830_dri2_resource { 603 XID id; 604 RESTYPE type; 605 struct list list; 606}; 607 608static struct i830_dri2_resource * 609get_resource(XID id, RESTYPE type) 610{ 611 struct i830_dri2_resource *resource; 612 void *ptr; 613 614 ptr = NULL; 615 dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess); 616 if (ptr) 617 return ptr; 618 619 resource = malloc(sizeof(*resource)); 620 if (resource == NULL) 621 return NULL; 622 623 if (!AddResource(id, type, resource)) { 624 free(resource); 625 return NULL; 626 } 627 628 resource->id = id; 629 resource->type = type; 630 list_init(&resource->list); 631 return resource; 632} 633 634static int 635i830_dri2_frame_event_client_gone(void *data, XID id) 636{ 637 struct i830_dri2_resource *resource = data; 638 639 while (!list_is_empty(&resource->list)) { 640 DRI2FrameEventPtr info = 641 list_first_entry(&resource->list, 642 DRI2FrameEventRec, 643 client_resource); 644 645 list_del(&info->client_resource); 646 info->client = NULL; 647 } 648 free(resource); 649 650 return Success; 651} 652 653static int 654i830_dri2_frame_event_drawable_gone(void *data, XID id) 655{ 656 struct i830_dri2_resource *resource = data; 657 658 while (!list_is_empty(&resource->list)) { 659 DRI2FrameEventPtr info = 660 list_first_entry(&resource->list, 661 DRI2FrameEventRec, 662 drawable_resource); 663 664 list_del(&info->drawable_resource); 665 info->drawable_id = None; 666 } 667 free(resource); 668 669 return Success; 670} 671 672static Bool 673i830_dri2_register_frame_event_resource_types(void) 674{ 675 frame_event_client_type = CreateNewResourceType(i830_dri2_frame_event_client_gone, "Frame Event Client"); 676 if (!frame_event_client_type) 677 return FALSE; 678 679 frame_event_drawable_type = CreateNewResourceType(i830_dri2_frame_event_drawable_gone, "Frame Event Drawable"); 680 if (!frame_event_drawable_type) 681 return FALSE; 682 683 return TRUE; 684} 685 686static XID 687get_client_id(ClientPtr client) 688{ 689#if HAS_DIXREGISTERPRIVATEKEY 690 XID *ptr = dixGetPrivateAddr(&client->devPrivates, &i830_client_key); 691#else 692 XID *ptr = dixLookupPrivate(&client->devPrivates, &i830_client_key); 693#endif 694 if (*ptr == 0) 695 *ptr = FakeClientID(client->index); 696 return *ptr; 697} 698 699/* 700 * Hook this frame event into the server resource 701 * database so we can clean it up if the drawable or 702 * client exits while the swap is pending 703 */ 704static Bool 705i830_dri2_add_frame_event(DRI2FrameEventPtr info) 706{ 707 struct i830_dri2_resource *resource; 708 709 resource = get_resource(get_client_id(info->client), 710 frame_event_client_type); 711 if (resource == NULL) 712 return FALSE; 713 714 list_add(&info->client_resource, &resource->list); 715 716 resource = get_resource(info->drawable_id, frame_event_drawable_type); 717 if (resource == NULL) { 718 list_del(&info->client_resource); 719 return FALSE; 720 } 721 722 list_add(&info->drawable_resource, &resource->list); 723 724 return TRUE; 725} 726 727static void 728i830_dri2_del_frame_event(DrawablePtr drawable, DRI2FrameEventPtr info) 729{ 730 list_del(&info->client_resource); 731 list_del(&info->drawable_resource); 732 733 if (info->front) 734 I830DRI2DestroyBuffer(drawable, info->front); 735 if (info->back) 736 I830DRI2DestroyBuffer(drawable, info->back); 737 738 free(info); 739} 740 741static struct intel_pixmap * 742intel_exchange_pixmap_buffers(struct intel_screen_private *intel, PixmapPtr front, PixmapPtr back) 743{ 744 struct intel_pixmap *new_front, *new_back; 745 RegionRec region; 746 747 /* Post damage on the front buffer so that listeners, such 748 * as DisplayLink know take a copy and shove it over the USB. 749 * also for sw cursors. 750 */ 751 region.extents.x1 = region.extents.y1 = 0; 752 region.extents.x2 = front->drawable.width; 753 region.extents.y2 = front->drawable.height; 754 region.data = NULL; 755 DamageRegionAppend(&front->drawable, ®ion); 756 757 new_front = intel_get_pixmap_private(back); 758 new_back = intel_get_pixmap_private(front); 759 intel_set_pixmap_private(front, new_front); 760 intel_set_pixmap_private(back, new_back); 761 new_front->busy = 1; 762 new_back->busy = -1; 763 764 intel_glamor_exchange_buffers(intel, front, back); 765 766 DamageRegionProcessPending(&front->drawable); 767 768 return new_front; 769} 770 771static void 772I830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back) 773{ 774 I830DRI2BufferPrivatePtr front_priv, back_priv; 775 int tmp; 776 struct intel_pixmap *new_front; 777 778 front_priv = front->driverPrivate; 779 back_priv = back->driverPrivate; 780 781 /* Swap BO names so DRI works */ 782 tmp = front->name; 783 front->name = back->name; 784 back->name = tmp; 785 786 /* Swap pixmap bos */ 787 new_front = intel_exchange_pixmap_buffers(intel, 788 front_priv->pixmap, 789 back_priv->pixmap); 790 dri_bo_unreference (intel->front_buffer); 791 intel->front_buffer = new_front->bo; 792 dri_bo_reference (intel->front_buffer); 793} 794 795static PixmapPtr 796intel_glamor_create_back_pixmap(ScreenPtr screen, 797 PixmapPtr front_pixmap, 798 drm_intel_bo *back_bo) 799{ 800 PixmapPtr back_pixmap; 801 802 back_pixmap = screen->CreatePixmap(screen, 803 0, 804 0, 805 front_pixmap->drawable.depth, 806 0); 807 if (back_pixmap == NULL) 808 return NULL; 809 810 screen->ModifyPixmapHeader(back_pixmap, 811 front_pixmap->drawable.width, 812 front_pixmap->drawable.height, 813 0, 0, 814 front_pixmap->devKind, 815 0); 816 intel_set_pixmap_bo(back_pixmap, back_bo); 817 if (!intel_glamor_create_textured_pixmap(back_pixmap)) { 818 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 819 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 820 "Failed to create textured back pixmap.\n"); 821 screen->DestroyPixmap(back_pixmap); 822 return NULL; 823 } 824 return back_pixmap; 825} 826 827static drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv) 828{ 829 drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap); 830 assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */ 831 return bo; 832} 833 834/* 835 * Our internal swap routine takes care of actually exchanging, blitting, or 836 * flipping buffers as necessary. 837 */ 838static Bool 839I830DRI2ScheduleFlip(struct intel_screen_private *intel, 840 DrawablePtr draw, 841 DRI2FrameEventPtr info) 842{ 843 I830DRI2BufferPrivatePtr priv = info->back->driverPrivate; 844 drm_intel_bo *new_back, *old_back; 845 int tmp_name; 846 847 if (!intel->use_triple_buffer) { 848 info->type = DRI2_SWAP; 849 if (!intel_do_pageflip(intel, 850 get_pixmap_bo(priv), 851 info, info->pipe)) 852 return FALSE; 853 854 I830DRI2ExchangeBuffers(intel, info->front, info->back); 855 return TRUE; 856 } 857 858 if (intel->pending_flip[info->pipe]) { 859 assert(intel->pending_flip[info->pipe]->chain == NULL); 860 intel->pending_flip[info->pipe]->chain = info; 861 return TRUE; 862 } 863 864 if (intel->back_buffer == NULL) { 865 I830DRI2BufferPrivatePtr priv; 866 PixmapPtr front_pixmap, back_pixmap; 867 ScreenPtr screen; 868 869 new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer", 870 intel->front_buffer->size, 0); 871 if (new_back == NULL) 872 return FALSE; 873 874 if (intel->front_tiling != I915_TILING_NONE) { 875 uint32_t tiling = intel->front_tiling; 876 drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch); 877 if (tiling != intel->front_tiling) { 878 drm_intel_bo_unreference(new_back); 879 return FALSE; 880 } 881 } 882 883 drm_intel_bo_disable_reuse(new_back); 884 dri_bo_flink(new_back, &intel->back_name); 885 886 if ((intel->uxa_flags & UXA_USE_GLAMOR)) { 887 screen = draw->pScreen; 888 priv = info->front->driverPrivate; 889 front_pixmap = priv->pixmap; 890 891 back_pixmap = intel_glamor_create_back_pixmap(screen, 892 front_pixmap, 893 new_back); 894 if (back_pixmap == NULL) { 895 drm_intel_bo_unreference(new_back); 896 return FALSE; 897 } 898 intel->back_pixmap = back_pixmap; 899 } 900 } else { 901 new_back = intel->back_buffer; 902 intel->back_buffer = NULL; 903 } 904 905 old_back = get_pixmap_bo(priv); 906 if (!intel_do_pageflip(intel, old_back, info, info->pipe)) { 907 intel->back_buffer = new_back; 908 return FALSE; 909 } 910 info->type = DRI2_SWAP_CHAIN; 911 intel->pending_flip[info->pipe] = info; 912 913 priv = info->front->driverPrivate; 914 915 /* Exchange the current front-buffer with the fresh bo */ 916 917 intel->back_buffer = intel->front_buffer; 918 drm_intel_bo_reference(intel->back_buffer); 919 if (!(intel->uxa_flags & UXA_USE_GLAMOR)) { 920 intel_set_pixmap_bo(priv->pixmap, new_back); 921 drm_intel_bo_unreference(new_back); 922 } 923 else 924 intel_exchange_pixmap_buffers(intel, priv->pixmap, 925 intel->back_pixmap); 926 927 tmp_name = info->front->name; 928 info->front->name = intel->back_name; 929 intel->back_name = tmp_name; 930 931 /* Then flip DRI2 pointers and update the screen pixmap */ 932 I830DRI2ExchangeBuffers(intel, info->front, info->back); 933 DRI2SwapComplete(info->client, draw, 0, 0, 0, 934 DRI2_EXCHANGE_COMPLETE, 935 info->event_complete, 936 info->event_data); 937 return TRUE; 938} 939 940static Bool 941can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back) 942{ 943 ScrnInfoPtr pScrn = xf86ScreenToScrn(drawable->pScreen); 944 struct intel_screen_private *intel = intel_get_screen_private(pScrn); 945 I830DRI2BufferPrivatePtr front_priv = front->driverPrivate; 946 I830DRI2BufferPrivatePtr back_priv = back->driverPrivate; 947 PixmapPtr front_pixmap = front_priv->pixmap; 948 PixmapPtr back_pixmap = back_priv->pixmap; 949 struct intel_pixmap *front_intel = intel_get_pixmap_private(front_pixmap); 950 struct intel_pixmap *back_intel = intel_get_pixmap_private(back_pixmap); 951 952 if (!pScrn->vtSema) 953 return FALSE; 954 955 if (I830DRI2DrawablePipe(drawable) < 0) 956 return FALSE; 957 958 if (!DRI2CanFlip(drawable)) 959 return FALSE; 960 961 if (intel->shadow_present) 962 return FALSE; 963 964 if (!intel->use_pageflipping) 965 return FALSE; 966 967 if (front_pixmap->drawable.width != back_pixmap->drawable.width) 968 return FALSE; 969 970 if (front_pixmap->drawable.height != back_pixmap->drawable.height) 971 return FALSE; 972 973 /* XXX should we be checking depth instead of bpp? */ 974#if 0 975 if (front_pixmap->drawable.depth != back_pixmap->drawable.depth) 976 return FALSE; 977#else 978 if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) 979 return FALSE; 980#endif 981 982 /* prevent an implicit tiling mode change */ 983 if (front_intel->tiling != back_intel->tiling) 984 return FALSE; 985 986 return TRUE; 987} 988 989void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec, 990 unsigned int tv_usec, DRI2FrameEventPtr swap_info) 991{ 992 intel_screen_private *intel = swap_info->intel; 993 DrawablePtr drawable; 994 int status; 995 996 if (!swap_info->drawable_id) 997 status = BadDrawable; 998 else 999 status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient, 1000 M_ANY, DixWriteAccess); 1001 if (status != Success) { 1002 i830_dri2_del_frame_event(NULL, swap_info); 1003 return; 1004 } 1005 1006 1007 switch (swap_info->type) { 1008 case DRI2_FLIP: 1009 /* If we can still flip... */ 1010 if (can_exchange(drawable, swap_info->front, swap_info->back) && 1011 I830DRI2ScheduleFlip(intel, drawable, swap_info)) 1012 return; 1013 1014 /* else fall through to exchange/blit */ 1015 case DRI2_SWAP: { 1016 I830DRI2FallbackBlitSwap(drawable, 1017 swap_info->front, swap_info->back); 1018 DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec, 1019 DRI2_BLIT_COMPLETE, 1020 swap_info->client ? swap_info->event_complete : NULL, 1021 swap_info->event_data); 1022 break; 1023 } 1024 case DRI2_WAITMSC: 1025 if (swap_info->client) 1026 DRI2WaitMSCComplete(swap_info->client, drawable, 1027 frame, tv_sec, tv_usec); 1028 break; 1029 default: 1030 xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 1031 "%s: unknown vblank event received\n", __func__); 1032 /* Unknown type */ 1033 break; 1034 } 1035 1036 i830_dri2_del_frame_event(drawable, swap_info); 1037} 1038 1039void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec, 1040 unsigned int tv_usec, DRI2FrameEventPtr flip_info) 1041{ 1042 struct intel_screen_private *intel = flip_info->intel; 1043 DrawablePtr drawable; 1044 DRI2FrameEventPtr chain; 1045 1046 drawable = NULL; 1047 if (flip_info->drawable_id) 1048 dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient, 1049 M_ANY, DixWriteAccess); 1050 1051 1052 /* We assume our flips arrive in order, so we don't check the frame */ 1053 switch (flip_info->type) { 1054 case DRI2_SWAP: 1055 if (!drawable) 1056 break; 1057 1058 /* Check for too small vblank count of pageflip completion, taking wraparound 1059 * into account. This usually means some defective kms pageflip completion, 1060 * causing wrong (msc, ust) return values and possible visual corruption. 1061 */ 1062 if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) { 1063 static int limit = 5; 1064 1065 /* XXX we are currently hitting this path with older 1066 * kernels, so make it quieter. 1067 */ 1068 if (limit) { 1069 xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 1070 "%s: Pageflip completion has impossible msc %d < target_msc %d\n", 1071 __func__, frame, flip_info->frame); 1072 limit--; 1073 } 1074 1075 /* All-0 values signal timestamping failure. */ 1076 frame = tv_sec = tv_usec = 0; 1077 } 1078 1079 DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec, 1080 DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL, 1081 flip_info->event_data); 1082 break; 1083 1084 case DRI2_SWAP_CHAIN: 1085 assert(intel->pending_flip[flip_info->pipe] == flip_info); 1086 intel->pending_flip[flip_info->pipe] = NULL; 1087 1088 chain = flip_info->chain; 1089 if (chain) { 1090 DrawablePtr chain_drawable = NULL; 1091 if (chain->drawable_id) 1092 dixLookupDrawable(&chain_drawable, 1093 chain->drawable_id, 1094 serverClient, 1095 M_ANY, DixWriteAccess); 1096 if (chain_drawable == NULL) { 1097 i830_dri2_del_frame_event(chain_drawable, chain); 1098 } else if (!can_exchange(chain_drawable, chain->front, chain->back) || 1099 !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) { 1100 I830DRI2FallbackBlitSwap(chain_drawable, 1101 chain->front, 1102 chain->back); 1103 1104 DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec, 1105 DRI2_BLIT_COMPLETE, 1106 chain->client ? chain->event_complete : NULL, 1107 chain->event_data); 1108 i830_dri2_del_frame_event(chain_drawable, chain); 1109 } 1110 } 1111 break; 1112 1113 default: 1114 xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING, 1115 "%s: unknown vblank event received\n", __func__); 1116 /* Unknown type */ 1117 break; 1118 } 1119 1120 i830_dri2_del_frame_event(drawable, flip_info); 1121} 1122 1123static uint32_t pipe_select(int pipe) 1124{ 1125 if (pipe > 1) 1126 return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 1127 else if (pipe > 0) 1128 return DRM_VBLANK_SECONDARY; 1129 else 1130 return 0; 1131} 1132 1133/* 1134 * ScheduleSwap is responsible for requesting a DRM vblank event for the 1135 * appropriate frame. 1136 * 1137 * In the case of a blit (e.g. for a windowed swap) or buffer exchange, 1138 * the vblank requested can simply be the last queued swap frame + the swap 1139 * interval for the drawable. 1140 * 1141 * In the case of a page flip, we request an event for the last queued swap 1142 * frame + swap interval - 1, since we'll need to queue the flip for the frame 1143 * immediately following the received event. 1144 * 1145 * The client will be blocked if it tries to perform further GL commands 1146 * after queueing a swap, though in the Intel case after queueing a flip, the 1147 * client is free to queue more commands; they'll block in the kernel if 1148 * they access buffers busy with the flip. 1149 * 1150 * When the swap is complete, the driver should call into the server so it 1151 * can send any swap complete events that have been requested. 1152 */ 1153static int 1154I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, 1155 DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor, 1156 CARD64 remainder, DRI2SwapEventPtr func, void *data) 1157{ 1158 ScreenPtr screen = draw->pScreen; 1159 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1160 intel_screen_private *intel = intel_get_screen_private(scrn); 1161 drmVBlank vbl; 1162 int ret, pipe = I830DRI2DrawablePipe(draw), flip = 0; 1163 DRI2FrameEventPtr swap_info = NULL; 1164 enum DRI2FrameEventType swap_type = DRI2_SWAP; 1165 CARD64 current_msc; 1166 1167 /* Drawable not displayed... just complete the swap */ 1168 if (pipe == -1) 1169 goto blit_fallback; 1170 1171 /* Truncate to match kernel interfaces; means occasional overflow 1172 * misses, but that's generally not a big deal */ 1173 *target_msc &= 0xffffffff; 1174 divisor &= 0xffffffff; 1175 remainder &= 0xffffffff; 1176 1177 swap_info = calloc(1, sizeof(DRI2FrameEventRec)); 1178 if (!swap_info) 1179 goto blit_fallback; 1180 1181 swap_info->intel = intel; 1182 swap_info->drawable_id = draw->id; 1183 swap_info->client = client; 1184 swap_info->event_complete = func; 1185 swap_info->event_data = data; 1186 swap_info->front = front; 1187 swap_info->back = back; 1188 swap_info->pipe = pipe; 1189 1190 if (!i830_dri2_add_frame_event(swap_info)) { 1191 free(swap_info); 1192 swap_info = NULL; 1193 goto blit_fallback; 1194 } 1195 1196 I830DRI2ReferenceBuffer(front); 1197 I830DRI2ReferenceBuffer(back); 1198 1199 /* Get current count */ 1200 vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe); 1201 vbl.request.sequence = 0; 1202 ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1203 if (ret) { 1204 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1205 "first get vblank counter failed: %s\n", 1206 strerror(errno)); 1207 goto blit_fallback; 1208 } 1209 1210 current_msc = vbl.reply.sequence; 1211 1212 /* Flips need to be submitted one frame before */ 1213 if (can_exchange(draw, front, back)) { 1214 swap_type = DRI2_FLIP; 1215 flip = 1; 1216 } 1217 1218 swap_info->type = swap_type; 1219 1220 /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. 1221 * Do it early, so handling of different timing constraints 1222 * for divisor, remainder and msc vs. target_msc works. 1223 */ 1224 if (*target_msc > 0) 1225 *target_msc -= flip; 1226 1227 /* 1228 * If divisor is zero, or current_msc is smaller than target_msc 1229 * we just need to make sure target_msc passes before initiating 1230 * the swap. 1231 */ 1232 if (divisor == 0 || current_msc < *target_msc) { 1233 /* 1234 * If we can, schedule the flip directly from here rather 1235 * than waiting for an event from the kernel for the current 1236 * (or a past) MSC. 1237 */ 1238 if (flip && divisor == 0 && current_msc >= *target_msc && 1239 I830DRI2ScheduleFlip(intel, draw, swap_info)) 1240 return TRUE; 1241 1242 vbl.request.type = 1243 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 1244 1245 /* If non-pageflipping, but blitting/exchanging, we need to use 1246 * DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later 1247 * on. 1248 */ 1249 if (flip == 0) 1250 vbl.request.type |= DRM_VBLANK_NEXTONMISS; 1251 1252 /* If target_msc already reached or passed, set it to 1253 * current_msc to ensure we return a reasonable value back 1254 * to the caller. This makes swap_interval logic more robust. 1255 */ 1256 if (current_msc >= *target_msc) 1257 *target_msc = current_msc; 1258 1259 vbl.request.sequence = *target_msc; 1260 vbl.request.signal = (unsigned long)swap_info; 1261 ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1262 if (ret) { 1263 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1264 "divisor 0 get vblank counter failed: %s\n", 1265 strerror(errno)); 1266 goto blit_fallback; 1267 } 1268 1269 *target_msc = vbl.reply.sequence + flip; 1270 swap_info->frame = *target_msc; 1271 1272 return TRUE; 1273 } 1274 1275 /* 1276 * If we get here, target_msc has already passed or we don't have one, 1277 * and we need to queue an event that will satisfy the divisor/remainder 1278 * equation. 1279 */ 1280 vbl.request.type = 1281 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 1282 if (flip == 0) 1283 vbl.request.type |= DRM_VBLANK_NEXTONMISS; 1284 1285 vbl.request.sequence = current_msc - (current_msc % divisor) + 1286 remainder; 1287 1288 /* 1289 * If the calculated deadline vbl.request.sequence is smaller than 1290 * or equal to current_msc, it means we've passed the last point 1291 * when effective onset frame seq could satisfy 1292 * seq % divisor == remainder, so we need to wait for the next time 1293 * this will happen. 1294 1295 * This comparison takes the 1 frame swap delay in pageflipping mode 1296 * into account, as well as a potential DRM_VBLANK_NEXTONMISS delay 1297 * if we are blitting/exchanging instead of flipping. 1298 */ 1299 if (vbl.request.sequence <= current_msc) 1300 vbl.request.sequence += divisor; 1301 1302 /* Account for 1 frame extra pageflip delay if flip > 0 */ 1303 vbl.request.sequence -= flip; 1304 1305 vbl.request.signal = (unsigned long)swap_info; 1306 ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1307 if (ret) { 1308 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1309 "final get vblank counter failed: %s\n", 1310 strerror(errno)); 1311 goto blit_fallback; 1312 } 1313 1314 /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ 1315 *target_msc = vbl.reply.sequence + flip; 1316 swap_info->frame = *target_msc; 1317 1318 return TRUE; 1319 1320blit_fallback: 1321 I830DRI2FallbackBlitSwap(draw, front, back); 1322 DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); 1323 if (swap_info) 1324 i830_dri2_del_frame_event(draw, swap_info); 1325 *target_msc = 0; /* offscreen, so zero out target vblank count */ 1326 return TRUE; 1327} 1328 1329static uint64_t gettime_us(void) 1330{ 1331 struct timespec tv; 1332 1333 if (clock_gettime(CLOCK_MONOTONIC, &tv)) 1334 return 0; 1335 1336 return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000; 1337} 1338 1339/* 1340 * Get current frame count and frame count timestamp, based on drawable's 1341 * crtc. 1342 */ 1343static int 1344I830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc) 1345{ 1346 ScreenPtr screen = draw->pScreen; 1347 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1348 intel_screen_private *intel = intel_get_screen_private(scrn); 1349 drmVBlank vbl; 1350 int ret, pipe = I830DRI2DrawablePipe(draw); 1351 1352 /* Drawable not displayed, make up a *monotonic* value */ 1353 if (pipe == -1) { 1354 *ust = gettime_us(); 1355 *msc = 0; 1356 return TRUE; 1357 } 1358 1359 vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe); 1360 vbl.request.sequence = 0; 1361 1362 ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1363 if (ret) { 1364 static int limit = 5; 1365 if (limit) { 1366 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1367 "%s:%d get vblank counter failed: %s\n", 1368 __FUNCTION__, __LINE__, 1369 strerror(errno)); 1370 limit--; 1371 } 1372 return FALSE; 1373 } 1374 1375 *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; 1376 *msc = vbl.reply.sequence; 1377 1378 return TRUE; 1379} 1380 1381/* 1382 * Request a DRM event when the requested conditions will be satisfied. 1383 * 1384 * We need to handle the event and ask the server to wake up the client when 1385 * we receive it. 1386 */ 1387static int 1388I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc, 1389 CARD64 divisor, CARD64 remainder) 1390{ 1391 ScreenPtr screen = draw->pScreen; 1392 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1393 intel_screen_private *intel = intel_get_screen_private(scrn); 1394 DRI2FrameEventPtr wait_info; 1395 drmVBlank vbl; 1396 int ret, pipe = I830DRI2DrawablePipe(draw); 1397 CARD64 current_msc; 1398 1399 /* Truncate to match kernel interfaces; means occasional overflow 1400 * misses, but that's generally not a big deal */ 1401 target_msc &= 0xffffffff; 1402 divisor &= 0xffffffff; 1403 remainder &= 0xffffffff; 1404 1405 /* Drawable not visible, return immediately */ 1406 if (pipe == -1) 1407 goto out_complete; 1408 1409 wait_info = calloc(1, sizeof(DRI2FrameEventRec)); 1410 if (!wait_info) 1411 goto out_complete; 1412 1413 wait_info->intel = intel; 1414 wait_info->drawable_id = draw->id; 1415 wait_info->client = client; 1416 wait_info->type = DRI2_WAITMSC; 1417 1418 if (!i830_dri2_add_frame_event(wait_info)) { 1419 free(wait_info); 1420 wait_info = NULL; 1421 goto out_complete; 1422 } 1423 1424 /* Get current count */ 1425 vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe); 1426 vbl.request.sequence = 0; 1427 ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1428 if (ret) { 1429 static int limit = 5; 1430 if (limit) { 1431 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1432 "%s:%d get vblank counter failed: %s\n", 1433 __FUNCTION__, __LINE__, 1434 strerror(errno)); 1435 limit--; 1436 } 1437 goto out_free; 1438 } 1439 1440 current_msc = vbl.reply.sequence; 1441 1442 /* 1443 * If divisor is zero, or current_msc is smaller than target_msc, 1444 * we just need to make sure target_msc passes before waking up the 1445 * client. 1446 */ 1447 if (divisor == 0 || current_msc < target_msc) { 1448 /* If target_msc already reached or passed, set it to 1449 * current_msc to ensure we return a reasonable value back 1450 * to the caller. This keeps the client from continually 1451 * sending us MSC targets from the past by forcibly updating 1452 * their count on this call. 1453 */ 1454 if (current_msc >= target_msc) 1455 target_msc = current_msc; 1456 vbl.request.type = 1457 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 1458 vbl.request.sequence = target_msc; 1459 vbl.request.signal = (unsigned long)wait_info; 1460 ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1461 if (ret) { 1462 static int limit = 5; 1463 if (limit) { 1464 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1465 "%s:%d get vblank counter failed: %s\n", 1466 __FUNCTION__, __LINE__, 1467 strerror(errno)); 1468 limit--; 1469 } 1470 goto out_free; 1471 } 1472 1473 wait_info->frame = vbl.reply.sequence; 1474 DRI2BlockClient(client, draw); 1475 return TRUE; 1476 } 1477 1478 /* 1479 * If we get here, target_msc has already passed or we don't have one, 1480 * so we queue an event that will satisfy the divisor/remainder equation. 1481 */ 1482 vbl.request.type = 1483 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe); 1484 1485 vbl.request.sequence = current_msc - (current_msc % divisor) + 1486 remainder; 1487 1488 /* 1489 * If calculated remainder is larger than requested remainder, 1490 * it means we've passed the last point where 1491 * seq % divisor == remainder, so we need to wait for the next time 1492 * that will happen. 1493 */ 1494 if ((current_msc % divisor) >= remainder) 1495 vbl.request.sequence += divisor; 1496 1497 vbl.request.signal = (unsigned long)wait_info; 1498 ret = drmWaitVBlank(intel->drmSubFD, &vbl); 1499 if (ret) { 1500 static int limit = 5; 1501 if (limit) { 1502 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1503 "%s:%d get vblank counter failed: %s\n", 1504 __FUNCTION__, __LINE__, 1505 strerror(errno)); 1506 limit--; 1507 } 1508 goto out_free; 1509 } 1510 1511 wait_info->frame = vbl.reply.sequence; 1512 DRI2BlockClient(client, draw); 1513 1514 return TRUE; 1515 1516out_free: 1517 i830_dri2_del_frame_event(draw, wait_info); 1518out_complete: 1519 DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); 1520 return TRUE; 1521} 1522 1523static int dri2_server_generation; 1524#endif 1525 1526static int has_i830_dri(void) 1527{ 1528 return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0; 1529} 1530 1531static const char *dri_driver_name(intel_screen_private *intel) 1532{ 1533 const char *s = xf86GetOptValString(intel->Options, OPTION_DRI); 1534 Bool dummy; 1535 1536 if (s == NULL || xf86getBoolValue(&dummy, s)) { 1537 if (INTEL_INFO(intel)->gen < 030) 1538 return has_i830_dri() ? "i830" : "i915"; 1539 else if (INTEL_INFO(intel)->gen < 040) 1540 return "i915"; 1541 else 1542 return "i965"; 1543 } 1544 1545 return s; 1546} 1547 1548Bool I830DRI2ScreenInit(ScreenPtr screen) 1549{ 1550 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1551 intel_screen_private *intel = intel_get_screen_private(scrn); 1552 DRI2InfoRec info; 1553 int dri2_major = 1; 1554 int dri2_minor = 0; 1555#if DRI2INFOREC_VERSION >= 4 1556 const char *driverNames[1]; 1557#endif 1558 1559 if (intel->force_fallback) { 1560 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1561 "cannot enable DRI2 whilst forcing software fallbacks\n"); 1562 return FALSE; 1563 } 1564 1565 if (xf86LoaderCheckSymbol("DRI2Version")) 1566 DRI2Version(&dri2_major, &dri2_minor); 1567 1568 if (dri2_minor < 1) { 1569 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1570 "DRI2 requires DRI2 module version 1.1.0 or later\n"); 1571 return FALSE; 1572 } 1573 1574#if HAS_DIXREGISTERPRIVATEKEY 1575 if (!dixRegisterPrivateKey(&i830_client_key, PRIVATE_CLIENT, sizeof(XID))) 1576 return FALSE; 1577#else 1578 if (!dixRequestPrivate(&i830_client_key, sizeof(XID))) 1579 return FALSE; 1580#endif 1581 1582 1583#if DRI2INFOREC_VERSION >= 4 1584 if (serverGeneration != dri2_server_generation) { 1585 dri2_server_generation = serverGeneration; 1586 if (!i830_dri2_register_frame_event_resource_types()) { 1587 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1588 "Cannot register DRI2 frame event resources\n"); 1589 return FALSE; 1590 } 1591 } 1592#endif 1593 1594 intel->deviceName = drmGetDeviceNameFromFd(intel->drmSubFD); 1595 memset(&info, '\0', sizeof(info)); 1596 info.fd = intel->drmSubFD; 1597 info.driverName = dri_driver_name(intel); 1598 info.deviceName = intel->deviceName; 1599 1600#if DRI2INFOREC_VERSION == 1 1601 info.version = 1; 1602 info.CreateBuffers = I830DRI2CreateBuffers; 1603 info.DestroyBuffers = I830DRI2DestroyBuffers; 1604#elif DRI2INFOREC_VERSION == 2 1605 /* The ABI between 2 and 3 was broken so we could get rid of 1606 * the multi-buffer alloc functions. Make sure we indicate the 1607 * right version so DRI2 can reject us if it's version 3 or above. */ 1608 info.version = 2; 1609 info.CreateBuffer = I830DRI2CreateBuffer; 1610 info.DestroyBuffer = I830DRI2DestroyBuffer; 1611#else 1612 info.version = 3; 1613 info.CreateBuffer = I830DRI2CreateBuffer; 1614 info.DestroyBuffer = I830DRI2DestroyBuffer; 1615#endif 1616 1617 info.CopyRegion = I830DRI2CopyRegion; 1618#if DRI2INFOREC_VERSION >= 4 1619 info.version = 4; 1620 info.ScheduleSwap = I830DRI2ScheduleSwap; 1621 info.GetMSC = I830DRI2GetMSC; 1622 info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC; 1623 info.numDrivers = 1; 1624 info.driverNames = driverNames; 1625 driverNames[0] = info.driverName; 1626#endif 1627 1628 return DRI2ScreenInit(screen, &info); 1629} 1630 1631void I830DRI2CloseScreen(ScreenPtr screen) 1632{ 1633 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 1634 intel_screen_private *intel = intel_get_screen_private(scrn); 1635 1636 DRI2CloseScreen(screen); 1637 intel->directRenderingType = DRI_NONE; 1638 drmFree(intel->deviceName); 1639} 1640