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