i965 Gen6: Implement gl_ClipVertex.
authorPaul Berry <stereotype441@gmail.com>
Mon, 26 Sep 2011 20:43:04 +0000 (13:43 -0700)
committerPaul Berry <stereotype441@gmail.com>
Wed, 5 Oct 2011 18:51:00 +0000 (11:51 -0700)
This patch implements proper support for gl_ClipVertex by causing the
new VS backend to populate the clip distance VUE slots using
VERT_RESULT_CLIP_VERTEX when appropriate, and by using the
untransformed clip planes in ctx->Transform.EyeUserPlane rather than
the transformed clip planes in ctx->Transform._ClipUserPlane when a
GLSL-based vertex shader is in use.

When not using a GLSL-based vertex shader, we use
ctx->Transform._ClipUserPlane (which is what we used prior to this
patch).  This ensures that clipping is still performed correctly for
fixed function and ARB vertex programs.  A new function,
brw_select_clip_planes() is used to determine whether to use
_ClipUserPlane or EyeUserPlane, so that the logic for making this
decision is shared between the new and old vertex shaders.

Fixes the following Piglit tests on i965 Gen6:
- vs-clip-vertex-const-accept
- vs-clip-vertex-const-reject
- vs-clip-vertex-different-from-position
- vs-clip-vertex-equal-to-position
- vs-clip-vertex-homogeneity
- vs-clip-based-on-position
- vs-clip-based-on-position-homogeneity
- clip-plane-transformation clipvert_pos
- clip-plane-transformation pos_clipvert
- clip-plane-transformation pos

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Chad Versace <chad@chad-versace.us>
src/mesa/drivers/dri/i965/brw_context.h
src/mesa/drivers/dri/i965/brw_curbe.c
src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp
src/mesa/drivers/dri/i965/brw_vs.c
src/mesa/drivers/dri/i965/gen6_vs_state.c
src/mesa/main/mtypes.h

index d32eded90d1344a86ee66fd9a0453d0216e5dc05..e26437fa448fc456b1dcd0513699fcf1e286dc8a 100644 (file)
@@ -899,6 +899,7 @@ struct brw_context
 };
 
 
+
 #define BRW_PACKCOLOR8888(r,g,b,a)  ((r<<24) | (g<<16) | (b<<8) | a)
 
 struct brw_instruction_info {
@@ -966,6 +967,8 @@ int brw_disasm (FILE *file, struct brw_instruction *inst, int gen);
 void brw_compute_vue_map(struct brw_vue_map *vue_map,
                          const struct intel_context *intel, int nr_userclip,
                          GLbitfield64 outputs_written);
+gl_clip_plane *brw_select_clip_planes(struct gl_context *ctx);
+
 
 /*======================================================================
  * Inline conversion functions.  These are better-typed than the
index e1676de1e025386febdeb88b68c978cf58214a2d..25c7e0908fd3c47512225e1f4496b4fb2f65bf06 100644 (file)
@@ -188,6 +188,7 @@ static void prepare_constant_buffer(struct brw_context *brw)
    const GLuint bufsz = sz * 16 * sizeof(GLfloat);
    GLfloat *buf;
    GLuint i;
+   gl_clip_plane *clip_planes;
 
    if (sz == 0) {
       brw->curbe.last_bufsz  = 0;
@@ -232,12 +233,13 @@ static void prepare_constant_buffer(struct brw_context *brw)
       /* Clip planes: _NEW_TRANSFORM plus _NEW_PROJECTION to get to
        * clip-space:
        */
+      clip_planes = brw_select_clip_planes(ctx);
       for (j = 0; j < MAX_CLIP_PLANES; j++) {
         if (ctx->Transform.ClipPlanesEnabled & (1<<j)) {
-           buf[offset + i * 4 + 0] = ctx->Transform._ClipUserPlane[j][0];
-           buf[offset + i * 4 + 1] = ctx->Transform._ClipUserPlane[j][1];
-           buf[offset + i * 4 + 2] = ctx->Transform._ClipUserPlane[j][2];
-           buf[offset + i * 4 + 3] = ctx->Transform._ClipUserPlane[j][3];
+           buf[offset + i * 4 + 0] = clip_planes[j][0];
+           buf[offset + i * 4 + 1] = clip_planes[j][1];
+           buf[offset + i * 4 + 2] = clip_planes[j][2];
+           buf[offset + i * 4 + 3] = clip_planes[j][3];
            i++;
         }
       }
index ad8b43365ad5a3915fac7d442cee60e1d241070e..17bde91bb2c64c90f1d871909985c19f115b8f5b 100644 (file)
@@ -557,6 +557,8 @@ vec4_visitor::setup_uniform_values(int loc, const glsl_type *type)
 void
 vec4_visitor::setup_uniform_clipplane_values()
 {
+   gl_clip_plane *clip_planes = brw_select_clip_planes(ctx);
+
    int compacted_clipplane_index = 0;
    for (int i = 0; i < MAX_CLIP_PLANES; ++i) {
       if (ctx->Transform.ClipPlanesEnabled & (1 << i)) {
@@ -564,7 +566,7 @@ vec4_visitor::setup_uniform_clipplane_values()
          this->userplane[compacted_clipplane_index] = dst_reg(UNIFORM, this->uniforms);
          this->userplane[compacted_clipplane_index].type = BRW_REGISTER_TYPE_F;
          for (int j = 0; j < 4; ++j) {
-            c->prog_data.param[this->uniforms * 4 + j] = &ctx->Transform._ClipUserPlane[i][j];
+            c->prog_data.param[this->uniforms * 4 + j] = &clip_planes[i][j];
          }
          ++compacted_clipplane_index;
          ++this->uniforms;
@@ -1863,9 +1865,27 @@ vec4_visitor::emit_clip_distances(struct brw_reg reg, int offset)
       return;
    }
 
+   /* From the GLSL 1.30 spec, section 7.1 (Vertex Shader Special Variables):
+    *
+    *     "If a linked set of shaders forming the vertex stage contains no
+    *     static write to gl_ClipVertex or gl_ClipDistance, but the
+    *     application has requested clipping against user clip planes through
+    *     the API, then the coordinate written to gl_Position is used for
+    *     comparison against the user clip planes."
+    *
+    * This function is only called if the shader didn't write to
+    * gl_ClipDistance.  Accordingly, we use gl_ClipVertex to perform clipping
+    * if the user wrote to it; otherwise we use gl_Position.
+    */
+   gl_vert_result clip_vertex = VERT_RESULT_CLIP_VERTEX;
+   if (!(c->prog_data.outputs_written
+         & BITFIELD64_BIT(VERT_RESULT_CLIP_VERTEX))) {
+      clip_vertex = VERT_RESULT_HPOS;
+   }
+
    for (int i = 0; i + offset < c->key.nr_userclip && i < 4; ++i) {
       emit(DP4(dst_reg(brw_writemask(reg, 1 << i)),
-               src_reg(output_reg[VERT_RESULT_HPOS]),
+               src_reg(output_reg[clip_vertex]),
                src_reg(this->userplane[i + offset])));
    }
 }
index 93c68381380059367acdf6d323c272776e86a221..3a9b780382ad140f8aea996460635b1d329563c1 100644 (file)
@@ -137,15 +137,47 @@ brw_compute_vue_map(struct brw_vue_map *vue_map,
    /* The hardware doesn't care about the rest of the vertex outputs, so just
     * assign them contiguously.  Don't reassign outputs that already have a
     * slot.
+    *
+    * Also, don't assign a slot for VERT_RESULT_CLIP_VERTEX, since it is
+    * unsupported in pre-GEN6, and in GEN6+ the vertex shader converts it into
+    * clip distances.
     */
    for (int i = 0; i < VERT_RESULT_MAX; ++i) {
       if ((outputs_written & BITFIELD64_BIT(i)) &&
-          vue_map->vert_result_to_slot[i] == -1) {
+          vue_map->vert_result_to_slot[i] == -1 &&
+          i != VERT_RESULT_CLIP_VERTEX) {
          assign_vue_slot(vue_map, i);
       }
    }
 }
 
+
+/**
+ * Decide which set of clip planes should be used when clipping via
+ * gl_Position or gl_ClipVertex.
+ */
+gl_clip_plane *brw_select_clip_planes(struct gl_context *ctx)
+{
+   if (ctx->Shader.CurrentVertexProgram) {
+      /* There is currently a GLSL vertex shader, so clip according to GLSL
+       * rules, which means compare gl_ClipVertex (or gl_Position, if
+       * gl_ClipVertex wasn't assigned) against the eye-coordinate clip planes
+       * that were stored in EyeUserPlane at the time the clip planes were
+       * specified.
+       */
+      return ctx->Transform.EyeUserPlane;
+   } else {
+      /* Either we are using fixed function or an ARB vertex program.  In
+       * either case the clip planes are going to be compared against
+       * gl_Position (which is in clip coordinates) so we have to clip using
+       * _ClipUserPlane, which was transformed into clip coordinates by Mesa
+       * core.
+       */
+      return ctx->Transform._ClipUserPlane;
+   }
+}
+
+
 static bool
 do_vs_prog(struct brw_context *brw,
           struct gl_shader_program *prog,
index 0f6f6a7e06272efea90c93cb2e6462e13839c71c..14a96fca6b15cb24cb8e8e4d664c9fe69e51fef8 100644 (file)
@@ -77,9 +77,10 @@ gen6_prepare_vs_push_constants(struct brw_context *brw)
           * until we redo the VS backend.
           */
          if (!uses_clip_distance) {
+            gl_clip_plane *clip_planes = brw_select_clip_planes(ctx);
             for (i = 0; i < MAX_CLIP_PLANES; i++) {
                if (ctx->Transform.ClipPlanesEnabled & (1 << i)) {
-                  memcpy(param, ctx->Transform._ClipUserPlane[i], 4 * sizeof(float));
+                  memcpy(param, clip_planes[i], 4 * sizeof(float));
                   param += 4;
                   params_uploaded++;
                }
index 71cbe0443d9482b37042d42349c1db8a9815e4c0..4fe442fa4084d4d066d19638a0373bd3e166f61b 100644 (file)
@@ -1492,14 +1492,21 @@ struct gl_texture_attrib
 };
 
 
+/**
+ * Data structure representing a single clip plane (e.g. one of the elements
+ * of the ctx->Transform.EyeUserPlane or ctx->Transform._ClipUserPlane array).
+ */
+typedef GLfloat gl_clip_plane[4];
+
+
 /**
  * Transformation attribute group (GL_TRANSFORM_BIT).
  */
 struct gl_transform_attrib
 {
    GLenum MatrixMode;                          /**< Matrix mode */
-   GLfloat EyeUserPlane[MAX_CLIP_PLANES][4];   /**< User clip planes */
-   GLfloat _ClipUserPlane[MAX_CLIP_PLANES][4]; /**< derived */
+   gl_clip_plane EyeUserPlane[MAX_CLIP_PLANES];        /**< User clip planes */
+   gl_clip_plane _ClipUserPlane[MAX_CLIP_PLANES]; /**< derived */
    GLbitfield ClipPlanesEnabled;                /**< on/off bitmask */
    GLboolean Normalize;                                /**< Normalize all normals? */
    GLboolean RescaleNormals;                   /**< GL_EXT_rescale_normal */