dri: Hold reference to buffers across swap

As we schedule swaps for some time in the future and may process a
detachment prior to receiving the vblank notification from the kernel,
we need to hold a reference to the buffers for our swap event handler.

Fixes:
  Bug 28080 - "glresize" causes X server segfault with indirect rendering.
  https://bugs.freedesktop.org/show_bug.cgi?id=28080

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2010-05-14 10:32:12 +01:00
parent 8de09a0707
commit 0d2392d44a
1 changed files with 27 additions and 5 deletions

View File

@ -75,6 +75,7 @@ extern XF86ModuleData dri2ModuleData;
#endif
typedef struct {
int refcnt;
PixmapPtr pixmap;
unsigned int attachment;
} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr;
@ -147,6 +148,7 @@ I830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
buffers[i].cpp = pixmap->drawable.bitsPerPixel / 8;
buffers[i].driverPrivate = &privates[i];
buffers[i].flags = 0; /* not tiled */
privates[i].refcnt = 1;
privates[i].pixmap = pixmap;
privates[i].attachment = attachments[i];
@ -223,6 +225,7 @@ I830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
buffer->driverPrivate = privates;
buffer->format = format;
buffer->flags = 0; /* not tiled */
privates->refcnt = 1;
privates->pixmap = pixmap;
privates->attachment = attachment;
@ -262,17 +265,27 @@ static void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
{
if (buffer) {
I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
ScreenPtr screen = drawable->pScreen;
if (--private->refcnt == 0) {
ScreenPtr screen = private->pixmap->drawable.pScreen;
screen->DestroyPixmap(private->pixmap);
screen->DestroyPixmap(private->pixmap);
xfree(private);
xfree(buffer);
xfree(private);
xfree(buffer);
}
}
}
#endif
static void I830DRI2ReferenceBuffer(DRI2Buffer2Ptr buffer)
{
if (buffer) {
I830DRI2BufferPrivatePtr private = buffer->driverPrivate;
private->refcnt++;
}
}
static void
I830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
@ -510,6 +523,8 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
M_ANY, DixWriteAccess);
if (status != Success) {
I830DRI2DestroyBuffer(NULL, event->front);
I830DRI2DestroyBuffer(NULL, event->back);
xfree(event);
return;
}
@ -568,6 +583,8 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
break;
}
I830DRI2DestroyBuffer(drawable, event->front);
I830DRI2DestroyBuffer(drawable, event->back);
xfree(event);
}
@ -661,6 +678,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
swap_info->event_data = data;
swap_info->front = front;
swap_info->back = back;
I830DRI2ReferenceBuffer(front);
I830DRI2ReferenceBuffer(back);
/* Get current count */
vbl.request.type = DRM_VBLANK_RELATIVE;
@ -791,8 +810,11 @@ blit_fallback:
I830DRI2CopyRegion(draw, &region, front, back);
DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
if (swap_info)
if (swap_info) {
I830DRI2DestroyBuffer(draw, swap_info->front);
I830DRI2DestroyBuffer(draw, swap_info->back);
xfree(swap_info);
}
*target_msc = 0; /* offscreen, so zero out target vblank count */
return TRUE;
}