[gtk+/wip/otte/shader: 147/151] gsksltype: Implement arrays



commit 6b176037d850ecfbace3645715c8a7befc678dae
Author: Benjamin Otte <otte redhat com>
Date:   Sun Oct 22 04:29:36 2017 +0200

    gsksltype: Implement arrays
    
    This is incomplete as we can only declare variables using array types
    but not as arrays of static types yet.

 gsk/gskslexpression.c                              |  191 +++++++++++++
 gsk/gsksltype.c                                    |  286 ++++++++++++++++++++
 gsk/gsksltypeprivate.h                             |    7 +
 gsk/gskslvalue.c                                   |   25 ++-
 gsk/gskslvalueprivate.h                            |    2 +
 gsk/gskspvwriter.c                                 |   47 ++++
 gsk/gskspvwriterprivate.h                          |    4 +
 .../errors/array-of-array-indexing-order.glsl      |    8 +
 8 files changed, 568 insertions(+), 2 deletions(-)
---
diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c
index 2172df3..2063ab2 100644
--- a/gsk/gskslexpression.c
+++ b/gsk/gskslexpression.c
@@ -1200,6 +1200,154 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_FUNCTION_CALL = {
   gsk_sl_expression_default_get_spv_access_chain
 };
 
+/* INDEX */
+
+typedef struct _GskSlExpressionIndex GskSlExpressionIndex;
+
+struct _GskSlExpressionIndex {
+  GskSlExpression parent;
+
+  GskSlExpression *expr;
+  GskSlExpression *index_expr;
+};
+
+static void
+gsk_sl_expression_index_free (GskSlExpression *expression)
+{
+  GskSlExpressionIndex *index = (GskSlExpressionIndex *) expression;
+
+  gsk_sl_expression_unref (index->expr);
+  gsk_sl_expression_unref (index->index_expr);
+
+  g_slice_free (GskSlExpressionIndex, index);
+}
+
+static void
+gsk_sl_expression_index_print (const GskSlExpression *expression,
+                               GskSlPrinter          *printer)
+{
+  const GskSlExpressionIndex *index = (const GskSlExpressionIndex *) expression;
+
+  gsk_sl_expression_print (index->expr, printer);
+  gsk_sl_printer_append (printer, "[");
+  gsk_sl_expression_print (index->index_expr, printer);
+  gsk_sl_printer_append (printer, "]");
+}
+
+static gboolean
+gsk_sl_expression_index_is_assignable (const GskSlExpression  *expression,
+                                       GError                **error)
+{
+  const GskSlExpressionIndex *index = (const GskSlExpressionIndex *) expression;
+
+  return gsk_sl_expression_is_assignable (index->expr, error);
+}
+
+static GskSlType *
+gsk_sl_expression_index_get_return_type (const GskSlExpression *expression)
+{
+  const GskSlExpressionIndex *index = (const GskSlExpressionIndex *) expression;
+
+  return gsk_sl_type_get_index_type (gsk_sl_expression_get_return_type (index->expr));
+}
+
+static GskSlValue *
+gsk_sl_expression_index_get_constant (const GskSlExpression *expression)
+{
+  const GskSlExpressionIndex *index = (const GskSlExpressionIndex *) expression;
+  GskSlValue *result, *value, *index_value;
+
+  value = gsk_sl_expression_get_constant (index->expr);
+  if (value == NULL)
+    return NULL;
+
+  index_value = gsk_sl_expression_get_constant (index->index_expr);
+  if (index_value == NULL)
+    {
+      gsk_sl_value_free (value);
+      return NULL;
+    }
+
+  result = gsk_sl_value_new_index (value, *(guint32 *) gsk_sl_value_get_data (index_value));
+
+  gsk_sl_value_free (index_value);
+  gsk_sl_value_free (value);
+
+  return result;
+}
+
+static guint32
+gsk_sl_expression_index_write_spv (const GskSlExpression *expression,
+                                   GskSpvWriter          *writer)
+{
+  const GskSlExpressionIndex *index = (const GskSlExpressionIndex *) expression;
+  guint32 value_id, index_id, variable_id;
+  GskSlType *type;
+
+  type = gsk_sl_expression_get_return_type (index->expr);
+  index_id = gsk_sl_expression_write_spv (index->index_expr, writer);
+  value_id = gsk_sl_expression_write_spv (index->expr, writer);
+  if (gsk_sl_type_is_vector (type))
+    {
+      return gsk_spv_writer_vector_extract_dynamic (writer,
+                                                    gsk_sl_type_get_index_type (type),
+                                                    value_id,
+                                                    index_id);
+    }
+
+  /* we get here when we can't use an access chain on index->expr.
+   * So we create a temporary variable and use an access chain on that one */
+  variable_id = gsk_spv_writer_variable (writer,
+                                         GSK_SPV_WRITER_SECTION_DECLARE,
+                                         type,
+                                         GSK_SPV_STORAGE_CLASS_FUNCTION,
+                                         GSK_SPV_STORAGE_CLASS_FUNCTION,
+                                         value_id);
+  variable_id = gsk_spv_writer_access_chain (writer,
+                                             gsk_sl_type_get_index_type (type),
+                                             GSK_SPV_STORAGE_CLASS_FUNCTION,
+                                             variable_id,
+                                             (guint32[1]) { index_id },
+                                             1);
+  return gsk_spv_writer_load (writer,
+                              gsk_sl_type_get_index_type (type),
+                              variable_id,
+                              0);
+}
+
+static GskSpvAccessChain *
+gsk_sl_expression_index_get_spv_access_chain (const GskSlExpression *expression,
+                                              GskSpvWriter          *writer)
+{
+  const GskSlExpressionIndex *index = (const GskSlExpressionIndex *) expression;
+  GskSpvAccessChain *chain;
+
+  chain = gsk_sl_expression_get_spv_access_chain (index->expr, writer);
+  if (chain == NULL)
+    return NULL;
+  if (gsk_spv_access_chain_has_swizzle (chain))
+    {
+      gsk_spv_access_chain_free (chain);
+      return NULL;
+    }
+
+  gsk_spv_access_chain_add_dynamic_index (chain,
+                                          gsk_sl_type_get_index_type (gsk_sl_expression_get_return_type 
(index->expr)),
+                                          index->index_expr);
+
+  return chain;
+}
+
+static const GskSlExpressionClass GSK_SL_EXPRESSION_INDEX = {
+  gsk_sl_expression_index_free,
+  gsk_sl_expression_index_print,
+  gsk_sl_expression_index_is_assignable,
+  gsk_sl_expression_index_get_return_type,
+  gsk_sl_expression_index_get_constant,
+  gsk_sl_expression_index_write_spv,
+  gsk_sl_expression_index_get_spv_access_chain
+};
+
 /* MEMBER */
 
 typedef struct _GskSlExpressionMember GskSlExpressionMember;
@@ -2299,6 +2447,49 @@ gsk_sl_expression_parse_postfix (GskSlScope        *scope,
               continue;
             }
         }
+      else if (gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACKET))
+        {
+          GskSlExpressionIndex *index;
+          GskSlExpression *index_expr;
+          GskSlType *type;
+
+          gsk_sl_preprocessor_consume (stream, NULL);
+
+          index_expr = gsk_sl_expression_parse (scope, stream);
+
+          token = gsk_sl_preprocessor_get (stream);
+          if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACKET))
+            {
+              gsk_sl_preprocessor_error (stream, SYNTAX, "Expected closing \"]\" after array index.");
+              gsk_sl_expression_unref (index_expr);
+              continue;
+            }
+          gsk_sl_preprocessor_consume (stream, NULL);
+
+          type = gsk_sl_expression_get_return_type (index_expr);
+          if (!gsk_sl_type_equal (type, gsk_sl_type_get_scalar (GSK_SL_INT)) &&
+              !gsk_sl_type_equal (type, gsk_sl_type_get_scalar (GSK_SL_UINT)))
+            {
+              gsk_sl_preprocessor_error (stream, SYNTAX, "Array index must be an integer type, not %s.", 
gsk_sl_type_get_name (type));
+              gsk_sl_expression_unref (index_expr);
+              continue;
+            }
+
+          type = gsk_sl_expression_get_return_type (expr);
+          if (gsk_sl_type_get_length (type) == 0)
+            {
+              gsk_sl_preprocessor_error (stream, SYNTAX, "Cannot index values of type %s.", 
gsk_sl_type_get_name (type));
+              gsk_sl_expression_unref (index_expr);
+              continue;
+            }
+          /* XXX: do range check for constants here */
+
+          index = gsk_sl_expression_new (GskSlExpressionIndex, &GSK_SL_EXPRESSION_INDEX);
+          index->expr = expr;
+          index->index_expr = index_expr;
+
+          expr = (GskSlExpression *) index;
+        }
       else if (gsk_sl_token_is (token, GSK_SL_TOKEN_INC_OP) ||
                gsk_sl_token_is (token, GSK_SL_TOKEN_DEC_OP))
         {
diff --git a/gsk/gsksltype.c b/gsk/gsksltype.c
index 2ebfce5..dd557eb 100644
--- a/gsk/gsksltype.c
+++ b/gsk/gsksltype.c
@@ -20,6 +20,7 @@
 
 #include "gsksltypeprivate.h"
 
+#include "gskslexpressionprivate.h"
 #include "gskslfunctionprivate.h"
 #include "gskslimagetypeprivate.h"
 #include "gskslpreprocessorprivate.h"
@@ -1077,6 +1078,219 @@ static const GskSlTypeClass GSK_SL_TYPE_MATRIX = {
   gsk_sl_type_matrix_write_value_spv
 };
 
+/* ARRAY */
+
+typedef struct _GskSlTypeArray GskSlTypeArray;
+
+struct _GskSlTypeArray {
+  GskSlType parent;
+
+  char *name;
+  GskSlType *type;
+  gsize length;
+};
+
+static void
+gsk_sl_type_array_free (GskSlType *type)
+{
+  GskSlTypeArray *array = (GskSlTypeArray *) type;
+
+  gsk_sl_type_unref (array->type);
+  g_free (array->name);
+
+  g_slice_free (GskSlTypeArray, array);
+}
+
+static const char *
+gsk_sl_type_array_get_name (const GskSlType *type)
+{
+  const GskSlTypeArray *array = (const GskSlTypeArray *) type;
+
+  return array->name;
+}
+
+static GskSlScalarType
+gsk_sl_type_array_get_scalar_type (const GskSlType *type)
+{
+  const GskSlTypeArray *array = (const GskSlTypeArray *) type;
+
+  return gsk_sl_type_get_scalar_type (array->type);
+}
+
+static const GskSlImageType *
+gsk_sl_type_array_get_image_type (const GskSlType *type)
+{
+  return NULL;
+}
+
+static GskSlType *
+gsk_sl_type_array_get_index_type (const GskSlType *type)
+{
+  const GskSlTypeArray *array = (const GskSlTypeArray *) type;
+
+  return array->type;
+}
+
+static gsize
+gsk_sl_type_array_get_index_stride (const GskSlType *type)
+{
+  const GskSlTypeArray *array = (const GskSlTypeArray *) type;
+
+  return gsk_sl_type_get_size (array->type);
+}
+
+static guint
+gsk_sl_type_array_get_length (const GskSlType *type)
+{
+  const GskSlTypeArray *array = (const GskSlTypeArray *) type;
+
+  return array->length;
+}
+
+static gsize
+gsk_sl_type_array_get_size (const GskSlType *type)
+{
+  const GskSlTypeArray *array = (const GskSlTypeArray *) type;
+
+  return array->length * gsk_sl_type_array_get_size (array->type);
+}
+
+static gsize
+gsk_sl_type_array_get_n_components (const GskSlType *type)
+{
+  const GskSlTypeArray *array = (const GskSlTypeArray *) type;
+
+  return gsk_sl_type_array_get_n_components (array->type) * array->length;
+}
+
+static guint
+gsk_sl_type_array_get_n_members (const GskSlType *type)
+{
+  return 0;
+}
+
+static const GskSlTypeMember *
+gsk_sl_type_array_get_member (const GskSlType *type,
+                               guint            n)
+{
+  return NULL;
+}
+
+static gboolean
+gsk_sl_type_array_can_convert (const GskSlType *target,
+                               const GskSlType *source)
+{
+  return gsk_sl_type_equal (target, source);
+}
+
+static guint32
+gsk_sl_type_array_write_spv (GskSlType    *type,
+                             GskSpvWriter *writer)
+{
+  GskSlTypeArray *array = (GskSlTypeArray *) type;
+  GskSlValue *value;
+  guint32 type_id, length_id;
+
+  type_id = gsk_spv_writer_get_id_for_type (writer, array->type);
+  value = gsk_sl_value_new (gsk_sl_type_get_scalar (GSK_SL_INT));
+  *(gint32 *) gsk_sl_value_get_data (value) = array->length;
+  length_id = gsk_spv_writer_get_id_for_value (writer, value);
+  gsk_sl_value_free (value);
+
+  return gsk_spv_writer_type_array (writer,
+                                    type_id,
+                                    length_id);
+}
+
+static void
+gsk_sl_type_array_print_value (const GskSlType *type,
+                               GskSlPrinter    *printer,
+                               gconstpointer    value)
+{
+  GskSlTypeArray *array = (GskSlTypeArray *) type;
+  gsize i, stride;
+  const guchar *data;
+
+  data = value;
+  stride = gsk_sl_type_array_get_index_stride (type);
+  gsk_sl_printer_append (printer, array->name);
+  gsk_sl_printer_append (printer, " (");
+
+  for (i = 0; i < array->length; i++)
+    {
+      if (i > 0)
+        gsk_sl_printer_append (printer, ", ");
+      gsk_sl_type_print_value (array->type, printer, data + i * stride);
+    }
+
+  gsk_sl_printer_append (printer, ")");
+}
+
+static gboolean
+gsk_sl_type_array_value_equal (const GskSlType *type,
+                               gconstpointer    a,
+                               gconstpointer    b)
+{
+  GskSlTypeArray *array = (GskSlTypeArray *) type;
+  gsize i, stride;
+  const guchar *adata;
+  const guchar *bdata;
+
+  adata = a;
+  bdata = b;
+  stride = gsk_sl_type_array_get_index_stride (type);
+  for (i = 0; i < array->length; i++)
+    {
+      if (!gsk_sl_type_value_equal (array->type, adata + i * stride, bdata + i * stride))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static guint32
+gsk_sl_type_array_write_value_spv (GskSlType     *type,
+                                   GskSpvWriter  *writer,
+                                   gconstpointer  value)
+{
+  GskSlTypeArray *array = (GskSlTypeArray *) type;
+  guint32 value_ids[array->length];
+  gsize i, stride;
+  const guchar *data;
+
+  data = value;
+  stride = gsk_sl_type_array_get_index_stride (type);
+
+  for (i = 0; i < array->length; i++)
+    {
+      value_ids[i] = gsk_sl_type_write_value_spv (array->type, writer, data + i * stride);
+    }
+
+  return gsk_spv_writer_constant_composite (writer,
+                                            type,
+                                            value_ids,
+                                            array->length);
+}
+
+static const GskSlTypeClass GSK_SL_TYPE_ARRAY = {
+  gsk_sl_type_array_free,
+  gsk_sl_type_array_get_name,
+  gsk_sl_type_array_get_scalar_type,
+  gsk_sl_type_array_get_image_type,
+  gsk_sl_type_array_get_index_type,
+  gsk_sl_type_array_get_index_stride,
+  gsk_sl_type_array_get_length,
+  gsk_sl_type_array_get_size,
+  gsk_sl_type_array_get_n_components,
+  gsk_sl_type_array_get_n_members,
+  gsk_sl_type_array_get_member,
+  gsk_sl_type_array_can_convert,
+  gsk_sl_type_array_write_spv,
+  gsk_sl_type_array_print_value,
+  gsk_sl_type_array_value_equal,
+  gsk_sl_type_array_write_value_spv
+};
+
 /* SAMPLER */
 
 typedef struct _GskSlTypeSampler GskSlTypeSampler;
@@ -1916,6 +2130,70 @@ gsk_sl_type_get_matching (GskSlType       *type,
     }
 }
 
+static char *
+gsk_sl_array_type_generate_name (GskSlType *type)
+{
+  GString *string = g_string_new (NULL);
+
+  for (; gsk_sl_type_is_array (type); type = gsk_sl_type_get_index_type (type))
+    {
+      g_string_append_printf (string, "[%u]", gsk_sl_type_get_length (type));
+    }
+
+  g_string_prepend (string, gsk_sl_type_get_name (type));
+
+  return g_string_free (string, FALSE);
+}
+
+GskSlType *
+gsk_sl_type_new_array (GskSlType *type,
+                       gsize      length)
+{
+  GskSlTypeArray *result;
+
+  result = gsk_sl_type_new (GskSlTypeArray, &GSK_SL_TYPE_ARRAY);
+
+  result->type = gsk_sl_type_ref (type);
+  result->length = length;
+
+  result->name = gsk_sl_array_type_generate_name (&result->parent);
+
+  return &result->parent;
+}
+
+GskSlType *
+gsk_sl_type_parse_array (GskSlType         *type,
+                         GskSlScope        *scope,
+                         GskSlPreprocessor *preproc)
+{
+  GskSlType *array;
+  const GskSlToken *token;
+  gsize length;
+
+  token = gsk_sl_preprocessor_get (preproc);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_BRACKET))
+    return type;
+
+  gsk_sl_preprocessor_consume (preproc, NULL);
+
+  length = gsk_sl_expression_parse_integral_constant (scope, preproc, 1, G_MAXINT);
+
+  token = gsk_sl_preprocessor_get (preproc);
+  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_BRACKET))
+    {
+      gsk_sl_preprocessor_error (preproc, SYNTAX, "Expected closing \"]\"");
+      return type;
+    }
+  gsk_sl_preprocessor_consume (preproc, NULL);
+
+  type = gsk_sl_type_parse_array (type, scope, preproc);
+
+  array = gsk_sl_type_new_array (type, length);
+  gsk_sl_type_unref (type);
+
+  return array;
+}
+
 GskSlType *
 gsk_sl_type_new_parse (GskSlScope        *scope,
                        GskSlPreprocessor *preproc)
@@ -2191,6 +2469,8 @@ gsk_sl_type_new_parse (GskSlScope        *scope,
 
   gsk_sl_preprocessor_consume (preproc, NULL);
 
+  type = gsk_sl_type_parse_array (type, scope, preproc);
+
   return type;
 }
 
@@ -2426,6 +2706,12 @@ gsk_sl_type_is_basic (const GskSlType *type)
 }
 
 gboolean
+gsk_sl_type_is_array (const GskSlType *type)
+{
+  return type->class == &GSK_SL_TYPE_ARRAY;
+}
+
+gboolean
 gsk_sl_type_is_struct (const GskSlType *type)
 {
   return type->class == &GSK_SL_TYPE_STRUCT;
diff --git a/gsk/gsksltypeprivate.h b/gsk/gsksltypeprivate.h
index da3871b..ee3f0d7 100644
--- a/gsk/gsksltypeprivate.h
+++ b/gsk/gsksltypeprivate.h
@@ -29,8 +29,14 @@ typedef struct _GskSlTypeBuilder GskSlTypeBuilder;
 
 gsize                   gsk_sl_scalar_type_get_size             (GskSlScalarType      type);
 
+GskSlType *             gsk_sl_type_new_array                   (GskSlType           *type,
+                                                                 gsize                length);
 GskSlType *             gsk_sl_type_new_parse                   (GskSlScope          *scope,
                                                                  GskSlPreprocessor   *preproc);
+GskSlType *             gsk_sl_type_parse_array                 (GskSlType           *type,
+                                                                 GskSlScope          *scope,
+                                                                 GskSlPreprocessor   *preproc);
+
 GskSlType *             gsk_sl_type_get_void                    (void);
 GskSlType *             gsk_sl_type_get_scalar                  (GskSlScalarType      scalar);
 GskSlType *             gsk_sl_type_get_vector                  (GskSlScalarType      scalar,
@@ -50,6 +56,7 @@ gboolean                gsk_sl_type_is_scalar                   (const GskSlType
 gboolean                gsk_sl_type_is_vector                   (const GskSlType     *type);
 gboolean                gsk_sl_type_is_matrix                   (const GskSlType     *type);
 gboolean                gsk_sl_type_is_basic                    (const GskSlType     *type);
+gboolean                gsk_sl_type_is_array                    (const GskSlType     *type);
 gboolean                gsk_sl_type_is_struct                   (const GskSlType     *type);
 gboolean                gsk_sl_type_is_block                    (const GskSlType     *type);
 gboolean                gsk_sl_type_is_sampler                  (const GskSlType     *type);
diff --git a/gsk/gskslvalue.c b/gsk/gskslvalue.c
index f930f98..475b460 100644
--- a/gsk/gskslvalue.c
+++ b/gsk/gskslvalue.c
@@ -160,15 +160,36 @@ gsk_sl_value_new_convert (GskSlValue *source,
 }
 
 GskSlValue *
+gsk_sl_value_new_index (GskSlValue *value,
+                        gsize       n)
+{
+  GskSlType *index_type;
+  gpointer data;
+
+  if (n >= gsk_sl_type_get_length (value->type))
+    return NULL;
+
+  index_type = gsk_sl_type_get_index_type (value->type);
+
+  data = g_memdup ((guchar *) value->data + gsk_sl_type_get_index_stride (value->type) * n,
+                   gsk_sl_type_get_size (index_type));
+
+  return gsk_sl_value_new_for_data (index_type, data, g_free, data);
+}
+
+GskSlValue *
 gsk_sl_value_new_member (GskSlValue *value,
                          guint       n)
 {
+  GskSlType *member_type;
   gpointer data;
 
+  member_type = gsk_sl_type_get_member_type (value->type, n);
+
   data = g_memdup ((guchar *) value->data + gsk_sl_type_get_member_offset (value->type, n),
-                   gsk_sl_type_get_size (gsk_sl_type_get_member_type (value->type, n)));
+                   gsk_sl_type_get_size (member_type));
 
-  return gsk_sl_value_new_for_data (value->type, data, g_free, data);
+  return gsk_sl_value_new_for_data (member_type, data, g_free, data);
 }
 
 /**
diff --git a/gsk/gskslvalueprivate.h b/gsk/gskslvalueprivate.h
index 0ce2637..4e32c5c 100644
--- a/gsk/gskslvalueprivate.h
+++ b/gsk/gskslvalueprivate.h
@@ -30,6 +30,8 @@ GskSlValue *            gsk_sl_value_new_for_data               (GskSlType
                                                                  gpointer             user_data);
 GskSlValue *            gsk_sl_value_new_convert                (GskSlValue          *source,
                                                                  GskSlType           *new_type);
+GskSlValue *            gsk_sl_value_new_index                  (GskSlValue          *value,
+                                                                 gsize                n);
 GskSlValue *            gsk_sl_value_new_member                 (GskSlValue          *value,
                                                                  guint                n);
 GskSlValue *            gsk_sl_value_copy                       (const GskSlValue    *source);
diff --git a/gsk/gskspvwriter.c b/gsk/gskspvwriter.c
index bda442e..24a9f0c 100644
--- a/gsk/gskspvwriter.c
+++ b/gsk/gskspvwriter.c
@@ -20,6 +20,7 @@
 
 #include "gskspvwriterprivate.h"
 
+#include "gskslexpressionprivate.h"
 #include "gskslfunctionprivate.h"
 #include "gskslfunctiontypeprivate.h"
 #include "gskslimagetypeprivate.h"
@@ -812,6 +813,7 @@ struct _GskSpvAccessChain
   GskSlVariable *variable;
   GskSlType *type;
   GArray *chain;
+  GSList *pending_indexes;
   guint32 swizzle[4];
   guint swizzle_length;
 };
@@ -839,6 +841,7 @@ gsk_spv_access_chain_free (GskSpvAccessChain *chain)
 {
   if (chain->chain)
     g_array_free (chain->chain, TRUE);
+  g_slist_free_full (chain->pending_indexes, (GDestroyNotify) gsk_sl_expression_unref);
   gsk_sl_type_unref (chain->type);
   gsk_sl_variable_unref (chain->variable);
   gsk_spv_writer_unref (chain->writer);
@@ -851,6 +854,8 @@ gsk_spv_access_chain_add_index (GskSpvAccessChain *chain,
                                 GskSlType         *type,
                                 guint32            index_id)
 {
+  g_assert (!gsk_spv_access_chain_has_swizzle (chain));
+
   if (chain->chain == NULL)
     chain->chain = g_array_new (FALSE, FALSE, sizeof (guint32));
   gsk_sl_type_unref (chain->type);
@@ -860,6 +865,22 @@ gsk_spv_access_chain_add_index (GskSpvAccessChain *chain,
 }
 
 void
+gsk_spv_access_chain_add_dynamic_index (GskSpvAccessChain *chain,
+                                        GskSlType         *type,
+                                        GskSlExpression   *expr)
+{
+  gsk_spv_access_chain_add_index (chain, type, 0);
+
+  chain->pending_indexes = g_slist_prepend (chain->pending_indexes, gsk_sl_expression_ref (expr));
+}
+
+gboolean
+gsk_spv_access_chain_has_swizzle (GskSpvAccessChain *chain)
+{
+  return chain->swizzle_length > 0;
+}
+
+void
 gsk_spv_access_chain_swizzle (GskSpvAccessChain *chain,
                               const guint       *indexes,
                               guint              length)
@@ -916,11 +937,37 @@ gsk_spv_access_chain_swizzle (GskSpvAccessChain *chain,
     }
 }
 
+static void
+gsk_spv_access_resolve_pending (GskSpvAccessChain *chain)
+{
+  GSList *l;
+  guint i;
+
+  if (chain->pending_indexes == NULL)
+    return;
+  
+  i = chain->chain->len;
+  l = chain->pending_indexes;
+  while (i-- > 0)
+    {
+      if (g_array_index (chain->chain, guint32, i) != 0)
+        continue;
+
+      g_array_index (chain->chain, guint32, i) = gsk_sl_expression_write_spv (l->data, chain->writer);
+      l = l->next;
+    }
+
+  g_slist_free_full (chain->pending_indexes, (GDestroyNotify) gsk_sl_expression_unref);
+  chain->pending_indexes = NULL;
+}
+
 static guint32
 gsk_spv_access_get_variable (GskSpvAccessChain *chain)
 {
   guint32 variable_id;
     
+  gsk_spv_access_resolve_pending (chain);
+
   variable_id = gsk_spv_writer_get_id_for_variable (chain->writer,
                                                     chain->variable);
 
diff --git a/gsk/gskspvwriterprivate.h b/gsk/gskspvwriterprivate.h
index 4d7e1d3..bf84788 100644
--- a/gsk/gskspvwriterprivate.h
+++ b/gsk/gskspvwriterprivate.h
@@ -104,9 +104,13 @@ void                    gsk_spv_access_chain_free               (GskSpvAccessCha
 void                    gsk_spv_access_chain_add_index          (GskSpvAccessChain      *chain,
                                                                  GskSlType              *type,
                                                                  guint32                 index_id);
+void                    gsk_spv_access_chain_add_dynamic_index  (GskSpvAccessChain      *chain,
+                                                                 GskSlType              *type,
+                                                                 GskSlExpression        *expr);
 void                    gsk_spv_access_chain_swizzle            (GskSpvAccessChain      *chain,
                                                                  const guint            *indexes,
                                                                  guint                   n_indexes);
+gboolean                gsk_spv_access_chain_has_swizzle        (GskSpvAccessChain      *chain);
 guint32                 gsk_spv_access_chain_load               (GskSpvAccessChain      *chain);
 void                    gsk_spv_access_chain_store              (GskSpvAccessChain      *chain,
                                                                  guint32                 value);
diff --git a/testsuite/gsksl/errors/array-of-array-indexing-order.glsl 
b/testsuite/gsksl/errors/array-of-array-indexing-order.glsl
new file mode 100644
index 0000000..fe6048e
--- /dev/null
+++ b/testsuite/gsksl/errors/array-of-array-indexing-order.glsl
@@ -0,0 +1,8 @@
+void
+main  ()
+{
+  float[2][3] x;
+  float[2] y;
+
+  bool b = x[1] == y;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]