diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-09-23 09:46:36 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-09-23 10:49:46 +0100 |
commit | bee26a8e2eaefdcb2072ce8ba92585d3bf713c82 (patch) | |
tree | fe485aa330b94925fa7d75174c3e5bc549de3c76 | |
parent | c4f5da7ab9e02c3994fe9668630480f85e706e89 (diff) |
sna/dri: Sanitize the backbuffer flip cache
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/sna_dri.c | 116 |
1 files changed, 85 insertions, 31 deletions
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c index cf37f94b..2f1ccffa 100644 --- a/src/sna/sna_dri.c +++ b/src/sna/sna_dri.c @@ -93,6 +93,12 @@ static inline struct kgem_bo *ref(struct kgem_bo *bo) return bo; } +static inline void unref(struct kgem_bo *bo) +{ + assert(bo->refcnt > 1); + bo->refcnt--; +} + /* Prefer to enable TILING_Y if this buffer will never be a * candidate for pageflipping */ @@ -854,6 +860,12 @@ static inline int sna_wait_vblank(struct sna *sna, drmVBlank *vbl) #if DRI2INFOREC_VERSION >= 4 +struct dri_bo { + struct list link; + struct kgem_bo *bo; + uint32_t name; +}; + struct sna_dri_frame_event { DrawablePtr draw; ClientPtr client; @@ -874,15 +886,16 @@ struct sna_dri_frame_event { unsigned int fe_tv_sec; unsigned int fe_tv_usec; - struct dri_bo { + struct { struct kgem_bo *bo; uint32_t name; - } scanout[2], cache; + } scanout[2]; + + struct list cache; int mode; }; - static inline struct sna_dri_frame_event * to_frame_event(uintptr_t data) { @@ -1000,8 +1013,19 @@ sna_dri_frame_event_info_free(struct sna *sna, kgem_bo_destroy(&sna->kgem, info->scanout[0].bo); } - if (info->cache.bo) - kgem_bo_destroy(&sna->kgem, info->cache.bo); + while (!list_is_empty(&info->cache)) { + struct dri_bo *c; + + c = list_first_entry(&info->cache, struct dri_bo, link); + list_del(&c->link); + + if (c->bo) { + assert(c->bo->refcnt == 1); + kgem_bo_destroy(&sna->kgem, c->bo); + } + + free(c); + } if (info->bo) kgem_bo_destroy(&sna->kgem, info->bo); @@ -1439,33 +1463,39 @@ sna_dri_immediate_blit(struct sna *sna, return ret; } - static void sna_dri_flip_get_back(struct sna *sna, struct sna_dri_frame_event *info) { + struct dri_bo *c; struct kgem_bo *bo; uint32_t name; - DBG(("%s: scanout=(%d, %d), back=%d, cache=%d\n", + DBG(("%s: scanout=(%d, %d), back=%d, cache?=%d\n", __FUNCTION__, info->scanout[0].bo ? info->scanout[0].bo->handle : 0, info->scanout[1].bo ? info->scanout[1].bo->handle : 0, get_private(info->back)->bo->handle, - info->cache.bo ? info->cache.bo->handle : 0)); + !list_is_empty(&info->cache))); bo = get_private(info->back)->bo; assert(bo->refcnt); assert(bo->flush); - if (!(bo == info->scanout[0].bo || bo == info->scanout[1].bo)) + if (!(bo == info->scanout[0].bo || bo == info->scanout[1].bo)) { + DBG(("%s: reuse unattached back\n", __FUNCTION__)); return; + } - bo = info->cache.bo; - name = info->cache.name; - if (bo == NULL || - bo == info->scanout[0].bo || - bo == info->scanout[1].bo) { - struct kgem_bo *old_bo = bo; - + bo = NULL; + if (!list_is_empty(&info->cache)) { + c = list_first_entry(&info->cache, struct dri_bo, link); + bo = c->bo; + name = c->name; + DBG(("%s: reuse cache handle=%d,name=%d\n", __FUNCTION__, + bo->handle, name)); + list_move_tail(&c->link, &info->cache); + c->bo = NULL; + } + if (bo == NULL) { DBG(("%s: allocating new backbuffer\n", __FUNCTION__)); bo = kgem_create_2d(&sna->kgem, info->draw->width, @@ -1481,25 +1511,19 @@ sna_dri_flip_get_back(struct sna *sna, struct sna_dri_frame_event *info) kgem_bo_destroy(&sna->kgem, bo); return; } - - if (old_bo) { - DBG(("%s: discarding old backbuffer\n", __FUNCTION__)); - kgem_bo_destroy(&sna->kgem, old_bo); - } } - info->cache.bo = get_private(info->back)->bo; - info->cache.name = info->back->name; - assert(info->cache.bo->refcnt); - assert(info->cache.name); + assert(!(bo == info->scanout[0].bo || bo == info->scanout[1].bo)); + assert(name); + unref(get_private(info->back)->bo); get_private(info->back)->bo = bo; info->back->name = name; assert(get_private(info->back)->bo != info->scanout[0].bo); assert(get_private(info->back)->bo != info->scanout[1].bo); - assert(bo->refcnt); + assert(bo->refcnt == 1); assert(bo->flush); } @@ -1587,14 +1611,40 @@ static void sna_dri_flip_event(struct sna *sna, flip->fe_tv_usec, flip->type)); - if (flip->cache.bo == NULL) { - flip->cache = flip->scanout[1]; - flip->scanout[1].bo = NULL; - } if (flip->scanout[1].bo) { - kgem_bo_destroy(&sna->kgem, flip->scanout[1].bo); + struct dri_bo *c = NULL; + + DBG(("%s: retiring previous scanout handle=%d,name=%d\n", + __FUNCTION__, + flip->scanout[1].bo->handle, + flip->scanout[1].name)); + + if (flip->scanout[1].bo != flip->scanout[0].bo) { + assert(flip->scanout[1].bo->refcnt == 1); + + if (!list_is_empty(&flip->cache)) + c = list_last_entry(&flip->cache, struct dri_bo, link); + if (c) { + if (c->bo == NULL) + _list_del(&c->link); + else + c = NULL; + } + if (c == NULL) + c = malloc(sizeof(*c)); + if (c != NULL) { + c->bo = flip->scanout[1].bo; + c->name = flip->scanout[1].name; + list_add(&c->link, &flip->cache); + } + } + + if (c == NULL) + kgem_bo_destroy(&sna->kgem, flip->scanout[1].bo); + flip->scanout[1].bo = NULL; } + if (sna->dri.flip_pending == flip) sna->dri.flip_pending = NULL; @@ -1771,6 +1821,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, if (info == NULL) return false; + list_init(&info->cache); info->type = use_triple_buffer(sna, client); info->draw = draw; info->client = client; @@ -1822,6 +1873,7 @@ out: if (info == NULL) return false; + list_init(&info->cache); info->draw = draw; info->client = client; info->event_complete = func; @@ -1993,6 +2045,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, if (!info) goto blit; + list_init(&info->cache); info->draw = draw; info->client = client; info->event_complete = func; @@ -2202,6 +2255,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc, if (!info) goto out_complete; + list_init(&info->cache); info->draw = draw; info->client = client; info->type = DRI2_WAITMSC; |