i965: Implement Pause/ResumeTransformfeedback driver hooks on Gen7+.
authorKenneth Graunke <kenneth@whitecape.org>
Mon, 27 May 2013 00:53:14 +0000 (17:53 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 31 Oct 2013 18:04:37 +0000 (11:04 -0700)
The ARB_transform_feedback2 extension introduces the ability to pause
and resume transform feedback sessions.  Although only one can be active
at a time, it's possible to switch between multiple transform feedback
objects while paused.

In order to facilitate this, we need to save/restore the SO_WRITE_OFFSET
registers so that after resuming, the GPU continues writing where it
left off.

This functionality also exists in ES 3.0, but somehow we completely
forgot to implement it.

v2: Reduce alignment from 4096 to 64 (it seemed excessive).
v3: Use I915_GEM_DOMAIN_INSTRUCTION instead of RENDER, for consistency
    with other writes.  It shouldn't matter on IVB+.

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
src/mesa/drivers/dri/i965/brw_context.c
src/mesa/drivers/dri/i965/brw_context.h
src/mesa/drivers/dri/i965/gen6_sol.c
src/mesa/drivers/dri/i965/gen7_sol_state.c

index 2df12ed423db632454fa61c33211d7ef6255f862..90d9be449c1115eefcbcb50b917a584f38529b54 100644 (file)
@@ -255,6 +255,8 @@ brw_init_driver_functions(struct brw_context *brw,
    if (brw->gen >= 7) {
       functions->BeginTransformFeedback = gen7_begin_transform_feedback;
       functions->EndTransformFeedback = gen7_end_transform_feedback;
+      functions->PauseTransformFeedback = gen7_pause_transform_feedback;
+      functions->ResumeTransformFeedback = gen7_resume_transform_feedback;
    } else {
       functions->BeginTransformFeedback = brw_begin_transform_feedback;
       functions->EndTransformFeedback = brw_end_transform_feedback;
index 19d846de0a01ef9e6f8cdfb8a75e99004b45de1f..23c27d825bc78dafbfcf5bca5e560f0e280923b0 100644 (file)
@@ -889,6 +889,9 @@ struct intel_batchbuffer {
 
 struct brw_transform_feedback_object {
    struct gl_transform_feedback_object base;
+
+   /** A buffer to hold SO_WRITE_OFFSET(n) values while paused. */
+   drm_intel_bo *offset_bo;
 };
 
 /**
@@ -1597,6 +1600,12 @@ gen7_begin_transform_feedback(struct gl_context *ctx, GLenum mode,
 void
 gen7_end_transform_feedback(struct gl_context *ctx,
                            struct gl_transform_feedback_object *obj);
+void
+gen7_pause_transform_feedback(struct gl_context *ctx,
+                              struct gl_transform_feedback_object *obj);
+void
+gen7_resume_transform_feedback(struct gl_context *ctx,
+                               struct gl_transform_feedback_object *obj);
 
 /* brw_blorp_blit.cpp */
 GLbitfield
index 484be42b39012cffecc9cffacc31fe1d151aa7e0..cbc95f4b51a0a029541a66366a9a910c2a7f1b2b 100644 (file)
@@ -144,6 +144,9 @@ brw_new_transform_feedback(struct gl_context *ctx, GLuint name)
 
    _mesa_init_transform_feedback_object(&brw_obj->base, name);
 
+   brw_obj->offset_bo =
+      drm_intel_bo_alloc(brw->bufmgr, "transform feedback offsets", 16, 64);
+
    return &brw_obj->base;
 }
 
@@ -158,6 +161,8 @@ brw_delete_transform_feedback(struct gl_context *ctx,
       _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
    }
 
+   drm_intel_bo_unreference(brw_obj->offset_bo);
+
    free(brw_obj);
 }
 
index abfe0a0746d49bcf55b2a9036dd0377aa72ad999..bdb17e3b81dbc2d052929ad4323a16bbe850e571 100644 (file)
@@ -273,3 +273,43 @@ gen7_end_transform_feedback(struct gl_context *ctx,
 
    intel_batchbuffer_emit_mi_flush(brw);
 }
+
+void
+gen7_pause_transform_feedback(struct gl_context *ctx,
+                              struct gl_transform_feedback_object *obj)
+{
+   struct brw_context *brw = brw_context(ctx);
+   struct brw_transform_feedback_object *brw_obj =
+      (struct brw_transform_feedback_object *) obj;
+
+   /* Save the SOL buffer offset register values. */
+   for (int i = 0; i < 4; i++) {
+      BEGIN_BATCH(3);
+      OUT_BATCH(MI_STORE_REGISTER_MEM | (3 - 2));
+      OUT_BATCH(GEN7_SO_WRITE_OFFSET(i));
+      OUT_RELOC(brw_obj->offset_bo,
+                I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
+                i * sizeof(uint32_t));
+      ADVANCE_BATCH();
+   }
+}
+
+void
+gen7_resume_transform_feedback(struct gl_context *ctx,
+                               struct gl_transform_feedback_object *obj)
+{
+   struct brw_context *brw = brw_context(ctx);
+   struct brw_transform_feedback_object *brw_obj =
+      (struct brw_transform_feedback_object *) obj;
+
+   /* Reload the SOL buffer offset registers. */
+   for (int i = 0; i < 4; i++) {
+      BEGIN_BATCH(3);
+      OUT_BATCH(GEN7_MI_LOAD_REGISTER_MEM | (3 - 2));
+      OUT_BATCH(GEN7_SO_WRITE_OFFSET(i));
+      OUT_RELOC(brw_obj->offset_bo,
+                I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
+                i * sizeof(uint32_t));
+      ADVANCE_BATCH();
+   }
+}