sna/dri2: Move scanout processing from frame event to global

The scanout is a global property, track it as so. The primary benefit to
this is it strengthens our assertions that we never hand out an active
scanout for use as a back buffer.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2014-05-26 08:23:45 +01:00
parent 05f149285b
commit 2a0dc7ed49
3 changed files with 83 additions and 61 deletions

View File

@ -315,6 +315,10 @@ struct sna {
#if HAVE_DRI2
void *flip_pending;
struct {
struct kgem_bo *bo;
uint32_t name;
} scanout[2];
#endif
} dri2;
@ -496,6 +500,7 @@ void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_vblank *event)
void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event);
void sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap);
void sna_dri2_destroy_window(WindowPtr win);
void sna_dri2_reset_scanout(struct sna *sna);
void sna_dri2_close(struct sna *sna, ScreenPtr pScreen);
#else
static inline bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen) { return false; }
@ -503,6 +508,7 @@ static inline void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_
static inline void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event) { }
static inline void sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap) { }
static inline void sna_dri2_destroy_window(WindowPtr win) { }
static inline void sna_dri2_reset_scanout(struct sna *sna) { }
static inline void sna_dri2_close(struct sna *sna, ScreenPtr pScreen) { }
#endif

View File

@ -4505,6 +4505,8 @@ sna_crtc_config_notify(ScreenPtr screen)
DBG(("%s\n", __FUNCTION__));
sna_dri2_reset_scanout(sna);
sna_mode_update(sna);
sna_cursors_reload(sna);
}

View File

@ -112,11 +112,6 @@ struct sna_dri2_frame_event {
struct sna_dri2_frame_event *chain;
struct {
struct kgem_bo *bo;
uint32_t name;
} scanout[2];
struct list cache;
int mode;
@ -130,15 +125,15 @@ sna_dri2_get_back(struct sna *sna, struct sna_dri2_frame_event *info)
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,
sna->dri2.scanout[0].bo ? sna->dri2.scanout[0].bo->handle : 0,
sna->dri2.scanout[1].bo ? sna->dri2.scanout[1].bo->handle : 0,
get_private(info->back)->bo->handle,
!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 == sna->dri2.scanout[0].bo || bo == sna->dri2.scanout[1].bo)) {
DBG(("%s: reuse unattached back\n", __FUNCTION__));
return;
}
@ -173,15 +168,15 @@ sna_dri2_get_back(struct sna *sna, struct sna_dri2_frame_event *info)
}
}
assert(!(bo == info->scanout[0].bo || bo == info->scanout[1].bo));
assert(!(bo == sna->dri2.scanout[0].bo || bo == sna->dri2.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(get_private(info->back)->bo != sna->dri2.scanout[0].bo);
assert(get_private(info->back)->bo != sna->dri2.scanout[1].bo);
assert(bo->refcnt == 1);
assert(bo->flush);
@ -247,6 +242,9 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
DBG(("%s: replacing back buffer\n", __FUNCTION__));
sna_dri2_get_back(to_sna_from_drawable(draw), info);
}
assert(get_private(buffer)->bo != to_sna_from_drawable(draw)->dri2.scanout[0].bo);
assert(get_private(buffer)->bo != to_sna_from_drawable(draw)->dri2.scanout[1].bo);
}
}
@ -1192,13 +1190,6 @@ sna_dri2_frame_event_info_free(struct sna *sna,
_sna_dri2_destroy_buffer(sna, info->front);
_sna_dri2_destroy_buffer(sna, info->back);
assert(info->scanout[1].bo == NULL);
if (info->scanout[0].bo) {
assert(info->scanout[0].bo->scanout);
kgem_bo_destroy(&sna->kgem, info->scanout[0].bo);
}
while (!list_is_empty(&info->cache)) {
struct dri_bo *c;
@ -1254,6 +1245,25 @@ void sna_dri2_destroy_window(WindowPtr win)
free(priv);
}
static void
update_scanout(struct sna *sna, struct sna_dri2_frame_event *info, struct kgem_bo *bo, int name)
{
assert(sna->dri2.scanout[1].bo == NULL);
assert(sna->dri2.scanout[0].bo->scanout);
assert(sna->dri2.scanout[0].bo->refcnt);
sna->dri2.scanout[1] = sna->dri2.scanout[0];
sna->dri2.scanout[0].bo = ref(bo);
sna->dri2.scanout[0].name = name;
assert(sna->dri2.scanout[0].bo->scanout);
DBG(("%s: pending scanout handle=%d, active scanout handle=%d\n",
__FUNCTION__, sna->dri2.scanout[0].bo->handle, sna->dri2.scanout[1].bo->handle));
assert(sna->dri2.scanout[0].bo->handle != sna->dri2.scanout[1].bo->handle);
assert(sna->dri2.flip_pending == NULL || sna->dri2.flip_pending == info);
sna->dri2.flip_pending = info;
}
static bool
sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
{
@ -1264,29 +1274,22 @@ sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
assert(sna_pixmap_get_buffer(sna->front) == info->front);
assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
assert(info->scanout[0].bo);
assert(info->scanout[0].bo->scanout);
assert(info->scanout[1].bo == NULL);
assert(sna->dri2.scanout[0].bo);
assert(sna->dri2.scanout[0].bo->scanout);
assert(sna->dri2.scanout[1].bo == NULL);
assert(bo->refcnt);
info->count = sna_page_flip(sna, bo, info, info->pipe);
if (!info->count)
return false;
DBG(("%s: mark handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n",
update_scanout(sna, info, bo, info->back->name);
DBG(("%s: marked handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n",
__FUNCTION__, bo->handle,
get_private(info->front)->bo->handle, info->front->name,
get_private(info->back)->bo->handle, info->back->name));
info->scanout[1] = info->scanout[0];
info->scanout[0].bo = ref(bo);
info->scanout[0].name = info->back->name;
assert(info->scanout[0].bo->scanout);
DBG(("%s: pending scanout handle=%d, active scanout handle=%d\n",
__FUNCTION__, info->scanout[0].bo->handle, info->scanout[1].bo->handle));
assert(info->scanout[0].bo->handle != info->scanout[1].bo->handle);
tmp.bo = get_private(info->front)->bo;
tmp.name = info->front->name;
@ -1298,8 +1301,6 @@ sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
info->back->name = tmp.name;
get_private(info->back)->bo = tmp.bo;
sna->dri2.flip_pending = info;
info->queued = true;
return true;
}
@ -1773,23 +1774,18 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
if (info->mode > 0){
struct kgem_bo *bo =get_private(info->front)->bo;
info->type = info->mode;
if (get_private(info->front)->bo != sna_pixmap(sna->front)->gpu_bo)
if (bo != sna_pixmap(sna->front)->gpu_bo)
return false;
info->count = sna_page_flip(sna,
get_private(info->front)->bo,
info, info->pipe);
info->count = sna_page_flip(sna, bo, info, info->pipe);
if (!info->count)
return false;
assert(info->scanout[0].bo->scanout);
info->scanout[1] = info->scanout[0];
info->scanout[0].bo = ref(get_private(info->front)->bo);
info->scanout[0].name = info->front->name;
assert(info->scanout[0].bo->scanout);
sna->dri2.flip_pending = info;
update_scanout(sna, info, bo, info->front->name);
} else {
info->type = -info->mode;
@ -1870,18 +1866,18 @@ static void sna_dri2_flip_event(struct sna *sna,
assert(!sna->mode.shadow_flip);
if (flip->scanout[1].bo) {
if (sna->dri2.scanout[1].bo) {
struct dri_bo *c = NULL;
DBG(("%s: retiring previous scanout handle=%d, name=%d, refcnt=%d (current scanout handle=%d)\n",
__FUNCTION__,
flip->scanout[1].bo->handle,
flip->scanout[1].name,
flip->scanout[1].bo->refcnt,
flip->scanout[0].bo->handle));
sna->dri2.scanout[1].bo->handle,
sna->dri2.scanout[1].name,
sna->dri2.scanout[1].bo->refcnt,
sna->dri2.scanout[0].bo->handle));
if (flip->scanout[1].bo != flip->scanout[0].bo &&
flip->scanout[1].bo->refcnt == 1) {
if (sna->dri2.scanout[1].bo != sna->dri2.scanout[0].bo &&
sna->dri2.scanout[1].bo->refcnt == 1) {
DBG(("%s: adding old scanout to flip cache\n", __FUNCTION__));
if (!list_is_empty(&flip->cache))
c = list_last_entry(&flip->cache, struct dri_bo, link);
@ -1894,19 +1890,19 @@ static void sna_dri2_flip_event(struct sna *sna,
if (c == NULL)
c = malloc(sizeof(*c));
if (c != NULL) {
c->bo = flip->scanout[1].bo;
c->name = flip->scanout[1].name;
c->bo = sna->dri2.scanout[1].bo;
c->name = sna->dri2.scanout[1].name;
list_add(&c->link, &flip->cache);
}
}
if (c == NULL) {
DBG(("%s: not caching old scanout handle=%d, still busy\n",
__FUNCTION__, flip->scanout[1].bo->handle));
kgem_bo_destroy(&sna->kgem, flip->scanout[1].bo);
__FUNCTION__, sna->dri2.scanout[1].bo->handle));
kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[1].bo);
}
flip->scanout[1].bo = NULL;
sna->dri2.scanout[1].bo = NULL;
}
if (sna->dri2.flip_pending == flip)
@ -2114,9 +2110,12 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
info->front = sna_dri2_reference_buffer(front);
info->back = sna_dri2_reference_buffer(back);
info->scanout[0].bo = ref(get_private(front)->bo);
info->scanout[0].name = info->front->name;
assert(info->scanout[0].bo->scanout);
if (sna->dri2.scanout[0].bo == NULL) {
sna->dri2.scanout[0].bo = ref(get_private(front)->bo);
sna->dri2.scanout[0].name = info->front->name;
}
assert(sna->dri2.scanout[0].bo == get_private(front)->bo);
assert(sna->dri2.scanout[0].bo->scanout);
if (sna->dri2.flip_pending) {
/* We need to first wait (one vblank) for the
@ -2161,9 +2160,12 @@ out:
info->front = sna_dri2_reference_buffer(front);
info->back = sna_dri2_reference_buffer(back);
info->scanout[0].bo = ref(get_private(front)->bo);
info->scanout[0].name = info->front->name;
assert(info->scanout[0].bo->scanout);
if (sna->dri2.scanout[0].bo == NULL) {
sna->dri2.scanout[0].bo = ref(get_private(front)->bo);
sna->dri2.scanout[0].name = info->front->name;
}
assert(sna->dri2.scanout[0].bo == get_private(front)->bo);
assert(sna->dri2.scanout[0].bo->scanout);
/*
* If divisor is zero, or current_msc is smaller than target_msc
@ -2675,6 +2677,18 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
return DRI2ScreenInit(screen, &info);
}
void sna_dri2_reset_scanout(struct sna *sna)
{
if (sna->dri2.scanout[1].bo != NULL) {
kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[1].bo);
sna->dri2.scanout[1].bo = NULL;
}
if (sna->dri2.scanout[0].bo != NULL) {
kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[0].bo);
sna->dri2.scanout[0].bo = NULL;
}
}
void sna_dri2_close(struct sna *sna, ScreenPtr screen)
{
DBG(("%s()\n", __FUNCTION__));