sna/dri2: Keep the per-drawable swap cache alive for 50ms

The purpose is to keep the recent history of buffers for a DRI client
for tracking the relevant age.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2015-01-29 11:45:50 +00:00
parent 2e7ae76038
commit 58fe408978
2 changed files with 122 additions and 93 deletions

View File

@ -1486,6 +1486,8 @@ static void sna_crtc_disable_override(struct sna *sna, struct sna_crtc *crtc)
if (crtc->client_bo == NULL)
return;
assert(crtc->client_bo->refcnt > crtc->client_bo->active_scanout);
if (!crtc->transform) {
DrawableRec tmp;
@ -7022,10 +7024,13 @@ void sna_shadow_set_crtc(struct sna *sna,
assert(!sna_crtc->transform);
if (sna_crtc->client_bo != bo) {
if (sna_crtc->client_bo)
if (sna_crtc->client_bo) {
assert(sna_crtc->client_bo->refcnt > sna_crtc->client_bo->active_scanout);
kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo);
}
sna_crtc->client_bo = kgem_bo_reference(bo);
assert(sna_crtc->client_bo->refcnt > sna_crtc->client_bo->active_scanout);
sna_crtc_damage(crtc);
}
@ -7080,6 +7085,7 @@ void sna_shadow_unset_crtc(struct sna *sna,
if (sna_crtc->client_bo == NULL)
return;
assert(sna_crtc->client_bo->refcnt > sna_crtc->client_bo->active_scanout);
kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo);
sna_crtc->client_bo = NULL;
list_del(&sna_crtc->shadow_link);
@ -7515,8 +7521,10 @@ fixup_shadow:
y = crtc->base->y;
}
if (crtc->bo == flip_bo)
if (crtc->bo == flip_bo) {
assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
continue;
}
if (flip_bo->pitch != crtc->bo->pitch || (y << 16 | x) != crtc->offset) {
DBG(("%s: changing pitch (new %d =?= old %d) or offset (new %x =?= old %x)\n",

View File

@ -134,14 +134,23 @@ struct sna_dri2_event {
struct list cache;
struct list link;
int mode;
int flip_continue;
int keepalive;
};
static void sna_dri2_flip_event(struct sna_dri2_event *flip);
inline static DRI2BufferPtr dri2_window_get_front(WindowPtr win);
static int front_pitch(DrawablePtr draw)
{
DRI2BufferPtr buffer = sna_pixmap_get_buffer(get_drawable_pixmap(draw));
DRI2BufferPtr buffer;
buffer = NULL;
if (draw->type != DRAWABLE_PIXMAP)
buffer = dri2_window_get_front((WindowPtr)draw);
if (buffer == NULL)
buffer = sna_pixmap_get_buffer(get_drawable_pixmap(draw));
return buffer ? buffer->pitch : 0;
}
@ -156,14 +165,16 @@ sna_dri2_get_back(struct sna *sna,
int flags;
bool reuse;
DBG(("%s: draw size=%dx%d, buffer size=%dx%d, is-scanout? %d, pitch=%d, front pitch=%d\n",
DBG(("%s: draw size=%dx%d, back buffer handle=%d size=%dx%d, is-scanout? %d, pitch=%d, front pitch=%d, has-cache?=%d\n",
__FUNCTION__, draw->width, draw->height,
get_private(back)->bo->handle,
get_private(back)->size & 0xffff, get_private(back)->size >> 16,
get_private(back)->bo->scanout,
back->pitch, front_pitch(draw)));
back->pitch, front_pitch(draw), info!=NULL));
reuse = (draw->height << 16 | draw->width) == get_private(back)->size;
if (reuse && get_private(back)->bo->scanout)
reuse = front_pitch(draw) == back->pitch;
DBG(("%s: reuse backbuffer? %d\n", __FUNCTION__, reuse));
if (reuse) {
bo = get_private(back)->bo;
assert(bo->refcnt);
@ -180,6 +191,8 @@ sna_dri2_get_back(struct sna *sna,
if (info) {
struct dri_bo *c;
list_for_each_entry(c, &info->cache, link) {
DBG(("%s: cache: handle=%d, active=%d\n",
__FUNCTION__, c->bo ? c->bo->handle : 0, c->bo ? c->bo->active_scanout : -1));
if (c->bo && c->bo->active_scanout == 0) {
bo = c->bo;
name = c->name;
@ -189,8 +202,6 @@ sna_dri2_get_back(struct sna *sna,
c->bo = NULL;
break;
}
DBG(("%s: cache: handle=%d, active=%d\n",
__FUNCTION__, c->bo ? c->bo->handle : 0, c->bo ? c->bo->active_scanout : -1));
}
}
if (bo == NULL) {
@ -306,6 +317,8 @@ mark_stale(DRI2BufferPtr back)
* stale frame. (This is mostly useful for tracking down
* driver bugs!)
*/
DBG(("%s(handle=%d) => %d\n", __FUNCTION__,
get_private(back)->bo->handle, xorg_can_triple_buffer()));
get_private(back)->stale = xorg_can_triple_buffer();
}
@ -327,7 +340,7 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
if (buffer->attachment == DRI2BufferBackLeft &&
draw->type != DRAWABLE_PIXMAP) {
DBG(("%s: replacing back buffer\n", __FUNCTION__));
DBG(("%s: replacing back buffer on window %ld\n", __FUNCTION__, draw->id));
sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw));
assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
@ -335,7 +348,6 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
assert(get_private(buffer)->bo->active_scanout == 0);
DBG(("reusing back buffer, age = %d\n", buffer->flags));
}
}
static bool swap_limit(DrawablePtr draw, int limit)
@ -354,6 +366,12 @@ static bool swap_limit(DrawablePtr draw, int limit)
#define USE_ASYNC_SWAP 0
#endif
#if USE_ASYNC_SWAP
#define KEEPALIVE 4 /* wait ~50ms before discarding swap caches */
#else
#define KEEPALIVE 1
#endif
#define COLOR_PREFER_TILING_Y 0
/* Prefer to enable TILING_Y if this buffer will never be a
@ -1555,6 +1573,7 @@ sna_dri2_flip(struct sna_dri2_event *info)
assert(get_private(info->back)->bo->refcnt);
assert(get_private(info->front)->bo != get_private(info->back)->bo);
info->keepalive = KEEPALIVE;
info->queued = true;
return true;
}
@ -1911,10 +1930,10 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
pixmap->drawable.width,
pixmap->drawable.height));
DBG(("%s: back_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
__FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
DBG(("%s: front_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
__FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
DBG(("%s: back_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
__FUNCTION__, back_bo->handle, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
DBG(("%s: front_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
__FUNCTION__, front_bo->handle, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
assert(front_bo->refcnt);
assert(back_bo->refcnt);
@ -1972,8 +1991,8 @@ static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr cr
if (tmp == NULL) {
back->attachment = -1;
if (get_private(back)->proxy == NULL) {
get_private(back)->pixmap = get_window_pixmap(win);
get_private(back)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(back)->pixmap));
get_private(back)->pixmap = get_private(front)->pixmap;
get_private(back)->proxy = sna_dri2_reference_buffer(get_private(front)->proxy ?: front);
}
dri2_window(win)->front = sna_dri2_reference_buffer(back);
return;
@ -1985,27 +2004,35 @@ static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr cr
get_private(tmp)->refcnt = 1;
get_private(tmp)->bo = get_private(back)->bo;
get_private(tmp)->size = get_private(back)->size;
get_private(tmp)->pixmap = get_window_pixmap(win);
get_private(tmp)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(tmp)->pixmap));
get_private(tmp)->pixmap = get_private(front)->pixmap;
get_private(tmp)->proxy = sna_dri2_reference_buffer(get_private(front)->proxy ?: front);
dri2_window(win)->front = tmp;
DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
back->name = 0;
back->flags = 0;
bo = kgem_create_2d(&sna->kgem,
draw->width, draw->height, draw->bitsPerPixel,
get_private(back)->bo->tiling,
CREATE_SCANOUT);
if (bo != NULL) {
get_private(back)->bo = bo;
back->pitch = bo->pitch;
back->name = kgem_bo_flink(&sna->kgem, bo);
}
if (back->name == 0) {
if (bo != NULL)
kgem_bo_destroy(&sna->kgem, bo);
get_private(back)->bo = NULL;
if (get_private(front)->proxy) {
DBG(("%s: reusing current proxy frontbuffer\n", __FUNCTION__));
front->attachment = DRI2BufferBackLeft;
ref(get_private(tmp)->bo);
back->attachment = -1;
} else {
DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
back->name = 0;
back->flags = 0;
bo = kgem_create_2d(&sna->kgem,
draw->width, draw->height, draw->bitsPerPixel,
get_private(back)->bo->tiling,
CREATE_SCANOUT);
if (bo != NULL) {
get_private(back)->bo = bo;
back->pitch = bo->pitch;
back->name = kgem_bo_flink(&sna->kgem, bo);
}
if (back->name == 0) {
if (bo != NULL)
kgem_bo_destroy(&sna->kgem, bo);
get_private(back)->bo = NULL;
back->attachment = -1;
}
}
}
@ -2326,47 +2353,40 @@ sna_dri2_immediate_blit(struct sna *sna,
static bool
sna_dri2_flip_continue(struct sna_dri2_event *info)
{
DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
struct kgem_bo *bo = get_private(info->front)->bo;
if (info->mode > 0){
struct kgem_bo *bo = get_private(info->front)->bo;
DBG(("%s(mode=%d)\n", __FUNCTION__, info->flip_continue));
assert(info->flip_continue > 0);
info->type = info->mode;
info->type = info->flip_continue;
if (bo != sna_pixmap(info->sna->front)->gpu_bo)
return false;
if (bo != sna_pixmap(info->sna->front)->gpu_bo)
return false;
if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
return false;
if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
return false;
assert(info->sna->dri2.flip_pending == NULL ||
info->sna->dri2.flip_pending == info);
info->sna->dri2.flip_pending = info;
assert(info->queued);
} else {
info->type = -info->mode;
assert(info->sna->dri2.flip_pending == NULL ||
info->sna->dri2.flip_pending == info);
info->sna->dri2.flip_pending = info;
assert(info->queued);
if (!info->draw)
return false;
if (!can_flip(info->sna, info->draw, info->front, info->back, info->crtc))
return false;
assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front);
if (!sna_dri2_flip(info))
return false;
if (!xorg_can_triple_buffer()) {
sna_dri2_get_back(info->sna, info->draw, info->back, info);
DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
frame_swap_complete(info, DRI2_FLIP_COMPLETE);
}
}
info->mode = 0;
info->flip_continue = 0;
return true;
}
static bool
sna_dri2_flip_keepalive(struct sna_dri2_event *info)
{
DBG(("%s(keepalive?=%d)\n", __FUNCTION__, info->keepalive-1));
assert(info->keepalive > 0);
if (!--info->keepalive)
return false;
info->flip_continue = FLIP_COMPLETE;
return sna_dri2_flip_continue(info);
}
static void chain_flip(struct sna *sna)
{
struct sna_dri2_event *chain = sna->dri2.flip_pending;
@ -2443,22 +2463,24 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
case FLIP_COMPLETE:
if (sna->dri2.flip_pending) {
DBG(("%s: pending flip\n", __FUNCTION__));
sna_dri2_event_free(flip);
chain_flip(sna);
} else if (!flip->mode) {
} else if (!flip->flip_continue) {
DBG(("%s: flip chain complete\n", __FUNCTION__));
if (!sna_dri2_flip_keepalive(flip)) {
if (flip->chain) {
sna_dri2_remove_event((WindowPtr)flip->draw,
flip);
chain_swap(flip->chain);
flip->draw = NULL;
}
if (flip->chain) {
sna_dri2_remove_event((WindowPtr)flip->draw,
flip);
chain_swap(flip->chain);
flip->draw = NULL;
sna_dri2_event_free(flip);
}
sna_dri2_event_free(flip);
} else if (!sna_dri2_flip_continue(flip)) {
DBG(("%s: no longer able to flip\n", __FUNCTION__));
if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode < 0))
if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->flip_continue == FLIP_COMPLETE))
sna_dri2_event_free(flip);
}
break;
@ -2579,7 +2601,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
info = sna->dri2.flip_pending;
DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n",
__FUNCTION__, sna_crtc_to_pipe(crtc),
info != NULL, info ? info->mode : 0,
info != NULL, info ? info->flip_continue : 0,
info && info->draw == draw));
if (info && info->draw == draw) {
@ -2589,21 +2611,16 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
_sna_dri2_destroy_buffer(sna, info->back);
info->back = sna_dri2_reference_buffer(back);
}
if (info->mode || current_msc >= *target_msc) {
DBG(("%s: executing xchg of pending flip\n",
__FUNCTION__));
sna_dri2_xchg(draw, front, back);
info->mode = type = FLIP_COMPLETE;
goto new_back;
} else {
DBG(("%s: executing xchg of pending flip\n", __FUNCTION__));
sna_dri2_xchg(draw, front, back);
if (!info->flip_continue && current_msc < *target_msc) {
DBG(("%s: chaining flip\n", __FUNCTION__));
type = FLIP_THROTTLE;
info->flip_continue = FLIP_THROTTLE;
info->keepalive++;
if (xorg_can_triple_buffer())
info->mode = -type;
else
info->mode = -FLIP_COMPLETE;
goto out;
goto out;
}
goto new_back;
}
info = sna_dri2_add_event(sna, draw, client);
@ -2626,7 +2643,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
__FUNCTION__));
info->type = type = FLIP;
sna->dri2.flip_pending = info;
assert(info->queued);
assert(!info->queued);
current_msc++;
} else {
info->type = type = use_triple_buffer(sna, client, *target_msc == 0);
@ -2727,8 +2744,9 @@ sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
return false;
sync = current_msc < *target_msc;
sync = current_msc < *target_msc && xorg_can_triple_buffer();
event = dri2_chain(draw) == NULL;
DBG(("%s: synchronous?=%d, send-event?=%d\n", __FUNCTION__, sync, event));
if (!sync || event) {
DBG(("%s: performing immediate xchg on pipe %d\n",
__FUNCTION__, sna_crtc_to_pipe(crtc)));
@ -2760,6 +2778,7 @@ sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
info->queued = true;
if (sna_wait_vblank(sna, &vbl, info->pipe)) {
DBG(("%s: vblank queue failed, unblocking client\n", __FUNCTION__));
sna_dri2_event_free(info);
goto complete;
}
@ -2788,8 +2807,9 @@ sna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc
if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
return false;
sync = current_msc < *target_msc;
sync = current_msc < *target_msc && xorg_can_triple_buffer();
event = dri2_chain(draw) == NULL;
DBG(("%s: synchronous?=%d, send-event?=%d\n", __FUNCTION__, sync, event));
if (!sync || event) {
DBG(("%s: performing immediate xchg only on pipe %d\n",
__FUNCTION__, sna_crtc_to_pipe(crtc)));
@ -2821,6 +2841,7 @@ sna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc
info->queued = true;
if (sna_wait_vblank(sna, &vbl, info->pipe)) {
DBG(("%s: vblank queue failed, unblocking client\n", __FUNCTION__));
sna_dri2_event_free(info);
goto complete;
}
@ -3089,8 +3110,8 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
swap = sna_crtc_last_swap(crtc);
*msc = draw_current_msc(draw, crtc, swap->msc);
*ust = ust64(swap->tv_sec, swap->tv_usec);
DBG(("%s: msc=%llu, ust=%llu\n", __FUNCTION__,
(long long)*msc, (long long)*ust));
DBG(("%s: msc=%llu [raw=%llu], ust=%llu\n", __FUNCTION__,
(long long)*msc, swap->msc, (long long)*ust));
return TRUE;
}