summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-07-08 00:17:27 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-07-08 10:00:41 +0100
commitec3dd64e739c4c2bbd8141de5275fe8a90f24a57 (patch)
tree1169dce1e147715745925e3117acc26548c81f82
parenta32694b0f07e35c22dd83bcfb828196d5d86628e (diff)
sna/dri: Enable chaining of page-flips
Trade off extra frames of latency for extra frames of anti-jitter buffering and loss of completion information; compiz users rejoice. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/sna_dri.c173
1 files changed, 135 insertions, 38 deletions
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index c89a7d24..2a8a8651 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -76,11 +76,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#define NDEBUG 1
#endif
+#define NO_TRIPPLE_BUFFER 0
+
enum frame_event_type {
DRI2_SWAP,
DRI2_SWAP_THROTTLE,
DRI2_ASYNC_FLIP,
DRI2_FLIP,
+ DRI2_FLIP_THROTTLE,
DRI2_WAITMSC,
};
@@ -113,6 +116,8 @@ struct sna_dri_frame_event {
PixmapPtr old_front;
PixmapPtr next_front;
uint32_t old_fb;
+
+ struct sna_dri_frame_event *chain;
};
static inline struct sna_dri_frame_event *
@@ -833,10 +838,69 @@ done:
sna_dri_frame_event_info_free(info);
}
+static int
+sna_dri_flip(struct sna *sna, DrawablePtr draw, struct sna_dri_frame_event *info)
+{
+ struct sna_dri_private *front_priv = info->front->driverPrivate;
+ struct sna_dri_frame_event *pending;
+ ScreenPtr screen = draw->pScreen;
+ PixmapPtr pixmap;
+
+ if (NO_TRIPPLE_BUFFER)
+ return sna_dri_schedule_flip(sna, draw, info);
+
+ info->type = DRI2_FLIP_THROTTLE;
+
+ pending = sna->dri.flip_pending[info->pipe];
+ if (pending) {
+ if (pending->type != DRI2_FLIP_THROTTLE) {
+ /* We need to first wait (one vblank) for the
+ * async flips to complete beofore this client can
+ * take over.
+ */
+ info->type = DRI2_FLIP;
+ return sna_dri_schedule_flip(sna, draw, info);
+ }
+
+ DBG(("%s: chaining flip\n", __FUNCION__));
+ assert(pending->chain == NULL);
+ pending->chain = info;
+ return TRUE;
+ }
+
+ if (!sna_dri_schedule_flip(sna, draw, info))
+ return FALSE;
+
+ info->old_front =
+ sna_set_screen_pixmap(sna, get_pixmap(info->back));
+ sna->dri.flip_pending[info->pipe] = info;
+
+ if ((pixmap = screen->CreatePixmap(screen,
+ draw->width,
+ draw->height,
+ draw->depth,
+ SNA_CREATE_FB))) {
+ DBG(("%s: new back buffer\n", __FUNCTION__));
+ front_priv->pixmap->refcnt--;
+ front_priv->pixmap = pixmap;
+ front_priv->bo = sna_pixmap_set_dri(sna, pixmap);
+ info->front->name = kgem_bo_flink(&sna->kgem, front_priv->bo);
+ info->front->pitch = front_priv->bo->pitch;
+ }
+
+ sna_dri_exchange_buffers(draw, info->front, info->back);
+ DRI2SwapComplete(info->client, draw, 0, 0, 0,
+ DRI2_EXCHANGE_COMPLETE,
+ info->event_complete,
+ info->event_data);
+ return TRUE;
+}
+
static void sna_dri_flip_event(struct sna *sna,
struct sna_dri_frame_event *flip)
{
DrawablePtr drawable;
+ struct sna_dri_frame_event *chain;
int status;
DBG(("%s(frame=%d, tv=%d.%06d, type=%d)\n",
@@ -854,45 +918,76 @@ static void sna_dri_flip_event(struct sna *sna,
* into account. This usually means some defective kms pageflip completion,
* causing wrong (msc, ust) return values and possible visual corruption.
*/
- if (!flip->drawable_id)
- return;
-
- status = dixLookupDrawable(&drawable,
- flip->drawable_id,
- serverClient,
- M_ANY, DixWriteAccess);
- if (status != Success)
- return;
-
- if ((flip->fe_frame < flip->frame) &&
- (flip->frame - flip->fe_frame < 5)) {
- static int limit = 5;
-
- /* XXX we are currently hitting this path with older
- * kernels, so make it quieter.
- */
- if (limit) {
- xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
- "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
- __func__, flip->fe_frame, flip->frame);
- limit--;
+ if (flip->drawable_id) {
+ status = dixLookupDrawable(&drawable,
+ flip->drawable_id,
+ serverClient,
+ M_ANY, DixWriteAccess);
+ if (status == Success) {
+ if ((flip->fe_frame < flip->frame) &&
+ (flip->frame - flip->fe_frame < 5)) {
+ static int limit = 5;
+
+ /* XXX we are currently hitting this path with older
+ * kernels, so make it quieter.
+ */
+ if (limit) {
+ xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
+ "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
+ __func__, flip->fe_frame, flip->frame);
+ limit--;
+ }
+
+ /* All-0 values signal timestamping failure. */
+ flip->fe_frame = flip->fe_tv_sec = flip->fe_tv_usec = 0;
+ }
+
+ DBG(("%s: flip complete\n", __FUNCTION__));
+ DRI2SwapComplete(flip->client, drawable,
+ flip->fe_frame,
+ flip->fe_tv_sec,
+ flip->fe_tv_usec,
+ DRI2_FLIP_COMPLETE,
+ flip->client ? flip->event_complete : NULL,
+ flip->event_data);
}
-
- /* All-0 values signal timestamping failure. */
- flip->fe_frame = flip->fe_tv_sec = flip->fe_tv_usec = 0;
}
- DBG(("%s: flip complete\n", __FUNCTION__));
- DRI2SwapComplete(flip->client, drawable,
- flip->fe_frame,
- flip->fe_tv_sec,
- flip->fe_tv_usec,
- DRI2_FLIP_COMPLETE,
- flip->client ? flip->event_complete : NULL,
- flip->event_data);
+ sna_mode_delete_fb(flip->sna, flip->old_front, flip->old_fb);
+ sna_dri_frame_event_info_free(flip);
+ break;
+
+ case DRI2_FLIP_THROTTLE:
+ assert(sna->dri.flip_pending[flip->pipe] == flip);
+ sna->dri.flip_pending[flip->pipe] = NULL;
+
+ chain = flip->chain;
sna_mode_delete_fb(flip->sna, flip->old_front, flip->old_fb);
sna_dri_frame_event_info_free(flip);
+
+ if (chain) {
+ status = dixLookupDrawable(&drawable,
+ chain->drawable_id,
+ serverClient,
+ M_ANY, DixWriteAccess);
+ if (status == Success) {
+ if (!(can_flip(chain->sna, drawable,
+ chain->front, chain->back) &&
+ sna_dri_flip(chain->sna, drawable, chain))) {
+ sna_dri_copy(sna, drawable, NULL,
+ chain->front, chain->back, true);
+ DRI2SwapComplete(chain->client,
+ drawable,
+ 0, 0, 0,
+ DRI2_BLIT_COMPLETE,
+ chain->client ? chain->event_complete : NULL,
+ chain->event_data);
+ sna_dri_frame_event_info_free(chain);
+ }
+ } else
+ sna_dri_frame_event_info_free(chain);
+ }
break;
case DRI2_ASYNC_FLIP:
@@ -1052,12 +1147,8 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
info->type = swap_type;
if (divisor == 0) {
DBG(("%s: performing immediate swap\n", __FUNCTION__));
- if (flip && sna_dri_schedule_flip(sna, draw, info)) {
- info->old_front =
- sna_set_screen_pixmap(sna, get_pixmap(back));
- sna_dri_exchange_buffers(draw, front, back);
+ if (flip && sna_dri_flip(sna, draw, info))
return TRUE;
- }
DBG(("%s: emitting immediate vsync'ed blit, throttling client\n",
__FUNCTION__));
@@ -1200,6 +1291,7 @@ sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
DBG(("%s()\n", __FUNCTION__));
if (!can_flip(sna, draw, front, back)) {
+blit:
sna_dri_copy(sna, draw, NULL, front, back, false);
DRI2SwapComplete(client, draw, 0, 0, 0,
DRI2_BLIT_COMPLETE, func, data);
@@ -1259,6 +1351,11 @@ sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
front->name = kgem_bo_flink(&sna->kgem, front_priv->bo);
front->pitch = front_priv->bo->pitch;
}
+ } else if (info->type != DRI2_ASYNC_FLIP) {
+ /* A normal vsync'ed client is finishing, wait for it
+ * to unpin the old framebuffer before taking* pver.
+ */
+ goto blit;
}
if (front_priv->pixmap == info->next_front &&