sna/dri: Keep reference on swap buffers until the end of the pageflip

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2011-06-10 18:41:56 +01:00
parent cf6c790182
commit 6f035e80b9
1 changed files with 94 additions and 103 deletions

View File

@ -81,7 +81,6 @@ struct sna_dri_private {
int refcnt;
PixmapPtr pixmap;
struct kgem_bo *bo;
unsigned int attachment;
};
struct sna_dri_frame_event {
@ -244,7 +243,6 @@ sna_dri_create_buffer(DrawablePtr drawable,
private->refcnt = 1;
private->pixmap = pixmap;
private->bo = bo;
private->attachment = attachment;
if (buffer->name == 0) {
/* failed to name buffer */
@ -262,22 +260,26 @@ err:
return NULL;
}
static void _sna_dri_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
{
struct sna_dri_private *private = buffer->driverPrivate;
if (--private->refcnt == 0) {
if (private->pixmap) {
ScreenPtr screen = private->pixmap->drawable.pScreen;
screen->DestroyPixmap(private->pixmap);
} else
kgem_bo_destroy(&sna->kgem, private->bo);
free(buffer);
}
}
static void sna_dri_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
{
if (buffer && buffer->driverPrivate) {
struct sna_dri_private *private = buffer->driverPrivate;
if (--private->refcnt == 0) {
if (private->pixmap) {
ScreenPtr screen = private->pixmap->drawable.pScreen;
screen->DestroyPixmap(private->pixmap);
} else {
struct sna *sna = to_sna_from_drawable(drawable);
kgem_bo_destroy(&sna->kgem, private->bo);
}
free(buffer);
}
} else
if (buffer && buffer->driverPrivate)
_sna_dri_destroy_buffer(to_sna_from_drawable(drawable), buffer);
else
free(buffer);
}
@ -349,15 +351,15 @@ static void damage(DrawablePtr drawable, RegionPtr region)
static void
sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
DRI2BufferPtr dst_buffer, DRI2BufferPtr src_buffer)
{
struct sna *sna = to_sna_from_drawable(drawable);
struct sna_dri_private *srcPrivate = sourceBuffer->driverPrivate;
struct sna_dri_private *dstPrivate = destBuffer->driverPrivate;
struct sna_dri_private *srcPrivate = src_buffer->driverPrivate;
struct sna_dri_private *dstPrivate = dst_buffer->driverPrivate;
ScreenPtr screen = drawable->pScreen;
DrawablePtr src = (srcPrivate->attachment == DRI2BufferFrontLeft)
DrawablePtr src = (src_buffer->attachment == DRI2BufferFrontLeft)
? drawable : &srcPrivate->pixmap->drawable;
DrawablePtr dst = (dstPrivate->attachment == DRI2BufferFrontLeft)
DrawablePtr dst = (dst_buffer->attachment == DRI2BufferFrontLeft)
? drawable : &dstPrivate->pixmap->drawable;
GCPtr gc;
bool flush = false;
@ -368,6 +370,17 @@ sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
region ? REGION_EXTENTS(NULL, region)->x2 : dst->width,
region ? REGION_EXTENTS(NULL, region)->y2 : dst->height));
DBG(("%s: dst -- attachment=%d, name=%d, handle=%d\n",
__FUNCTION__,
dst_buffer->attachment,
dst_buffer->name,
dstPrivate->bo->handle));
DBG(("%s: src -- attachment=%d, name=%d, handle=%d\n",
__FUNCTION__,
src_buffer->attachment,
src_buffer->name,
srcPrivate->bo->handle));
gc = GetScratchGC(dst->depth, screen);
if (!gc)
return;
@ -520,31 +533,39 @@ sna_dri_add_frame_event(struct sna_dri_frame_event *frame_event)
}
static void
sna_dri_del_frame_event(struct sna_dri_frame_event *frame_event)
sna_dri_frame_event_info(struct sna_dri_frame_event *info)
{
if (frame_event->client_id)
FreeResourceByType(frame_event->client_id,
if (info->client_id)
FreeResourceByType(info->client_id,
frame_event_client_type,
TRUE);
if (frame_event->drawable_id)
FreeResourceByType(frame_event->drawable_id,
if (info->drawable_id)
FreeResourceByType(info->drawable_id,
frame_event_drawable_type,
TRUE);
if (info->front)
_sna_dri_destroy_buffer(info->sna, info->front);
if (info->back)
_sna_dri_destroy_buffer(info->sna, info->back);
free(info);
}
static void
sna_dri_exchange_buffers(DrawablePtr draw,
DRI2BufferPtr front, DRI2BufferPtr back)
DRI2BufferPtr front,
DRI2BufferPtr back)
{
int tmp;
DBG(("%s()\n", __FUNCTION__));
/* Swap BO names so DRI works */
tmp = front->name;
front->name = back->name;
back->name = tmp;
assert(front->format == back->format);
tmp = front->attachment;
front->attachment = back->attachment;
back->attachment = tmp;
}
/*
@ -553,53 +574,29 @@ sna_dri_exchange_buffers(DrawablePtr draw,
*/
static Bool
sna_dri_schedule_flip(struct sna *sna,
ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
DRI2BufferPtr back, DRI2SwapEventPtr func, void *data,
unsigned int target_msc)
DrawablePtr draw,
struct sna_dri_frame_event *info)
{
struct sna_dri *dri = &sna->dri;
struct sna_dri_private *back_priv;
struct sna_dri_frame_event *info;
/* Main crtc for this drawable shall finally deliver pageflip event. */
int ref_crtc_hw_id = sna_dri_get_pipe(draw);
DBG(("%s()\n", __FUNCTION__));
info = calloc(1, sizeof(struct sna_dri_frame_event));
if (!info)
return FALSE;
info->sna = sna;
info->drawable_id = draw->id;
info->client = client;
info->type = DRI2_SWAP;
info->event_complete = func;
info->event_data = data;
info->frame = target_msc;
if (!sna_dri_add_frame_event(info)) {
free(info);
return FALSE;
}
dri->fe_frame = 0;
dri->fe_tv_sec = 0;
dri->fe_tv_usec = 0;
/* Page flip the full screen buffer */
back_priv = back->driverPrivate;
back_priv = info->back->driverPrivate;
info->count = sna_do_pageflip(sna,
back_priv->pixmap,
info, ref_crtc_hw_id,
&info->old_front,
&info->old_fb);
if (info->count)
return TRUE;
sna_dri_del_frame_event(info);
free(info);
return FALSE;
return info->count != 0;
}
static Bool
@ -662,7 +659,6 @@ can_flip(struct sna * sna,
DRI2BufferPtr front,
DRI2BufferPtr back)
{
struct sna_dri_private *front_priv = front->driverPrivate;
struct sna_dri_private *back_priv = back->driverPrivate;
struct sna_pixmap *front_sna, *back_sna;
WindowPtr win = (WindowPtr)draw;
@ -673,10 +669,16 @@ can_flip(struct sna * sna,
assert(draw->type == DRAWABLE_WINDOW);
if (front_priv->attachment != DRI2BufferFrontLeft) {
if (front->format != back->format) {
DBG(("%s: no, format mismatch, front = %d, back = %d\n",
__FUNCTION__, front->format, back->format));
return FALSE;
}
if (front->attachment != DRI2BufferFrontLeft) {
DBG(("%s: no, front attachment [%d] is not FrontLeft [%d]\n",
__FUNCTION__,
front_priv->attachment,
front->attachment,
DRI2BufferFrontLeft));
return FALSE;
}
@ -772,7 +774,7 @@ static void sna_dri_vblank_handle(int fd,
void *data)
{
struct sna_dri_frame_event *swap_info = data;
DrawablePtr drawable;
DrawablePtr draw;
ScreenPtr screen;
ScrnInfoPtr scrn;
struct sna *sna;
@ -783,53 +785,46 @@ static void sna_dri_vblank_handle(int fd,
status = BadDrawable;
if (swap_info->drawable_id)
status = dixLookupDrawable(&drawable,
status = dixLookupDrawable(&draw,
swap_info->drawable_id,
serverClient,
M_ANY, DixWriteAccess);
if (status != Success)
goto done;
screen = drawable->pScreen;
screen = draw->pScreen;
scrn = xf86Screens[screen->myNum];
sna = to_sna(scrn);
switch (swap_info->type) {
case DRI2_FLIP:
/* If we can still flip... */
if (can_flip(sna, drawable,
if (can_flip(sna, draw,
swap_info->front, swap_info->back) &&
sna_dri_schedule_flip(sna,
swap_info->client,
drawable,
swap_info->front,
swap_info->back,
swap_info->event_complete,
swap_info->event_data,
swap_info->frame)) {
sna_dri_exchange_buffers(drawable,
swap_info->front,
swap_info->back);
break;
sna_dri_schedule_flip(sna, draw, swap_info)) {
sna_dri_exchange_buffers(draw,
swap_info->front,
swap_info->back);
return;
}
/* else fall through to exchange/blit */
case DRI2_SWAP: {
int swap_type;
if (DRI2CanExchange(drawable) &&
if (DRI2CanExchange(draw) &&
can_exchange(swap_info->front, swap_info->back)) {
sna_dri_exchange_buffers(drawable,
swap_info->front,
swap_info->back);
sna_dri_exchange_buffers(draw,
swap_info->front,
swap_info->back);
swap_type = DRI2_EXCHANGE_COMPLETE;
} else {
sna_dri_copy_region(drawable, NULL,
swap_info->front,
swap_info->back);
sna_dri_copy_region(draw, NULL,
swap_info->front,
swap_info->back);
swap_type = DRI2_BLIT_COMPLETE;
}
DRI2SwapComplete(swap_info->client,
drawable, frame,
draw, frame,
tv_sec, tv_usec,
swap_type,
swap_info->client ? swap_info->event_complete : NULL,
@ -838,7 +833,7 @@ static void sna_dri_vblank_handle(int fd,
}
case DRI2_WAITMSC:
if (swap_info->client)
DRI2WaitMSCComplete(swap_info->client, drawable,
DRI2WaitMSCComplete(swap_info->client, draw,
frame, tv_sec, tv_usec);
break;
default:
@ -849,13 +844,11 @@ static void sna_dri_vblank_handle(int fd,
}
done:
sna_dri_del_frame_event(swap_info);
sna_dri_destroy_buffer(drawable, swap_info->front);
sna_dri_destroy_buffer(drawable, swap_info->back);
free(swap_info);
sna_dri_frame_event_info(swap_info);
}
static void sna_dri_flip_event(struct sna *sna, struct sna_dri_frame_event *flip)
static void sna_dri_flip_event(struct sna *sna,
struct sna_dri_frame_event *flip)
{
DrawablePtr drawable;
int status;
@ -879,7 +872,7 @@ static void sna_dri_flip_event(struct sna *sna, struct sna_dri_frame_event *flip
/* We assume our flips arrive in order, so we don't check the frame */
switch (flip->type) {
case DRI2_SWAP:
case DRI2_FLIP:
/* Deliver cached msc, ust from reference crtc */
/* Check for too small vblank count of pageflip completion, taking wraparound
* into account. This usually means some defective kms pageflip completion,
@ -903,12 +896,13 @@ static void sna_dri_flip_event(struct sna *sna, struct sna_dri_frame_event *flip
sna->dri.fe_frame = sna->dri.fe_tv_sec = sna->dri.fe_tv_usec = 0;
}
DBG(("%s: swap complete\n", __FUNCTION__));
DBG(("%s: flip complete\n", __FUNCTION__));
DRI2SwapComplete(flip->client, drawable,
sna->dri.fe_frame,
sna->dri.fe_tv_sec,
sna->dri.fe_tv_usec,
DRI2_FLIP_COMPLETE, flip->client ? flip->event_complete : NULL,
DRI2_FLIP_COMPLETE,
flip->client ? flip->event_complete : NULL,
flip->event_data);
break;
@ -949,8 +943,7 @@ sna_dri_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
sna_dri_flip_event(info->sna, info);
sna_mode_delete_fb(info->sna, info->old_front, info->old_fb);
sna_dri_del_frame_event(info);
free(info);
sna_dri_frame_event_info(info);
}
/*
@ -1003,6 +996,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
if (!swap_info)
goto blit_fallback;
swap_info->sna = sna;
swap_info->drawable_id = draw->id;
swap_info->client = client;
swap_info->event_complete = func;
@ -1141,12 +1135,8 @@ blit_fallback:
sna_dri_copy_region(draw, NULL, front, back);
DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
if (swap_info) {
sna_dri_del_frame_event(swap_info);
sna_dri_destroy_buffer(draw, swap_info->front);
sna_dri_destroy_buffer(draw, swap_info->back);
free(swap_info);
}
if (swap_info)
sna_dri_frame_event_info(swap_info);
*target_msc = 0; /* offscreen, so zero out target vblank count */
return TRUE;
}
@ -1367,6 +1357,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
if (!wait_info)
goto out_complete;
wait_info->sna = sna;
wait_info->drawable_id = draw->id;
wait_info->client = client;
wait_info->type = DRI2_WAITMSC;