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
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
26 #include <xwayland-config.h>
32 #include <windowstr.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
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
)
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
,
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
)
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
;
117 xwl_present_entered_for_each_frame_callback(void)
119 return entered_for_each_frame_callback
;
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
,
136 iter_func(xwl_present_window
);
138 entered_for_each_frame_callback
= FALSE
;
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;
150 xwl_present_timer_callback(OsTimerPtr timer
,
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
))
162 flip_pending
= xorg_list_first_entry(&xwl_present_window
->flip_queue
, present_vblank_rec
,
165 if (flip_pending
->queued
)
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
);
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();
189 if (xwl_window
&& xwl_window
->frame_callback
&&
190 !xorg_list_is_empty(&xwl_present_window
->frame_callback_list
))
191 timeout
= TIMER_LEN_FLIP
;
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
,
207 xwl_present_window
->timer_armed
= now
;
210 xwl_present_window
->frame_timer
= TimerSet(xwl_present_window
->frame_timer
,
212 &xwl_present_timer_callback
,
215 xwl_present_free_timer(xwl_present_window
);
221 xwl_present_execute(present_vblank_ptr vblank
, uint64_t ust
, uint64_t crtc_msc
);
224 xwl_present_queue_vblank(ScreenPtr screen
,
225 WindowPtr present_window
,
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
;
238 xwl_present_get_ust_msc(ScreenPtr screen
,
239 WindowPtr present_window
,
243 struct xwl_present_window
*xwl_present_window
= xwl_present_window_get_priv(present_window
);
244 if (!xwl_present_window
)
247 *ust
= xwl_present_window
->ust
;
248 *msc
= xwl_present_window
->msc
;
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
259 if (options
& PresentOptionAsyncMayTear
)
262 return target_msc
- 1;
266 * When the wait fence or previous flip is completed, it's time
267 * to re-try the request
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
,
281 vblank
->exec_msc
= xwl_present_get_exec_msc(event
->options
,
284 vblank
->queued
= TRUE
;
285 if (msc_is_after(vblank
->exec_msc
, crtc_msc
) &&
286 xwl_present_queue_vblank(vblank
->screen
, vblank
->window
,
289 vblank
->exec_msc
) == Success
) {
293 xwl_present_execute(vblank
, ust
, crtc_msc
);
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
);
310 xwl_present_release_pixmap(struct xwl_present_event
*event
)
315 xwl_pixmap_del_buffer_release_cb(event
->pixmap
);
316 dixDestroyPixmap(event
->pixmap
, event
->pixmap
->drawable
.id
);
317 event
->pixmap
= NULL
;
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
);
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
,
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
));
346 xwl_present_toplvl_pixmap_window(WindowPtr window
)
348 ScreenPtr screen
= window
->drawable
.pScreen
;
349 PixmapPtr pixmap
= (*screen
->GetWindowPixmap
)(window
);
350 WindowPtr w
= window
;
355 if ( (*screen
->GetWindowPixmap
)(next_w
) != pixmap
) {
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
);
382 xwl_present_free_idle_vblank(vblank
);
384 xwl_present_free_event(event
);
386 xwl_present_window
->flip_active
= NULL
;
389 xwl_present_flip_try_ready(xwl_present_window
);
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
);
415 /* If this flip used explicit sync, we won't get a release event */
416 || (xwl_screen
->explicit_sync
&& vblank
->release_syncobj
)
419 xwl_present_free_event(event
);
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
);
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
)
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
;
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
;
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
)
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
;
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
);
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
,
495 free(xwl_present_window
);
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
;
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
,
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
);
526 xwl_present_free_event(event
);
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
);
554 xwl_present_timer_callback(OsTimerPtr timer
,
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
);
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
);
585 xwl_present_sync_callback(void *data
,
586 struct wl_callback
*callback
,
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
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
)
612 rr_private
= rrGetScrPriv(present_window
->drawable
.pScreen
);
614 if (rr_private
->numCrtcs
== 0)
617 return rr_private
->crtcs
[0];
621 * Queue an event to report back to the Present extension when the specified
625 xwl_present_queue_vblank(ScreenPtr screen
,
626 WindowPtr present_window
,
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
);
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 */
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
);
660 * Remove a pending vblank event so that it is not reported
664 xwl_present_abort_vblank(ScreenPtr screen
,
665 WindowPtr present_window
,
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__
);
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
);
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)
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
;
716 xwl_present_flush_fenced(WindowPtr window
)
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
);
728 xwl_present_check_flip(RRCrtcPtr crtc
,
729 WindowPtr present_window
,
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
;
742 *reason
= PRESENT_FLIP_REASON_UNKNOWN
;
747 xwl_present_maybe_set_reason(xwl_window
, reason
);
752 /* Source pixmap must align with window exactly */
756 /* Valid area must contain window (for simplicity for now just never flip when one is set). */
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
)
765 if (!xwl_pixmap_get_wl_buffer(pixmap
))
768 /* Window must be same region as toplevel window */
769 if ( !RegionEqual(&present_window
->winSize
, &toplvl_window
->winSize
) )
772 /* Can't flip if window clipped by children */
773 if (!RegionEqual(&present_window
->clipList
, &present_window
->winSize
))
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
780 if (screen
->GetWindowPixmap(xwl_window
->surface_window
) != screen
->GetWindowPixmap(present_window
))
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
))
791 #ifdef XWL_HAS_GLAMOR
792 if (!xwl_glamor_supports_implicit_sync(xwl_window
->xwl_screen
) &&
793 !xwl_window
->xwl_screen
->explicit_sync
)
796 if (xwl_window
->xwl_screen
->glamor
&&
797 !xwl_glamor_check_flip(present_window
, pixmap
))
799 #endif /* XWL_HAS_GLAMOR */
805 * 'window' is being reconfigured. Check to see if it is involved
806 * in flipping and clean up as necessary.
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
821 if (!xwl_present_window
|| !window_priv
)
824 flip_pending
= xwl_present_get_pending_flip(xwl_present_window
);
825 flip_active
= xwl_present_window
->flip_active
;
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
852 xwl_present_clear_window_flip(WindowPtr window
)
854 /* xwl_present_cleanup cleaned up everything */
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
);
865 struct wl_buffer
*buffer
;
866 struct xwl_present_event
*event
= xwl_present_event_from_vblank(vblank
);
867 Bool implicit_sync
= TRUE
;
872 buffer
= xwl_pixmap_get_wl_buffer(pixmap
);
874 ErrorF("present: Error getting buffer\n");
878 damage_box
= RegionExtents(damage
);
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
;
894 /* transfer from acquire syncobj to implicit fence */
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 */
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
) {
931 if (event
->options
& PresentOptionAsyncMayTear
)
932 hint
= WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC
;
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
,
949 wl_display_flush(xwl_window
->xwl_screen
->display
);
953 #ifdef XWL_HAS_GLAMOR
955 xwl_present_acquire_fence_avail(int fd
, int xevents
, void *data
)
957 present_vblank_ptr vblank
= data
;
959 SetNotifyFd(fd
, NULL
, 0, NULL
);
963 xwl_present_re_execute(vblank
);
965 #endif /* XWL_HAS_GLAMOR */
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
,
985 #endif /* XWL_HAS_GLAMOR */
990 xwl_present_flush_blocked(struct xwl_present_window
*xwl_present_window
,
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
)
1000 xwl_present_window
->blocking_event
= 0;
1002 xorg_list_for_each_entry_safe(blocked_event
, tmp
,
1003 &xwl_present_window
->blocked_queue
,
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
;
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.
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
);
1047 if (present_execute_wait(vblank
, crtc_msc
) ||
1048 xwl_present_wait_acquire_fence_avail(xwl_screen
, vblank
)) {
1050 /* block execution of subsequent requests until this request is ready */
1051 xwl_present_window
->blocking_event
= event
->vblank
.event_id
;
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
1067 || vblank
->acquire_syncobj
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
;
1082 vblank
->queued
= FALSE
;
1084 if (!notify_only
&& !event
->copy_executed
) {
1085 ScreenPtr screen
= window
->drawable
.pScreen
;
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
);
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 */
1112 vblank
->pixmap
->screen_x
= old_pixmap
->screen_x
;
1113 vblank
->pixmap
->screen_y
= old_pixmap
->screen_y
;
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
);
1141 xwl_present_reset_timer(xwl_present_window
);
1143 xwl_present_flush_blocked(xwl_present_window
, crtc_msc
);
1147 vblank
->flip
= FALSE
;
1148 /* re-execute, falling through to copy */
1151 DebugPresent(("\tc %p %" PRIu64
": %08" PRIx32
" -> %08" PRIx32
"\n",
1152 vblank
, crtc_msc
, vblank
->pixmap
->drawable
.id
, vblank
->window
->drawable
.id
));
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
);
1174 present_execute_post(vblank
, ust
, crtc_msc
);
1178 xwl_present_pixmap(WindowPtr window
,
1185 RRCrtcPtr target_crtc
,
1186 SyncFence
*wait_fence
,
1187 SyncFence
*idle_fence
,
1189 struct dri3_syncobj
*acquire_syncobj
,
1190 struct dri3_syncobj
*release_syncobj
,
1191 uint64_t acquire_point
,
1192 uint64_t release_point
,
1195 uint64_t target_window_msc
,
1198 present_notify_ptr notifies
,
1201 static uint64_t xwl_present_event_id
;
1203 uint64_t target_msc
;
1204 uint64_t crtc_msc
= 0;
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
;
1218 if (!(caps
& PresentCapabilitySyncobj
) &&
1219 (acquire_syncobj
|| release_syncobj
))
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
,
1241 event
= calloc(1, sizeof(*event
));
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
,
1249 acquire_syncobj
, release_syncobj
, acquire_point
, release_point
,
1251 options
, caps
, notifies
, num_notifies
, target_msc
, crtc_msc
)) {
1252 present_vblank_destroy(vblank
);
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
)
1267 DebugPresent(("present_queue_vblank failed\n"));
1270 xwl_present_execute(vblank
, ust
, crtc_msc
);
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
);
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
)
1296 if (compRedirectWindow(serverClient
, window
, CompositeRedirectManual
) != Success
) {
1297 xwl_present_window
->redirect_failed
= TRUE
;
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
;
1308 if (!xwl_window
->surface_window_damage
)
1309 xwl_window
->surface_window_damage
= RegionCreate(NullBox
, 1);
1311 xwl_present_window
->redirected
= TRUE
;
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
;
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
)
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
);
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())
1357 if (present_screen_priv(screen
))
1360 screen_priv
= present_screen_priv_init(screen
);
1364 if (!dixRegisterPrivateKey(&xwl_present_window_private_key
, PRIVATE_WINDOW
, 0))
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
;