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