diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index 83d67517a..ca0de1516 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -43,6 +43,8 @@ #define TIMER_LEN_COPY 17 // ~60fps #define TIMER_LEN_FLIP 1000 // 1fps +static uint64_t present_wnmd_event_id; + static DevPrivateKeyRec xwl_present_window_private_key; static struct xwl_present_window * @@ -69,6 +71,9 @@ xwl_present_window_get_priv(WindowPtr window) xorg_list_init(&xwl_present_window->frame_callback_list); xorg_list_init(&xwl_present_window->wait_list); xorg_list_init(&xwl_present_window->release_list); + xorg_list_init(&xwl_present_window->exec_queue); + xorg_list_init(&xwl_present_window->flip_queue); + xorg_list_init(&xwl_present_window->idle_queue); dixSetPrivate(&window->devPrivates, &xwl_present_window_private_key, @@ -117,6 +122,722 @@ xwl_present_reset_timer(struct xwl_present_window *xwl_present_window) } } + +static void +present_wnmd_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc); + +static int +present_wnmd_queue_vblank(ScreenPtr screen, + WindowPtr window, + RRCrtcPtr crtc, + uint64_t event_id, + uint64_t msc) +{ + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + return (*screen_priv->wnmd_info->queue_vblank) (window, crtc, event_id, msc); +} + +static uint32_t +present_wnmd_query_capabilities(present_screen_priv_ptr screen_priv) +{ + return screen_priv->wnmd_info->capabilities; +} + +static RRCrtcPtr +present_wnmd_get_crtc(present_screen_priv_ptr screen_priv, WindowPtr window) +{ + return (*screen_priv->wnmd_info->get_crtc)(window); +} + +static int +present_wnmd_get_ust_msc(ScreenPtr screen, WindowPtr window, uint64_t *ust, uint64_t *msc) +{ + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + return (*screen_priv->wnmd_info->get_ust_msc)(window, ust, msc); +} + +/* + * When the wait fence or previous flip is completed, it's time + * to re-try the request + */ +static void +present_wnmd_re_execute(present_vblank_ptr vblank) +{ + uint64_t ust = 0, crtc_msc = 0; + + (void) present_wnmd_get_ust_msc(vblank->screen, vblank->window, &ust, &crtc_msc); + present_wnmd_execute(vblank, ust, crtc_msc); +} + +static void +present_wnmd_flip_try_ready(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + present_vblank_ptr vblank; + + xorg_list_for_each_entry(vblank, &xwl_present_window->flip_queue, event_queue) { + if (vblank->queued) { + present_wnmd_re_execute(vblank); + return; + } + } +} + +static void +present_wnmd_free_idle_vblank(present_vblank_ptr vblank) +{ + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + present_vblank_destroy(vblank); +} + +/* + * Free any left over idle vblanks + */ +static void +present_wnmd_free_idle_vblanks(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + present_vblank_ptr vblank, tmp; + + xorg_list_for_each_entry_safe(vblank, tmp, &xwl_present_window->idle_queue, event_queue) { + present_wnmd_free_idle_vblank(vblank); + } + + if (xwl_present_window->flip_active) { + present_wnmd_free_idle_vblank(xwl_present_window->flip_active); + xwl_present_window->flip_active = NULL; + } +} + +static WindowPtr +present_wnmd_toplvl_pixmap_window(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + PixmapPtr pixmap = (*screen->GetWindowPixmap)(window); + WindowPtr w = window; + WindowPtr next_w; + + while(w->parent) { + next_w = w->parent; + if ( (*screen->GetWindowPixmap)(next_w) != pixmap) { + break; + } + w = next_w; + } + return w; +} + +static void +present_wnmd_flips_stop(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + present_screen_priv_ptr screen_priv = present_screen_priv(window->drawable.pScreen); + + assert (!xwl_present_window->flip_pending); + + (*screen_priv->wnmd_info->flips_stop) (window); + + present_wnmd_free_idle_vblanks(window); + present_wnmd_flip_try_ready(window); +} + +static void +present_wnmd_flip_notify_vblank(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) +{ + WindowPtr window = vblank->window; + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + + DebugPresent(("\tn %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", + vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc, + vblank->pixmap ? vblank->pixmap->drawable.id : 0, + vblank->window ? vblank->window->drawable.id : 0)); + + assert (vblank == xwl_present_window->flip_pending); + + xorg_list_del(&vblank->event_queue); + + if (xwl_present_window->flip_active) { + if (xwl_present_window->flip_active->flip_idler) + present_wnmd_free_idle_vblank(xwl_present_window->flip_active); + else + /* Put the previous flip in the idle_queue and wait for further notice from + * the Wayland compositor + */ + xorg_list_append(&xwl_present_window->flip_active->event_queue, &xwl_present_window->idle_queue); + } + + xwl_present_window->flip_active = vblank; + xwl_present_window->flip_pending = NULL; + + present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc); + + if (vblank->abort_flip) + present_wnmd_flips_stop(window); + + present_wnmd_flip_try_ready(window); +} + +static void +present_wnmd_event_notify(WindowPtr window, uint64_t event_id, uint64_t ust, uint64_t msc) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + present_window_priv_ptr window_priv = present_window_priv(window); + present_vblank_ptr vblank; + + if (!window_priv) + return; + if (!event_id) + return; + + DebugPresent(("\te %" PRIu64 " ust %" PRIu64 " msc %" PRIu64 "\n", event_id, ust, msc)); + xorg_list_for_each_entry(vblank, &xwl_present_window->exec_queue, event_queue) { + if (event_id == vblank->event_id) { + present_wnmd_execute(vblank, ust, msc); + return; + } + } + xorg_list_for_each_entry(vblank, &xwl_present_window->flip_queue, event_queue) { + if (vblank->event_id == event_id) { + assert(vblank->queued); + present_wnmd_execute(vblank, ust, msc); + return; + } + } + + /* Copies which were executed but need their completion event sent */ + xorg_list_for_each_entry(vblank, &xwl_present_window->idle_queue, event_queue) { + if (vblank->event_id == event_id) { + present_execute_post(vblank, ust, msc); + return; + } + } +} + +static void +present_wnmd_flip_notify(WindowPtr window, uint64_t event_id, uint64_t ust, uint64_t msc) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + present_vblank_ptr vblank; + + xorg_list_for_each_entry(vblank, &xwl_present_window->flip_queue, event_queue) { + if (vblank->event_id == event_id) { + assert(!vblank->queued); + assert(vblank->window); + present_wnmd_flip_notify_vblank(vblank, ust, msc); + return; + } + } +} + +static void +present_wnmd_idle_notify(WindowPtr window, uint64_t event_id) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + present_vblank_ptr vblank; + + if (xwl_present_window->flip_active && xwl_present_window->flip_active->event_id == event_id) { + /* Active flip is allowed to become idle directly when it becomes unactive again. */ + xwl_present_window->flip_active->flip_idler = TRUE; + return; + } + + xorg_list_for_each_entry(vblank, &xwl_present_window->idle_queue, event_queue) { + if (vblank->event_id == event_id) { + present_wnmd_free_idle_vblank(vblank); + return; + } + } + + xorg_list_for_each_entry(vblank, &xwl_present_window->flip_queue, event_queue) { + if (vblank->event_id == event_id) { + vblank->flip_idler = TRUE; + return; + } + } +} + +static Bool +present_wnmd_check_flip(RRCrtcPtr crtc, + WindowPtr window, + PixmapPtr pixmap, + Bool sync_flip, + RegionPtr valid, + int16_t x_off, + int16_t y_off, + PresentFlipReason *reason) +{ + ScreenPtr screen = window->drawable.pScreen; + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + WindowPtr toplvl_window = present_wnmd_toplvl_pixmap_window(window); + + if (reason) + *reason = PRESENT_FLIP_REASON_UNKNOWN; + + if (!screen_priv) + return FALSE; + + if (!screen_priv->wnmd_info) + return FALSE; + + if (!crtc) + return FALSE; + + /* Check to see if the driver supports flips at all */ + if (!screen_priv->wnmd_info->flip) + return FALSE; + + /* Source pixmap must align with window exactly */ + if (x_off || y_off) + return FALSE; + + /* Valid area must contain window (for simplicity for now just never flip when one is set). */ + if (valid) + return FALSE; + + /* Flip pixmap must have same dimensions as window */ + if (window->drawable.width != pixmap->drawable.width || + window->drawable.height != pixmap->drawable.height) + return FALSE; + + /* Window must be same region as toplevel window */ + if ( !RegionEqual(&window->winSize, &toplvl_window->winSize) ) + return FALSE; + + /* Can't flip if window clipped by children */ + if (!RegionEqual(&window->clipList, &window->winSize)) + return FALSE; + + /* Ask the driver for permission */ + if (screen_priv->wnmd_info->check_flip2) { + if (!(*screen_priv->wnmd_info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) { + DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", + window->drawable.id, pixmap ? pixmap->drawable.id : 0)); + return FALSE; + } + } + + return TRUE; +} + +/* + * 'window' is being reconfigured. Check to see if it is involved + * in flipping and clean up as necessary. + */ +static void +present_wnmd_check_flip_window (WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + present_window_priv_ptr window_priv = present_window_priv(window); + present_vblank_ptr flip_pending; + present_vblank_ptr flip_active; + present_vblank_ptr vblank; + PresentFlipReason reason; + + /* If this window hasn't ever been used with Present, it can't be + * flipping + */ + if (!xwl_present_window || !window_priv) + return; + + flip_pending = xwl_present_window->flip_pending; + flip_active = xwl_present_window->flip_active; + + if (flip_pending) { + if (!present_wnmd_check_flip(flip_pending->crtc, flip_pending->window, flip_pending->pixmap, + flip_pending->sync_flip, flip_pending->valid, 0, 0, NULL)) + xwl_present_window->flip_pending->abort_flip = TRUE; + } else if (flip_active) { + if (!present_wnmd_check_flip(flip_active->crtc, flip_active->window, flip_active->pixmap, + flip_active->sync_flip, flip_active->valid, 0, 0, NULL)) + present_wnmd_flips_stop(window); + } + + /* Now check any queued vblanks */ + xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) { + if (vblank->queued && vblank->flip && + !present_wnmd_check_flip(vblank->crtc, window, vblank->pixmap, + vblank->sync_flip, vblank->valid, 0, 0, &reason)) { + vblank->flip = FALSE; + vblank->reason = reason; + } + } +} + +/* + * Clean up any pending or current flips for this window + */ +static void +present_wnmd_clear_window_flip(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window); + present_vblank_ptr vblank, tmp; + + xorg_list_for_each_entry_safe(vblank, tmp, &xwl_present_window->flip_queue, event_queue) { + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + present_vblank_destroy(vblank); + } + + xorg_list_for_each_entry_safe(vblank, tmp, &xwl_present_window->idle_queue, event_queue) { + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + present_vblank_destroy(vblank); + } + + vblank = xwl_present_window->flip_active; + if (vblank) { + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + present_vblank_destroy(vblank); + } + xwl_present_window->flip_active = NULL; +} + +static Bool +present_wnmd_flip(WindowPtr window, + RRCrtcPtr crtc, + uint64_t event_id, + uint64_t target_msc, + PixmapPtr pixmap, + Bool sync_flip, + RegionPtr damage) +{ + ScreenPtr screen = window->drawable.pScreen; + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + + return (*screen_priv->wnmd_info->flip) (window, + crtc, + event_id, + target_msc, + pixmap, + sync_flip, + damage); +} + +static void +present_wnmd_cancel_flip(WindowPtr window) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + + if (xwl_present_window->flip_pending) + xwl_present_window->flip_pending->abort_flip = TRUE; + else if (xwl_present_window->flip_active) + present_wnmd_flips_stop(window); +} + +/* + * Once the required MSC has been reached, execute the pending request. + * + * For requests to actually present something, either blt contents to + * the window pixmap or queue a window buffer swap on the backend. + * + * For requests to just get the current MSC/UST combo, skip that part and + * go straight to event delivery. + */ +static void +present_wnmd_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) +{ + WindowPtr window = vblank->window; + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window); + present_window_priv_ptr window_priv = present_window_priv(window); + + if (present_execute_wait(vblank, crtc_msc)) + return; + + if (vblank->flip && vblank->pixmap && vblank->window) { + if (xwl_present_window->flip_pending) { + DebugPresent(("\tr %" PRIu64 " %p (pending %p)\n", + vblank->event_id, vblank, + xwl_present_window->flip_pending)); + xorg_list_del(&vblank->event_queue); + xorg_list_append(&vblank->event_queue, &xwl_present_window->flip_queue); + vblank->flip_ready = TRUE; + return; + } + } + + xorg_list_del(&vblank->event_queue); + xorg_list_del(&vblank->window_list); + vblank->queued = FALSE; + + if (vblank->pixmap && vblank->window) { + ScreenPtr screen = window->drawable.pScreen; + + if (vblank->flip) { + RegionPtr damage; + + DebugPresent(("\tf %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", + vblank->event_id, vblank, crtc_msc, + vblank->pixmap->drawable.id, vblank->window->drawable.id)); + + /* Prepare to flip by placing it in the flip queue + */ + xorg_list_add(&vblank->event_queue, &xwl_present_window->flip_queue); + + /* Set update region as damaged */ + if (vblank->update) { + damage = RegionDuplicate(vblank->update); + /* Translate update region to screen space */ + assert(vblank->x_off == 0 && vblank->y_off == 0); + RegionTranslate(damage, window->drawable.x, window->drawable.y); + RegionIntersect(damage, damage, &window->clipList); + } else + damage = RegionDuplicate(&window->clipList); + + /* Try to flip - the vblank is now pending + */ + xwl_present_window->flip_pending = vblank; + // ask the driver + if (present_wnmd_flip(vblank->window, vblank->crtc, vblank->event_id, + vblank->target_msc, vblank->pixmap, vblank->sync_flip, damage)) { + WindowPtr toplvl_window = present_wnmd_toplvl_pixmap_window(vblank->window); + PixmapPtr old_pixmap = screen->GetWindowPixmap(window); + + /* Replace window pixmap with flip pixmap */ +#ifdef COMPOSITE + vblank->pixmap->screen_x = old_pixmap->screen_x; + vblank->pixmap->screen_y = old_pixmap->screen_y; +#endif + present_set_tree_pixmap(toplvl_window, old_pixmap, vblank->pixmap); + vblank->pixmap->refcnt++; + dixDestroyPixmap(old_pixmap, old_pixmap->drawable.id); + + /* Report damage */ + DamageDamageRegion(&vblank->window->drawable, damage); + RegionDestroy(damage); + return; + } + + xorg_list_del(&vblank->event_queue); + /* Flip failed. Clear the flip_pending field + */ + xwl_present_window->flip_pending = NULL; + vblank->flip = FALSE; + } + DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", + vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id)); + + present_wnmd_cancel_flip(window); + + present_execute_copy(vblank, crtc_msc); + assert(!vblank->queued); + + if (present_wnmd_queue_vblank(screen, window, vblank->crtc, + vblank->event_id, crtc_msc + 1) + == Success) { + xorg_list_add(&vblank->event_queue, &xwl_present_window->idle_queue); + xorg_list_append(&vblank->window_list, &window_priv->vblank); + + return; + } + } + + present_execute_post(vblank, ust, crtc_msc); +} + +static void +present_wnmd_update_window_crtc(WindowPtr window, RRCrtcPtr crtc, uint64_t new_msc) +{ + present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); + + /* Crtc unchanged, no offset. */ + if (crtc == window_priv->crtc) + return; + + /* No crtc earlier to offset against, just set the crtc. */ + if (window_priv->crtc == PresentCrtcNeverSet) { + window_priv->msc_offset = 0; + window_priv->crtc = crtc; + return; + } + + /* In window-mode the last correct msc-offset is always kept + * in window-priv struct because msc is saved per window and + * not per crtc as in screen-mode. + */ + window_priv->msc_offset += new_msc - window_priv->msc; + window_priv->crtc = crtc; +} + +static int +present_wnmd_pixmap(WindowPtr window, + PixmapPtr pixmap, + CARD32 serial, + RegionPtr valid, + RegionPtr update, + int16_t x_off, + int16_t y_off, + RRCrtcPtr target_crtc, + SyncFence *wait_fence, + SyncFence *idle_fence, + uint32_t options, + uint64_t target_window_msc, + uint64_t divisor, + uint64_t remainder, + present_notify_ptr notifies, + int num_notifies) +{ + uint64_t ust = 0; + uint64_t target_msc; + uint64_t crtc_msc = 0; + int ret; + present_vblank_ptr vblank, tmp; + ScreenPtr screen = window->drawable.pScreen; + struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window); + present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + + if (!window_priv) + return BadAlloc; + + target_crtc = present_wnmd_get_crtc(screen_priv, window); + + ret = present_wnmd_get_ust_msc(screen, window, &ust, &crtc_msc); + + present_wnmd_update_window_crtc(window, target_crtc, crtc_msc); + + if (ret == Success) { + /* Stash the current MSC away in case we need it later + */ + window_priv->msc = crtc_msc; + } + + target_msc = present_get_target_msc(target_window_msc + window_priv->msc_offset, + crtc_msc, + divisor, + remainder, + options); + + /* + * Look for a matching presentation already on the list... + */ + + if (!update && pixmap) { + xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) { + + if (!vblank->pixmap) + continue; + + if (!vblank->queued) + continue; + + if (vblank->target_msc != target_msc) + continue; + + present_vblank_scrap(vblank); + if (vblank->flip_ready) + present_wnmd_re_execute(vblank); + } + } + + vblank = present_vblank_create(window, + pixmap, + serial, + valid, + update, + x_off, + y_off, + target_crtc, + wait_fence, + idle_fence, + options, + screen_priv->wnmd_info->capabilities, + notifies, + num_notifies, + target_msc, + crtc_msc); + if (!vblank) + return BadAlloc; + + vblank->event_id = ++present_wnmd_event_id; + + /* WNMD presentations always complete (at least) one frame after they + * are executed + */ + vblank->exec_msc = vblank->target_msc - 1; + + xorg_list_append(&vblank->event_queue, &xwl_present_window->exec_queue); + vblank->queued = TRUE; + if (crtc_msc < vblank->exec_msc) { + if (present_wnmd_queue_vblank(screen, window, target_crtc, vblank->event_id, vblank->exec_msc) == Success) { + return Success; + } + DebugPresent(("present_queue_vblank failed\n")); + } + + present_wnmd_execute(vblank, ust, crtc_msc); + return Success; +} + +static void +present_wnmd_abort_vblank(ScreenPtr screen, WindowPtr window, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) +{ + struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window); + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + present_vblank_ptr vblank; + + (*screen_priv->wnmd_info->abort_vblank) (window, crtc, event_id, msc); + + xorg_list_for_each_entry(vblank, &xwl_present_window->exec_queue, event_queue) { + if (vblank->event_id == event_id) { + xorg_list_del(&vblank->event_queue); + vblank->queued = FALSE; + return; + } + } + xorg_list_for_each_entry(vblank, &xwl_present_window->flip_queue, event_queue) { + if (vblank->event_id == event_id) { + xorg_list_del(&vblank->event_queue); + vblank->queued = FALSE; + return; + } + } +} + +static void +present_wnmd_flush(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + present_screen_priv_ptr screen_priv = present_screen_priv(screen); + + (*screen_priv->wnmd_info->flush) (window); +} + +/* + * Initialize a screen for use with present in window flip mode (wnmd) + */ +static int +present_wnmd_screen_init(ScreenPtr screen, present_wnmd_info_ptr info) +{ + present_screen_priv_ptr screen_priv; + + if (!present_screen_register_priv_keys()) + return FALSE; + + if (present_screen_priv(screen)) + return TRUE; + + screen_priv = present_screen_priv_init(screen); + if (!screen_priv) + return FALSE; + + screen_priv->wnmd_info = info; + + screen_priv->query_capabilities = &present_wnmd_query_capabilities; + screen_priv->get_crtc = &present_wnmd_get_crtc; + + screen_priv->check_flip = &present_wnmd_check_flip; + screen_priv->check_flip_window = &present_wnmd_check_flip_window; + screen_priv->clear_window_flip = &present_wnmd_clear_window_flip; + + screen_priv->present_pixmap = &present_wnmd_pixmap; + screen_priv->queue_vblank = &present_wnmd_queue_vblank; + screen_priv->flush = &present_wnmd_flush; + screen_priv->re_execute = &present_wnmd_re_execute; + + screen_priv->abort_vblank = &present_wnmd_abort_vblank; + + return TRUE; +} + + static void xwl_present_release_pixmap(struct xwl_present_event *event) { diff --git a/hw/xwayland/xwayland-present.h b/hw/xwayland/xwayland-present.h index 35b579469..e595f4de2 100644 --- a/hw/xwayland/xwayland-present.h +++ b/hw/xwayland/xwayland-present.h @@ -29,6 +29,7 @@ #include #include +#include #include "xwayland-types.h" @@ -47,6 +48,12 @@ struct xwl_present_window { struct xorg_list wait_list; struct xorg_list release_list; + struct xorg_list exec_queue; + struct xorg_list flip_queue; + struct xorg_list idle_queue; + + present_vblank_ptr flip_pending; + present_vblank_ptr flip_active; }; struct xwl_present_event { diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index bb18e5c94..3fe5d82a7 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -687,6 +687,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) if (!xwl_screen_init_cursor(xwl_screen)) return FALSE; + xwl_screen->DestroyWindow = pScreen->DestroyWindow; + pScreen->DestroyWindow = xwl_destroy_window; + #ifdef XWL_HAS_GLAMOR if (xwl_screen->glamor) { xwl_glamor_select_backend(xwl_screen, use_eglstreams); @@ -714,9 +717,6 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xwl_screen->UnrealizeWindow = pScreen->UnrealizeWindow; pScreen->UnrealizeWindow = xwl_unrealize_window; - xwl_screen->DestroyWindow = pScreen->DestroyWindow; - pScreen->DestroyWindow = xwl_destroy_window; - xwl_screen->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = xwl_close_screen; diff --git a/present/Makefile.am b/present/Makefile.am index 269bd5db5..a2d58212c 100644 --- a/present/Makefile.am +++ b/present/Makefile.am @@ -14,7 +14,6 @@ libpresent_la_SOURCES = \ present_request.c \ present_scmd.c \ present_screen.c \ - present_vblank.c \ - present_wnmd.c + present_vblank.c sdk_HEADERS = present.h presentext.h diff --git a/present/meson.build b/present/meson.build index aa7ce86ff..1a74a9cbc 100644 --- a/present/meson.build +++ b/present/meson.build @@ -9,7 +9,6 @@ srcs_present = [ 'present_scmd.c', 'present_screen.c', 'present_vblank.c', - 'present_wnmd.c', ] hdrs_present = [ diff --git a/present/present.h b/present/present.h index 86744a838..a09b3846a 100644 --- a/present/present.h +++ b/present/present.h @@ -161,30 +161,8 @@ typedef struct present_wnmd_info { extern _X_EXPORT void present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc); -/* - * Called when 'event_id' occurs for 'window'. - * 'ust' and 'msc' indicate when the event actually happened - */ -extern _X_EXPORT void -present_wnmd_event_notify(WindowPtr window, uint64_t event_id, uint64_t ust, uint64_t msc); - -/* - * Called when presentation 'event_id' occurs for 'window'. - * 'ust' and 'msc' indicate when the presentation actually happened. - */ -extern _X_EXPORT void -present_wnmd_flip_notify(WindowPtr window, uint64_t event_id, uint64_t ust, uint64_t msc); - -/* - * Called when the flipped Pixmap associated with 'event_id' is not used anymore by the DDX. - */ -extern _X_EXPORT void -present_wnmd_idle_notify(WindowPtr window, uint64_t event_id); - extern _X_EXPORT Bool present_screen_init(ScreenPtr screen, present_screen_info_ptr info); -extern _X_EXPORT Bool -present_wnmd_screen_init(ScreenPtr screen, present_wnmd_info_ptr info); typedef void (*present_complete_notify_proc)(WindowPtr window, CARD8 kind, diff --git a/present/present_priv.h b/present/present_priv.h index 811250b09..5f62dd43d 100644 --- a/present/present_priv.h +++ b/present/present_priv.h @@ -219,14 +219,6 @@ struct present_window_priv { uint64_t msc; /* Last reported MSC from the current crtc */ struct xorg_list vblank; struct xorg_list notifies; - - /* Used for window flips */ - struct xorg_list exec_queue; - struct xorg_list flip_queue; - struct xorg_list idle_queue; - - present_vblank_ptr flip_pending; - present_vblank_ptr flip_active; }; #define PresentCrtcNeverSet ((RRCrtcPtr) 1) diff --git a/present/present_screen.c b/present/present_screen.c index c2ae773a1..15684eda4 100644 --- a/present/present_screen.c +++ b/present/present_screen.c @@ -42,10 +42,6 @@ present_get_window_priv(WindowPtr window, Bool create) xorg_list_init(&window_priv->vblank); xorg_list_init(&window_priv->notifies); - xorg_list_init(&window_priv->exec_queue); - xorg_list_init(&window_priv->flip_queue); - xorg_list_init(&window_priv->idle_queue); - window_priv->window = window; window_priv->crtc = PresentCrtcNeverSet; dixSetPrivate(&window->devPrivates, &present_window_private_key, window_priv); diff --git a/present/present_wnmd.c b/present/present_wnmd.c deleted file mode 100644 index 061698209..000000000 --- a/present/present_wnmd.c +++ /dev/null @@ -1,746 +0,0 @@ -/* - * Copyright © 2018 Roman Gilg - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - */ - -#include "present_priv.h" - -/* - * Window flip mode - * - * Provides per-window flips. Flips can be processed on windows that - * have the same size as their parents, which they share their pixmap with. - * - * A flip still requires a copy currently, since the original pixmap needs - * to be updated with the new pixmap content. Just a flip of all windows - * to the new pixmap is difficult, because the original pixmap might not be - * controlled by the Xserver. - * - */ - -static uint64_t present_wnmd_event_id; - -static void -present_wnmd_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc); - -static int -present_wnmd_queue_vblank(ScreenPtr screen, - WindowPtr window, - RRCrtcPtr crtc, - uint64_t event_id, - uint64_t msc) -{ - present_screen_priv_ptr screen_priv = present_screen_priv(screen); - return (*screen_priv->wnmd_info->queue_vblank) (window, crtc, event_id, msc); -} - -static uint32_t -present_wnmd_query_capabilities(present_screen_priv_ptr screen_priv) -{ - return screen_priv->wnmd_info->capabilities; -} - -static RRCrtcPtr -present_wnmd_get_crtc(present_screen_priv_ptr screen_priv, WindowPtr window) -{ - return (*screen_priv->wnmd_info->get_crtc)(window); -} - -static int -present_wnmd_get_ust_msc(ScreenPtr screen, WindowPtr window, uint64_t *ust, uint64_t *msc) -{ - present_screen_priv_ptr screen_priv = present_screen_priv(screen); - return (*screen_priv->wnmd_info->get_ust_msc)(window, ust, msc); -} - -/* - * When the wait fence or previous flip is completed, it's time - * to re-try the request - */ -static void -present_wnmd_re_execute(present_vblank_ptr vblank) -{ - uint64_t ust = 0, crtc_msc = 0; - - (void) present_wnmd_get_ust_msc(vblank->screen, vblank->window, &ust, &crtc_msc); - present_wnmd_execute(vblank, ust, crtc_msc); -} - -static void -present_wnmd_flip_try_ready(WindowPtr window) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - present_vblank_ptr vblank; - - xorg_list_for_each_entry(vblank, &window_priv->flip_queue, event_queue) { - if (vblank->queued) { - present_wnmd_re_execute(vblank); - return; - } - } -} - -static void -present_wnmd_free_idle_vblank(present_vblank_ptr vblank) -{ - present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); - present_vblank_destroy(vblank); -} - -/* - * Free any left over idle vblanks - */ -static void -present_wnmd_free_idle_vblanks(WindowPtr window) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - present_vblank_ptr vblank, tmp; - - xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->idle_queue, event_queue) { - present_wnmd_free_idle_vblank(vblank); - } - - if (window_priv->flip_active) { - present_wnmd_free_idle_vblank(window_priv->flip_active); - window_priv->flip_active = NULL; - } -} - -static WindowPtr -present_wnmd_toplvl_pixmap_window(WindowPtr window) -{ - ScreenPtr screen = window->drawable.pScreen; - PixmapPtr pixmap = (*screen->GetWindowPixmap)(window); - WindowPtr w = window; - WindowPtr next_w; - - while(w->parent) { - next_w = w->parent; - if ( (*screen->GetWindowPixmap)(next_w) != pixmap) { - break; - } - w = next_w; - } - return w; -} - -static void -present_wnmd_flips_stop(WindowPtr window) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - present_screen_priv_ptr screen_priv = present_screen_priv(window->drawable.pScreen); - - assert (!window_priv->flip_pending); - - (*screen_priv->wnmd_info->flips_stop) (window); - - present_wnmd_free_idle_vblanks(window_priv->window); - present_wnmd_flip_try_ready(window_priv->window); -} - -static void -present_wnmd_flip_notify_vblank(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) -{ - WindowPtr window = vblank->window; - present_window_priv_ptr window_priv = present_window_priv(window); - - DebugPresent(("\tn %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", - vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc, - vblank->pixmap ? vblank->pixmap->drawable.id : 0, - vblank->window ? vblank->window->drawable.id : 0)); - - assert (vblank == window_priv->flip_pending); - - xorg_list_del(&vblank->event_queue); - - if (window_priv->flip_active) { - if (window_priv->flip_active->flip_idler) - present_wnmd_free_idle_vblank(window_priv->flip_active); - else - /* Put the previous flip in the idle_queue and wait for further notice from DDX */ - xorg_list_append(&window_priv->flip_active->event_queue, &window_priv->idle_queue); - } - - window_priv->flip_active = vblank; - window_priv->flip_pending = NULL; - - present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc); - - if (vblank->abort_flip) - present_wnmd_flips_stop(window); - - present_wnmd_flip_try_ready(window); -} - -void -present_wnmd_event_notify(WindowPtr window, uint64_t event_id, uint64_t ust, uint64_t msc) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - present_vblank_ptr vblank; - - if (!window_priv) - return; - if (!event_id) - return; - - DebugPresent(("\te %" PRIu64 " ust %" PRIu64 " msc %" PRIu64 "\n", event_id, ust, msc)); - xorg_list_for_each_entry(vblank, &window_priv->exec_queue, event_queue) { - if (event_id == vblank->event_id) { - present_wnmd_execute(vblank, ust, msc); - return; - } - } - xorg_list_for_each_entry(vblank, &window_priv->flip_queue, event_queue) { - if (vblank->event_id == event_id) { - assert(vblank->queued); - present_wnmd_execute(vblank, ust, msc); - return; - } - } - - /* Copies which were executed but need their completion event sent */ - xorg_list_for_each_entry(vblank, &window_priv->idle_queue, event_queue) { - if (vblank->event_id == event_id) { - present_execute_post(vblank, ust, msc); - return; - } - } -} - -void -present_wnmd_flip_notify(WindowPtr window, uint64_t event_id, uint64_t ust, uint64_t msc) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - present_vblank_ptr vblank; - - xorg_list_for_each_entry(vblank, &window_priv->flip_queue, event_queue) { - if (vblank->event_id == event_id) { - assert(!vblank->queued); - assert(vblank->window); - present_wnmd_flip_notify_vblank(vblank, ust, msc); - return; - } - } -} - -void -present_wnmd_idle_notify(WindowPtr window, uint64_t event_id) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - present_vblank_ptr vblank; - - if (window_priv->flip_active && window_priv->flip_active->event_id == event_id) { - /* Active flip is allowed to become idle directly when it becomes unactive again. */ - window_priv->flip_active->flip_idler = TRUE; - return; - } - - xorg_list_for_each_entry(vblank, &window_priv->idle_queue, event_queue) { - if (vblank->event_id == event_id) { - present_wnmd_free_idle_vblank(vblank); - return; - } - } - - xorg_list_for_each_entry(vblank, &window_priv->flip_queue, event_queue) { - if (vblank->event_id == event_id) { - vblank->flip_idler = TRUE; - return; - } - } -} - -static Bool -present_wnmd_check_flip(RRCrtcPtr crtc, - WindowPtr window, - PixmapPtr pixmap, - Bool sync_flip, - RegionPtr valid, - int16_t x_off, - int16_t y_off, - PresentFlipReason *reason) -{ - ScreenPtr screen = window->drawable.pScreen; - present_screen_priv_ptr screen_priv = present_screen_priv(screen); - WindowPtr toplvl_window = present_wnmd_toplvl_pixmap_window(window); - - if (reason) - *reason = PRESENT_FLIP_REASON_UNKNOWN; - - if (!screen_priv) - return FALSE; - - if (!screen_priv->wnmd_info) - return FALSE; - - if (!crtc) - return FALSE; - - /* Check to see if the driver supports flips at all */ - if (!screen_priv->wnmd_info->flip) - return FALSE; - - /* Source pixmap must align with window exactly */ - if (x_off || y_off) - return FALSE; - - /* Valid area must contain window (for simplicity for now just never flip when one is set). */ - if (valid) - return FALSE; - - /* Flip pixmap must have same dimensions as window */ - if (window->drawable.width != pixmap->drawable.width || - window->drawable.height != pixmap->drawable.height) - return FALSE; - - /* Window must be same region as toplevel window */ - if ( !RegionEqual(&window->winSize, &toplvl_window->winSize) ) - return FALSE; - - /* Can't flip if window clipped by children */ - if (!RegionEqual(&window->clipList, &window->winSize)) - return FALSE; - - /* Ask the driver for permission */ - if (screen_priv->wnmd_info->check_flip2) { - if (!(*screen_priv->wnmd_info->check_flip2) (crtc, window, pixmap, sync_flip, reason)) { - DebugPresent(("\td %08" PRIx32 " -> %08" PRIx32 "\n", - window->drawable.id, pixmap ? pixmap->drawable.id : 0)); - return FALSE; - } - } - - return TRUE; -} - -/* - * 'window' is being reconfigured. Check to see if it is involved - * in flipping and clean up as necessary. - */ -static void -present_wnmd_check_flip_window (WindowPtr window) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - present_vblank_ptr flip_pending; - present_vblank_ptr flip_active; - present_vblank_ptr vblank; - PresentFlipReason reason; - - /* If this window hasn't ever been used with Present, it can't be - * flipping - */ - if (!window_priv) - return; - - flip_pending = window_priv->flip_pending; - flip_active = window_priv->flip_active; - - if (flip_pending) { - if (!present_wnmd_check_flip(flip_pending->crtc, flip_pending->window, flip_pending->pixmap, - flip_pending->sync_flip, flip_pending->valid, 0, 0, NULL)) - window_priv->flip_pending->abort_flip = TRUE; - } else if (flip_active) { - if (!present_wnmd_check_flip(flip_active->crtc, flip_active->window, flip_active->pixmap, - flip_active->sync_flip, flip_active->valid, 0, 0, NULL)) - present_wnmd_flips_stop(window); - } - - /* Now check any queued vblanks */ - xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) { - if (vblank->queued && vblank->flip && - !present_wnmd_check_flip(vblank->crtc, window, vblank->pixmap, - vblank->sync_flip, vblank->valid, 0, 0, &reason)) { - vblank->flip = FALSE; - vblank->reason = reason; - } - } -} - -/* - * Clean up any pending or current flips for this window - */ -static void -present_wnmd_clear_window_flip(WindowPtr window) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - present_vblank_ptr vblank, tmp; - - xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->flip_queue, event_queue) { - present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); - present_vblank_destroy(vblank); - } - - xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->idle_queue, event_queue) { - present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); - present_vblank_destroy(vblank); - } - - vblank = window_priv->flip_active; - if (vblank) { - present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); - present_vblank_destroy(vblank); - } - window_priv->flip_active = NULL; -} - -static Bool -present_wnmd_flip(WindowPtr window, - RRCrtcPtr crtc, - uint64_t event_id, - uint64_t target_msc, - PixmapPtr pixmap, - Bool sync_flip, - RegionPtr damage) -{ - ScreenPtr screen = window->drawable.pScreen; - present_screen_priv_ptr screen_priv = present_screen_priv(screen); - - return (*screen_priv->wnmd_info->flip) (window, - crtc, - event_id, - target_msc, - pixmap, - sync_flip, - damage); -} - -static void -present_wnmd_cancel_flip(WindowPtr window) -{ - present_window_priv_ptr window_priv = present_window_priv(window); - - if (window_priv->flip_pending) - window_priv->flip_pending->abort_flip = TRUE; - else if (window_priv->flip_active) - present_wnmd_flips_stop(window); -} - -/* - * Once the required MSC has been reached, execute the pending request. - * - * For requests to actually present something, either blt contents to - * the window pixmap or queue a window buffer swap on the backend. - * - * For requests to just get the current MSC/UST combo, skip that part and - * go straight to event delivery. - */ -static void -present_wnmd_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc) -{ - WindowPtr window = vblank->window; - present_window_priv_ptr window_priv = present_window_priv(window); - - if (present_execute_wait(vblank, crtc_msc)) - return; - - if (vblank->flip && vblank->pixmap && vblank->window) { - if (window_priv->flip_pending) { - DebugPresent(("\tr %" PRIu64 " %p (pending %p)\n", - vblank->event_id, vblank, - window_priv->flip_pending)); - xorg_list_del(&vblank->event_queue); - xorg_list_append(&vblank->event_queue, &window_priv->flip_queue); - vblank->flip_ready = TRUE; - return; - } - } - - xorg_list_del(&vblank->event_queue); - xorg_list_del(&vblank->window_list); - vblank->queued = FALSE; - - if (vblank->pixmap && vblank->window) { - ScreenPtr screen = window->drawable.pScreen; - - if (vblank->flip) { - RegionPtr damage; - - DebugPresent(("\tf %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", - vblank->event_id, vblank, crtc_msc, - vblank->pixmap->drawable.id, vblank->window->drawable.id)); - - /* Prepare to flip by placing it in the flip queue - */ - xorg_list_add(&vblank->event_queue, &window_priv->flip_queue); - - /* Set update region as damaged */ - if (vblank->update) { - damage = RegionDuplicate(vblank->update); - /* Translate update region to screen space */ - assert(vblank->x_off == 0 && vblank->y_off == 0); - RegionTranslate(damage, window->drawable.x, window->drawable.y); - RegionIntersect(damage, damage, &window->clipList); - } else - damage = RegionDuplicate(&window->clipList); - - /* Try to flip - the vblank is now pending - */ - window_priv->flip_pending = vblank; - // ask the driver - if (present_wnmd_flip(vblank->window, vblank->crtc, vblank->event_id, - vblank->target_msc, vblank->pixmap, vblank->sync_flip, damage)) { - WindowPtr toplvl_window = present_wnmd_toplvl_pixmap_window(vblank->window); - PixmapPtr old_pixmap = screen->GetWindowPixmap(window); - - /* Replace window pixmap with flip pixmap */ -#ifdef COMPOSITE - vblank->pixmap->screen_x = old_pixmap->screen_x; - vblank->pixmap->screen_y = old_pixmap->screen_y; -#endif - present_set_tree_pixmap(toplvl_window, old_pixmap, vblank->pixmap); - vblank->pixmap->refcnt++; - dixDestroyPixmap(old_pixmap, old_pixmap->drawable.id); - - /* Report damage */ - DamageDamageRegion(&vblank->window->drawable, damage); - RegionDestroy(damage); - return; - } - - xorg_list_del(&vblank->event_queue); - /* Flip failed. Clear the flip_pending field - */ - window_priv->flip_pending = NULL; - vblank->flip = FALSE; - } - DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", - vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id)); - - present_wnmd_cancel_flip(window); - - present_execute_copy(vblank, crtc_msc); - assert(!vblank->queued); - - if (present_wnmd_queue_vblank(screen, window, vblank->crtc, - vblank->event_id, crtc_msc + 1) - == Success) { - xorg_list_add(&vblank->event_queue, &window_priv->idle_queue); - xorg_list_append(&vblank->window_list, &window_priv->vblank); - - return; - } - } - - present_execute_post(vblank, ust, crtc_msc); -} - -static void -present_wnmd_update_window_crtc(WindowPtr window, RRCrtcPtr crtc, uint64_t new_msc) -{ - present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); - - /* Crtc unchanged, no offset. */ - if (crtc == window_priv->crtc) - return; - - /* No crtc earlier to offset against, just set the crtc. */ - if (window_priv->crtc == PresentCrtcNeverSet) { - window_priv->msc_offset = 0; - window_priv->crtc = crtc; - return; - } - - /* In window-mode the last correct msc-offset is always kept - * in window-priv struct because msc is saved per window and - * not per crtc as in screen-mode. - */ - window_priv->msc_offset += new_msc - window_priv->msc; - window_priv->crtc = crtc; -} - -static int -present_wnmd_pixmap(WindowPtr window, - PixmapPtr pixmap, - CARD32 serial, - RegionPtr valid, - RegionPtr update, - int16_t x_off, - int16_t y_off, - RRCrtcPtr target_crtc, - SyncFence *wait_fence, - SyncFence *idle_fence, - uint32_t options, - uint64_t target_window_msc, - uint64_t divisor, - uint64_t remainder, - present_notify_ptr notifies, - int num_notifies) -{ - uint64_t ust = 0; - uint64_t target_msc; - uint64_t crtc_msc = 0; - int ret; - present_vblank_ptr vblank, tmp; - ScreenPtr screen = window->drawable.pScreen; - present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE); - present_screen_priv_ptr screen_priv = present_screen_priv(screen); - - if (!window_priv) - return BadAlloc; - - target_crtc = present_wnmd_get_crtc(screen_priv, window); - - ret = present_wnmd_get_ust_msc(screen, window, &ust, &crtc_msc); - - present_wnmd_update_window_crtc(window, target_crtc, crtc_msc); - - if (ret == Success) { - /* Stash the current MSC away in case we need it later - */ - window_priv->msc = crtc_msc; - } - - target_msc = present_get_target_msc(target_window_msc + window_priv->msc_offset, - crtc_msc, - divisor, - remainder, - options); - - /* - * Look for a matching presentation already on the list... - */ - - if (!update && pixmap) { - xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) { - - if (!vblank->pixmap) - continue; - - if (!vblank->queued) - continue; - - if (vblank->target_msc != target_msc) - continue; - - present_vblank_scrap(vblank); - if (vblank->flip_ready) - present_wnmd_re_execute(vblank); - } - } - - vblank = present_vblank_create(window, - pixmap, - serial, - valid, - update, - x_off, - y_off, - target_crtc, - wait_fence, - idle_fence, - options, - screen_priv->wnmd_info->capabilities, - notifies, - num_notifies, - target_msc, - crtc_msc); - if (!vblank) - return BadAlloc; - - vblank->event_id = ++present_wnmd_event_id; - - /* WNMD presentations always complete (at least) one frame after they - * are executed - */ - vblank->exec_msc = vblank->target_msc - 1; - - xorg_list_append(&vblank->event_queue, &window_priv->exec_queue); - vblank->queued = TRUE; - if (crtc_msc < vblank->exec_msc) { - if (present_wnmd_queue_vblank(screen, window, target_crtc, vblank->event_id, vblank->exec_msc) == Success) { - return Success; - } - DebugPresent(("present_queue_vblank failed\n")); - } - - present_wnmd_execute(vblank, ust, crtc_msc); - return Success; -} - -static void -present_wnmd_abort_vblank(ScreenPtr screen, WindowPtr window, RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) -{ - present_screen_priv_ptr screen_priv = present_screen_priv(screen); - present_window_priv_ptr window_priv = present_window_priv(window); - present_vblank_ptr vblank; - - (*screen_priv->wnmd_info->abort_vblank) (window, crtc, event_id, msc); - - xorg_list_for_each_entry(vblank, &window_priv->exec_queue, event_queue) { - if (vblank->event_id == event_id) { - xorg_list_del(&vblank->event_queue); - vblank->queued = FALSE; - return; - } - } - xorg_list_for_each_entry(vblank, &window_priv->flip_queue, event_queue) { - if (vblank->event_id == event_id) { - xorg_list_del(&vblank->event_queue); - vblank->queued = FALSE; - return; - } - } -} - -static void -present_wnmd_flush(WindowPtr window) -{ - ScreenPtr screen = window->drawable.pScreen; - present_screen_priv_ptr screen_priv = present_screen_priv(screen); - - (*screen_priv->wnmd_info->flush) (window); -} - -/* - * Initialize a screen for use with present in window flip mode (wnmd) - */ -int -present_wnmd_screen_init(ScreenPtr screen, present_wnmd_info_ptr info) -{ - present_screen_priv_ptr screen_priv; - - if (!present_screen_register_priv_keys()) - return FALSE; - - if (present_screen_priv(screen)) - return TRUE; - - screen_priv = present_screen_priv_init(screen); - if (!screen_priv) - return FALSE; - - screen_priv->wnmd_info = info; - - screen_priv->query_capabilities = &present_wnmd_query_capabilities; - screen_priv->get_crtc = &present_wnmd_get_crtc; - - screen_priv->check_flip = &present_wnmd_check_flip; - screen_priv->check_flip_window = &present_wnmd_check_flip_window; - screen_priv->clear_window_flip = &present_wnmd_clear_window_flip; - - screen_priv->present_pixmap = &present_wnmd_pixmap; - screen_priv->queue_vblank = &present_wnmd_queue_vblank; - screen_priv->flush = &present_wnmd_flush; - screen_priv->re_execute = &present_wnmd_re_execute; - - screen_priv->abort_vblank = &present_wnmd_abort_vblank; - - return TRUE; -}