present_scmd.c revision 5a7dfde8
1/* 2 * Copyright © 2013 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_XORG_CONFIG_H 24#include <xorg-config.h> 25#endif 26 27#include "present_priv.h" 28#include <misync.h> 29#include <misyncstr.h> 30#ifdef MONOTONIC_CLOCK 31#include <time.h> 32#endif 33 34/* 35 * Screen flip mode 36 * 37 * Provides the default mode for drivers, that do not 38 * support flips and the full screen flip mode. 39 * 40 */ 41 42static uint64_t present_event_id; 43static struct xorg_list present_exec_queue; 44static struct xorg_list present_flip_queue; 45 46static void 47present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc); 48 49static void 50present_scmd_create_event_id(present_window_priv_ptr window_priv, 51 present_vblank_ptr vblank) 52{ 53 vblank->event_id = ++present_event_id; 54} 55 56static inline PixmapPtr 57present_flip_pending_pixmap(ScreenPtr screen) 58{ 59 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 60 61 if (!screen_priv) 62 return NULL; 63 64 if (!screen_priv->flip_pending) 65 return NULL; 66 67 return screen_priv->flip_pending->pixmap; 68} 69 70static Bool 71present_check_flip(RRCrtcPtr crtc, 72 WindowPtr window, 73 PixmapPtr pixmap, 74 Bool sync_flip, 75 RegionPtr valid, 76 int16_t x_off, 77 int16_t y_off, 78 PresentFlipReason *reason) 79{ 80 ScreenPtr screen = window->drawable.pScreen; 81 PixmapPtr window_pixmap; 82 WindowPtr root = screen->root; 83 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 84 85 if (reason) 86 *reason = PRESENT_FLIP_REASON_UNKNOWN; 87 88 if (!screen_priv) 89 return FALSE; 90 91 if (!screen_priv->info) 92 return FALSE; 93 94 if (!crtc) 95 return FALSE; 96 97 /* Check to see if the driver supports flips at all */ 98 if (!screen_priv->info->flip) 99 return FALSE; 100 101 /* Make sure the window hasn't been redirected with Composite */ 102 window_pixmap = screen->GetWindowPixmap(window); 103 if (window_pixmap != screen->GetScreenPixmap(screen) && 104 window_pixmap != screen_priv->flip_pixmap && 105 window_pixmap != present_flip_pending_pixmap(screen)) 106 return FALSE; 107 108 /* Check for full-screen window */ 109 if (!RegionEqual(&window->clipList, &root->winSize)) { 110 return FALSE; 111 } 112 113 /* Source pixmap must align with window exactly */ 114 if (x_off || y_off) { 115 return FALSE; 116 } 117 118 /* Make sure the area marked as valid fills the screen */ 119 if (valid && !RegionEqual(valid, &root->winSize)) { 120 return FALSE; 121 } 122 123 /* Does the window match the pixmap exactly? */ 124 if (window->drawable.x != 0 || window->drawable.y != 0 || 125#ifdef COMPOSITE 126 window->drawable.x != pixmap->screen_x || window->drawable.y != pixmap->screen_y || 127#endif 128 window->drawable.width != pixmap->drawable.width || 129 window->drawable.height != pixmap->drawable.height) { 130 return FALSE; 131 } 132 133 /* Ask the driver for permission */ 134 if (screen_priv->info->version >= 1 && screen_priv->info->check_flip2) { 135 if (!(*screen_priv->info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) { 136 DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0)); 137 return FALSE; 138 } 139 } else if (screen_priv->info->check_flip) { 140 if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) { 141 DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0)); 142 return FALSE; 143 } 144 } 145 146 return TRUE; 147} 148 149static Bool 150present_flip(RRCrtcPtr crtc, 151 uint64_t event_id, 152 uint64_t target_msc, 153 PixmapPtr pixmap, 154 Bool sync_flip) 155{ 156 ScreenPtr screen = crtc->pScreen; 157 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 158 159 return (*screen_priv->info->flip) (crtc, event_id, target_msc, pixmap, sync_flip); 160} 161 162static RRCrtcPtr 163present_scmd_get_crtc(present_screen_priv_ptr screen_priv, WindowPtr window) 164{ 165 if (!screen_priv->info) 166 return NULL; 167 168 return (*screen_priv->info->get_crtc)(window); 169} 170 171static uint32_t 172present_scmd_query_capabilities(present_screen_priv_ptr screen_priv) 173{ 174 if (!screen_priv->info) 175 return 0; 176 177 return screen_priv->info->capabilities; 178} 179 180static int 181present_get_ust_msc(ScreenPtr screen, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc) 182{ 183 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 184 185 if (crtc == NULL) 186 return present_fake_get_ust_msc(screen, ust, msc); 187 else 188 return (*screen_priv->info->get_ust_msc)(crtc, ust, msc); 189} 190 191static void 192present_flush(WindowPtr window) 193{ 194 ScreenPtr screen = window->drawable.pScreen; 195 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 196 197 if (!screen_priv) 198 return; 199 200 if (!screen_priv->info) 201 return; 202 203 (*screen_priv->info->flush) (window); 204} 205 206static int 207present_queue_vblank(ScreenPtr screen, 208 WindowPtr window, 209 RRCrtcPtr crtc, 210 uint64_t event_id, 211 uint64_t msc) 212{ 213 Bool ret; 214 215 if (crtc == NULL) 216 ret = present_fake_queue_vblank(screen, event_id, msc); 217 else 218 { 219 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 220 ret = (*screen_priv->info->queue_vblank) (crtc, event_id, msc); 221 } 222 return ret; 223} 224 225static uint64_t 226present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc) 227{ 228 present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); 229 230 if (crtc != window_priv->crtc) { 231 uint64_t old_ust, old_msc; 232 233 if (window_priv->crtc == PresentCrtcNeverSet) { 234 window_priv->msc_offset = 0; 235 } else { 236 /* The old CRTC may have been turned off, in which case 237 * we'll just use whatever previous MSC we'd seen from this CRTC 238 */ 239 240 if (present_get_ust_msc(window->drawable.pScreen, window_priv->crtc, &old_ust, &old_msc) != Success) 241 old_msc = window_priv->msc; 242 243 window_priv->msc_offset += new_msc - old_msc; 244 } 245 window_priv->crtc = crtc; 246 } 247 248 return window_msc + window_priv->msc_offset; 249} 250 251/* 252 * When the wait fence or previous flip is completed, it's time 253 * to re-try the request 254 */ 255static void 256present_re_execute(present_vblank_ptr vblank) 257{ 258 uint64_t ust = 0, crtc_msc = 0; 259 260 if (vblank->crtc) 261 (void) present_get_ust_msc(vblank->screen, vblank->crtc, &ust, &crtc_msc); 262 263 present_execute(vblank, ust, crtc_msc); 264} 265 266static void 267present_flip_try_ready(ScreenPtr screen) 268{ 269 present_vblank_ptr vblank; 270 271 xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) { 272 if (vblank->queued) { 273 present_re_execute(vblank); 274 return; 275 } 276 } 277} 278 279static void 280present_flip_idle(ScreenPtr screen) 281{ 282 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 283 284 if (screen_priv->flip_pixmap) { 285 present_pixmap_idle(screen_priv->flip_pixmap, screen_priv->flip_window, 286 screen_priv->flip_serial, screen_priv->flip_idle_fence); 287 if (screen_priv->flip_idle_fence) 288 present_fence_destroy(screen_priv->flip_idle_fence); 289 dixDestroyPixmap(screen_priv->flip_pixmap, screen_priv->flip_pixmap->drawable.id); 290 screen_priv->flip_crtc = NULL; 291 screen_priv->flip_window = NULL; 292 screen_priv->flip_serial = 0; 293 screen_priv->flip_pixmap = NULL; 294 screen_priv->flip_idle_fence = NULL; 295 } 296} 297 298void 299present_restore_screen_pixmap(ScreenPtr screen) 300{ 301 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 302 PixmapPtr screen_pixmap = (*screen->GetScreenPixmap)(screen); 303 PixmapPtr flip_pixmap; 304 WindowPtr flip_window; 305 306 if (screen_priv->flip_pending) { 307 flip_window = screen_priv->flip_pending->window; 308 flip_pixmap = screen_priv->flip_pending->pixmap; 309 } else { 310 flip_window = screen_priv->flip_window; 311 flip_pixmap = screen_priv->flip_pixmap; 312 } 313 314 assert (flip_pixmap); 315 316 /* Update the screen pixmap with the current flip pixmap contents 317 * Only do this the first time for a particular unflip operation, or 318 * we'll probably scribble over other windows 319 */ 320 if (screen->root && screen->GetWindowPixmap(screen->root) == flip_pixmap) 321 present_copy_region(&screen_pixmap->drawable, flip_pixmap, NULL, 0, 0); 322 323 /* Switch back to using the screen pixmap now to avoid 324 * 2D applications drawing to the wrong pixmap. 325 */ 326 if (flip_window) 327 present_set_tree_pixmap(flip_window, flip_pixmap, screen_pixmap); 328 if (screen->root) 329 present_set_tree_pixmap(screen->root, NULL, screen_pixmap); 330} 331 332void 333present_set_abort_flip(ScreenPtr screen) 334{ 335 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 336 337 if (!screen_priv->flip_pending->abort_flip) { 338 present_restore_screen_pixmap(screen); 339 screen_priv->flip_pending->abort_flip = TRUE; 340 } 341} 342 343static void 344present_unflip(ScreenPtr screen) 345{ 346 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 347 348 assert (!screen_priv->unflip_event_id); 349 assert (!screen_priv->flip_pending); 350 351 present_restore_screen_pixmap(screen); 352 353 screen_priv->unflip_event_id = ++present_event_id; 354 DebugPresent(("u %" PRIu64 "\n", screen_priv->unflip_event_id)); 355 (*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id); 356} 357 358static void 359present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) 360{ 361 ScreenPtr screen = vblank->screen; 362 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 363 364 DebugPresent(("\tn %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", 365 vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc, 366 vblank->pixmap ? vblank->pixmap->drawable.id : 0, 367 vblank->window ? vblank->window->drawable.id : 0)); 368 369 assert (vblank == screen_priv->flip_pending); 370 371 present_flip_idle(screen); 372 373 xorg_list_del(&vblank->event_queue); 374 375 /* Transfer reference for pixmap and fence from vblank to screen_priv */ 376 screen_priv->flip_crtc = vblank->crtc; 377 screen_priv->flip_window = vblank->window; 378 screen_priv->flip_serial = vblank->serial; 379 screen_priv->flip_pixmap = vblank->pixmap; 380 screen_priv->flip_sync = vblank->sync_flip; 381 screen_priv->flip_idle_fence = vblank->idle_fence; 382 383 vblank->pixmap = NULL; 384 vblank->idle_fence = NULL; 385 386 screen_priv->flip_pending = NULL; 387 388 if (vblank->abort_flip) 389 present_unflip(screen); 390 391 present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc); 392 present_vblank_destroy(vblank); 393 394 present_flip_try_ready(screen); 395} 396 397void 398present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc) 399{ 400 present_vblank_ptr vblank; 401 int s; 402 403 if (!event_id) 404 return; 405 DebugPresent(("\te %" PRIu64 " ust %" PRIu64 " msc %" PRIu64 "\n", event_id, ust, msc)); 406 xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) { 407 int64_t match = event_id - vblank->event_id; 408 if (match == 0) { 409 present_execute(vblank, ust, msc); 410 return; 411 } 412 } 413 xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) { 414 if (vblank->event_id == event_id) { 415 if (vblank->queued) 416 present_execute(vblank, ust, msc); 417 else 418 present_flip_notify(vblank, ust, msc); 419 return; 420 } 421 } 422 423 for (s = 0; s < screenInfo.numScreens; s++) { 424 ScreenPtr screen = screenInfo.screens[s]; 425 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 426 427 if (event_id == screen_priv->unflip_event_id) { 428 DebugPresent(("\tun %" PRIu64 "\n", event_id)); 429 screen_priv->unflip_event_id = 0; 430 present_flip_idle(screen); 431 present_flip_try_ready(screen); 432 return; 433 } 434 } 435} 436 437/* 438 * 'window' is being reconfigured. Check to see if it is involved 439 * in flipping and clean up as necessary 440 */ 441static void 442present_check_flip_window (WindowPtr window) 443{ 444 ScreenPtr screen = window->drawable.pScreen; 445 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 446 present_window_priv_ptr window_priv = present_window_priv(window); 447 present_vblank_ptr flip_pending = screen_priv->flip_pending; 448 present_vblank_ptr vblank; 449 PresentFlipReason reason; 450 451 /* If this window hasn't ever been used with Present, it can't be 452 * flipping 453 */ 454 if (!window_priv) 455 return; 456 457 if (screen_priv->unflip_event_id) 458 return; 459 460 if (flip_pending) { 461 /* 462 * Check pending flip 463 */ 464 if (flip_pending->window == window) { 465 if (!present_check_flip(flip_pending->crtc, window, flip_pending->pixmap, 466 flip_pending->sync_flip, NULL, 0, 0, NULL)) 467 present_set_abort_flip(screen); 468 } 469 } else { 470 /* 471 * Check current flip 472 */ 473 if (window == screen_priv->flip_window) { 474 if (!present_check_flip(screen_priv->flip_crtc, window, screen_priv->flip_pixmap, screen_priv->flip_sync, NULL, 0, 0, NULL)) 475 present_unflip(screen); 476 } 477 } 478 479 /* Now check any queued vblanks */ 480 xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) { 481 if (vblank->queued && vblank->flip && !present_check_flip(vblank->crtc, window, vblank->pixmap, vblank->sync_flip, NULL, 0, 0, &reason)) { 482 vblank->flip = FALSE; 483 vblank->reason = reason; 484 if (vblank->sync_flip) 485 vblank->exec_msc = vblank->target_msc; 486 } 487 } 488} 489 490static Bool 491present_scmd_can_window_flip(WindowPtr window) 492{ 493 ScreenPtr screen = window->drawable.pScreen; 494 PixmapPtr window_pixmap; 495 WindowPtr root = screen->root; 496 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 497 498 if (!screen_priv) 499 return FALSE; 500 501 if (!screen_priv->info) 502 return FALSE; 503 504 /* Check to see if the driver supports flips at all */ 505 if (!screen_priv->info->flip) 506 return FALSE; 507 508 /* Make sure the window hasn't been redirected with Composite */ 509 window_pixmap = screen->GetWindowPixmap(window); 510 if (window_pixmap != screen->GetScreenPixmap(screen) && 511 window_pixmap != screen_priv->flip_pixmap && 512 window_pixmap != present_flip_pending_pixmap(screen)) 513 return FALSE; 514 515 /* Check for full-screen window */ 516 if (!RegionEqual(&window->clipList, &root->winSize)) { 517 return FALSE; 518 } 519 520 /* Does the window match the pixmap exactly? */ 521 if (window->drawable.x != 0 || window->drawable.y != 0) { 522 return FALSE; 523 } 524 525 return TRUE; 526} 527 528/* 529 * Once the required MSC has been reached, execute the pending request. 530 * 531 * For requests to actually present something, either blt contents to 532 * the screen or queue a frame buffer swap. 533 * 534 * For requests to just get the current MSC/UST combo, skip that part and 535 * go straight to event delivery 536 */ 537 538static void 539present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) 540{ 541 WindowPtr window = vblank->window; 542 ScreenPtr screen = window->drawable.pScreen; 543 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 544 545 if (present_execute_wait(vblank, crtc_msc)) 546 return; 547 548 if (vblank->flip && vblank->pixmap && vblank->window) { 549 if (screen_priv->flip_pending || screen_priv->unflip_event_id) { 550 DebugPresent(("\tr %" PRIu64 " %p (pending %p unflip %" PRIu64 ")\n", 551 vblank->event_id, vblank, 552 screen_priv->flip_pending, screen_priv->unflip_event_id)); 553 xorg_list_del(&vblank->event_queue); 554 xorg_list_append(&vblank->event_queue, &present_flip_queue); 555 vblank->flip_ready = TRUE; 556 return; 557 } 558 } 559 560 xorg_list_del(&vblank->event_queue); 561 xorg_list_del(&vblank->window_list); 562 vblank->queued = FALSE; 563 564 if (vblank->pixmap && vblank->window) { 565 566 if (vblank->flip) { 567 568 DebugPresent(("\tf %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", 569 vblank->event_id, vblank, crtc_msc, 570 vblank->pixmap->drawable.id, vblank->window->drawable.id)); 571 572 /* Prepare to flip by placing it in the flip queue and 573 * and sticking it into the flip_pending field 574 */ 575 screen_priv->flip_pending = vblank; 576 577 xorg_list_add(&vblank->event_queue, &present_flip_queue); 578 /* Try to flip 579 */ 580 if (present_flip(vblank->crtc, vblank->event_id, vblank->target_msc, vblank->pixmap, vblank->sync_flip)) { 581 RegionPtr damage; 582 583 /* Fix window pixmaps: 584 * 1) Restore previous flip window pixmap 585 * 2) Set current flip window pixmap to the new pixmap 586 */ 587 if (screen_priv->flip_window && screen_priv->flip_window != window) 588 present_set_tree_pixmap(screen_priv->flip_window, 589 screen_priv->flip_pixmap, 590 (*screen->GetScreenPixmap)(screen)); 591 present_set_tree_pixmap(vblank->window, NULL, vblank->pixmap); 592 present_set_tree_pixmap(screen->root, NULL, vblank->pixmap); 593 594 /* Report update region as damaged 595 */ 596 if (vblank->update) { 597 damage = vblank->update; 598 RegionIntersect(damage, damage, &window->clipList); 599 } else 600 damage = &window->clipList; 601 602 DamageDamageRegion(&vblank->window->drawable, damage); 603 return; 604 } 605 606 xorg_list_del(&vblank->event_queue); 607 /* Oops, flip failed. Clear the flip_pending field 608 */ 609 screen_priv->flip_pending = NULL; 610 vblank->flip = FALSE; 611 vblank->exec_msc = vblank->target_msc; 612 } 613 DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", 614 vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id)); 615 if (screen_priv->flip_pending) { 616 617 /* Check pending flip 618 */ 619 if (window == screen_priv->flip_pending->window) 620 present_set_abort_flip(screen); 621 } else if (!screen_priv->unflip_event_id) { 622 623 /* Check current flip 624 */ 625 if (window == screen_priv->flip_window) 626 present_unflip(screen); 627 } 628 629 present_execute_copy(vblank, crtc_msc); 630 631 if (vblank->queued) { 632 xorg_list_add(&vblank->event_queue, &present_exec_queue); 633 xorg_list_append(&vblank->window_list, 634 &present_get_window_priv(window, TRUE)->vblank); 635 return; 636 } 637 } 638 639 present_execute_post(vblank, ust, crtc_msc); 640} 641 642static int 643present_scmd_pixmap(WindowPtr window, 644 PixmapPtr pixmap, 645 CARD32 serial, 646 RegionPtr valid, 647 RegionPtr update, 648 int16_t x_off, 649 int16_t y_off, 650 RRCrtcPtr target_crtc, 651 SyncFence *wait_fence, 652 SyncFence *idle_fence, 653 uint32_t options, 654 uint64_t window_msc, 655 uint64_t divisor, 656 uint64_t remainder, 657 present_notify_ptr notifies, 658 int num_notifies) 659{ 660 uint64_t ust = 0; 661 uint64_t target_msc; 662 uint64_t crtc_msc = 0; 663 int ret; 664 present_vblank_ptr vblank, tmp; 665 ScreenPtr screen = window->drawable.pScreen; 666 present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); 667 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 668 669 if (!window_priv) 670 return BadAlloc; 671 672 if (!screen_priv || !screen_priv->info) 673 target_crtc = NULL; 674 else if (!target_crtc) { 675 /* Update the CRTC if we have a pixmap or we don't have a CRTC 676 */ 677 if (!pixmap) 678 target_crtc = window_priv->crtc; 679 680 if (!target_crtc || target_crtc == PresentCrtcNeverSet) 681 target_crtc = present_get_crtc(window); 682 } 683 684 ret = present_get_ust_msc(screen, target_crtc, &ust, &crtc_msc); 685 686 target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc); 687 688 if (ret == Success) { 689 /* Stash the current MSC away in case we need it later 690 */ 691 window_priv->msc = crtc_msc; 692 } 693 694 present_adjust_timings(options, 695 &crtc_msc, 696 &target_msc, 697 divisor, 698 remainder); 699 700 /* 701 * Look for a matching presentation already on the list and 702 * don't bother doing the previous one if this one will overwrite it 703 * in the same frame 704 */ 705 706 if (!update && pixmap) { 707 xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) { 708 709 if (!vblank->pixmap) 710 continue; 711 712 if (!vblank->queued) 713 continue; 714 715 if (vblank->crtc != target_crtc || vblank->target_msc != target_msc) 716 continue; 717 718 DebugPresent(("\tx %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 " (crtc %p)\n", 719 vblank->event_id, vblank, vblank->target_msc, 720 vblank->pixmap->drawable.id, vblank->window->drawable.id, 721 vblank->crtc)); 722 723 present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); 724 present_fence_destroy(vblank->idle_fence); 725 dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id); 726 727 vblank->pixmap = NULL; 728 vblank->idle_fence = NULL; 729 vblank->flip = FALSE; 730 if (vblank->flip_ready) 731 present_re_execute(vblank); 732 } 733 } 734 735 vblank = present_vblank_create(window, 736 pixmap, 737 serial, 738 valid, 739 update, 740 x_off, 741 y_off, 742 target_crtc, 743 wait_fence, 744 idle_fence, 745 options, 746 screen_priv->info ? &screen_priv->info->capabilities : NULL, 747 notifies, 748 num_notifies, 749 target_msc, 750 crtc_msc); 751 752 if (!vblank) 753 return BadAlloc; 754 755 if (vblank->flip && vblank->sync_flip) 756 vblank->exec_msc--; 757 758 xorg_list_append(&vblank->event_queue, &present_exec_queue); 759 vblank->queued = TRUE; 760 if (msc_is_after(vblank->exec_msc, crtc_msc)) { 761 ret = present_queue_vblank(screen, window, target_crtc, vblank->event_id, vblank->exec_msc); 762 if (ret == Success) 763 return Success; 764 765 DebugPresent(("present_queue_vblank failed\n")); 766 } 767 768 present_execute(vblank, ust, crtc_msc); 769 770 return Success; 771} 772 773static void 774present_scmd_abort_vblank(ScreenPtr screen, WindowPtr window, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 775{ 776 present_vblank_ptr vblank; 777 778 if (crtc == NULL) 779 present_fake_abort_vblank(screen, event_id, msc); 780 else 781 { 782 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 783 784 (*screen_priv->info->abort_vblank) (crtc, event_id, msc); 785 } 786 787 xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) { 788 int64_t match = event_id - vblank->event_id; 789 if (match == 0) { 790 xorg_list_del(&vblank->event_queue); 791 vblank->queued = FALSE; 792 return; 793 } 794 } 795 xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) { 796 if (vblank->event_id == event_id) { 797 xorg_list_del(&vblank->event_queue); 798 vblank->queued = FALSE; 799 return; 800 } 801 } 802} 803 804static void 805present_scmd_flip_destroy(ScreenPtr screen) 806{ 807 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 808 809 /* Reset window pixmaps back to the screen pixmap */ 810 if (screen_priv->flip_pending) 811 present_set_abort_flip(screen); 812 813 /* Drop reference to any pending flip or unflip pixmaps. */ 814 present_flip_idle(screen); 815} 816 817void 818present_scmd_init_mode_hooks(present_screen_priv_ptr screen_priv) 819{ 820 screen_priv->query_capabilities = &present_scmd_query_capabilities; 821 screen_priv->get_crtc = &present_scmd_get_crtc; 822 823 screen_priv->check_flip = &present_check_flip; 824 screen_priv->check_flip_window = &present_check_flip_window; 825 screen_priv->can_window_flip = &present_scmd_can_window_flip; 826 827 screen_priv->present_pixmap = &present_scmd_pixmap; 828 screen_priv->create_event_id = &present_scmd_create_event_id; 829 830 screen_priv->queue_vblank = &present_queue_vblank; 831 screen_priv->flush = &present_flush; 832 screen_priv->re_execute = &present_re_execute; 833 834 screen_priv->abort_vblank = &present_scmd_abort_vblank; 835 screen_priv->flip_destroy = &present_scmd_flip_destroy; 836} 837 838Bool 839present_init(void) 840{ 841 xorg_list_init(&present_exec_queue); 842 xorg_list_init(&present_flip_queue); 843 present_fake_queue_init(); 844 return TRUE; 845} 846