xwayland/present: Skip queued flip when a new one becomes ready
[xserver.git] / hw / xwayland / xwayland-present.c
blob60427cca0e944d649f2929d41e71e56baeb11f8d
1 /*
2 * Copyright © 2018 Roman Gilg
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of the
9 * copyright holders not be used in advertising or publicity
10 * pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no
12 * representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied
14 * warranty.
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
21 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
22 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 * SOFTWARE.
26 #include <xwayland-config.h>
28 #include <compint.h>
29 #ifdef XWL_HAS_GLAMOR
30 #include <glamor.h>
31 #endif
32 #include <windowstr.h>
33 #include <present.h>
34 #include <sys/eventfd.h>
36 #include "xwayland-present.h"
37 #include "xwayland-screen.h"
38 #include "xwayland-shm.h"
39 #include "xwayland-window.h"
40 #include "xwayland-window-buffers.h"
41 #include "xwayland-pixmap.h"
43 #include "tearing-control-v1-client-protocol.h"
44 #include "linux-drm-syncobj-v1-client-protocol.h"
46 #define XWL_PRESENT_CAPS PresentCapabilityAsync | PresentCapabilityAsyncMayTear
50 * When not flipping let Present copy with 60fps.
51 * When flipping wait on frame_callback, otherwise
52 * the surface is not visible, in this case update
53 * with long interval.
55 #define TIMER_LEN_COPY 17 // ~60fps
56 #define TIMER_LEN_FLIP 1000 // 1fps
58 static DevPrivateKeyRec xwl_present_window_private_key;
60 static struct xwl_present_window *
61 xwl_present_window_priv(WindowPtr window)
63 return dixGetPrivate(&window->devPrivates,
64 &xwl_present_window_private_key);
67 static struct xwl_present_window *
68 xwl_present_window_get_priv(WindowPtr window)
70 struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
72 if (xwl_present_window == NULL) {
73 xwl_present_window = calloc (1, sizeof (struct xwl_present_window));
74 if (!xwl_present_window)
75 return NULL;
77 xwl_present_window->window = window;
78 xwl_present_window->msc = 1;
79 xwl_present_window->ust = GetTimeInMicros();
81 xorg_list_init(&xwl_present_window->frame_callback_list);
82 xorg_list_init(&xwl_present_window->wait_list);
83 xorg_list_init(&xwl_present_window->flip_queue);
84 xorg_list_init(&xwl_present_window->idle_queue);
85 xorg_list_init(&xwl_present_window->blocked_queue);
87 dixSetPrivate(&window->devPrivates,
88 &xwl_present_window_private_key,
89 xwl_present_window);
92 return xwl_present_window;
95 static struct xwl_present_event *
96 xwl_present_event_from_id(WindowPtr present_window, uint64_t event_id)
98 present_window_priv_ptr window_priv = present_get_window_priv(present_window, TRUE);
99 struct xwl_present_event *event;
101 xorg_list_for_each_entry(event, &window_priv->vblank, vblank.window_list) {
102 if (event->vblank.event_id == event_id)
103 return event;
105 return NULL;
108 static struct xwl_present_event *
109 xwl_present_event_from_vblank(present_vblank_ptr vblank)
111 return container_of(vblank, struct xwl_present_event, vblank);
114 static Bool entered_for_each_frame_callback;
116 Bool
117 xwl_present_entered_for_each_frame_callback(void)
119 return entered_for_each_frame_callback;
122 void
123 xwl_present_for_each_frame_callback(struct xwl_window *xwl_window,
124 void iter_func(struct xwl_present_window *))
126 struct xwl_present_window *xwl_present_window, *tmp;
128 if (entered_for_each_frame_callback)
129 FatalError("Nested xwl_present_for_each_frame_callback call");
131 entered_for_each_frame_callback = TRUE;
133 xorg_list_for_each_entry_safe(xwl_present_window, tmp,
134 &xwl_window->frame_callback_list,
135 frame_callback_list)
136 iter_func(xwl_present_window);
138 entered_for_each_frame_callback = FALSE;
141 static void
142 xwl_present_free_timer(struct xwl_present_window *xwl_present_window)
144 TimerFree(xwl_present_window->frame_timer);
145 xwl_present_window->frame_timer = NULL;
146 xwl_present_window->timer_armed = 0;
149 static CARD32
150 xwl_present_timer_callback(OsTimerPtr timer,
151 CARD32 time,
152 void *arg);
154 static present_vblank_ptr
155 xwl_present_get_pending_flip(struct xwl_present_window *xwl_present_window)
157 present_vblank_ptr flip_pending;
159 if (xorg_list_is_empty(&xwl_present_window->flip_queue))
160 return NULL;
162 flip_pending = xorg_list_first_entry(&xwl_present_window->flip_queue, present_vblank_rec,
163 event_queue);
165 if (flip_pending->queued)
166 return NULL;
168 return flip_pending;
171 static inline Bool
172 xwl_present_has_pending_events(struct xwl_present_window *xwl_present_window)
174 present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window);
176 return (flip_pending && flip_pending->sync_flip) ||
177 !xorg_list_is_empty(&xwl_present_window->wait_list) ||
178 !xorg_list_is_empty(&xwl_present_window->blocked_queue);
181 void
182 xwl_present_reset_timer(struct xwl_present_window *xwl_present_window)
184 if (xwl_present_has_pending_events(xwl_present_window)) {
185 struct xwl_window *xwl_window = xwl_window_from_window(xwl_present_window->window);
186 CARD32 now = GetTimeInMillis();
187 CARD32 timeout;
189 if (xwl_window && xwl_window->frame_callback &&
190 !xorg_list_is_empty(&xwl_present_window->frame_callback_list))
191 timeout = TIMER_LEN_FLIP;
192 else
193 timeout = TIMER_LEN_COPY;
195 /* Make sure the timer callback runs if at least a second has passed
196 * since we first armed the timer. This can happen e.g. if the Wayland
197 * compositor doesn't send a pending frame event, e.g. because the
198 * Wayland surface isn't visible anywhere.
200 if (xwl_present_window->timer_armed) {
201 if ((int)(now - xwl_present_window->timer_armed) > 1000) {
202 xwl_present_timer_callback(xwl_present_window->frame_timer, now,
203 xwl_present_window);
204 return;
206 } else {
207 xwl_present_window->timer_armed = now;
210 xwl_present_window->frame_timer = TimerSet(xwl_present_window->frame_timer,
211 0, timeout,
212 &xwl_present_timer_callback,
213 xwl_present_window);
214 } else {
215 xwl_present_free_timer(xwl_present_window);
220 static void
221 xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
223 static int
224 xwl_present_queue_vblank(ScreenPtr screen,
225 WindowPtr present_window,
226 RRCrtcPtr crtc,
227 uint64_t event_id,
228 uint64_t msc);
230 static uint32_t
231 xwl_present_query_capabilities(present_screen_priv_ptr screen_priv)
233 struct xwl_screen *xwl_screen = xwl_screen_get(screen_priv->pScreen);
234 return xwl_screen->present_capabilities;
237 static int
238 xwl_present_get_ust_msc(ScreenPtr screen,
239 WindowPtr present_window,
240 uint64_t *ust,
241 uint64_t *msc)
243 struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
244 if (!xwl_present_window)
245 return BadAlloc;
247 *ust = xwl_present_window->ust;
248 *msc = xwl_present_window->msc;
250 return Success;
253 static uint64_t
254 xwl_present_get_exec_msc(uint32_t options, uint64_t target_msc)
256 /* Synchronous Xwayland presentations always complete (at least) one frame after they
257 * are executed
259 if (options & PresentOptionAsyncMayTear)
260 return target_msc;
262 return target_msc - 1;
266 * When the wait fence or previous flip is completed, it's time
267 * to re-try the request
269 static void
270 xwl_present_re_execute(present_vblank_ptr vblank)
272 struct xwl_present_event *event = xwl_present_event_from_vblank(vblank);
273 uint64_t ust = 0, crtc_msc = 0;
275 (void) xwl_present_get_ust_msc(vblank->screen, vblank->window, &ust, &crtc_msc);
276 /* re-compute target / exec msc */
277 vblank->target_msc = present_get_target_msc(0, crtc_msc,
278 event->divisor,
279 event->remainder,
280 event->options);
281 vblank->exec_msc = xwl_present_get_exec_msc(event->options,
282 vblank->target_msc);
284 vblank->queued = TRUE;
285 if (msc_is_after(vblank->exec_msc, crtc_msc) &&
286 xwl_present_queue_vblank(vblank->screen, vblank->window,
287 vblank->crtc,
288 vblank->event_id,
289 vblank->exec_msc) == Success) {
290 return;
293 xwl_present_execute(vblank, ust, crtc_msc);
296 static void
297 xwl_present_flip_try_ready(struct xwl_present_window *xwl_present_window)
299 present_vblank_ptr vblank;
301 xorg_list_for_each_entry(vblank, &xwl_present_window->flip_queue, event_queue) {
302 if (vblank->queued) {
303 xwl_present_re_execute(vblank);
304 return;
309 static void
310 xwl_present_release_pixmap(struct xwl_present_event *event)
312 if (!event->pixmap)
313 return;
315 xwl_pixmap_del_buffer_release_cb(event->pixmap);
316 dixDestroyPixmap(event->pixmap, event->pixmap->drawable.id);
317 event->pixmap = NULL;
320 static void
321 xwl_present_free_event(struct xwl_present_event *event)
323 xwl_present_release_pixmap(event);
324 xorg_list_del(&event->vblank.event_queue);
325 present_vblank_destroy(&event->vblank);
328 static void
329 xwl_present_free_idle_vblank(present_vblank_ptr vblank)
331 #ifdef XWL_HAS_GLAMOR
332 if (vblank->release_syncobj) {
333 /* transfer implicit fence to release syncobj */
334 int fence_fd = xwl_glamor_dmabuf_export_sync_file(vblank->pixmap);
335 vblank->release_syncobj->import_fence(vblank->release_syncobj,
336 vblank->release_point,
337 fence_fd);
338 } else
339 #endif /* XWL_HAS_GLAMOR */
340 present_pixmap_idle(vblank->pixmap, vblank->window,
341 vblank->serial, vblank->idle_fence);
342 xwl_present_free_event(xwl_present_event_from_vblank(vblank));
345 static WindowPtr
346 xwl_present_toplvl_pixmap_window(WindowPtr window)
348 ScreenPtr screen = window->drawable.pScreen;
349 PixmapPtr pixmap = (*screen->GetWindowPixmap)(window);
350 WindowPtr w = window;
351 WindowPtr next_w;
353 while(w->parent) {
354 next_w = w->parent;
355 if ( (*screen->GetWindowPixmap)(next_w) != pixmap) {
356 break;
358 w = next_w;
360 return w;
363 static void
364 xwl_present_flips_stop(WindowPtr window)
366 struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
367 present_vblank_ptr vblank, tmp;
369 /* Change back to the fast refresh rate */
370 xwl_present_reset_timer(xwl_present_window);
372 /* Free any left over idle vblanks */
373 xorg_list_for_each_entry_safe(vblank, tmp, &xwl_present_window->idle_queue, event_queue)
374 xwl_present_free_idle_vblank(vblank);
376 if (xwl_present_window->flip_active) {
377 struct xwl_present_event *event;
379 vblank = xwl_present_window->flip_active;
380 event = xwl_present_event_from_vblank(vblank);
381 if (event->pixmap)
382 xwl_present_free_idle_vblank(vblank);
383 else
384 xwl_present_free_event(event);
386 xwl_present_window->flip_active = NULL;
389 xwl_present_flip_try_ready(xwl_present_window);
392 static void
393 xwl_present_flip_notify_vblank(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
395 WindowPtr window = vblank->window;
396 struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
397 struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
398 uint8_t mode = PresentCompleteModeFlip;
400 DebugPresent(("\tn %" PRIu64 " %p %" PRIu64 " %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
401 vblank->event_id, vblank, vblank->exec_msc, vblank->target_msc,
402 vblank->pixmap ? vblank->pixmap->drawable.id : 0,
403 vblank->window ? vblank->window->drawable.id : 0));
405 assert (&vblank->event_queue == xwl_present_window->flip_queue.next);
407 xorg_list_del(&vblank->event_queue);
409 if (xwl_present_window->flip_active) {
410 struct xwl_present_event *event =
411 xwl_present_event_from_vblank(xwl_present_window->flip_active);
413 if (!event->pixmap
414 #ifdef DRI3
415 /* If this flip used explicit sync, we won't get a release event */
416 || (xwl_screen->explicit_sync && vblank->release_syncobj)
417 #endif /* DRI3 */
419 xwl_present_free_event(event);
420 } else
421 /* Put the previous flip in the idle_queue and wait for further notice from
422 * the Wayland compositor
424 xorg_list_append(&xwl_present_window->flip_active->event_queue, &xwl_present_window->idle_queue);
427 xwl_present_window->flip_active = vblank;
429 if (vblank->reason == PRESENT_FLIP_REASON_BUFFER_FORMAT)
430 mode = PresentCompleteModeSuboptimalCopy;
432 present_vblank_notify(vblank, PresentCompleteKindPixmap, mode, ust, crtc_msc);
434 if (vblank->abort_flip)
435 xwl_present_flips_stop(window);
437 xwl_present_flip_try_ready(xwl_present_window);
440 static void
441 xwl_present_update_window_crtc(present_window_priv_ptr window_priv, RRCrtcPtr crtc, uint64_t new_msc)
443 /* Crtc unchanged, no offset. */
444 if (crtc == window_priv->crtc)
445 return;
447 /* No crtc earlier to offset against, just set the crtc. */
448 if (window_priv->crtc == PresentCrtcNeverSet) {
449 window_priv->msc_offset = 0;
450 window_priv->crtc = crtc;
451 return;
454 /* In window-mode the last correct msc-offset is always kept
455 * in window-priv struct because msc is saved per window and
456 * not per crtc as in screen-mode.
458 window_priv->msc_offset += new_msc - window_priv->msc;
459 window_priv->crtc = crtc;
463 void
464 xwl_present_cleanup(WindowPtr window)
466 struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
467 present_window_priv_ptr window_priv = present_window_priv(window);
468 struct xwl_present_event *event, *tmp;
470 if (!xwl_present_window)
471 return;
473 xorg_list_del(&xwl_present_window->frame_callback_list);
475 if (xwl_present_window->sync_callback) {
476 wl_callback_destroy(xwl_present_window->sync_callback);
477 xwl_present_window->sync_callback = NULL;
480 if (window_priv) {
481 /* Clear remaining events */
482 xorg_list_for_each_entry_safe(event, tmp, &window_priv->vblank, vblank.window_list)
483 xwl_present_free_event(event);
486 /* Clear timer */
487 xwl_present_free_timer(xwl_present_window);
488 TimerFree(xwl_present_window->unredirect_timer);
490 /* Remove from privates so we don't try to access it later */
491 dixSetPrivate(&window->devPrivates,
492 &xwl_present_window_private_key,
493 NULL);
495 free(xwl_present_window);
498 static void
499 xwl_present_buffer_release(void *data)
501 struct xwl_present_window *xwl_present_window;
502 struct xwl_present_event *event = data;
503 present_vblank_ptr vblank;
505 if (!event)
506 return;
508 vblank = &event->vblank;
510 #ifdef XWL_HAS_GLAMOR
511 if (vblank->release_syncobj) {
512 /* transfer implicit fence to release syncobj */
513 int fence_fd = xwl_glamor_dmabuf_export_sync_file(vblank->pixmap);
514 vblank->release_syncobj->import_fence(vblank->release_syncobj,
515 vblank->release_point,
516 fence_fd);
517 } else
518 #endif /* XWL_HAS_GLAMOR */
519 present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
521 xwl_present_window = xwl_present_window_priv(vblank->window);
522 if (xwl_present_window->flip_active == vblank ||
523 xwl_present_get_pending_flip(xwl_present_window) == vblank)
524 xwl_present_release_pixmap(event);
525 else
526 xwl_present_free_event(event);
529 static void
530 xwl_present_msc_bump(struct xwl_present_window *xwl_present_window)
532 present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window);
533 uint64_t msc = ++xwl_present_window->msc;
534 present_vblank_ptr vblank, tmp;
536 xwl_present_window->ust = GetTimeInMicros();
538 xwl_present_window->timer_armed = 0;
540 if (flip_pending && flip_pending->sync_flip)
541 xwl_present_flip_notify_vblank(flip_pending, xwl_present_window->ust, msc);
543 xorg_list_for_each_entry_safe(vblank, tmp, &xwl_present_window->wait_list, event_queue) {
544 if (vblank->exec_msc <= msc) {
545 DebugPresent(("\te %" PRIu64 " ust %" PRIu64 " msc %" PRIu64 "\n",
546 vblank->event_id, xwl_present_window->ust, msc));
548 xwl_present_execute(vblank, xwl_present_window->ust, msc);
553 static CARD32
554 xwl_present_timer_callback(OsTimerPtr timer,
555 CARD32 time,
556 void *arg)
558 struct xwl_present_window *xwl_present_window = arg;
560 /* If we were expecting a frame callback for this window, it didn't arrive
561 * in a second. Stop listening to it to avoid double-bumping the MSC
563 xorg_list_del(&xwl_present_window->frame_callback_list);
565 xwl_present_msc_bump(xwl_present_window);
566 xwl_present_reset_timer(xwl_present_window);
568 return 0;
571 void
572 xwl_present_frame_callback(struct xwl_present_window *xwl_present_window)
574 xorg_list_del(&xwl_present_window->frame_callback_list);
576 xwl_present_msc_bump(xwl_present_window);
578 /* we do not need the timer anymore for this frame,
579 * reset it for potentially the next one
581 xwl_present_reset_timer(xwl_present_window);
584 static void
585 xwl_present_sync_callback(void *data,
586 struct wl_callback *callback,
587 uint32_t time)
589 present_vblank_ptr vblank = data;
590 struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(vblank->window);
592 wl_callback_destroy(xwl_present_window->sync_callback);
593 xwl_present_window->sync_callback = NULL;
595 xwl_present_flip_notify_vblank(vblank, xwl_present_window->ust, xwl_present_window->msc);
598 static const struct wl_callback_listener xwl_present_sync_listener = {
599 xwl_present_sync_callback
602 static RRCrtcPtr
603 xwl_present_get_crtc(present_screen_priv_ptr screen_priv,
604 WindowPtr present_window)
606 struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
607 rrScrPrivPtr rr_private;
609 if (xwl_present_window == NULL)
610 return NULL;
612 rr_private = rrGetScrPriv(present_window->drawable.pScreen);
614 if (rr_private->numCrtcs == 0)
615 return NULL;
617 return rr_private->crtcs[0];
621 * Queue an event to report back to the Present extension when the specified
622 * MSC has passed
624 static int
625 xwl_present_queue_vblank(ScreenPtr screen,
626 WindowPtr present_window,
627 RRCrtcPtr crtc,
628 uint64_t event_id,
629 uint64_t msc)
631 struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(present_window);
632 struct xwl_window *xwl_window = xwl_window_from_window(present_window);
633 struct xwl_present_event *event = xwl_present_event_from_id(present_window, event_id);
635 if (!event) {
636 ErrorF("present: Error getting event\n");
637 return BadImplementation;
640 event->vblank.exec_msc = msc;
642 xorg_list_del(&event->vblank.event_queue);
643 xorg_list_append(&event->vblank.event_queue, &xwl_present_window->wait_list);
645 /* Hook up to frame callback */
646 if (xwl_window &&
647 xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
648 xorg_list_add(&xwl_present_window->frame_callback_list,
649 &xwl_window->frame_callback_list);
652 if ((xwl_window && xwl_window->frame_callback) ||
653 !xwl_present_window->frame_timer)
654 xwl_present_reset_timer(xwl_present_window);
656 return Success;
660 * Remove a pending vblank event so that it is not reported
661 * to the extension
663 static void
664 xwl_present_abort_vblank(ScreenPtr screen,
665 WindowPtr present_window,
666 RRCrtcPtr crtc,
667 uint64_t event_id,
668 uint64_t msc)
670 static Bool called;
672 if (called)
673 return;
675 /* xwl_present_cleanup should have cleaned up everything,
676 * present_free_window_vblank shouldn't need to call this.
678 ErrorF("Unexpected call to %s:\n", __func__);
679 xorg_backtrace();
682 static void
683 xwl_present_flush(WindowPtr window)
685 #ifdef XWL_HAS_GLAMOR
686 ScreenPtr screen = window->drawable.pScreen;
687 struct xwl_screen *xwl_screen = xwl_screen_get(screen);
689 if (xwl_screen->glamor)
690 glamor_block_handler(screen);
691 #endif
694 static void
695 xwl_present_maybe_set_reason(struct xwl_window *xwl_window, PresentFlipReason *reason)
697 struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
699 if (!reason || xwl_screen->dmabuf_protocol_version < 4)
700 return;
702 if (xwl_window->feedback.unprocessed_feedback_pending) {
703 xwl_window->feedback.unprocessed_feedback_pending = 0;
705 *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT;
708 if (xwl_screen->default_feedback.unprocessed_feedback_pending) {
709 xwl_screen->default_feedback.unprocessed_feedback_pending = 0;
711 *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT;
715 static int
716 xwl_present_flush_fenced(WindowPtr window)
718 int fence = -1;
719 #ifdef XWL_HAS_GLAMOR
720 struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
721 fence = xwl_glamor_get_fence(xwl_screen);
722 #endif /* XWL_HAS_GLAMOR */
723 xwl_present_flush(window);
724 return fence;
727 static Bool
728 xwl_present_check_flip(RRCrtcPtr crtc,
729 WindowPtr present_window,
730 PixmapPtr pixmap,
731 Bool sync_flip,
732 RegionPtr valid,
733 int16_t x_off,
734 int16_t y_off,
735 PresentFlipReason *reason)
737 WindowPtr toplvl_window = xwl_present_toplvl_pixmap_window(present_window);
738 struct xwl_window *xwl_window = xwl_window_from_window(present_window);
739 ScreenPtr screen = pixmap->drawable.pScreen;
741 if (reason)
742 *reason = PRESENT_FLIP_REASON_UNKNOWN;
744 if (!xwl_window)
745 return FALSE;
747 xwl_present_maybe_set_reason(xwl_window, reason);
749 if (!crtc)
750 return FALSE;
752 /* Source pixmap must align with window exactly */
753 if (x_off || y_off)
754 return FALSE;
756 /* Valid area must contain window (for simplicity for now just never flip when one is set). */
757 if (valid)
758 return FALSE;
760 /* Flip pixmap must have same dimensions as window */
761 if (present_window->drawable.width != pixmap->drawable.width ||
762 present_window->drawable.height != pixmap->drawable.height)
763 return FALSE;
765 if (!xwl_pixmap_get_wl_buffer(pixmap))
766 return FALSE;
768 /* Window must be same region as toplevel window */
769 if ( !RegionEqual(&present_window->winSize, &toplvl_window->winSize) )
770 return FALSE;
772 /* Can't flip if window clipped by children */
773 if (!RegionEqual(&present_window->clipList, &present_window->winSize))
774 return FALSE;
776 /* Can't flip if the window pixmap doesn't match the xwl_window parent
777 * window's, e.g. because a client redirected this window or one of its
778 * parents.
780 if (screen->GetWindowPixmap(xwl_window->surface_window) != screen->GetWindowPixmap(present_window))
781 return FALSE;
784 * We currently only allow flips of windows, that have the same
785 * dimensions as their xwl_window parent window. For the case of
786 * different sizes subsurfaces are presumably the way forward.
788 if (!RegionEqual(&xwl_window->toplevel->winSize, &present_window->winSize))
789 return FALSE;
791 #ifdef XWL_HAS_GLAMOR
792 if (!xwl_glamor_supports_implicit_sync(xwl_window->xwl_screen) &&
793 !xwl_window->xwl_screen->explicit_sync)
794 return FALSE;
796 if (xwl_window->xwl_screen->glamor &&
797 !xwl_glamor_check_flip(present_window, pixmap))
798 return FALSE;
799 #endif /* XWL_HAS_GLAMOR */
801 return TRUE;
805 * 'window' is being reconfigured. Check to see if it is involved
806 * in flipping and clean up as necessary.
808 static void
809 xwl_present_check_flip_window (WindowPtr window)
811 struct xwl_present_window *xwl_present_window = xwl_present_window_priv(window);
812 present_window_priv_ptr window_priv = present_window_priv(window);
813 present_vblank_ptr flip_pending;
814 present_vblank_ptr flip_active;
815 present_vblank_ptr vblank;
816 PresentFlipReason reason;
818 /* If this window hasn't ever been used with Present, it can't be
819 * flipping
821 if (!xwl_present_window || !window_priv)
822 return;
824 flip_pending = xwl_present_get_pending_flip(xwl_present_window);
825 flip_active = xwl_present_window->flip_active;
827 if (flip_pending) {
828 if (!xwl_present_check_flip(flip_pending->crtc, flip_pending->window, flip_pending->pixmap,
829 flip_pending->sync_flip, flip_pending->valid, 0, 0, NULL))
830 flip_pending->abort_flip = TRUE;
831 } else if (flip_active) {
832 if (!xwl_present_check_flip(flip_active->crtc, flip_active->window, flip_active->pixmap,
833 flip_active->sync_flip, flip_active->valid, 0, 0, NULL))
834 xwl_present_flips_stop(window);
837 /* Now check any queued vblanks */
838 xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
839 if (vblank->queued && vblank->flip &&
840 !xwl_present_check_flip(vblank->crtc, window, vblank->pixmap,
841 vblank->sync_flip, vblank->valid, 0, 0, &reason)) {
842 vblank->flip = FALSE;
843 vblank->reason = reason;
849 * Clean up any pending or current flips for this window
851 static void
852 xwl_present_clear_window_flip(WindowPtr window)
854 /* xwl_present_cleanup cleaned up everything */
857 static Bool
858 xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage)
860 WindowPtr present_window = vblank->window;
861 PixmapPtr pixmap = vblank->pixmap;
862 struct xwl_window *xwl_window = xwl_window_from_window(present_window);
863 struct xwl_present_window *xwl_present_window = xwl_present_window_priv(present_window);
864 BoxPtr damage_box;
865 struct wl_buffer *buffer;
866 struct xwl_present_event *event = xwl_present_event_from_vblank(vblank);
867 Bool implicit_sync = TRUE;
869 if (!xwl_window)
870 return FALSE;
872 buffer = xwl_pixmap_get_wl_buffer(pixmap);
873 if (!buffer) {
874 ErrorF("present: Error getting buffer\n");
875 return FALSE;
878 damage_box = RegionExtents(damage);
880 pixmap->refcnt++;
882 event->pixmap = pixmap;
884 #ifdef XWL_HAS_GLAMOR
885 if (vblank->acquire_syncobj && vblank->release_syncobj) {
886 if (xwl_window->xwl_screen->explicit_sync) {
887 xwl_glamor_dri3_syncobj_passthrough(xwl_window,
888 vblank->acquire_syncobj,
889 vblank->release_syncobj,
890 vblank->acquire_point,
891 vblank->release_point);
892 implicit_sync = FALSE;
893 } else {
894 /* transfer from acquire syncobj to implicit fence */
895 int fence_fd =
896 vblank->acquire_syncobj->export_fence(vblank->acquire_syncobj,
897 vblank->acquire_point);
898 xwl_glamor_dmabuf_import_sync_file(vblank->pixmap, fence_fd);
901 #endif /* XWL_HAS_GLAMOR */
903 if (implicit_sync) {
904 xwl_pixmap_set_buffer_release_cb(pixmap, xwl_present_buffer_release, event);
906 if (xwl_window->surface_sync) {
907 wp_linux_drm_syncobj_surface_v1_destroy(xwl_window->surface_sync);
908 xwl_window->surface_sync = NULL;
912 /* We can flip directly to the main surface (full screen window without clips) */
913 wl_surface_attach(xwl_window->surface, buffer, 0, 0);
915 if (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) {
916 xorg_list_add(&xwl_present_window->frame_callback_list,
917 &xwl_window->frame_callback_list);
920 if (!xwl_window->frame_callback)
921 xwl_window_create_frame_callback(xwl_window);
923 xwl_surface_damage(xwl_window->xwl_screen, xwl_window->surface,
924 damage_box->x1 - present_window->drawable.x,
925 damage_box->y1 - present_window->drawable.y,
926 damage_box->x2 - damage_box->x1,
927 damage_box->y2 - damage_box->y1);
929 if (xwl_window->tearing_control) {
930 uint32_t hint;
931 if (event->options & PresentOptionAsyncMayTear)
932 hint = WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC;
933 else
934 hint = WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC;
936 wp_tearing_control_v1_set_presentation_hint(xwl_window->tearing_control, hint);
939 wl_surface_commit(xwl_window->surface);
941 if (!vblank->sync_flip) {
942 xwl_present_window->sync_callback =
943 wl_display_sync(xwl_window->xwl_screen->display);
944 wl_callback_add_listener(xwl_present_window->sync_callback,
945 &xwl_present_sync_listener,
946 &event->vblank);
949 wl_display_flush(xwl_window->xwl_screen->display);
950 return TRUE;
953 #ifdef XWL_HAS_GLAMOR
954 static void
955 xwl_present_acquire_fence_avail(int fd, int xevents, void *data)
957 present_vblank_ptr vblank = data;
959 SetNotifyFd(fd, NULL, 0, NULL);
960 close(fd);
961 vblank->efd = -1;
963 xwl_present_re_execute(vblank);
965 #endif /* XWL_HAS_GLAMOR */
967 static Bool
968 xwl_present_wait_acquire_fence_avail(struct xwl_screen *xwl_screen,
969 present_vblank_ptr vblank)
971 #ifdef XWL_HAS_GLAMOR
972 /* If the compositor does not support explicit sync we need to wait for the
973 * acquire fence to be submitted before flipping. */
974 if (vblank->flip && !xwl_screen->explicit_sync &&
975 vblank->pixmap && vblank->acquire_syncobj &&
976 !vblank->acquire_syncobj->has_fence(vblank->acquire_syncobj,
977 vblank->acquire_point)) {
978 vblank->efd = eventfd(0, EFD_CLOEXEC);
979 SetNotifyFd(vblank->efd, xwl_present_acquire_fence_avail, X_NOTIFY_READ, vblank);
980 vblank->acquire_syncobj->submitted_eventfd(vblank->acquire_syncobj,
981 vblank->acquire_point,
982 vblank->efd);
983 return TRUE;
985 #endif /* XWL_HAS_GLAMOR */
986 return FALSE;
989 static void
990 xwl_present_flush_blocked(struct xwl_present_window *xwl_present_window,
991 uint64_t crtc_msc)
993 struct xwl_screen *xwl_screen =
994 xwl_screen_get(xwl_present_window->window->drawable.pScreen);
995 struct xwl_present_event *blocked_event, *tmp;
997 if (!xwl_present_window->blocking_event)
998 return;
1000 xwl_present_window->blocking_event = 0;
1002 xorg_list_for_each_entry_safe(blocked_event, tmp,
1003 &xwl_present_window->blocked_queue,
1004 blocked) {
1005 present_vblank_ptr blocked_vblank = &blocked_event->vblank;
1006 xorg_list_del(&blocked_event->blocked);
1007 if (present_execute_wait(blocked_vblank, crtc_msc) ||
1008 xwl_present_wait_acquire_fence_avail(xwl_screen, blocked_vblank)) {
1009 xwl_present_window->blocking_event = blocked_vblank->event_id;
1010 return;
1013 xwl_present_re_execute(blocked_vblank);
1018 * Once the required MSC has been reached, execute the pending request.
1020 * For requests to actually present something, either blt contents to
1021 * the window pixmap or queue a window buffer swap on the backend.
1023 * For requests to just get the current MSC/UST combo, skip that part and
1024 * go straight to event delivery.
1026 static void
1027 xwl_present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
1029 WindowPtr window = vblank->window;
1030 struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
1031 present_vblank_ptr flip_pending = xwl_present_get_pending_flip(xwl_present_window);
1032 struct xwl_present_event *event = xwl_present_event_from_vblank(vblank);
1033 struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
1034 Bool notify_only = !vblank->window || !vblank->pixmap;
1036 xorg_list_del(&vblank->event_queue);
1038 if (!notify_only && !event->copy_executed &&
1039 xwl_present_window->blocking_event &&
1040 xwl_present_window->blocking_event != event->vblank.event_id) {
1041 /* an earlier request is blocking execution */
1042 xorg_list_append(&event->blocked, &xwl_present_window->blocked_queue);
1043 return;
1046 retry:
1047 if (present_execute_wait(vblank, crtc_msc) ||
1048 xwl_present_wait_acquire_fence_avail(xwl_screen, vblank)) {
1049 if (!notify_only)
1050 /* block execution of subsequent requests until this request is ready */
1051 xwl_present_window->blocking_event = event->vblank.event_id;
1052 return;
1055 if (flip_pending && vblank->flip && !notify_only) {
1056 present_vblank_ptr flip_queued_last;
1058 flip_queued_last = xorg_list_last_entry(&xwl_present_window->flip_queue,
1059 present_vblank_rec, event_queue);
1061 /* Do mailbox handling for queued flips, to prevent the flip queue from
1062 * growing unbounded.
1064 if (flip_queued_last != flip_pending &&
1065 (flip_queued_last->sync_flip
1066 #ifdef DRI3
1067 || vblank->acquire_syncobj
1068 #endif
1069 )) {
1070 xorg_list_del(&flip_queued_last->event_queue);
1071 present_vblank_scrap(flip_queued_last);
1072 xwl_present_re_execute(flip_queued_last);
1075 DebugPresent(("\tr %" PRIu64 " %p (pending %p)\n",
1076 vblank->event_id, vblank, flip_pending));
1077 xorg_list_append(&vblank->event_queue, &xwl_present_window->flip_queue);
1078 vblank->flip_ready = TRUE;
1079 return;
1082 vblank->queued = FALSE;
1084 if (!notify_only && !event->copy_executed) {
1085 ScreenPtr screen = window->drawable.pScreen;
1086 int ret;
1088 if (vblank->flip) {
1089 RegionPtr damage;
1091 DebugPresent(("\tf %" PRIu64 " %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
1092 vblank->event_id, vblank, crtc_msc,
1093 vblank->pixmap->drawable.id, vblank->window->drawable.id));
1095 /* Set update region as damaged */
1096 if (vblank->update) {
1097 damage = RegionDuplicate(vblank->update);
1098 /* Translate update region to screen space */
1099 assert(vblank->x_off == 0 && vblank->y_off == 0);
1100 RegionTranslate(damage, window->drawable.x, window->drawable.y);
1101 RegionIntersect(damage, damage, &window->clipList);
1102 } else
1103 damage = RegionDuplicate(&window->clipList);
1105 if (xwl_present_flip(vblank, damage)) {
1106 WindowPtr toplvl_window = xwl_present_toplvl_pixmap_window(vblank->window);
1107 struct xwl_window *xwl_window = xwl_window_from_window(window);
1108 PixmapPtr old_pixmap = screen->GetWindowPixmap(window);
1110 /* Replace window pixmap with flip pixmap */
1111 #ifdef COMPOSITE
1112 vblank->pixmap->screen_x = old_pixmap->screen_x;
1113 vblank->pixmap->screen_y = old_pixmap->screen_y;
1114 #endif
1115 present_set_tree_pixmap(toplvl_window, old_pixmap, vblank->pixmap);
1117 if (toplvl_window == screen->root &&
1118 screen->GetScreenPixmap(screen) == old_pixmap)
1119 screen->SetScreenPixmap(vblank->pixmap);
1121 vblank->pixmap->refcnt++;
1122 dixDestroyPixmap(old_pixmap, old_pixmap->drawable.id);
1124 /* Report damage, let damage_report ignore it though */
1125 xwl_screen->ignore_damage = TRUE;
1126 DamageDamageRegion(&vblank->window->drawable, damage);
1127 xwl_screen->ignore_damage = FALSE;
1128 RegionDestroy(damage);
1130 /* Clear damage region, to ensure damage_report is called before
1131 * any drawing to the window
1133 xwl_window_buffer_add_damage_region(xwl_window);
1134 RegionEmpty(xwl_window_get_damage_region(xwl_window));
1135 xorg_list_del(&xwl_window->link_damage);
1137 /* Put pending flip at the flip queue head */
1138 xorg_list_add(&vblank->event_queue, &xwl_present_window->flip_queue);
1140 /* Realign timer */
1141 xwl_present_reset_timer(xwl_present_window);
1143 xwl_present_flush_blocked(xwl_present_window, crtc_msc);
1144 return;
1147 vblank->flip = FALSE;
1148 /* re-execute, falling through to copy */
1149 goto retry;
1151 DebugPresent(("\tc %p %" PRIu64 ": %08" PRIx32 " -> %08" PRIx32 "\n",
1152 vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
1154 if (flip_pending)
1155 flip_pending->abort_flip = TRUE;
1156 else if (xwl_present_window->flip_active)
1157 xwl_present_flips_stop(window);
1159 present_execute_copy(vblank, crtc_msc);
1160 assert(!vblank->queued);
1162 /* Set the copy_executed field, so this will fall through to present_execute_post next time */
1163 event->copy_executed = TRUE;
1165 ret = xwl_present_queue_vblank(screen, window, vblank->crtc,
1166 vblank->event_id, crtc_msc + 1);
1168 xwl_present_flush_blocked(xwl_present_window, crtc_msc);
1170 if (ret == Success)
1171 return;
1174 present_execute_post(vblank, ust, crtc_msc);
1177 static int
1178 xwl_present_pixmap(WindowPtr window,
1179 PixmapPtr pixmap,
1180 CARD32 serial,
1181 RegionPtr valid,
1182 RegionPtr update,
1183 int16_t x_off,
1184 int16_t y_off,
1185 RRCrtcPtr target_crtc,
1186 SyncFence *wait_fence,
1187 SyncFence *idle_fence,
1188 #ifdef DRI3
1189 struct dri3_syncobj *acquire_syncobj,
1190 struct dri3_syncobj *release_syncobj,
1191 uint64_t acquire_point,
1192 uint64_t release_point,
1193 #endif /* DRI3 */
1194 uint32_t options,
1195 uint64_t target_window_msc,
1196 uint64_t divisor,
1197 uint64_t remainder,
1198 present_notify_ptr notifies,
1199 int num_notifies)
1201 static uint64_t xwl_present_event_id;
1202 uint64_t ust = 0;
1203 uint64_t target_msc;
1204 uint64_t crtc_msc = 0;
1205 int ret;
1206 present_vblank_ptr vblank;
1207 ScreenPtr screen = window->drawable.pScreen;
1208 present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
1209 present_screen_priv_ptr screen_priv = present_screen_priv(screen);
1210 struct xwl_screen *xwl_screen = xwl_screen_get(screen_priv->pScreen);
1211 uint32_t caps = xwl_screen->present_capabilities;
1212 struct xwl_present_event *event;
1214 if (!window_priv)
1215 return BadAlloc;
1217 #ifdef DRI3
1218 if (!(caps & PresentCapabilitySyncobj) &&
1219 (acquire_syncobj || release_syncobj))
1220 return BadValue;
1221 #endif /* DRI3 */
1223 target_crtc = xwl_present_get_crtc(screen_priv, window);
1225 ret = xwl_present_get_ust_msc(screen, window, &ust, &crtc_msc);
1227 xwl_present_update_window_crtc(window_priv, target_crtc, crtc_msc);
1229 if (ret == Success) {
1230 /* Stash the current MSC away in case we need it later
1232 window_priv->msc = crtc_msc;
1235 target_msc = present_get_target_msc(target_window_msc + window_priv->msc_offset,
1236 crtc_msc,
1237 divisor,
1238 remainder,
1239 options);
1241 event = calloc(1, sizeof(*event));
1242 if (!event)
1243 return BadAlloc;
1245 vblank = &event->vblank;
1246 if (!present_vblank_init(vblank, window, pixmap, serial, valid, update, x_off, y_off,
1247 target_crtc, wait_fence, idle_fence,
1248 #ifdef DRI3
1249 acquire_syncobj, release_syncobj, acquire_point, release_point,
1250 #endif /* DRI3 */
1251 options, caps, notifies, num_notifies, target_msc, crtc_msc)) {
1252 present_vblank_destroy(vblank);
1253 return BadAlloc;
1256 vblank->event_id = ++xwl_present_event_id;
1257 event->options = options;
1258 event->divisor = divisor;
1259 event->remainder = remainder;
1260 vblank->exec_msc = xwl_present_get_exec_msc(options, vblank->target_msc);
1262 vblank->queued = TRUE;
1263 if (crtc_msc < vblank->exec_msc) {
1264 if (xwl_present_queue_vblank(screen, window, target_crtc, vblank->event_id, vblank->exec_msc) == Success)
1265 return Success;
1267 DebugPresent(("present_queue_vblank failed\n"));
1270 xwl_present_execute(vblank, ust, crtc_msc);
1271 return Success;
1274 void
1275 xwl_present_unrealize_window(struct xwl_present_window *xwl_present_window)
1277 /* The pending frame callback may never be called, so drop it and shorten
1278 * the frame timer interval.
1280 xorg_list_del(&xwl_present_window->frame_callback_list);
1282 /* Make sure the timer callback doesn't get called */
1283 xwl_present_window->timer_armed = 0;
1284 xwl_present_reset_timer(xwl_present_window);
1287 Bool
1288 xwl_present_maybe_redirect_window(WindowPtr window, PixmapPtr pixmap)
1290 struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
1291 struct xwl_window *xwl_window = xwl_window_from_window(window);
1293 if (xwl_present_window->redirect_failed)
1294 return FALSE;
1296 if (compRedirectWindow(serverClient, window, CompositeRedirectManual) != Success) {
1297 xwl_present_window->redirect_failed = TRUE;
1298 return FALSE;
1301 xwl_window_update_surface_window(xwl_window);
1302 if (xwl_window->surface_window != window) {
1303 compUnredirectWindow(serverClient, window, CompositeRedirectManual);
1304 xwl_present_window->redirect_failed = TRUE;
1305 return FALSE;
1308 if (!xwl_window->surface_window_damage)
1309 xwl_window->surface_window_damage = RegionCreate(NullBox, 1);
1311 xwl_present_window->redirected = TRUE;
1312 return TRUE;
1315 static CARD32
1316 unredirect_window(OsTimerPtr timer, CARD32 time, void *arg)
1318 WindowPtr window = arg;
1319 struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
1321 compUnredirectWindow(serverClient, window, CompositeRedirectManual);
1322 xwl_present_window->redirected = FALSE;
1324 xwl_present_window->unredirect_timer = NULL;
1325 return 0;
1328 Bool
1329 xwl_present_maybe_unredirect_window(WindowPtr window)
1331 struct xwl_present_window *xwl_present_window = xwl_present_window_get_priv(window);
1333 if (!xwl_present_window || !xwl_present_window->redirected)
1334 return FALSE;
1336 /* This function may get called from composite layer code, in which case
1337 * calling compUnredirectWindow would blow up. To avoid this, set up a timer
1338 * which will call it "as soon as possible".
1340 if (!xwl_present_window->unredirect_timer) {
1341 xwl_present_window->unredirect_timer =
1342 TimerSet(NULL, 0, 1, unredirect_window, window);
1345 return TRUE;
1348 Bool
1349 xwl_present_init(ScreenPtr screen)
1351 struct xwl_screen *xwl_screen = xwl_screen_get(screen);
1352 present_screen_priv_ptr screen_priv;
1354 if (!present_screen_register_priv_keys())
1355 return FALSE;
1357 if (present_screen_priv(screen))
1358 return TRUE;
1360 screen_priv = present_screen_priv_init(screen);
1361 if (!screen_priv)
1362 return FALSE;
1364 if (!dixRegisterPrivateKey(&xwl_present_window_private_key, PRIVATE_WINDOW, 0))
1365 return FALSE;
1367 xwl_screen->present_capabilities = XWL_PRESENT_CAPS;
1368 #ifdef XWL_HAS_GLAMOR
1369 if (xwl_glamor_supports_syncobjs(xwl_screen))
1370 xwl_screen->present_capabilities |=
1371 PresentCapabilitySyncobj;
1372 #endif /* XWL_HAS_GLAMOR */
1374 screen_priv->query_capabilities = xwl_present_query_capabilities;
1375 screen_priv->get_crtc = xwl_present_get_crtc;
1377 screen_priv->check_flip = xwl_present_check_flip;
1378 screen_priv->check_flip_window = xwl_present_check_flip_window;
1379 screen_priv->clear_window_flip = xwl_present_clear_window_flip;
1381 screen_priv->present_pixmap = xwl_present_pixmap;
1382 screen_priv->queue_vblank = xwl_present_queue_vblank;
1383 screen_priv->flush = xwl_present_flush;
1384 screen_priv->flush_fenced = xwl_present_flush_fenced;
1385 screen_priv->re_execute = xwl_present_re_execute;
1387 screen_priv->abort_vblank = xwl_present_abort_vblank;
1389 return TRUE;