11b5d61b8Smrg/*
21b5d61b8Smrg * Copyright © 2013 Keith Packard
31b5d61b8Smrg *
41b5d61b8Smrg * Permission to use, copy, modify, distribute, and sell this software and its
51b5d61b8Smrg * documentation for any purpose is hereby granted without fee, provided that
61b5d61b8Smrg * the above copyright notice appear in all copies and that both that copyright
71b5d61b8Smrg * notice and this permission notice appear in supporting documentation, and
81b5d61b8Smrg * that the name of the copyright holders not be used in advertising or
91b5d61b8Smrg * publicity pertaining to distribution of the software without specific,
101b5d61b8Smrg * written prior permission.  The copyright holders make no representations
111b5d61b8Smrg * about the suitability of this software for any purpose.  It is provided "as
121b5d61b8Smrg * is" without express or implied warranty.
131b5d61b8Smrg *
141b5d61b8Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
151b5d61b8Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
161b5d61b8Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
171b5d61b8Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
181b5d61b8Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
191b5d61b8Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
201b5d61b8Smrg * OF THIS SOFTWARE.
211b5d61b8Smrg */
221b5d61b8Smrg
231b5d61b8Smrg#include "present_priv.h"
241b5d61b8Smrg
251b5d61b8Smrgvoid
261b5d61b8Smrgpresent_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_t ust, uint64_t crtc_msc)
271b5d61b8Smrg{
281b5d61b8Smrg    int n;
291b5d61b8Smrg
301b5d61b8Smrg    if (vblank->window)
311b5d61b8Smrg        present_send_complete_notify(vblank->window, kind, mode, vblank->serial, ust, crtc_msc - vblank->msc_offset);
321b5d61b8Smrg    for (n = 0; n < vblank->num_notifies; n++) {
331b5d61b8Smrg        WindowPtr   window = vblank->notifies[n].window;
341b5d61b8Smrg        CARD32      serial = vblank->notifies[n].serial;
351b5d61b8Smrg
361b5d61b8Smrg        if (window)
371b5d61b8Smrg            present_send_complete_notify(window, kind, mode, serial, ust, crtc_msc - vblank->msc_offset);
381b5d61b8Smrg    }
391b5d61b8Smrg}
401b5d61b8Smrg
41ed6184dfSmrg/* The memory vblank points to must be 0-initialized before calling this function.
42ed6184dfSmrg *
43ed6184dfSmrg * If this function returns FALSE, present_vblank_destroy must be called to clean
44ed6184dfSmrg * up.
45ed6184dfSmrg */
46ed6184dfSmrgBool
47ed6184dfSmrgpresent_vblank_init(present_vblank_ptr vblank,
48ed6184dfSmrg                    WindowPtr window,
49ed6184dfSmrg                    PixmapPtr pixmap,
50ed6184dfSmrg                    CARD32 serial,
51ed6184dfSmrg                    RegionPtr valid,
52ed6184dfSmrg                    RegionPtr update,
53ed6184dfSmrg                    int16_t x_off,
54ed6184dfSmrg                    int16_t y_off,
55ed6184dfSmrg                    RRCrtcPtr target_crtc,
56ed6184dfSmrg                    SyncFence *wait_fence,
57ed6184dfSmrg                    SyncFence *idle_fence,
58ed6184dfSmrg                    uint32_t options,
59ed6184dfSmrg                    const uint32_t capabilities,
60ed6184dfSmrg                    present_notify_ptr notifies,
61ed6184dfSmrg                    int num_notifies,
62ed6184dfSmrg                    uint64_t target_msc,
63ed6184dfSmrg                    uint64_t crtc_msc)
641b5d61b8Smrg{
651b5d61b8Smrg    ScreenPtr                   screen = window->drawable.pScreen;
661b5d61b8Smrg    present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
671b5d61b8Smrg    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
681b5d61b8Smrg    PresentFlipReason           reason = PRESENT_FLIP_REASON_UNKNOWN;
691b5d61b8Smrg
70a035e2b2Smrg    if (target_crtc) {
71a035e2b2Smrg        screen_priv = present_screen_priv(target_crtc->pScreen);
72a035e2b2Smrg    }
73a035e2b2Smrg
741b5d61b8Smrg    xorg_list_append(&vblank->window_list, &window_priv->vblank);
751b5d61b8Smrg    xorg_list_init(&vblank->event_queue);
761b5d61b8Smrg
771b5d61b8Smrg    vblank->screen = screen;
781b5d61b8Smrg    vblank->window = window;
791b5d61b8Smrg    vblank->pixmap = pixmap;
801b5d61b8Smrg
811b5d61b8Smrg    if (pixmap) {
821b5d61b8Smrg        vblank->kind = PresentCompleteKindPixmap;
831b5d61b8Smrg        pixmap->refcnt++;
841b5d61b8Smrg    } else
851b5d61b8Smrg        vblank->kind = PresentCompleteKindNotifyMSC;
861b5d61b8Smrg
871b5d61b8Smrg    vblank->serial = serial;
881b5d61b8Smrg
891b5d61b8Smrg    if (valid) {
901b5d61b8Smrg        vblank->valid = RegionDuplicate(valid);
911b5d61b8Smrg        if (!vblank->valid)
921b5d61b8Smrg            goto no_mem;
931b5d61b8Smrg    }
941b5d61b8Smrg    if (update) {
951b5d61b8Smrg        vblank->update = RegionDuplicate(update);
961b5d61b8Smrg        if (!vblank->update)
971b5d61b8Smrg            goto no_mem;
981b5d61b8Smrg    }
991b5d61b8Smrg
1001b5d61b8Smrg    vblank->x_off = x_off;
1011b5d61b8Smrg    vblank->y_off = y_off;
1025a7dfde8Smrg    vblank->target_msc = target_msc;
1035a7dfde8Smrg    vblank->exec_msc = target_msc;
1041b5d61b8Smrg    vblank->crtc = target_crtc;
1051b5d61b8Smrg    vblank->msc_offset = window_priv->msc_offset;
1061b5d61b8Smrg    vblank->notifies = notifies;
1071b5d61b8Smrg    vblank->num_notifies = num_notifies;
1081b5d61b8Smrg    vblank->has_suboptimal = (options & PresentOptionSuboptimal);
1091b5d61b8Smrg
1101b5d61b8Smrg    if (pixmap != NULL &&
1111b5d61b8Smrg        !(options & PresentOptionCopy) &&
112ed6184dfSmrg        screen_priv->check_flip) {
1135a7dfde8Smrg        if (msc_is_after(target_msc, crtc_msc) &&
1141b5d61b8Smrg            screen_priv->check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason))
1151b5d61b8Smrg        {
1161b5d61b8Smrg            vblank->flip = TRUE;
1171b5d61b8Smrg            vblank->sync_flip = TRUE;
118ed6184dfSmrg        } else if ((capabilities & PresentCapabilityAsync) &&
1191b5d61b8Smrg            screen_priv->check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason))
1201b5d61b8Smrg        {
1211b5d61b8Smrg            vblank->flip = TRUE;
1221b5d61b8Smrg        }
1231b5d61b8Smrg    }
1241b5d61b8Smrg    vblank->reason = reason;
1251b5d61b8Smrg
1261b5d61b8Smrg    if (wait_fence) {
1271b5d61b8Smrg        vblank->wait_fence = present_fence_create(wait_fence);
1281b5d61b8Smrg        if (!vblank->wait_fence)
1291b5d61b8Smrg            goto no_mem;
1301b5d61b8Smrg    }
1311b5d61b8Smrg
1321b5d61b8Smrg    if (idle_fence) {
1331b5d61b8Smrg        vblank->idle_fence = present_fence_create(idle_fence);
1341b5d61b8Smrg        if (!vblank->idle_fence)
1351b5d61b8Smrg            goto no_mem;
1361b5d61b8Smrg    }
1371b5d61b8Smrg
1381b5d61b8Smrg    if (pixmap)
139e23ec014Smrg        DebugPresent(("q %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 " (crtc %p) flip %d vsync %d serial %d\n",
1405a7dfde8Smrg                      vblank->event_id, vblank, target_msc,
1411b5d61b8Smrg                      vblank->pixmap->drawable.id, vblank->window->drawable.id,
1421b5d61b8Smrg                      target_crtc, vblank->flip, vblank->sync_flip, vblank->serial));
143ed6184dfSmrg    return TRUE;
1441b5d61b8Smrg
1451b5d61b8Smrgno_mem:
1461b5d61b8Smrg    vblank->notifies = NULL;
147ed6184dfSmrg    return FALSE;
148ed6184dfSmrg}
149ed6184dfSmrg
150ed6184dfSmrgpresent_vblank_ptr
151ed6184dfSmrgpresent_vblank_create(WindowPtr window,
152ed6184dfSmrg                      PixmapPtr pixmap,
153ed6184dfSmrg                      CARD32 serial,
154ed6184dfSmrg                      RegionPtr valid,
155ed6184dfSmrg                      RegionPtr update,
156ed6184dfSmrg                      int16_t x_off,
157ed6184dfSmrg                      int16_t y_off,
158ed6184dfSmrg                      RRCrtcPtr target_crtc,
159ed6184dfSmrg                      SyncFence *wait_fence,
160ed6184dfSmrg                      SyncFence *idle_fence,
161ed6184dfSmrg                      uint32_t options,
162ed6184dfSmrg                      const uint32_t capabilities,
163ed6184dfSmrg                      present_notify_ptr notifies,
164ed6184dfSmrg                      int num_notifies,
165ed6184dfSmrg                      uint64_t target_msc,
166ed6184dfSmrg                      uint64_t crtc_msc)
167ed6184dfSmrg{
168ed6184dfSmrg    present_vblank_ptr vblank = calloc(1, sizeof(present_vblank_rec));
169ed6184dfSmrg
170ed6184dfSmrg    if (!vblank)
171ed6184dfSmrg        return NULL;
172ed6184dfSmrg
173ed6184dfSmrg    if (present_vblank_init(vblank, window, pixmap, serial, valid, update,
174ed6184dfSmrg                            x_off, y_off, target_crtc, wait_fence, idle_fence,
175ed6184dfSmrg                            options, capabilities, notifies, num_notifies,
176ed6184dfSmrg                            target_msc, crtc_msc))
177ed6184dfSmrg        return vblank;
178ed6184dfSmrg
1791b5d61b8Smrg    present_vblank_destroy(vblank);
1801b5d61b8Smrg    return NULL;
1811b5d61b8Smrg}
1821b5d61b8Smrg
1831b5d61b8Smrgvoid
1841b5d61b8Smrgpresent_vblank_scrap(present_vblank_ptr vblank)
1851b5d61b8Smrg{
1865a7dfde8Smrg    DebugPresent(("\tx %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 " (crtc %p)\n",
1875a7dfde8Smrg                  vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc,
1881b5d61b8Smrg                  vblank->pixmap->drawable.id, vblank->window->drawable.id,
1891b5d61b8Smrg                  vblank->crtc));
1901b5d61b8Smrg
1911b5d61b8Smrg    present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
1921b5d61b8Smrg    present_fence_destroy(vblank->idle_fence);
1931b5d61b8Smrg    dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
1941b5d61b8Smrg
1951b5d61b8Smrg    vblank->pixmap = NULL;
1961b5d61b8Smrg    vblank->idle_fence = NULL;
1971b5d61b8Smrg    vblank->flip = FALSE;
1981b5d61b8Smrg}
1991b5d61b8Smrg
2001b5d61b8Smrgvoid
2011b5d61b8Smrgpresent_vblank_destroy(present_vblank_ptr vblank)
2021b5d61b8Smrg{
2031b5d61b8Smrg    /* Remove vblank from window and screen lists */
2041b5d61b8Smrg    xorg_list_del(&vblank->window_list);
2051b5d61b8Smrg    /* Also make sure vblank is removed from event queue (wnmd) */
2061b5d61b8Smrg    xorg_list_del(&vblank->event_queue);
2071b5d61b8Smrg
2085a7dfde8Smrg    DebugPresent(("\td %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
2095a7dfde8Smrg                  vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc,
2101b5d61b8Smrg                  vblank->pixmap ? vblank->pixmap->drawable.id : 0,
2111b5d61b8Smrg                  vblank->window ? vblank->window->drawable.id : 0));
2121b5d61b8Smrg
2131b5d61b8Smrg    /* Drop pixmap reference */
2141b5d61b8Smrg    if (vblank->pixmap)
2151b5d61b8Smrg        dixDestroyPixmap(vblank->pixmap, vblank->pixmap->drawable.id);
2161b5d61b8Smrg
2171b5d61b8Smrg    /* Free regions */
2181b5d61b8Smrg    if (vblank->valid)
2191b5d61b8Smrg        RegionDestroy(vblank->valid);
2201b5d61b8Smrg    if (vblank->update)
2211b5d61b8Smrg        RegionDestroy(vblank->update);
2221b5d61b8Smrg
2231b5d61b8Smrg    if (vblank->wait_fence)
2241b5d61b8Smrg        present_fence_destroy(vblank->wait_fence);
2251b5d61b8Smrg
2261b5d61b8Smrg    if (vblank->idle_fence)
2271b5d61b8Smrg        present_fence_destroy(vblank->idle_fence);
2281b5d61b8Smrg
2291b5d61b8Smrg    if (vblank->notifies)
2301b5d61b8Smrg        present_destroy_notifies(vblank->notifies, vblank->num_notifies);
2311b5d61b8Smrg
2321b5d61b8Smrg    free(vblank);
2331b5d61b8Smrg}
234