sna/dri: Prevent scheduling a swap on stale buffers

If the screen has been reconfigured and the DRI client tries to swap the
old buffers (having not processed the invalidate event and retrieved the
current names), quietly drop the request. If we try to obey the request,
we will end up attaching a back buffer that is the wrong size to the
scanout...

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2012-11-12 14:06:06 +00:00
parent 34aa1e3b27
commit b27ecf3059
1 changed files with 75 additions and 21 deletions

View File

@ -98,9 +98,10 @@ struct sna_dri_frame_event {
};
struct sna_dri_private {
int refcnt;
PixmapPtr pixmap;
struct kgem_bo *bo;
unsigned long serial;
int refcnt;
};
static inline struct sna_dri_frame_event *
@ -259,6 +260,8 @@ sna_dri_create_buffer(DrawablePtr draw,
assert(private->pixmap == pixmap);
assert(sna_pixmap(pixmap)->gpu_bo == private->bo);
assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name);
assert(8*private->bo->pitch >= pixmap->drawable.width * pixmap->drawable.bitsPerPixel);
assert(private->bo->pitch * pixmap->drawable.height <= kgem_bo_size(private->bo));
private->refcnt++;
return buffer;
@ -353,6 +356,7 @@ sna_dri_create_buffer(DrawablePtr draw,
private->refcnt = 1;
private->bo = bo;
private->pixmap = pixmap;
private->serial = get_drawable_pixmap(draw)->drawable.serialNumber;
if (buffer->name == 0)
goto err;
@ -1064,6 +1068,15 @@ can_flip(struct sna * sna,
}
assert(get_private(front)->pixmap == sna->front);
assert(get_private(front)->serial == pixmap->drawable.serialNumber);
if (get_private(back)->serial != pixmap->drawable.serialNumber) {
DBG(("%s: no, DRI2 drawable has a stale reference to the pixmap (DRI2 pixmap=%ld, X pixmap=%ld)\n",
__FUNCTION__,
get_private(back)->serial,
pixmap->drawable.serialNumber));
return false;
}
DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n",
__FUNCTION__,
@ -1154,9 +1167,34 @@ can_exchange(struct sna * sna,
return false;
}
assert(get_private(front)->serial == pixmap->drawable.serialNumber);
if (get_private(back)->serial != pixmap->drawable.serialNumber) {
DBG(("%s: no, DRI2 drawable has a stale reference to the pixmap (DRI2 pixmap=%ld, X pixmap=%ld)\n",
__FUNCTION__,
get_private(back)->serial,
pixmap->drawable.serialNumber));
return false;
}
return true;
}
static bool
can_blit(struct sna * sna,
DrawablePtr draw,
DRI2BufferPtr front,
DRI2BufferPtr back)
{
PixmapPtr pixmap;
if (draw->type == DRAWABLE_PIXMAP)
return true;
pixmap = get_drawable_pixmap(draw);
return (get_private(front)->serial == pixmap->drawable.serialNumber &&
get_private(back)->serial == pixmap->drawable.serialNumber);
}
inline static uint32_t pipe_select(int pipe)
{
/* The third pipe was introduced with IvyBridge long after
@ -1236,7 +1274,7 @@ static void chain_swap(struct sna *sna,
DBG(("%s: performing chained exchange\n", __FUNCTION__));
sna_dri_exchange_buffers(draw, chain->front, chain->back);
type = DRI2_EXCHANGE_COMPLETE;
} else {
} else if (can_blit(sna, draw, chain->front, chain->back)) {
DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
chain->bo = sna_dri_copy_to_front(sna, draw, NULL,
@ -1245,6 +1283,12 @@ static void chain_swap(struct sna *sna,
true);
type = DRI2_BLIT_COMPLETE;
} else {
DRI2SwapComplete(chain->client, draw,
0, 0, 0, DRI2_BLIT_COMPLETE,
chain->client ? chain->event_complete : NULL, chain->event_data);
sna_dri_frame_event_info_free(sna, draw, chain);
return;
}
DRI2SwapComplete(chain->client, draw,
@ -1309,10 +1353,11 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
}
/* else fall through to blit */
case DRI2_SWAP:
info->bo = sna_dri_copy_to_front(sna, draw, NULL,
get_private(info->front)->bo,
get_private(info->back)->bo,
true);
if (can_blit(sna, draw, info->front, info->back))
info->bo = sna_dri_copy_to_front(sna, draw, NULL,
get_private(info->front)->bo,
get_private(info->back)->bo,
true);
info->type = DRI2_SWAP_WAIT;
/* fall through to SwapComplete */
case DRI2_SWAP_WAIT:
@ -1411,12 +1456,14 @@ static void chain_flip(struct sna *sna)
} else
sna->dri.flip_pending = chain;
} else {
DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
if (can_blit(sna, chain->draw, chain->front, chain->back)) {
DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
chain->bo = sna_dri_copy_to_front(sna, chain->draw, NULL,
get_private(chain->front)->bo,
get_private(chain->back)->bo,
true);
chain->bo = sna_dri_copy_to_front(sna, chain->draw, NULL,
get_private(chain->front)->bo,
get_private(chain->back)->bo,
true);
}
DRI2SwapComplete(chain->client, chain->draw, 0, 0, 0,
DRI2_BLIT_COMPLETE, chain->client ? chain->event_complete : NULL, chain->event_data);
sna_dri_frame_event_info_free(sna, chain->draw, chain);
@ -1494,10 +1541,12 @@ static void sna_dri_flip_event(struct sna *sna,
DBG(("%s: no longer able to flip\n", __FUNCTION__));
if (flip->draw) {
flip->bo = sna_dri_copy_to_front(sna, flip->draw, NULL,
get_private(flip->front)->bo,
get_private(flip->back)->bo,
false);
if (can_blit(sna, flip->draw, flip->front, flip->back)) {
flip->bo = sna_dri_copy_to_front(sna, flip->draw, NULL,
get_private(flip->front)->bo,
get_private(flip->back)->bo,
false);
}
DRI2SwapComplete(flip->client, flip->draw,
0, 0, 0,
DRI2_BLIT_COMPLETE,
@ -1966,10 +2015,15 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
info->type = swap_type;
if (divisor == 0) {
if (can_exchange(sna, draw, front, back))
if (can_exchange(sna, draw, front, back)) {
sna_dri_immediate_xchg(sna, draw, info);
else
} else if (can_blit(sna, draw, front, back)) {
sna_dri_immediate_blit(sna, draw, info);
} else {
DRI2SwapComplete(client, draw, 0, 0, 0,
DRI2_BLIT_COMPLETE, func, data);
sna_dri_frame_event_info_free(sna, draw, info);
}
return TRUE;
}
@ -2044,17 +2098,17 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
return TRUE;
blit_fallback:
pipe = DRI2_BLIT_COMPLETE;
if (can_exchange(sna, draw, front, back)) {
DBG(("%s -- xchg\n", __FUNCTION__));
sna_dri_exchange_buffers(draw, front, back);
pipe = DRI2_EXCHANGE_COMPLETE;
} else {
} else if (can_blit(sna, draw, front, back)) {
DBG(("%s -- blit\n", __FUNCTION__));
sna_dri_copy_to_front(sna, draw, NULL,
get_private(front)->bo,
get_private(back)->bo,
false);
pipe = DRI2_BLIT_COMPLETE;
}
if (info)
sna_dri_frame_event_info_free(sna, draw, info);
@ -2078,17 +2132,17 @@ sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
if (!can_flip(sna, draw, front, back)) {
blit:
name = DRI2_BLIT_COMPLETE;
if (can_exchange(sna, draw, front, back)) {
DBG(("%s: unable to flip, so xchg\n", __FUNCTION__));
sna_dri_exchange_buffers(draw, front, back);
name = DRI2_EXCHANGE_COMPLETE;
} else {
} else if (can_blit(sna, draw, front, back)) {
DBG(("%s: unable to flip, so blit\n", __FUNCTION__));
sna_dri_copy_to_front(sna, draw, NULL,
get_private(front)->bo,
get_private(back)->bo,
false);
name = DRI2_BLIT_COMPLETE;
}
DRI2SwapComplete(client, draw, 0, 0, 0, name, func, data);