i965 gen6: Implement rasterizer discard.
authorPaul Berry <stereotype441@gmail.com>
Wed, 14 Dec 2011 18:44:49 +0000 (10:44 -0800)
committerPaul Berry <stereotype441@gmail.com>
Tue, 20 Dec 2011 23:22:08 +0000 (15:22 -0800)
This patch enables rasterizer discard functionality (a part of
transform feedback) in Gen6, by generating an alternate GS program
when rasterizer discard is active.  Instead of forwarding vertices
down the pipeline, the alternate GS program uses a URB Write message
to deallocate the URB entry that was allocated by FF sync and
terminate the thread.

Note: parts of the Sandy Bridge PRM seem to imply that we could do
this more efficiently, by clearing the GEN6_GS_RENDERING_ENABLE bit,
and not allocating a URB entry at all.  However, it's not clear how we
are supposed to terminate the thread if we do that.  Volume 2 part 1,
section 4.5.4, says "GS threads must terminate by sending a URB_WRITE
message with the EOT and Complete bits set.", and my experiments so
far confirm that.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/drivers/dri/i965/brw_gs.c
src/mesa/drivers/dri/i965/brw_gs.h
src/mesa/drivers/dri/i965/brw_gs_emit.c

index 1e605efd6e4ab378fdccd833119a96d8f38c405d..ee3f94ca613e7b1cdfda47f6f293c6add0127c9e 100644 (file)
@@ -208,6 +208,12 @@ static void populate_key( struct brw_context *brw,
                linked_xfb_info->Outputs[i].OutputRegister;
          }
       }
+      /* On Gen6, GS is also used for rasterizer discard. */
+      /* _NEW_TRANSFORM_FEEDBACK */
+      if (ctx->TransformFeedback.RasterDiscard) {
+         key->need_gs_prog = true;
+         key->rasterizer_discard = true;
+      }
    } else {
       /* Pre-gen6, GS is used to transform QUADLIST, QUADSTRIP, and LINELOOP
        * into simpler primitives.
index 33d8d7ab5a77a402229ba9d4ea902388899cb421..7bf2248a5ede3c416b04af5c1d5d63fb278ecf74 100644 (file)
@@ -50,6 +50,7 @@ struct brw_gs_prog_key {
    GLuint pv_first:1;
    GLuint need_gs_prog:1;
    GLuint userclip_active:1;
+   GLuint rasterizer_discard:1;
 
    /**
     * Number of varyings that are output to transform feedback.
index 269a49559a5d293cc1e511cdf5c420ca2f9f73bd..1f96a164637eee888bc351f55ab5daf34b34a0aa 100644 (file)
@@ -192,6 +192,28 @@ static void brw_gs_emit_vue(struct brw_gs_compile *c,
    }
 }
 
+/**
+ * De-allocate the URB entry that was previously allocated to this thread
+ * (without writing any vertex data to it), and terminate the thread.  This is
+ * used to implement RASTERIZER_DISCARD functionality.
+ */
+static void brw_gs_terminate(struct brw_gs_compile *c)
+{
+   struct brw_compile *p = &c->func;
+   brw_urb_WRITE(p,
+                 retype(brw_null_reg(), BRW_REGISTER_TYPE_UD), /* dest */
+                 0, /* msg_reg_nr */
+                 c->reg.header, /* src0 */
+                 false, /* allocate */
+                 false, /* used */
+                 1, /* msg_length */
+                 0, /* response_length */
+                 true, /* eot */
+                 true, /* writes_complete */
+                 0, /* offset */
+                 BRW_URB_SWIZZLE_NONE);
+}
+
 /**
  * Send an FF_SYNC message to ensure that all previously spawned GS threads
  * have finished sending primitives down the pipeline, and to allocate a URB
@@ -409,6 +431,14 @@ gen6_sol_program(struct brw_gs_compile *c, struct brw_gs_prog_key *key,
 
    brw_gs_ff_sync(c, 1);
 
+   /* If RASTERIZER_DISCARD is enabled, we have nothing further to do, so
+    * release the URB that was just allocated, and terminate the thread.
+    */
+   if (key->rasterizer_discard) {
+      brw_gs_terminate(c);
+      return;
+   }
+
    brw_gs_overwrite_header_dw2_from_r0(c);
    switch (num_verts) {
    case 1: