Mesa (master): mesa: Fix transform feedback of unsubscripted gl_ClipDistance array.

Paul Berry stereotype441 at kemper.freedesktop.org
Wed Jan 11 16:03:48 UTC 2012


Module: Mesa
Branch: master
Commit: 642e5b413e0890b2070ba78fde42db381eaf02e5
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=642e5b413e0890b2070ba78fde42db381eaf02e5

Author: Paul Berry <stereotype441 at gmail.com>
Date:   Wed Jan  4 13:57:52 2012 -0800

mesa: Fix transform feedback of unsubscripted gl_ClipDistance array.

On drivers that set gl_shader_compiler_options::LowerClipDistance (for
example i965), we need to handle transform feedback of gl_ClipDistance
specially, to account for the fact that the hardware represents it as
an array of vec4's rather than an array of floats.

The previous way this was accounted for (translating the request for
gl_ClipDistance[n] to a request for a component of
gl_ClipDistanceMESA[n/4]) doesn't work when performing transform
feedback on the whole unsubscripted array, because we need to keep
track of the size of the gl_ClipDistance array prior to the lowering
pass.  So I replaced it with a boolean is_clip_distance_mesa, which
switches on the special logic that is needed to handle the lowered
version of gl_ClipDistance.

Fixes Piglit tests "EXT_transform_feedback/builtin-varyings
gl_ClipDistance[{1,2,3,5,6,7}]-no-subscript".

Reviewed-by: Eric Anholt <eric at anholt.net>

---

 src/glsl/linker.cpp    |   89 ++++++++++++++++++++++++++++++------------------
 src/mesa/main/mtypes.h |    2 +
 2 files changed, 58 insertions(+), 33 deletions(-)

diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index f32c217..39a9c46 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -246,7 +246,8 @@ count_attribute_slots(const glsl_type *t)
 /**
  * Verify that a vertex shader executable meets all semantic requirements.
  *
- * Also sets prog->Vert.UsesClipDistance as a side effect.
+ * Also sets prog->Vert.UsesClipDistance and prog->Vert.ClipDistanceArraySize
+ * as a side effect.
  *
  * \param shader  Vertex shader executable to be verified
  */
@@ -264,6 +265,8 @@ validate_vertex_shader_executable(struct gl_shader_program *prog,
       return false;
    }
 
+   prog->Vert.ClipDistanceArraySize = 0;
+
    if (prog->Version >= 130) {
       /* From section 7.1 (Vertex Shader Special Variables) of the
        * GLSL 1.30 spec:
@@ -282,6 +285,10 @@ validate_vertex_shader_executable(struct gl_shader_program *prog,
          return false;
       }
       prog->Vert.UsesClipDistance = clip_distance.variable_found();
+      ir_variable *clip_distance_var =
+         shader->symbols->get_variable("gl_ClipDistance");
+      if (clip_distance_var)
+         prog->Vert.ClipDistanceArraySize = clip_distance_var->type->length;
    }
 
    return true;
@@ -1399,7 +1406,10 @@ public:
     */
    bool matches_var(ir_variable *var) const
    {
-      return strcmp(var->name, this->var_name) == 0;
+      if (this->is_clip_distance_mesa)
+         return strcmp(var->name, "gl_ClipDistanceMESA") == 0;
+      else
+         return strcmp(var->name, this->var_name) == 0;
    }
 
    /**
@@ -1408,10 +1418,10 @@ public:
     */
    unsigned num_components() const
    {
-      if (this->single_component == -1)
-         return this->vector_elements * this->matrix_columns * this->size;
+      if (this->is_clip_distance_mesa)
+         return this->size;
       else
-         return 1;
+         return this->vector_elements * this->matrix_columns * this->size;
    }
 
 private:
@@ -1437,11 +1447,10 @@ private:
    unsigned array_subscript;
 
    /**
-    * Which component to extract from the vertex shader output location that
-    * the linker assigned to this variable.  -1 if all components should be
-    * extracted.
+    * True if the variable is gl_ClipDistance and the driver lowers
+    * gl_ClipDistance to gl_ClipDistanceMESA.
     */
-   int single_component;
+   bool is_clip_distance_mesa;
 
    /**
     * The vertex shader output location that the linker assigned for this
@@ -1487,7 +1496,7 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
 
    this->location = -1;
    this->orig_name = input;
-   this->single_component = -1;
+   this->is_clip_distance_mesa = false;
 
    const char *bracket = strrchr(input, '[');
 
@@ -1503,17 +1512,13 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
       this->is_subscripted = false;
    }
 
-   /* For drivers that lower gl_ClipDistance to gl_ClipDistanceMESA, we need
-    * to convert a request for gl_ClipDistance[n] into a request for a
-    * component of gl_ClipDistanceMESA[n/4].
+   /* For drivers that lower gl_ClipDistance to gl_ClipDistanceMESA, this
+    * class must behave specially to account for the fact that gl_ClipDistance
+    * is converted from a float[8] to a vec4[2].
     */
    if (ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerClipDistance &&
        strcmp(this->var_name, "gl_ClipDistance") == 0) {
-      this->var_name = "gl_ClipDistanceMESA";
-      if (this->is_subscripted) {
-         this->single_component = this->array_subscript % 4;
-         this->array_subscript /= 4;
-      }
+      this->is_clip_distance_mesa = true;
    }
 
    return true;
@@ -1533,8 +1538,6 @@ tfeedback_decl::is_same(const tfeedback_decl &x, const tfeedback_decl &y)
       return false;
    if (x.is_subscripted && x.array_subscript != y.array_subscript)
       return false;
-   if (x.single_component != y.single_component)
-      return false;
    return true;
 }
 
@@ -1555,27 +1558,36 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
       /* Array variable */
       const unsigned matrix_cols =
          output_var->type->fields.array->matrix_columns;
+      unsigned actual_array_size = this->is_clip_distance_mesa ?
+         prog->Vert.ClipDistanceArraySize : output_var->type->array_size();
 
       if (this->is_subscripted) {
          /* Check array bounds. */
-         if (this->array_subscript >=
-             (unsigned) output_var->type->array_size()) {
+         if (this->array_subscript >= actual_array_size) {
             linker_error(prog, "Transform feedback varying %s has index "
-                         "%i, but the array size is %i.",
+                         "%i, but the array size is %u.",
                          this->orig_name, this->array_subscript,
-                         output_var->type->array_size());
+                         actual_array_size);
             return false;
          }
-         this->location =
-            output_var->location + this->array_subscript * matrix_cols;
+         if (this->is_clip_distance_mesa) {
+            this->location =
+               output_var->location + this->array_subscript / 4;
+         } else {
+            this->location =
+               output_var->location + this->array_subscript * matrix_cols;
+         }
          this->size = 1;
       } else {
          this->location = output_var->location;
-         this->size = (unsigned) output_var->type->array_size();
+         this->size = actual_array_size;
       }
       this->vector_elements = output_var->type->fields.array->vector_elements;
       this->matrix_columns = matrix_cols;
-      this->type = output_var->type->fields.array->gl_type;
+      if (this->is_clip_distance_mesa)
+         this->type = GL_FLOAT;
+      else
+         this->type = output_var->type->fields.array->gl_type;
    } else {
       /* Regular variable (scalar, vector, or matrix) */
       if (this->is_subscripted) {
@@ -1590,6 +1602,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
       this->matrix_columns = output_var->type->matrix_columns;
       this->type = output_var->type->gl_type;
    }
+
    /* From GL_EXT_transform_feedback:
     *   A program will fail to link if:
     *
@@ -1634,18 +1647,28 @@ tfeedback_decl::store(struct gl_shader_program *prog,
                    this->orig_name);
       return false;
    }
+   unsigned translated_size = this->size;
+   if (this->is_clip_distance_mesa)
+      translated_size = (translated_size + 3) / 4;
    unsigned components_so_far = 0;
-   for (unsigned index = 0; index < this->size; ++index) {
+   for (unsigned index = 0; index < translated_size; ++index) {
       for (unsigned v = 0; v < this->matrix_columns; ++v) {
-         unsigned num_components =
-            this->single_component >= 0 ? 1 : this->vector_elements;
+         unsigned num_components = this->vector_elements;
+         info->Outputs[info->NumOutputs].ComponentOffset = 0;
+         if (this->is_clip_distance_mesa) {
+            if (this->is_subscripted) {
+               num_components = 1;
+               info->Outputs[info->NumOutputs].ComponentOffset =
+                  this->array_subscript % 4;
+            } else {
+               num_components = MIN2(4, this->size - components_so_far);
+            }
+         }
          info->Outputs[info->NumOutputs].OutputRegister =
             this->location + v + index * this->matrix_columns;
          info->Outputs[info->NumOutputs].NumComponents = num_components;
          info->Outputs[info->NumOutputs].OutputBuffer = buffer;
          info->Outputs[info->NumOutputs].DstOffset = info->BufferStride[buffer];
-         info->Outputs[info->NumOutputs].ComponentOffset =
-            this->single_component >= 0 ? this->single_component : 0;
          ++info->NumOutputs;
          info->BufferStride[buffer] += num_components;
          components_so_far += num_components;
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 64d8c8d..bb46ba0 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2277,6 +2277,8 @@ struct gl_shader_program
    /** Vertex shader state - copied into gl_vertex_program at link time */
    struct {
       GLboolean UsesClipDistance; /**< True if gl_ClipDistance is written to. */
+      GLuint ClipDistanceArraySize; /**< Size of the gl_ClipDistance array, or
+                                         0 if not present. */
    } Vert;
 
    /* post-link info: */




More information about the mesa-commit mailing list