intel: Wait on the last swapbuffers to complete before queuing a new one.
authorEric Anholt <eric@anholt.net>
Tue, 21 Jul 2009 18:23:18 +0000 (11:23 -0700)
committerEric Anholt <eric@anholt.net>
Mon, 3 Aug 2009 20:34:07 +0000 (13:34 -0700)
This fixes jerkiness in doom3 and other apps since the kernel change to
throttle less absurdly, which led to a thundering herd of frames.

Because this is a rather minimal fix, there is at least one downside: If
the whole scene completes in one batchbuffer, we'll end up stalling the GPU.

Thanks to Michel Dänzer for suggesting using glFlush to signal frame end
instead of going to all the effort of adding a new DRI2 extension.

src/mesa/drivers/dri/intel/intel_batchbuffer.c
src/mesa/drivers/dri/intel/intel_context.c
src/mesa/drivers/dri/intel/intel_context.h

index 0f87fc46a44e0f862f42565df6f1fd0733e845df..e94b8368cde799e601ba4e7715296729bdc98ac0 100644 (file)
@@ -196,6 +196,11 @@ _intel_batchbuffer_flush(struct intel_batchbuffer *batch, const char *file,
    struct intel_context *intel = batch->intel;
    GLuint used = batch->ptr - batch->map;
 
+   if (intel->first_post_swapbuffers_batch == NULL) {
+      intel->first_post_swapbuffers_batch = intel->batch->buf;
+      drm_intel_bo_reference(intel->first_post_swapbuffers_batch);
+   }
+
    if (used == 0) {
       batch->cliprect_mode = IGNORE_CLIPRECTS;
       return;
index 4abb525f78e3755fbf63cc37c2b858225ddd33c8..7f5b8d76e56e28880781fcd405e0abf88cd8e4e1 100644 (file)
@@ -529,7 +529,27 @@ intelFlush(GLcontext * ctx)
 static void
 intel_glFlush(GLcontext *ctx)
 {
+   struct intel_context *intel = intel_context(ctx);
+
    intel_flush(ctx, GL_TRUE);
+
+   /* We're using glFlush as an indicator that a frame is done, which is
+    * what DRI2 does before calling SwapBuffers (and means we should catch
+    * people doing front-buffer rendering, as well)..
+    *
+    * Wait for the swapbuffers before the one we just emitted, so we don't
+    * get too many swaps outstanding for apps that are GPU-heavy but not
+    * CPU-heavy.
+    *
+    * Unfortunately, we don't have a handle to the batch containing the swap,
+    * and getting our hands on that doesn't seem worth it, so we just us the
+    * first batch we emitted after the last swap.
+    */
+   if (intel->first_post_swapbuffers_batch != NULL) {
+      drm_intel_bo_wait_rendering(intel->first_post_swapbuffers_batch);
+      drm_intel_bo_unreference(intel->first_post_swapbuffers_batch);
+      intel->first_post_swapbuffers_batch = NULL;
+   }
 }
 
 void
@@ -814,6 +834,8 @@ intelDestroyContext(__DRIcontextPrivate * driContextPriv)
       intel->prim.vb = NULL;
       dri_bo_unreference(intel->prim.vb_bo);
       intel->prim.vb_bo = NULL;
+      dri_bo_unreference(intel->first_post_swapbuffers_batch);
+      intel->first_post_swapbuffers_batch = NULL;
 
       if (release_texture_heaps) {
          /* Nothing is currently done here to free texture heaps;
index 08bea88c958809a1fe02c0eaa5d8606fae7bd263..e93eb1f293c7263df2c0d573bc40dab5b312d6ae 100644 (file)
@@ -178,6 +178,7 @@ struct intel_context
    GLboolean ttm;
 
    struct intel_batchbuffer *batch;
+   drm_intel_bo *first_post_swapbuffers_batch;
    GLboolean no_batch_wrap;
    unsigned batch_id;