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