present_scmd.c revision 25da500f
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 ": %08" PRIx32 " -> %08" PRIx32 "\n", 365 vblank->event_id, vblank, 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->requeue = TRUE; 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 } 612 DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", 613 vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id)); 614 if (screen_priv->flip_pending) { 615 616 /* Check pending flip 617 */ 618 if (window == screen_priv->flip_pending->window) 619 present_set_abort_flip(screen); 620 } else if (!screen_priv->unflip_event_id) { 621 622 /* Check current flip 623 */ 624 if (window == screen_priv->flip_window) 625 present_unflip(screen); 626 } 627 628 present_execute_copy(vblank, crtc_msc); 629 630 if (vblank->queued) { 631 xorg_list_add(&vblank->event_queue, &present_exec_queue); 632 xorg_list_append(&vblank->window_list, 633 &present_get_window_priv(window, TRUE)->vblank); 634 return; 635 } 636 } 637 638 present_execute_post(vblank, ust, crtc_msc); 639} 640 641static int 642present_scmd_pixmap(WindowPtr window, 643 PixmapPtr pixmap, 644 CARD32 serial, 645 RegionPtr valid, 646 RegionPtr update, 647 int16_t x_off, 648 int16_t y_off, 649 RRCrtcPtr target_crtc, 650 SyncFence *wait_fence, 651 SyncFence *idle_fence, 652 uint32_t options, 653 uint64_t window_msc, 654 uint64_t divisor, 655 uint64_t remainder, 656 present_notify_ptr notifies, 657 int num_notifies) 658{ 659 uint64_t ust = 0; 660 uint64_t target_msc; 661 uint64_t crtc_msc = 0; 662 int ret; 663 present_vblank_ptr vblank, tmp; 664 ScreenPtr screen = window->drawable.pScreen; 665 present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); 666 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 667 668 if (!window_priv) 669 return BadAlloc; 670 671 if (!screen_priv || !screen_priv->info) 672 target_crtc = NULL; 673 else if (!target_crtc) { 674 /* Update the CRTC if we have a pixmap or we don't have a CRTC 675 */ 676 if (!pixmap) 677 target_crtc = window_priv->crtc; 678 679 if (!target_crtc || target_crtc == PresentCrtcNeverSet) 680 target_crtc = present_get_crtc(window); 681 } 682 683 ret = present_get_ust_msc(screen, target_crtc, &ust, &crtc_msc); 684 685 target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc); 686 687 if (ret == Success) { 688 /* Stash the current MSC away in case we need it later 689 */ 690 window_priv->msc = crtc_msc; 691 } 692 693 present_adjust_timings(options, 694 &crtc_msc, 695 &target_msc, 696 divisor, 697 remainder); 698 699 /* 700 * Look for a matching presentation already on the list and 701 * don't bother doing the previous one if this one will overwrite it 702 * in the same frame 703 */ 704 705 if (!update && pixmap) { 706 xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) { 707 708 if (!vblank->pixmap) 709 continue; 710 711 if (!vblank->queued) 712 continue; 713 714 if (vblank->crtc != target_crtc || vblank->target_msc != target_msc) 715 continue; 716 717 DebugPresent(("\tx %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 " (crtc %p)\n", 718 vblank->event_id, vblank, vblank->target_msc, 719 vblank->pixmap->drawable.id, vblank->window->drawable.id, 720 vblank->crtc)); 721 722 present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); 723 present_fence_destroy(vblank->idle_fence); 724 dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id); 725 726 vblank->pixmap = NULL; 727 vblank->idle_fence = NULL; 728 vblank->flip = FALSE; 729 if (vblank->flip_ready) 730 present_re_execute(vblank); 731 } 732 } 733 734 vblank = present_vblank_create(window, 735 pixmap, 736 serial, 737 valid, 738 update, 739 x_off, 740 y_off, 741 target_crtc, 742 wait_fence, 743 idle_fence, 744 options, 745 screen_priv->info ? &screen_priv->info->capabilities : NULL, 746 notifies, 747 num_notifies, 748 &target_msc, 749 crtc_msc); 750 751 if (!vblank) 752 return BadAlloc; 753 754 xorg_list_append(&vblank->event_queue, &present_exec_queue); 755 vblank->queued = TRUE; 756 if (msc_is_after(target_msc, crtc_msc)) { 757 ret = present_queue_vblank(screen, window, target_crtc, vblank->event_id, target_msc); 758 if (ret == Success) 759 return Success; 760 761 DebugPresent(("present_queue_vblank failed\n")); 762 } 763 764 present_execute(vblank, ust, crtc_msc); 765 766 return Success; 767} 768 769static void 770present_scmd_abort_vblank(ScreenPtr screen, WindowPtr window, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) 771{ 772 present_vblank_ptr vblank; 773 774 if (crtc == NULL) 775 present_fake_abort_vblank(screen, event_id, msc); 776 else 777 { 778 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 779 780 (*screen_priv->info->abort_vblank) (crtc, event_id, msc); 781 } 782 783 xorg_list_for_each_entry(vblank, &present_exec_queue, event_queue) { 784 int64_t match = event_id - vblank->event_id; 785 if (match == 0) { 786 xorg_list_del(&vblank->event_queue); 787 vblank->queued = FALSE; 788 return; 789 } 790 } 791 xorg_list_for_each_entry(vblank, &present_flip_queue, event_queue) { 792 if (vblank->event_id == event_id) { 793 xorg_list_del(&vblank->event_queue); 794 vblank->queued = FALSE; 795 return; 796 } 797 } 798} 799 800static void 801present_scmd_flip_destroy(ScreenPtr screen) 802{ 803 present_screen_priv_ptr screen_priv = present_screen_priv(screen); 804 805 /* Reset window pixmaps back to the screen pixmap */ 806 if (screen_priv->flip_pending) 807 present_set_abort_flip(screen); 808 809 /* Drop reference to any pending flip or unflip pixmaps. */ 810 present_flip_idle(screen); 811} 812 813void 814present_scmd_init_mode_hooks(present_screen_priv_ptr screen_priv) 815{ 816 screen_priv->query_capabilities = &present_scmd_query_capabilities; 817 screen_priv->get_crtc = &present_scmd_get_crtc; 818 819 screen_priv->check_flip = &present_check_flip; 820 screen_priv->check_flip_window = &present_check_flip_window; 821 screen_priv->can_window_flip = &present_scmd_can_window_flip; 822 823 screen_priv->present_pixmap = &present_scmd_pixmap; 824 screen_priv->create_event_id = &present_scmd_create_event_id; 825 826 screen_priv->queue_vblank = &present_queue_vblank; 827 screen_priv->flush = &present_flush; 828 screen_priv->re_execute = &present_re_execute; 829 830 screen_priv->abort_vblank = &present_scmd_abort_vblank; 831 screen_priv->flip_destroy = &present_scmd_flip_destroy; 832} 833 834Bool 835present_init(void) 836{ 837 xorg_list_init(&present_exec_queue); 838 xorg_list_init(&present_flip_queue); 839 present_fake_queue_init(); 840 return TRUE; 841} 842