glsl: implement ARB_transform_feedback3 in the linker
authorMarek Olšák <maraeo@gmail.com>
Sun, 18 Dec 2011 01:39:34 +0000 (02:39 +0100)
committerMarek Olšák <maraeo@gmail.com>
Thu, 12 Jul 2012 11:05:58 +0000 (13:05 +0200)
Acked-by: Ian Romanick <ian.d.romanick@intel.com>
src/glsl/linker.cpp
src/mesa/main/extensions.c
src/mesa/main/mtypes.h

index 31094475216b3b010a9e64c548816671381e378d..f06298cf6e96d04d95007992720c0eeded79f05f 100644 (file)
@@ -1439,8 +1439,7 @@ public:
    bool accumulate_num_outputs(struct gl_shader_program *prog, unsigned *count);
    bool store(struct gl_context *ctx, struct gl_shader_program *prog,
               struct gl_transform_feedback_info *info, unsigned buffer,
-              unsigned varying, const unsigned max_outputs) const;
-
+              const unsigned max_outputs) const;
 
    /**
     * True if assign_location() has been called for this object.
@@ -1450,6 +1449,16 @@ public:
       return this->location != -1;
    }
 
+   bool is_next_buffer_separator() const
+   {
+      return this->next_buffer_separator;
+   }
+
+   bool is_varying() const
+   {
+      return !this->next_buffer_separator && !this->skip_components;
+   }
+
    /**
     * Determine whether this object refers to the variable var.
     */
@@ -1527,6 +1536,17 @@ private:
     * glGetTransformFeedbackVarying().
     */
    unsigned size;
+
+   /**
+    * How many components to skip. If non-zero, this is
+    * gl_SkipComponents{1,2,3,4} from ARB_transform_feedback3.
+    */
+   unsigned skip_components;
+
+   /**
+    * Whether this is gl_NextBuffer from ARB_transform_feedback3.
+    */
+   bool next_buffer_separator;
 };
 
 
@@ -1546,7 +1566,31 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
    this->location = -1;
    this->orig_name = input;
    this->is_clip_distance_mesa = false;
+   this->skip_components = 0;
+   this->next_buffer_separator = false;
 
+   if (ctx->Extensions.ARB_transform_feedback3) {
+      /* Parse gl_NextBuffer. */
+      if (strcmp(input, "gl_NextBuffer") == 0) {
+         this->next_buffer_separator = true;
+         return true;
+      }
+
+      /* Parse gl_SkipComponents. */
+      if (strcmp(input, "gl_SkipComponents1") == 0)
+         this->skip_components = 1;
+      else if (strcmp(input, "gl_SkipComponents2") == 0)
+         this->skip_components = 2;
+      else if (strcmp(input, "gl_SkipComponents3") == 0)
+         this->skip_components = 3;
+      else if (strcmp(input, "gl_SkipComponents4") == 0)
+         this->skip_components = 4;
+
+      if (this->skip_components)
+         return true;
+   }
+
+   /* Parse a declaration. */
    const char *bracket = strrchr(input, '[');
 
    if (bracket) {
@@ -1581,6 +1625,8 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
 bool
 tfeedback_decl::is_same(const tfeedback_decl &x, const tfeedback_decl &y)
 {
+   assert(x.is_varying() && y.is_varying());
+
    if (strcmp(x.var_name, y.var_name) != 0)
       return false;
    if (x.is_subscripted != y.is_subscripted)
@@ -1603,6 +1649,8 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
                                 struct gl_shader_program *prog,
                                 ir_variable *output_var)
 {
+   assert(this->is_varying());
+
    if (output_var->type->is_array()) {
       /* Array variable */
       const unsigned matrix_cols =
@@ -1677,6 +1725,10 @@ bool
 tfeedback_decl::accumulate_num_outputs(struct gl_shader_program *prog,
                                        unsigned *count)
 {
+   if (!this->is_varying()) {
+      return true;
+   }
+
    if (!this->is_assigned()) {
       /* From GL_EXT_transform_feedback:
        *   A program will fail to link if:
@@ -1709,9 +1761,16 @@ tfeedback_decl::accumulate_num_outputs(struct gl_shader_program *prog,
 bool
 tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
                       struct gl_transform_feedback_info *info,
-                      unsigned buffer,
-                      unsigned varying, const unsigned max_outputs) const
+                      unsigned buffer, const unsigned max_outputs) const
 {
+   assert(!this->next_buffer_separator);
+
+   /* Handle gl_SkipComponents. */
+   if (this->skip_components) {
+      info->BufferStride[buffer] += this->skip_components;
+      return true;
+   }
+
    /* From GL_EXT_transform_feedback:
     *   A program will fail to link if:
     *
@@ -1757,9 +1816,9 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
    }
    assert(components_so_far == this->num_components());
 
-   info->Varyings[varying].Name = ralloc_strdup(prog, this->orig_name);
-   info->Varyings[varying].Type = this->type;
-   info->Varyings[varying].Size = this->size;
+   info->Varyings[info->NumVarying].Name = ralloc_strdup(prog, this->orig_name);
+   info->Varyings[info->NumVarying].Type = this->type;
+   info->Varyings[info->NumVarying].Size = this->size;
    info->NumVarying++;
 
    return true;
@@ -1781,6 +1840,10 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog,
    for (unsigned i = 0; i < num_names; ++i) {
       if (!decls[i].init(ctx, prog, mem_ctx, varying_names[i]))
          return false;
+
+      if (!decls[i].is_varying())
+         continue;
+
       /* From GL_EXT_transform_feedback:
        *   A program will fail to link if:
        *
@@ -1792,6 +1855,9 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog,
        * feedback of arrays would be useless otherwise.
        */
       for (unsigned j = 0; j < i; ++j) {
+         if (!decls[j].is_varying())
+            continue;
+
          if (tfeedback_decl::is_same(decls[i], decls[j])) {
             linker_error(prog, "Transform feedback varying %s specified "
                          "more than once.", varying_names[i]);
@@ -1948,6 +2014,9 @@ assign_varying_locations(struct gl_context *ctx,
       }
 
       for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
+         if (!tfeedback_decls[i].is_varying())
+            continue;
+
          if (!tfeedback_decls[i].is_assigned() &&
              tfeedback_decls[i].matches_var(output_var)) {
             if (output_var->location == -1) {
@@ -2059,9 +2128,6 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
    memset(&prog->LinkedTransformFeedback, 0,
           sizeof(prog->LinkedTransformFeedback));
 
-   prog->LinkedTransformFeedback.NumBuffers =
-      separate_attribs_mode ? num_tfeedback_decls : 1;
-
    prog->LinkedTransformFeedback.Varyings =
       rzalloc_array(prog,
                    struct gl_transform_feedback_varying_info,
@@ -2077,14 +2143,37 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
                     struct gl_transform_feedback_output,
                     num_outputs);
 
-   for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
-      unsigned buffer = separate_attribs_mode ? i : 0;
-      if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback,
-                                    buffer, i, num_outputs))
-         return false;
+   unsigned num_buffers = 0;
+
+   if (separate_attribs_mode) {
+      /* GL_SEPARATE_ATTRIBS */
+      for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
+         if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback,
+                                       num_buffers, num_outputs))
+            return false;
+
+         num_buffers++;
+      }
+   }
+   else {
+      /* GL_INVERLEAVED_ATTRIBS */
+      for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
+         if (tfeedback_decls[i].is_next_buffer_separator()) {
+            num_buffers++;
+            continue;
+         }
+
+         if (!tfeedback_decls[i].store(ctx, prog,
+                                       &prog->LinkedTransformFeedback,
+                                       num_buffers, num_outputs))
+            return false;
+      }
+      num_buffers++;
    }
+
    assert(prog->LinkedTransformFeedback.NumOutputs == num_outputs);
 
+   prog->LinkedTransformFeedback.NumBuffers = num_buffers;
    return true;
 }
 
index dbc2813f255ebed218a130b6254e18bf696a9efb..0e3376561fa57bf0b9935ac16d19b8acf7a564a8 100644 (file)
@@ -141,6 +141,7 @@ static const struct extension extension_table[] = {
    { "GL_ARB_texture_swizzle",                     o(EXT_texture_swizzle),                     GL,             2008 },
    { "GL_ARB_timer_query",                         o(ARB_timer_query),                         GL,             2010 },
    { "GL_ARB_transform_feedback2",                 o(ARB_transform_feedback2),                 GL,             2010 },
+   { "GL_ARB_transform_feedback3",                 o(ARB_transform_feedback3),                 GL,             2010 },
    { "GL_ARB_transpose_matrix",                    o(ARB_transpose_matrix),                    GL,             1999 },
    { "GL_ARB_uniform_buffer_object",               o(ARB_uniform_buffer_object),               GL,             2009 },
    { "GL_ARB_vertex_array_bgra",                   o(EXT_vertex_array_bgra),                   GL,             2008 },
index bdbb5137eb3918cdeccbc903d5c3a8f07dde1454..276bfe5c1f532265d8c9f406fde5db3996add1a8 100644 (file)
@@ -2937,6 +2937,7 @@ struct gl_extensions
    GLboolean ARB_texture_storage;
    GLboolean ARB_timer_query;
    GLboolean ARB_transform_feedback2;
+   GLboolean ARB_transform_feedback3;
    GLboolean ARB_transpose_matrix;
    GLboolean ARB_uniform_buffer_object;
    GLboolean ARB_vertex_array_object;