diff options
Diffstat (limited to 'xserver/present/present_vblank.c')
-rw-r--r-- | xserver/present/present_vblank.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/xserver/present/present_vblank.c b/xserver/present/present_vblank.c new file mode 100644 index 000000000..2c124f4bb --- /dev/null +++ b/xserver/present/present_vblank.c @@ -0,0 +1,203 @@ +/* + * Copyright © 2013 Keith Packard + * + * 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. + */ + +#ifdef HAVE_XORG_CONFIG_H +#include <xorg-config.h> +#endif + +#include "present_priv.h" + +void +present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_t ust, uint64_t crtc_msc) +{ + int n; + + if (vblank->window) + present_send_complete_notify(vblank->window, kind, mode, vblank->serial, ust, crtc_msc - vblank->msc_offset); + for (n = 0; n < vblank->num_notifies; n++) { + WindowPtr window = vblank->notifies[n].window; + CARD32 serial = vblank->notifies[n].serial; + + if (window) + present_send_complete_notify(window, kind, mode, serial, ust, crtc_msc - vblank->msc_offset); + } +} + +present_vblank_ptr +present_vblank_create(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, + const uint32_t *capabilities, + present_notify_ptr notifies, + int num_notifies, + uint64_t *target_msc, + uint64_t crtc_msc) +{ + 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); + present_vblank_ptr vblank; + PresentFlipReason reason = PRESENT_FLIP_REASON_UNKNOWN; + + vblank = calloc (1, sizeof (present_vblank_rec)); + if (!vblank) + return NULL; + + xorg_list_append(&vblank->window_list, &window_priv->vblank); + xorg_list_init(&vblank->event_queue); + + vblank->screen = screen; + vblank->window = window; + vblank->pixmap = pixmap; + + screen_priv->create_event_id(window_priv, vblank); + + if (pixmap) { + vblank->kind = PresentCompleteKindPixmap; + pixmap->refcnt++; + } else + vblank->kind = PresentCompleteKindNotifyMSC; + + vblank->serial = serial; + + if (valid) { + vblank->valid = RegionDuplicate(valid); + if (!vblank->valid) + goto no_mem; + } + if (update) { + vblank->update = RegionDuplicate(update); + if (!vblank->update) + goto no_mem; + } + + vblank->x_off = x_off; + vblank->y_off = y_off; + vblank->target_msc = *target_msc; + vblank->crtc = target_crtc; + vblank->msc_offset = window_priv->msc_offset; + vblank->notifies = notifies; + vblank->num_notifies = num_notifies; + vblank->has_suboptimal = (options & PresentOptionSuboptimal); + vblank->flip_idler = FALSE; + + if (pixmap != NULL && + !(options & PresentOptionCopy) && + capabilities) { + if (msc_is_after(*target_msc, crtc_msc) && + screen_priv->check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason)) + { + vblank->flip = TRUE; + vblank->sync_flip = TRUE; + *target_msc = *target_msc - 1; + } else if ((*capabilities & PresentCapabilityAsync) && + screen_priv->check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason)) + { + vblank->flip = TRUE; + } + } + vblank->reason = reason; + + if (wait_fence) { + vblank->wait_fence = present_fence_create(wait_fence); + if (!vblank->wait_fence) + goto no_mem; + } + + if (idle_fence) { + vblank->idle_fence = present_fence_create(idle_fence); + if (!vblank->idle_fence) + goto no_mem; + } + + if (pixmap) + DebugPresent(("q %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 " (crtc %p) flip %d vsync %d serial %d\n", + vblank->event_id, vblank, *target_msc, + vblank->pixmap->drawable.id, vblank->window->drawable.id, + target_crtc, vblank->flip, vblank->sync_flip, vblank->serial)); + return vblank; + +no_mem: + vblank->notifies = NULL; + present_vblank_destroy(vblank); + return NULL; +} + +void +present_vblank_scrap(present_vblank_ptr vblank) +{ + DebugPresent(("\tx %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 " (crtc %p)\n", + vblank->event_id, vblank, vblank->target_msc, + vblank->pixmap->drawable.id, vblank->window->drawable.id, + vblank->crtc)); + + present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence); + present_fence_destroy(vblank->idle_fence); + dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id); + + vblank->pixmap = NULL; + vblank->idle_fence = NULL; + vblank->flip = FALSE; +} + +void +present_vblank_destroy(present_vblank_ptr vblank) +{ + /* Remove vblank from window and screen lists */ + xorg_list_del(&vblank->window_list); + /* Also make sure vblank is removed from event queue (wnmd) */ + xorg_list_del(&vblank->event_queue); + + DebugPresent(("\td %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n", + vblank->event_id, vblank, vblank->target_msc, + vblank->pixmap ? vblank->pixmap->drawable.id : 0, + vblank->window ? vblank->window->drawable.id : 0)); + + /* Drop pixmap reference */ + if (vblank->pixmap) + dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id); + + /* Free regions */ + if (vblank->valid) + RegionDestroy(vblank->valid); + if (vblank->update) + RegionDestroy(vblank->update); + + if (vblank->wait_fence) + present_fence_destroy(vblank->wait_fence); + + if (vblank->idle_fence) + present_fence_destroy(vblank->idle_fence); + + if (vblank->notifies) + present_destroy_notifies(vblank->notifies, vblank->num_notifies); + + free(vblank); +} |