present: Queue flips for later execution
When a flip (or unflip) is pending and a flip request comes in, leave it queued until the pending flip completes and then execute it. This fixes a bug where an application submitting back-to-back present_pixmap requests for sequential frames would alternate between flipping and copying as the pending flip would cause the new present_pixmap request to not use a flip. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Tested-by: Frank Binns <frank.binns@imgtec.com>
This commit is contained in:
parent
2f5cf9ff9a
commit
e6f5d9d7b7
|
@ -42,6 +42,9 @@ static struct xorg_list present_flip_queue;
|
||||||
#define DebugPresent(x)
|
#define DebugPresent(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copies the update region from a pixmap to the target drawable
|
* Copies the update region from a pixmap to the target drawable
|
||||||
*/
|
*/
|
||||||
|
@ -78,6 +81,20 @@ present_copy_region(DrawablePtr drawable,
|
||||||
FreeScratchGC(gc);
|
FreeScratchGC(gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline PixmapPtr
|
||||||
|
present_flip_pending_pixmap(ScreenPtr screen)
|
||||||
|
{
|
||||||
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
if (!screen_priv)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!screen_priv->flip_pending)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return screen_priv->flip_pending->pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
static Bool
|
static Bool
|
||||||
present_check_flip(RRCrtcPtr crtc,
|
present_check_flip(RRCrtcPtr crtc,
|
||||||
WindowPtr window,
|
WindowPtr window,
|
||||||
|
@ -88,6 +105,7 @@ present_check_flip(RRCrtcPtr crtc,
|
||||||
int16_t y_off)
|
int16_t y_off)
|
||||||
{
|
{
|
||||||
ScreenPtr screen = window->drawable.pScreen;
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
|
PixmapPtr window_pixmap;
|
||||||
WindowPtr root = screen->root;
|
WindowPtr root = screen->root;
|
||||||
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
|
@ -104,19 +122,11 @@ present_check_flip(RRCrtcPtr crtc,
|
||||||
if (!screen_priv->info->flip)
|
if (!screen_priv->info->flip)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Can't pend a flip while unflipping */
|
|
||||||
if (screen_priv->unflip_event_id) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Can't have two pending flips at the same time */
|
|
||||||
if (screen_priv->flip_pending) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure the window hasn't been redirected with Composite */
|
/* Make sure the window hasn't been redirected with Composite */
|
||||||
if (screen->GetWindowPixmap(window) != screen->GetScreenPixmap(screen) &&
|
window_pixmap = screen->GetWindowPixmap(window);
|
||||||
screen->GetWindowPixmap(window) != screen_priv->flip_pixmap)
|
if (window_pixmap != screen->GetScreenPixmap(screen) &&
|
||||||
|
window_pixmap != screen_priv->flip_pixmap &&
|
||||||
|
window_pixmap != present_flip_pending_pixmap(screen))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Check for full-screen window */
|
/* Check for full-screen window */
|
||||||
|
@ -147,6 +157,7 @@ present_check_flip(RRCrtcPtr crtc,
|
||||||
/* Ask the driver for permission */
|
/* Ask the driver for permission */
|
||||||
if (screen_priv->info->check_flip) {
|
if (screen_priv->info->check_flip) {
|
||||||
if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
|
if (!(*screen_priv->info->check_flip) (crtc, window, pixmap, sync_flip)) {
|
||||||
|
DebugPresent(("\td %08lx -> %08lx\n", window->drawable.id, pixmap ? pixmap->drawable.id : 0));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,8 +199,10 @@ present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct pr
|
||||||
{
|
{
|
||||||
if (present_fence)
|
if (present_fence)
|
||||||
present_fence_set_triggered(present_fence);
|
present_fence_set_triggered(present_fence);
|
||||||
if (window)
|
if (window) {
|
||||||
|
DebugPresent(("\ti %08lx\n", pixmap ? pixmap->drawable.id : 0));
|
||||||
present_send_idle_notify(window, serial, pixmap, present_fence);
|
present_send_idle_notify(window, serial, pixmap, present_fence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RRCrtcPtr
|
RRCrtcPtr
|
||||||
|
@ -227,9 +240,8 @@ present_query_capabilities(RRCrtcPtr crtc)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
present_get_ust_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
|
present_get_ust_msc(ScreenPtr screen, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
|
||||||
{
|
{
|
||||||
ScreenPtr screen = window->drawable.pScreen;
|
|
||||||
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
if (crtc == NULL)
|
if (crtc == NULL)
|
||||||
|
@ -283,7 +295,7 @@ present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc
|
||||||
* we'll just use whatever previous MSC we'd seen from this CRTC
|
* we'll just use whatever previous MSC we'd seen from this CRTC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (present_get_ust_msc(window, window_priv->crtc, &old_ust, &old_msc) != Success)
|
if (present_get_ust_msc(window->drawable.pScreen, window_priv->crtc, &old_ust, &old_msc) != Success)
|
||||||
old_msc = window_priv->msc;
|
old_msc = window_priv->msc;
|
||||||
|
|
||||||
window_priv->msc_offset += new_msc - old_msc;
|
window_priv->msc_offset += new_msc - old_msc;
|
||||||
|
@ -293,6 +305,34 @@ present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc
|
||||||
return window_msc + window_priv->msc_offset;
|
return window_msc + window_priv->msc_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When the wait fence or previous flip is completed, it's time
|
||||||
|
* to re-try the request
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
present_re_execute(present_vblank_ptr vblank)
|
||||||
|
{
|
||||||
|
uint64_t ust = 0, crtc_msc = 0;
|
||||||
|
|
||||||
|
if (vblank->crtc)
|
||||||
|
(void) present_get_ust_msc(vblank->screen, vblank->crtc, &ust, &crtc_msc);
|
||||||
|
|
||||||
|
present_execute(vblank, ust, crtc_msc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
present_flip_try_ready(ScreenPtr screen)
|
||||||
|
{
|
||||||
|
present_vblank_ptr vblank, tmp;
|
||||||
|
|
||||||
|
xorg_list_for_each_entry_safe(vblank, tmp, &present_exec_queue, event_queue) {
|
||||||
|
if (vblank->flip_ready) {
|
||||||
|
present_re_execute(vblank);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
present_flip_idle(ScreenPtr screen)
|
present_flip_idle(ScreenPtr screen)
|
||||||
{
|
{
|
||||||
|
@ -368,16 +408,14 @@ present_unflip(ScreenPtr screen)
|
||||||
(*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id);
|
(*screen_priv->info->unflip) (screen, screen_priv->unflip_event_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
|
present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
|
||||||
{
|
{
|
||||||
ScreenPtr screen = vblank->screen;
|
ScreenPtr screen = vblank->screen;
|
||||||
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
|
||||||
DebugPresent(("\tn %p %8lld: %08lx -> %08lx\n", vblank, vblank->target_msc,
|
DebugPresent(("\tn %lld %p %8lld: %08lx -> %08lx\n",
|
||||||
|
vblank->event_id, vblank, vblank->target_msc,
|
||||||
vblank->pixmap ? vblank->pixmap->drawable.id : 0,
|
vblank->pixmap ? vblank->pixmap->drawable.id : 0,
|
||||||
vblank->window->drawable.id));
|
vblank->window->drawable.id));
|
||||||
|
|
||||||
|
@ -404,6 +442,8 @@ present_flip_notify(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
|
||||||
|
|
||||||
present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
|
present_vblank_notify(vblank, PresentCompleteKindPixmap, PresentCompleteModeFlip, ust, crtc_msc);
|
||||||
present_vblank_destroy(vblank);
|
present_vblank_destroy(vblank);
|
||||||
|
|
||||||
|
present_flip_try_ready(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -436,6 +476,7 @@ present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc)
|
||||||
DebugPresent(("\tun %lld\n", event_id));
|
DebugPresent(("\tun %lld\n", event_id));
|
||||||
screen_priv->unflip_event_id = 0;
|
screen_priv->unflip_event_id = 0;
|
||||||
present_flip_idle(screen);
|
present_flip_idle(screen);
|
||||||
|
present_flip_try_ready(screen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,15 +539,7 @@ static void
|
||||||
present_wait_fence_triggered(void *param)
|
present_wait_fence_triggered(void *param)
|
||||||
{
|
{
|
||||||
present_vblank_ptr vblank = param;
|
present_vblank_ptr vblank = param;
|
||||||
WindowPtr window = vblank->window;
|
present_re_execute(vblank);
|
||||||
uint64_t ust = 0, crtc_msc = 0;
|
|
||||||
|
|
||||||
if (window) {
|
|
||||||
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
|
|
||||||
if (window_priv)
|
|
||||||
(void) present_get_ust_msc(window, window_priv->crtc, &ust, &crtc_msc);
|
|
||||||
}
|
|
||||||
present_execute(vblank, ust, crtc_msc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -534,14 +567,27 @@ present_execute(present_vblank_ptr vblank, uint64_t ust, uint64_t crtc_msc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vblank->flip && vblank->pixmap && vblank->window) {
|
||||||
|
if (screen_priv->flip_pending || screen_priv->unflip_event_id) {
|
||||||
|
DebugPresent(("\tr %lld %p (pending %p unflip %lld)\n",
|
||||||
|
vblank->event_id, vblank,
|
||||||
|
screen_priv->flip_pending, screen_priv->unflip_event_id));
|
||||||
|
vblank->flip_ready = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
xorg_list_del(&vblank->event_queue);
|
xorg_list_del(&vblank->event_queue);
|
||||||
vblank->queued = FALSE;
|
vblank->queued = FALSE;
|
||||||
|
|
||||||
if (vblank->pixmap && vblank->window) {
|
if (vblank->pixmap && vblank->window) {
|
||||||
|
|
||||||
if (vblank->flip && screen_priv->flip_pending == NULL && !screen_priv->unflip_event_id) {
|
if (vblank->flip) {
|
||||||
|
|
||||||
|
DebugPresent(("\tf %lld %p %8lld: %08lx -> %08lx\n",
|
||||||
|
vblank->event_id, vblank, crtc_msc,
|
||||||
|
vblank->pixmap->drawable.id, vblank->window->drawable.id));
|
||||||
|
|
||||||
DebugPresent(("\tf %p %8lld: %08lx -> %08lx\n", vblank, crtc_msc, vblank->pixmap->drawable.id, vblank->window->drawable.id));
|
|
||||||
/* Prepare to flip by placing it in the flip queue and
|
/* Prepare to flip by placing it in the flip queue and
|
||||||
* and sticking it into the flip_pending field
|
* and sticking it into the flip_pending field
|
||||||
*/
|
*/
|
||||||
|
@ -644,7 +690,7 @@ present_pixmap(WindowPtr window,
|
||||||
uint64_t target_msc;
|
uint64_t target_msc;
|
||||||
uint64_t crtc_msc;
|
uint64_t crtc_msc;
|
||||||
int ret;
|
int ret;
|
||||||
present_vblank_ptr vblank;
|
present_vblank_ptr vblank, tmp;
|
||||||
ScreenPtr screen = window->drawable.pScreen;
|
ScreenPtr screen = window->drawable.pScreen;
|
||||||
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
|
present_window_priv_ptr window_priv = present_get_window_priv(window, TRUE);
|
||||||
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
present_screen_priv_ptr screen_priv = present_screen_priv(screen);
|
||||||
|
@ -664,7 +710,7 @@ present_pixmap(WindowPtr window,
|
||||||
target_crtc = present_get_crtc(window);
|
target_crtc = present_get_crtc(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
present_get_ust_msc(window, target_crtc, &ust, &crtc_msc);
|
present_get_ust_msc(screen, target_crtc, &ust, &crtc_msc);
|
||||||
|
|
||||||
target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
|
target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
|
||||||
|
|
||||||
|
@ -698,7 +744,7 @@ present_pixmap(WindowPtr window,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!update) {
|
if (!update) {
|
||||||
xorg_list_for_each_entry(vblank, &window_priv->vblank, window_list) {
|
xorg_list_for_each_entry_safe(vblank, tmp, &window_priv->vblank, window_list) {
|
||||||
|
|
||||||
if (!vblank->pixmap)
|
if (!vblank->pixmap)
|
||||||
continue;
|
continue;
|
||||||
|
@ -706,11 +752,11 @@ present_pixmap(WindowPtr window,
|
||||||
if (!vblank->queued)
|
if (!vblank->queued)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (vblank->crtc != target_crtc || vblank->target_msc != target_msc)
|
if (vblank->crtc != target_crtc || vblank->target_msc > target_msc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
DebugPresent(("\tx %lld %p %8lld: %08lx -> %08lx (crtc %p)\n",
|
DebugPresent(("\tx %lld %p %8lld: %08lx -> %08lx (crtc %p)\n",
|
||||||
vblank->event_id, vblank, target_msc,
|
vblank->event_id, vblank, vblank->target_msc,
|
||||||
vblank->pixmap->drawable.id, vblank->window->drawable.id,
|
vblank->pixmap->drawable.id, vblank->window->drawable.id,
|
||||||
vblank->crtc));
|
vblank->crtc));
|
||||||
|
|
||||||
|
@ -720,6 +766,9 @@ present_pixmap(WindowPtr window,
|
||||||
|
|
||||||
vblank->pixmap = NULL;
|
vblank->pixmap = NULL;
|
||||||
vblank->idle_fence = NULL;
|
vblank->idle_fence = NULL;
|
||||||
|
vblank->flip = FALSE;
|
||||||
|
if (vblank->flip_ready)
|
||||||
|
present_re_execute(vblank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -875,7 +924,8 @@ present_vblank_destroy(present_vblank_ptr vblank)
|
||||||
/* Remove vblank from window and screen lists */
|
/* Remove vblank from window and screen lists */
|
||||||
xorg_list_del(&vblank->window_list);
|
xorg_list_del(&vblank->window_list);
|
||||||
|
|
||||||
DebugPresent(("\td %p %8lld: %08lx -> %08lx\n", vblank, vblank->target_msc,
|
DebugPresent(("\td %lld %p %8lld: %08lx -> %08lx\n",
|
||||||
|
vblank->event_id, vblank, vblank->target_msc,
|
||||||
vblank->pixmap ? vblank->pixmap->drawable.id : 0,
|
vblank->pixmap ? vblank->pixmap->drawable.id : 0,
|
||||||
vblank->window->drawable.id));
|
vblank->window->drawable.id));
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ struct present_vblank {
|
||||||
int num_notifies;
|
int num_notifies;
|
||||||
Bool queued; /* on present_exec_queue */
|
Bool queued; /* on present_exec_queue */
|
||||||
Bool flip; /* planning on using flip */
|
Bool flip; /* planning on using flip */
|
||||||
|
Bool flip_ready; /* wants to flip, but waiting for previous flip or unflip */
|
||||||
Bool sync_flip; /* do flip synchronous to vblank */
|
Bool sync_flip; /* do flip synchronous to vblank */
|
||||||
Bool abort_flip; /* aborting this flip */
|
Bool abort_flip; /* aborting this flip */
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue