glsl: parse new transform feedback layout qualifiers
authorTimothy Arceri <timothy.arceri@collabora.com>
Fri, 22 Jan 2016 01:45:10 +0000 (12:45 +1100)
committerTimothy Arceri <timothy.arceri@collabora.com>
Thu, 31 Mar 2016 01:50:00 +0000 (12:50 +1100)
We reuse the existing offset field for holding the xfb_offset
expression but create a new flag as to avoid hitting the rules
for the offset qualifier for UBOs.

xfb_buffer qualifiers require extra processing when merging as
they can be applied to global out defaults. We just apply the
same rules as we do for the stream qualifier as the spec says:

   "The *xfb_buffer* qualifier follows the same conventions,
    behavior, defaults, and inheritance rules as the qualifier
    stream, and the examples for stream apply here as well."

For xfb_stride we push everything into a global out field for
later processing as xfb_stride applies to the entire buffer.
We still need to have a separate field to store per variable
strides because they can still effect implicit offsets
e.g. when applied to block members with implicit offsets.

Reviewed-by: Dave Airlie <airlied@redhat.com>
src/compiler/glsl/ast.h
src/compiler/glsl/ast_type.cpp
src/compiler/glsl/glsl_parser.yy
src/compiler/glsl/glsl_parser_extras.cpp

index b144e24de88f9fa4dbba59f33de53a49c89e1727..7436edce88a92a1887b7808630099ea6228f956e 100644 (file)
@@ -562,6 +562,15 @@ struct ast_type_qualifier {
          unsigned explicit_stream:1; /**< stream value assigned explicitly by shader code */
          /** \} */
 
+         /** \name Layout qualifiers for GL_ARB_enhanced_layouts */
+         /** \{ */
+         unsigned explicit_xfb_offset:1; /**< xfb_offset value assigned explicitly by shader code */
+         unsigned xfb_buffer:1; /**< Has xfb_buffer value assigned  */
+         unsigned explicit_xfb_buffer:1; /**< xfb_buffer value assigned explicitly by shader code */
+         unsigned xfb_stride:1; /**< Is xfb_stride value yet to be merged with global values  */
+         unsigned explicit_xfb_stride:1; /**< xfb_stride value assigned explicitly by shader code */
+         /** \} */
+
         /** \name Layout qualifiers for GL_ARB_tessellation_shader */
         /** \{ */
         /* tess eval input layout */
@@ -618,6 +627,15 @@ struct ast_type_qualifier {
    /** Stream in GLSL 1.50 geometry shaders. */
    ast_expression *stream;
 
+   /** xfb_buffer specified via the GL_ARB_enhanced_layouts keyword. */
+   ast_expression *xfb_buffer;
+
+   /** xfb_stride specified via the GL_ARB_enhanced_layouts keyword. */
+   ast_expression *xfb_stride;
+
+   /** global xfb_stride values for each buffer */
+   ast_layout_expression *out_xfb_stride[MAX_FEEDBACK_BUFFERS];
+
    /**
     * Input or output primitive type in GLSL 1.50 geometry shaders
     * and tessellation shaders.
@@ -633,8 +651,9 @@ struct ast_type_qualifier {
    ast_expression *binding;
 
    /**
-    * Offset specified via GL_ARB_shader_atomic_counter's "offset"
-    * keyword.
+    * Offset specified via GL_ARB_shader_atomic_counter's or
+    * GL_ARB_enhanced_layouts "offset" keyword, or by GL_ARB_enhanced_layouts
+    * "xfb_offset" keyword.
     *
     * \note
     * This field is only valid if \c explicit_offset is set.
index ede6cc4500fc748d833ab43143f7656b210619c3..ab86577cc3e64828e989b9b0fc0403d2ed578e44 100644 (file)
@@ -229,6 +229,43 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
       }
    }
 
+   if (state->has_enhanced_layouts()) {
+      if (!this->flags.q.explicit_xfb_buffer) {
+         if (q.flags.q.xfb_buffer) {
+            this->flags.q.xfb_buffer = 1;
+            this->xfb_buffer = q.xfb_buffer;
+         } else if (!this->flags.q.xfb_buffer && this->flags.q.out) {
+            /* Assign global xfb_buffer value */
+            this->flags.q.xfb_buffer = 1;
+            this->xfb_buffer = state->out_qualifier->xfb_buffer;
+         }
+      }
+
+      if (q.flags.q.explicit_xfb_stride)
+         this->xfb_stride = q.xfb_stride;
+
+      /* Merge all we xfb_stride qualifiers into the global out */
+      if (q.flags.q.explicit_xfb_stride || this->flags.q.xfb_stride) {
+
+         /* Set xfb_stride flag to 0 to avoid adding duplicates every time
+          * there is a merge.
+          */
+         this->flags.q.xfb_stride = 0;
+
+         unsigned buff_idx;
+         if (process_qualifier_constant(state, loc, "xfb_buffer",
+                                        this->xfb_buffer, &buff_idx)) {
+            if (state->out_qualifier->out_xfb_stride[buff_idx]) {
+               state->out_qualifier->out_xfb_stride[buff_idx]->merge_qualifier(
+                  new(state) ast_layout_expression(*loc, this->xfb_stride));
+            } else {
+               state->out_qualifier->out_xfb_stride[buff_idx] =
+                  new(state) ast_layout_expression(*loc, this->xfb_stride);
+            }
+         }
+      }
+   }
+
    if (q.flags.q.vertices) {
       if (this->vertices) {
          this->vertices->merge_qualifier(q.vertices);
@@ -300,7 +337,7 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
    if (q.flags.q.explicit_binding)
       this->binding = q.binding;
 
-   if (q.flags.q.explicit_offset)
+   if (q.flags.q.explicit_offset || q.flags.q.explicit_xfb_offset)
       this->offset = q.offset;
 
    if (q.precision != ast_precision_none)
@@ -349,6 +386,10 @@ ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc,
                        "tessellation control or geometry shaders");
    }
 
+   /* Allow future assigments of global out's */
+   this->flags.q.explicit_xfb_buffer = 0;
+   this->flags.q.explicit_xfb_stride = 0;
+
    return r;
 }
 
index 5ed051a670559f87122ad201480ba537a395f2a8..1cecc09b8c86ae9301363ee33b3a74f2a074bfd2 100644 (file)
@@ -1541,6 +1541,25 @@ layout_qualifier_id:
          }
       }
 
+      if (state->has_enhanced_layouts()) {
+         if (match_layout_qualifier("xfb_buffer", $1, state) == 0) {
+            $$.flags.q.xfb_buffer = 1;
+            $$.flags.q.explicit_xfb_buffer = 1;
+            $$.xfb_buffer = $3;
+         }
+
+         if (match_layout_qualifier("xfb_offset", $1, state) == 0) {
+            $$.flags.q.explicit_xfb_offset = 1;
+            $$.offset = $3;
+         }
+
+         if (match_layout_qualifier("xfb_stride", $1, state) == 0) {
+            $$.flags.q.xfb_stride = 1;
+            $$.flags.q.explicit_xfb_stride = 1;
+            $$.xfb_stride = $3;
+         }
+      }
+
       static const char * const local_size_qualifiers[3] = {
          "local_size_x",
          "local_size_y",
@@ -1915,6 +1934,12 @@ storage_qualifier:
           $$.flags.q.explicit_stream = 0;
           $$.stream = state->out_qualifier->stream;
       }
+
+      if (state->has_enhanced_layouts()) {
+          $$.flags.q.xfb_buffer = 1;
+          $$.flags.q.explicit_xfb_buffer = 0;
+          $$.xfb_buffer = state->out_qualifier->xfb_buffer;
+      }
    }
    | UNIFORM
    {
index a8fa75395e00eb938498f520592d45db0fe166bd..76ae0f8816763c64c1d98073686ae7424784a7a5 100644 (file)
@@ -939,6 +939,13 @@ _mesa_ast_process_interface_block(YYLTYPE *locp,
       block->layout.stream = state->out_qualifier->stream;
    }
 
+   if (state->has_enhanced_layouts() && block->layout.flags.q.out) {
+      /* Assign global layout's xfb_buffer value. */
+      block->layout.flags.q.xfb_buffer = 1;
+      block->layout.flags.q.explicit_xfb_buffer = 0;
+      block->layout.xfb_buffer = state->out_qualifier->xfb_buffer;
+   }
+
    foreach_list_typed (ast_declarator_list, member, link, &block->declarations) {
       ast_type_qualifier& qualifier = member->type->qualifier;
       if ((qualifier.flags.i & interface_type_mask) == 0) {