summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-07-11 10:50:36 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-07-11 22:13:01 +0100
commit7538be3315b8683b05e8f6b22023baadcc0bc4da (patch)
tree5c7137fa88bfe15d852c981fcc234515d8eca193
parent2608a367acba7247e50754c3daeed09ba2e97d05 (diff)
dri: Enable triple-bufferred pageflips
By popular demand. Triple-buffering trade-offs output latency versus jitter. By having a pre-rendered frame ready to swap in following a pageflip, we avoid the scenario where the latency between receiving the flip complete signal from the kernel, waking up the vsynced application, it render the new frame and then for the server to process the swap request is greater than the frame interval, causing us to miss the vblank. The result is that application can become frame-locked to 30fps. Instead, we report to the application that the first frame swap is immediately completed, supply a new back buffer (or else the rendering would be blocked on waiting for the front-buffer to be swapped away from the scanout) and let them proceed to render the second frame. The second frame is added to the swap queue, and the client throttled to vrefresh. (If the client missed the vblank, the swap queue is empty and the client is immediately woken again, whilst the pageflip is pending.) Note, for practical reasons this only applies to page-flipping, for example, calls to glXSwapBuffer() on fullscreen applications. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--man/intel.man11
-rw-r--r--src/intel.h11
-rw-r--r--src/intel_display.c7
-rw-r--r--src/intel_dri.c297
-rw-r--r--src/intel_driver.c16
5 files changed, 217 insertions, 125 deletions
diff --git a/man/intel.man b/man/intel.man
index e5e05724..282b9f35 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -177,12 +177,23 @@ sure the display scanline is outside of the area to be copied before the copy
occurs. If disabled, no scanline synchronization is performed, meaning tearing
will likely occur. Note that when enabled, this option can adversely affect
the framerate of applications that render frames at less than refresh rate.
.IP
Default: enabled.
.TP
+.BI "Option \*qTripleBuffer\*q \*q" boolean \*q
+This option enables the use of a third buffer for page-flipping. The third
+buffer allows applications to run at vrefresh rates even if they occasionally
+fail to swapbuffers on time. The effect of such missed swaps is the output
+jitters between 60fps and 30fps, and in the worst case appears frame-locked
+to 30fps. The disadvantage of triple buffering is that there is an extra
+frame of latency, due to the pre-rendered frame sitting in the swap queue,
+between input and any display update.
+.IP
+Default: enabled.
+.TP
.BI "Option \*qTiling\*q \*q" boolean \*q
This option controls whether memory buffers for Pixmaps are allocated in tiled mode. In
most cases (especially for complex rendering), tiling dramatically improves
performance.
.IP
Default: enabled.
diff --git a/src/intel.h b/src/intel.h
index 9d64d30f..6135349f 100644
--- a/src/intel.h
+++ b/src/intel.h
@@ -257,13 +257,13 @@ typedef struct intel_screen_private {
#define RENDER_BATCH I915_EXEC_RENDER
#define BLT_BATCH I915_EXEC_BLT
unsigned int current_batch;
void *modes;
- drm_intel_bo *front_buffer;
+ drm_intel_bo *front_buffer, *back_buffer;
long front_pitch, front_tiling;
void *shadow_buffer;
int shadow_stride;
DamagePtr shadow_damage;
dri_bufmgr *bufmgr;
@@ -420,18 +420,21 @@ typedef struct intel_screen_private {
Bool directRenderingOpen;
int drmSubFD;
char *deviceName;
Bool use_pageflipping;
+ Bool use_triple_buffer;
Bool force_fallback;
Bool can_blt;
Bool has_kernel_flush;
Bool needs_flush;
Bool use_shadow;
+ struct _DRI2FrameEvent *pending_flip[2];
+
/* Broken-out options. */
OptionInfoPtr Options;
/* Driver phase/state information */
Bool suspended;
@@ -462,34 +465,40 @@ extern void intel_mode_fini(intel_screen_private *intel);
extern int intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc);
extern int intel_crtc_id(xf86CrtcPtr crtc);
extern int intel_output_dpms_status(xf86OutputPtr output);
enum DRI2FrameEventType {
DRI2_SWAP,
+ DRI2_SWAP_CHAIN,
DRI2_FLIP,
DRI2_WAITMSC,
};
#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(1,7,99,3,0)
typedef void (*DRI2SwapEventPtr)(ClientPtr client, void *data, int type,
CARD64 ust, CARD64 msc, CARD64 sbc);
#endif
typedef struct _DRI2FrameEvent {
+ struct intel_screen_private *intel;
+
XID drawable_id;
ClientPtr client;
enum DRI2FrameEventType type;
int frame;
+ int pipe;
struct list drawable_resource, client_resource;
/* for swaps & flips only */
DRI2SwapEventPtr event_complete;
void *event_data;
DRI2BufferPtr front;
DRI2BufferPtr back;
+
+ struct _DRI2FrameEvent *chain;
} DRI2FrameEventRec, *DRI2FrameEventPtr;
extern Bool intel_do_pageflip(intel_screen_private *intel,
dri_bo *new_front,
DRI2FrameEventPtr flip_info, int ref_crtc_hw_id);
diff --git a/src/intel_display.c b/src/intel_display.c
index b55b110f..e75819d4 100644
--- a/src/intel_display.c
+++ b/src/intel_display.c
@@ -1368,12 +1368,17 @@ intel_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
old_width = scrn->virtualX;
old_height = scrn->virtualY;
old_pitch = scrn->displayWidth;
old_fb_id = mode->fb_id;
old_front = intel->front_buffer;
+ if (intel->back_buffer) {
+ drm_intel_bo_unreference(intel->back_buffer);
+ intel->back_buffer = NULL;
+ }
+
intel->front_buffer = intel_allocate_framebuffer(scrn,
width, height,
intel->cpp,
&pitch,
&tiling);
if (!intel->front_buffer)
@@ -1444,12 +1449,14 @@ intel_do_pageflip(intel_screen_private *intel,
old_fb_id = mode->fb_id;
if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
scrn->depth, scrn->bitsPerPixel, pitch,
new_front->handle, &mode->fb_id))
goto error_out;
+ intel_batch_submit(scrn);
+
/*
* Queue flips on all enabled CRTCs
* Note that if/when we get per-CRTC buffers, we'll have to update this.
* Right now it assumes a single shared fb across all CRTCs, with the
* kernel fixing up the offset of each CRTC as necessary.
*
diff --git a/src/intel_dri.c b/src/intel_dri.c
index 38d7a6bc..0b284524 100644
--- a/src/intel_dri.c
+++ b/src/intel_dri.c
@@ -729,21 +729,27 @@ i830_dri2_add_frame_event(DRI2FrameEventPtr info)
list_add(&info->drawable_resource, &resource->list);
return TRUE;
}
static void
-i830_dri2_del_frame_event(DRI2FrameEventPtr info)
+i830_dri2_del_frame_event(DrawablePtr drawable, DRI2FrameEventPtr info)
{
list_del(&info->client_resource);
list_del(&info->drawable_resource);
+
+ if (info->front)
+ I830DRI2DestroyBuffer(drawable, info->front);
+ if (info->back)
+ I830DRI2DestroyBuffer(drawable, info->back);
+
+ free(info);
}
static void
-I830DRI2ExchangeBuffers(DrawablePtr draw, DRI2BufferPtr front,
- DRI2BufferPtr back)
+I830DRI2ExchangeBuffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
{
I830DRI2BufferPrivatePtr front_priv, back_priv;
struct intel_pixmap *front_intel, *back_intel;
ScreenPtr screen;
intel_screen_private *intel;
int tmp;
@@ -757,82 +763,124 @@ I830DRI2ExchangeBuffers(DrawablePtr draw, DRI2BufferPtr front,
back->name = tmp;
/* Swap pixmap bos */
front_intel = intel_get_pixmap_private(front_priv->pixmap);
back_intel = intel_get_pixmap_private(back_priv->pixmap);
intel_set_pixmap_private(front_priv->pixmap, back_intel);
- intel_set_pixmap_private(back_priv->pixmap, front_intel); /* should be screen */
+ intel_set_pixmap_private(back_priv->pixmap, front_intel);
- /* Do we need to update the Screen? */
screen = draw->pScreen;
intel = intel_get_screen_private(xf86Screens[screen->myNum]);
- if (front_intel->bo == intel->front_buffer) {
- dri_bo_unreference (intel->front_buffer);
- intel->front_buffer = back_intel->bo;
- dri_bo_reference (intel->front_buffer);
- intel_set_pixmap_private(screen->GetScreenPixmap(screen),
- back_intel);
- back_intel->busy = 1;
- front_intel->busy = -1;
- }
+
+ dri_bo_unreference (intel->front_buffer);
+ intel->front_buffer = back_intel->bo;
+ dri_bo_reference (intel->front_buffer);
+
+ intel_set_pixmap_private(screen->GetScreenPixmap(screen), back_intel);
+ back_intel->busy = 1;
+ front_intel->busy = -1;
}
/*
* Our internal swap routine takes care of actually exchanging, blitting, or
* flipping buffers as necessary.
*/
static Bool
I830DRI2ScheduleFlip(struct intel_screen_private *intel,
- ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
- DRI2BufferPtr back, DRI2SwapEventPtr func, void *data,
- unsigned int target_msc)
+ DrawablePtr draw,
+ DRI2FrameEventPtr info)
{
- I830DRI2BufferPrivatePtr back_priv;
- DRI2FrameEventPtr flip_info;
-
- /* Main crtc for this drawable shall finally deliver pageflip event. */
- int ref_crtc_hw_id = I830DRI2DrawablePipe(draw);
-
- flip_info = calloc(1, sizeof(DRI2FrameEventRec));
- if (!flip_info)
- return FALSE;
-
- flip_info->drawable_id = draw->id;
- flip_info->client = client;
- flip_info->type = DRI2_SWAP;
- flip_info->event_complete = func;
- flip_info->event_data = data;
- flip_info->frame = target_msc;
-
- if (!i830_dri2_add_frame_event(flip_info)) {
- free(flip_info);
- return FALSE;
+ I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
+ drm_intel_bo *new_back, *old_back;
+
+ if (!intel->use_triple_buffer) {
+ if (!intel_do_pageflip(intel,
+ intel_get_pixmap_bo(priv->pixmap),
+ info, info->pipe))
+ return FALSE;
+
+ info->type = DRI2_SWAP;
+ I830DRI2ExchangeBuffers(draw, info->front, info->back);
+ return TRUE;
}
- /* Page flip the full screen buffer */
- back_priv = back->driverPrivate;
- if (intel_do_pageflip(intel,
- intel_get_pixmap_bo(back_priv->pixmap),
- flip_info, ref_crtc_hw_id))
+ if (intel->pending_flip[info->pipe]) {
+ assert(intel->pending_flip[info->pipe]->chain == NULL);
+ intel->pending_flip[info->pipe]->chain = info;
return TRUE;
+ }
- i830_dri2_del_frame_event(flip_info);
- free(flip_info);
- return FALSE;
+ if (intel->back_buffer == NULL) {
+ new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer",
+ intel->front_buffer->size, 0);
+ if (new_back == NULL)
+ return FALSE;
+
+ if (intel->front_tiling != I915_TILING_NONE) {
+ uint32_t tiling = intel->front_tiling;
+ drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch);
+ if (tiling != intel->front_tiling) {
+ drm_intel_bo_unreference(new_back);
+ return FALSE;
+ }
+ }
+
+ drm_intel_bo_disable_reuse(new_back);
+ } else {
+ new_back = intel->back_buffer;
+ intel->back_buffer = NULL;
+ }
+
+ old_back = intel_get_pixmap_bo(priv->pixmap);
+ if (!intel_do_pageflip(intel, old_back, info, info->pipe)) {
+ intel->back_buffer = new_back;
+ return FALSE;
+ }
+ info->type = DRI2_SWAP_CHAIN;
+ intel->pending_flip[info->pipe] = info;
+
+ /* Exchange the current front-buffer with the fresh bo */
+ intel->back_buffer = intel->front_buffer;
+ drm_intel_bo_reference(intel->back_buffer);
+
+ priv = info->front->driverPrivate;
+ intel_set_pixmap_bo(priv->pixmap, new_back);
+ dri_bo_flink(new_back, &info->front->name);
+
+ /* Then flip DRI2 pointers and update the screen pixmap */
+ I830DRI2ExchangeBuffers(draw, info->front, info->back);
+ DRI2SwapComplete(info->client, draw, 0, 0, 0,
+ DRI2_EXCHANGE_COMPLETE,
+ info->event_complete,
+ info->event_data);
+ return TRUE;
}
static Bool
-can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
+can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
{
+ struct intel_screen_private *intel = intel_get_screen_private(xf86Screens[drawable->pScreen->myNum]);
I830DRI2BufferPrivatePtr front_priv = front->driverPrivate;
I830DRI2BufferPrivatePtr back_priv = back->driverPrivate;
PixmapPtr front_pixmap = front_priv->pixmap;
PixmapPtr back_pixmap = back_priv->pixmap;
struct intel_pixmap *front_intel = intel_get_pixmap_private(front_pixmap);
struct intel_pixmap *back_intel = intel_get_pixmap_private(back_pixmap);
+ if (drawable == NULL)
+ return FALSE;
+
+ if (!DRI2CanFlip(drawable))
+ return FALSE;
+
+ if (intel->shadow_present)
+ return FALSE;
+
+ if (!intel->use_pageflipping)
+ return FALSE;
+
if (front_pixmap->drawable.width != back_pixmap->drawable.width)
return FALSE;
if (front_pixmap->drawable.height != back_pixmap->drawable.height)
return FALSE;
@@ -852,155 +900,157 @@ can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
return TRUE;
}
void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, DRI2FrameEventPtr swap_info)
{
+ intel_screen_private *intel = swap_info->intel;
DrawablePtr drawable;
- ScreenPtr screen;
- ScrnInfoPtr scrn;
- intel_screen_private *intel;
int status;
if (!swap_info->drawable_id)
status = BadDrawable;
else
status = dixLookupDrawable(&drawable, swap_info->drawable_id, serverClient,
M_ANY, DixWriteAccess);
if (status != Success) {
- i830_dri2_del_frame_event(swap_info);
- I830DRI2DestroyBuffer(NULL, swap_info->front);
- I830DRI2DestroyBuffer(NULL, swap_info->back);
- free(swap_info);
+ i830_dri2_del_frame_event(NULL, swap_info);
return;
}
- screen = drawable->pScreen;
- scrn = xf86Screens[screen->myNum];
- intel = intel_get_screen_private(scrn);
switch (swap_info->type) {
case DRI2_FLIP:
/* If we can still flip... */
- if (DRI2CanFlip(drawable) && !intel->shadow_present &&
- intel->use_pageflipping &&
- can_exchange(swap_info->front, swap_info->back) &&
- I830DRI2ScheduleFlip(intel,
- swap_info->client, drawable, swap_info->front,
- swap_info->back, swap_info->event_complete,
- swap_info->event_data, swap_info->frame)) {
- I830DRI2ExchangeBuffers(drawable,
- swap_info->front, swap_info->back);
- break;
- }
+ if (can_exchange(drawable, swap_info->front, swap_info->back) &&
+ I830DRI2ScheduleFlip(intel, drawable, swap_info))
+ return;
+
/* else fall through to exchange/blit */
case DRI2_SWAP: {
- int swap_type;
-
- if (DRI2CanExchange(drawable) && can_exchange(swap_info->front,
- swap_info->back)) {
- I830DRI2ExchangeBuffers(drawable,
- swap_info->front, swap_info->back);
- swap_type = DRI2_EXCHANGE_COMPLETE;
- } else {
- BoxRec box;
- RegionRec region;
-
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = drawable->width;
- box.y2 = drawable->height;
- REGION_INIT(pScreen, &region, &box, 0);
-
- I830DRI2CopyRegion(drawable,
- &region, swap_info->front, swap_info->back);
- swap_type = DRI2_BLIT_COMPLETE;
- }
+ BoxRec box;
+ RegionRec region;
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = drawable->width;
+ box.y2 = drawable->height;
+ REGION_INIT(pScreen, &region, &box, 0);
+
+ I830DRI2CopyRegion(drawable,
+ &region, swap_info->front, swap_info->back);
DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
- swap_type,
+ DRI2_BLIT_COMPLETE,
swap_info->client ? swap_info->event_complete : NULL,
swap_info->event_data);
break;
}
case DRI2_WAITMSC:
if (swap_info->client)
DRI2WaitMSCComplete(swap_info->client, drawable,
frame, tv_sec, tv_usec);
break;
default:
- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
"%s: unknown vblank event received\n", __func__);
/* Unknown type */
break;
}
- i830_dri2_del_frame_event(swap_info);
- I830DRI2DestroyBuffer(drawable, swap_info->front);
- I830DRI2DestroyBuffer(drawable, swap_info->back);
- free(swap_info);
+ i830_dri2_del_frame_event(drawable, swap_info);
}
void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, DRI2FrameEventPtr flip_info)
{
+ struct intel_screen_private *intel = flip_info->intel;
DrawablePtr drawable;
- ScreenPtr screen;
- ScrnInfoPtr scrn;
- int status;
+ DRI2FrameEventPtr chain;
- if (!flip_info->drawable_id)
- status = BadDrawable;
- else
- status = dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient,
- M_ANY, DixWriteAccess);
- if (status != Success) {
- i830_dri2_del_frame_event(flip_info);
- free(flip_info);
- return;
- }
+ drawable = NULL;
+ if (flip_info->drawable_id)
+ dixLookupDrawable(&drawable, flip_info->drawable_id, serverClient,
+ M_ANY, DixWriteAccess);
- screen = drawable->pScreen;
- scrn = xf86Screens[screen->myNum];
/* We assume our flips arrive in order, so we don't check the frame */
switch (flip_info->type) {
case DRI2_SWAP:
+ if (!drawable)
+ break;
+
/* Check for too small vblank count of pageflip completion, taking wraparound
* into account. This usually means some defective kms pageflip completion,
* causing wrong (msc, ust) return values and possible visual corruption.
*/
if ((frame < flip_info->frame) && (flip_info->frame - frame < 5)) {
static int limit = 5;
/* XXX we are currently hitting this path with older
* kernels, so make it quieter.
*/
if (limit) {
- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
"%s: Pageflip completion has impossible msc %d < target_msc %d\n",
__func__, frame, flip_info->frame);
limit--;
}
/* All-0 values signal timestamping failure. */
frame = tv_sec = tv_usec = 0;
}
DRI2SwapComplete(flip_info->client, drawable, frame, tv_sec, tv_usec,
DRI2_FLIP_COMPLETE, flip_info->client ? flip_info->event_complete : NULL,
flip_info->event_data);
- break;
+ break;
+
+ case DRI2_SWAP_CHAIN:
+ assert(intel->pending_flip[flip_info->pipe] == flip_info);
+ intel->pending_flip[flip_info->pipe] = NULL;
+
+ chain = flip_info->chain;
+ if (chain) {
+ DrawablePtr chain_drawable = NULL;
+ if (chain->drawable_id)
+ dixLookupDrawable(&chain_drawable,
+ chain->drawable_id,
+ serverClient,
+ M_ANY, DixWriteAccess);
+ if (chain_drawable == NULL) {
+ i830_dri2_del_frame_event(chain_drawable, chain);
+ } else if (!can_exchange(chain_drawable, chain->front, chain->back) ||
+ !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) {
+ BoxRec box;
+ RegionRec region;
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = chain_drawable->width;
+ box.y2 = chain_drawable->height;
+ REGION_INIT(pScreen, &region, &box, 0);
+
+ I830DRI2CopyRegion(chain_drawable, &region,
+ chain->front, chain->back);
+ DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec,
+ DRI2_BLIT_COMPLETE,
+ chain->client ? chain->event_complete : NULL,
+ chain->event_data);
+ i830_dri2_del_frame_event(chain_drawable, chain);
+ }
+ }
+ break;
+
default:
- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
"%s: unknown vblank event received\n", __func__);
/* Unknown type */
break;
}
- i830_dri2_del_frame_event(flip_info);
- free(flip_info);
+ i830_dri2_del_frame_event(drawable, flip_info);
}
/*
* ScheduleSwap is responsible for requesting a DRM vblank event for the
* appropriate frame.
*
@@ -1047,18 +1097,20 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
remainder &= 0xffffffff;
swap_info = calloc(1, sizeof(DRI2FrameEventRec));
if (!swap_info)
goto blit_fallback;
+ swap_info->intel = intel;
swap_info->drawable_id = draw->id;
swap_info->client = client;
swap_info->event_complete = func;
swap_info->event_data = data;
swap_info->front = front;
swap_info->back = back;
+ swap_info->pipe = I830DRI2DrawablePipe(draw);
if (!i830_dri2_add_frame_event(swap_info)) {
free(swap_info);
swap_info = NULL;
goto blit_fallback;
}
@@ -1079,16 +1131,13 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
goto blit_fallback;
}
current_msc = vbl.reply.sequence;
/* Flips need to be submitted one frame before */
- if (intel->use_pageflipping &&
- !intel->shadow_present &&
- DRI2CanFlip(draw) &&
- can_exchange(front, back)) {
+ if (can_exchange(draw, front, back)) {
swap_type = DRI2_FLIP;
flip = 1;
}
swap_info->type = swap_type;
@@ -1102,12 +1151,15 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
/*
* If divisor is zero, or current_msc is smaller than target_msc
* we just need to make sure target_msc passes before initiating
* the swap.
*/
if (divisor == 0 || current_msc < *target_msc) {
+ if (flip && I830DRI2ScheduleFlip(intel, draw, swap_info))
+ return TRUE;
+
vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
/* If non-pageflipping, but blitting/exchanging, we need to use
* DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
@@ -1194,18 +1246,14 @@ blit_fallback:
box.y2 = draw->height;
REGION_INIT(pScreen, &region, &box, 0);
I830DRI2CopyRegion(draw, &region, front, back);
DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
- if (swap_info) {
- i830_dri2_del_frame_event(swap_info);
- I830DRI2DestroyBuffer(draw, swap_info->front);
- I830DRI2DestroyBuffer(draw, swap_info->back);
- free(swap_info);
- }
+ if (swap_info)
+ i830_dri2_del_frame_event(draw, swap_info);
*target_msc = 0; /* offscreen, so zero out target vblank count */
return TRUE;
}
/*
* Get current frame count and frame count timestamp, based on drawable's
@@ -1280,12 +1328,13 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
goto out_complete;
wait_info = calloc(1, sizeof(DRI2FrameEventRec));
if (!wait_info)
goto out_complete;
+ wait_info->intel = intel;
wait_info->drawable_id = draw->id;
wait_info->client = client;
wait_info->type = DRI2_WAITMSC;
/* Get current count */
vbl.request.type = DRM_VBLANK_RELATIVE;
diff --git a/src/intel_driver.c b/src/intel_driver.c
index 3efc7f40..7fc1c1a3 100644
--- a/src/intel_driver.c
+++ b/src/intel_driver.c
@@ -88,12 +88,13 @@ typedef enum {
OPTION_COLOR_KEY,
OPTION_FALLBACKDEBUG,
OPTION_TILING_FB,
OPTION_TILING_2D,
OPTION_SHADOW,
OPTION_SWAPBUFFERS_WAIT,
+ OPTION_TRIPLE_BUFFER,
#ifdef INTEL_XVMC
OPTION_XVMC,
#endif
OPTION_PREFER_OVERLAY,
OPTION_DEBUG_FLUSH_BATCHES,
OPTION_DEBUG_FLUSH_CACHES,
@@ -108,12 +109,13 @@ static OptionInfoRec I830Options[] = {
{OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
{OPTION_FALLBACKDEBUG, "FallbackDebug", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_TILING_2D, "Tiling", OPTV_BOOLEAN, {0}, TRUE},
{OPTION_TILING_FB, "LinearFramebuffer", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_SHADOW, "Shadow", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, TRUE},
+ {OPTION_TRIPLE_BUFFER, "TripleBuffer", OPTV_BOOLEAN, {0}, TRUE},
#ifdef INTEL_XVMC
{OPTION_XVMC, "XvMC", OPTV_BOOLEAN, {0}, TRUE},
#endif
{OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DEBUG_FLUSH_BATCHES, "DebugFlushBatches", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DEBUG_FLUSH_CACHES, "DebugFlushCaches", OPTV_BOOLEAN, {0}, FALSE},
@@ -653,12 +655,21 @@ static Bool I830PreInit(ScrnInfoPtr scrn, int flags)
intel->has_relaxed_fencing ? "enabled" : "disabled");
/* SwapBuffers delays to avoid tearing */
intel->swapbuffers_wait = xf86ReturnOptValBool(intel->Options,
OPTION_SWAPBUFFERS_WAIT,
TRUE);
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Wait on SwapBuffers? %s\n",
+ intel->swapbuffers_wait ? "enabled" : "disabled");
+
+ intel->use_triple_buffer =
+ xf86ReturnOptValBool(intel->Options,
+ OPTION_TRIPLE_BUFFER,
+ TRUE);
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Triple buffering? %s\n",
+ intel->use_triple_buffer ? "enabled" : "disabled");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Framebuffer %s\n",
intel->tiling & INTEL_TILING_FB ? "tiled" : "linear");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Pixmaps %s\n",
intel->tiling & INTEL_TILING_2D ? "tiled" : "linear");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "3D buffers %s\n",
@@ -1174,12 +1185,17 @@ static Bool I830CloseScreen(int scrnIndex, ScreenPtr screen)
if (intel->uxa_driver) {
uxa_driver_fini(screen);
free(intel->uxa_driver);
intel->uxa_driver = NULL;
}
+ if (intel->back_buffer) {
+ drm_intel_bo_unreference(intel->back_buffer);
+ intel->back_buffer = NULL;
+ }
+
if (intel->front_buffer) {
if (!intel->use_shadow)
intel_set_pixmap_bo(screen->GetScreenPixmap(screen),
NULL);
intel_mode_remove_fb(intel);
drm_intel_bo_unreference(intel->front_buffer);