[gtk+/wip/otte/shader: 208/269] gskspv: Add GskSpvAccessChain



commit b73576931eacb5fccb9ebf8e3f4bcef4fb3ee668
Author: Benjamin Otte <otte redhat com>
Date:   Mon Oct 9 05:37:41 2017 +0200

    gskspv: Add GskSpvAccessChain
    
    And use it to implement assignments.
    
    And because I rock, this is all assignments, including member variables
    swizzles and *= assignments. So this works:
      foo.member.rgba.rgb *= vec3(0);

 gsk/gskslexpression.c      |  128 ++++++++++++++++++++++++++++---
 gsk/gsksltypesprivate.h    |    1 +
 gsk/gskslvariable.c        |    6 ++
 gsk/gskslvariableprivate.h |    1 +
 gsk/gskspvwriter.c         |  181 ++++++++++++++++++++++++++++++++++++++++++++
 gsk/gskspvwriterprivate.h  |   13 +++
 6 files changed, 317 insertions(+), 13 deletions(-)
---
diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c
index 7b2985e..9a073f7 100644
--- a/gsk/gskslexpression.c
+++ b/gsk/gskslexpression.c
@@ -51,6 +51,8 @@ struct _GskSlExpressionClass {
   GskSlValue *          (* get_constant)                        (const GskSlExpression  *expression);
   guint32               (* write_spv)                           (const GskSlExpression  *expression,
                                                                  GskSpvWriter           *writer);
+  GskSpvAccessChain *   (* get_spv_access_chain)                (const GskSlExpression  *expression,
+                                                                 GskSpvWriter           *writer);
 };
 
 static GskSlExpression *
@@ -68,6 +70,13 @@ gsk_sl_expression_alloc (const GskSlExpressionClass *klass,
 }
 #define gsk_sl_expression_new(_name, _klass) ((_name *) gsk_sl_expression_alloc ((_klass), sizeof (_name)))
 
+static GskSpvAccessChain *
+gsk_sl_expression_get_spv_access_chain (const GskSlExpression *expression,
+                                        GskSpvWriter          *writer)
+{
+  return expression->class->get_spv_access_chain (expression, writer);
+}
+
 static gboolean
 gsk_sl_expression_default_is_assignable (const GskSlExpression  *expression,
                                          GError                **error)
@@ -80,6 +89,13 @@ gsk_sl_expression_default_is_assignable (const GskSlExpression  *expression,
   return FALSE;
 }
 
+static GskSpvAccessChain *
+gsk_sl_expression_default_get_spv_access_chain (const GskSlExpression *expression,
+                                                GskSpvWriter          *writer)
+{
+  return NULL;
+}
+
 /* ASSIGNMENT */
 
 typedef struct _GskSlExpressionAssignment GskSlExpressionAssignment;
@@ -88,6 +104,7 @@ struct _GskSlExpressionAssignment {
   GskSlExpression parent;
 
   const GskSlBinary *binary;
+  GskSlType *type;
   GskSlExpression *lvalue;
   GskSlExpression *rvalue;
 };
@@ -99,6 +116,7 @@ gsk_sl_expression_assignment_free (GskSlExpression *expression)
 
   gsk_sl_expression_unref (assignment->lvalue);
   gsk_sl_expression_unref (assignment->rvalue);
+  gsk_sl_type_unref (assignment->type);
 
   g_slice_free (GskSlExpressionAssignment, assignment);
 }
@@ -135,9 +153,34 @@ static guint32
 gsk_sl_expression_assignment_write_spv (const GskSlExpression *expression,
                                         GskSpvWriter          *writer)
 {
-  g_assert_not_reached ();
+  const GskSlExpressionAssignment *assignment = (const GskSlExpressionAssignment *) expression;
+  GskSpvAccessChain *chain;
+  GskSlType *rtype, *ltype;
+  guint32 rvalue;
 
-  return 0;
+  chain = gsk_sl_expression_get_spv_access_chain (assignment->lvalue, writer);
+  g_assert (chain);
+  ltype = gsk_sl_expression_get_return_type (assignment->lvalue),
+  rtype = gsk_sl_expression_get_return_type (assignment->rvalue),
+  rvalue = gsk_sl_expression_write_spv (assignment->rvalue, writer);
+
+  if (assignment->binary)
+    {
+      rvalue = gsk_sl_binary_write_spv (assignment->binary,
+                                        writer,
+                                        assignment->type,
+                                        ltype,
+                                        gsk_spv_access_chain_load (chain),
+                                        rtype,
+                                        rvalue);
+      rtype = assignment->type;
+    }
+
+  rvalue = gsk_spv_writer_convert (writer, rvalue, ltype, rtype);
+  gsk_spv_access_chain_store (chain, rvalue);
+  gsk_spv_access_chain_free (chain);
+
+  return rvalue;
 }
 
 static const GskSlExpressionClass GSK_SL_EXPRESSION_ASSIGNMENT = {
@@ -146,7 +189,8 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_ASSIGNMENT = {
   gsk_sl_expression_default_is_assignable,
   gsk_sl_expression_assignment_get_return_type,
   gsk_sl_expression_assignment_get_constant,
-  gsk_sl_expression_assignment_write_spv
+  gsk_sl_expression_assignment_write_spv,
+  gsk_sl_expression_default_get_spv_access_chain
 };
 
 /* BINARY */
@@ -219,7 +263,7 @@ gsk_sl_expression_binary_get_constant (const GskSlExpression *expression)
 
 static guint32
 gsk_sl_expression_binary_write_spv (const GskSlExpression *expression,
-                                            GskSpvWriter          *writer)
+                                    GskSpvWriter          *writer)
 {
   const GskSlExpressionBinary *binary = (const GskSlExpressionBinary *) expression;
 
@@ -238,7 +282,8 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_BINARY = {
   gsk_sl_expression_default_is_assignable,
   gsk_sl_expression_binary_get_return_type,
   gsk_sl_expression_binary_get_constant,
-  gsk_sl_expression_binary_write_spv
+  gsk_sl_expression_binary_write_spv,
+  gsk_sl_expression_default_get_spv_access_chain
 };
 
 /* REFERENCE */
@@ -324,13 +369,23 @@ gsk_sl_expression_reference_write_spv (const GskSlExpression *expression,
                               0);
 }
 
+static GskSpvAccessChain *
+gsk_sl_expression_reference_get_spv_access_chain (const GskSlExpression *expression,
+                                                  GskSpvWriter          *writer)
+{
+  GskSlExpressionReference *reference = (GskSlExpressionReference *) expression;
+
+  return gsk_spv_access_chain_new (writer, reference->variable);
+}
+
 static const GskSlExpressionClass GSK_SL_EXPRESSION_REFERENCE = {
   gsk_sl_expression_reference_free,
   gsk_sl_expression_reference_print,
   gsk_sl_expression_reference_is_assignable,
   gsk_sl_expression_reference_get_return_type,
   gsk_sl_expression_reference_get_constant,
-  gsk_sl_expression_reference_write_spv
+  gsk_sl_expression_reference_write_spv,
+  gsk_sl_expression_reference_get_spv_access_chain
 };
 
 /* CONSTRUCTOR CALL */
@@ -707,7 +762,8 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_CONSTRUCTOR = {
   gsk_sl_expression_default_is_assignable,
   gsk_sl_expression_constructor_get_return_type,
   gsk_sl_expression_constructor_get_constant,
-  gsk_sl_expression_constructor_write_spv
+  gsk_sl_expression_constructor_write_spv,
+  gsk_sl_expression_default_get_spv_access_chain
 };
 
 /* FUNCTION_CALL */
@@ -824,7 +880,8 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_FUNCTION_CALL = {
   gsk_sl_expression_default_is_assignable,
   gsk_sl_expression_function_call_get_return_type,
   gsk_sl_expression_function_call_get_constant,
-  gsk_sl_expression_function_call_write_spv
+  gsk_sl_expression_function_call_write_spv,
+  gsk_sl_expression_default_get_spv_access_chain
 };
 
 /* MEMBER */
@@ -909,13 +966,37 @@ gsk_sl_expression_member_write_spv (const GskSlExpression *expression,
                                            1);
 }
 
+static GskSpvAccessChain *
+gsk_sl_expression_member_get_spv_access_chain (const GskSlExpression *expression,
+                                               GskSpvWriter          *writer)
+{
+  const GskSlExpressionMember *member = (const GskSlExpressionMember *) expression;
+  GskSpvAccessChain *chain;
+  GskSlValue *value;
+  GskSlType *type;
+
+  chain = gsk_sl_expression_get_spv_access_chain (member->expr, writer);
+  if (chain == NULL)
+    return NULL;
+
+  value = gsk_sl_value_new_for_data (gsk_sl_type_get_scalar (GSK_SL_INT), &(gint32) { member->id }, NULL, 
NULL);
+  type = gsk_sl_expression_get_return_type (member->expr);
+  gsk_spv_access_chain_add_index (chain, 
+                                  gsk_sl_type_get_member_type (type, member->id),
+                                  gsk_spv_writer_get_id_for_value (writer, value));
+  gsk_sl_value_free (value);
+
+  return chain;
+}
+
 static const GskSlExpressionClass GSK_SL_EXPRESSION_MEMBER = {
   gsk_sl_expression_member_free,
   gsk_sl_expression_member_print,
   gsk_sl_expression_member_is_assignable,
   gsk_sl_expression_member_get_return_type,
   gsk_sl_expression_member_get_constant,
-  gsk_sl_expression_member_write_spv
+  gsk_sl_expression_member_write_spv,
+  gsk_sl_expression_member_get_spv_access_chain
 };
 
 /* SWIZZLE */
@@ -1101,13 +1182,32 @@ gsk_sl_expression_swizzle_write_spv (const GskSlExpression *expression,
     }
 }
 
+static GskSpvAccessChain *
+gsk_sl_expression_swizzle_get_spv_access_chain (const GskSlExpression *expression,
+                                                GskSpvWriter          *writer)
+{
+  const GskSlExpressionSwizzle *swizzle = (const GskSlExpressionSwizzle *) expression;
+  GskSpvAccessChain *chain;
+
+  chain = gsk_sl_expression_get_spv_access_chain (swizzle->expr, writer);
+  if (chain == NULL)
+    return NULL;
+
+  gsk_spv_access_chain_swizzle (chain, 
+                                swizzle->indexes,
+                                swizzle->length);
+
+  return chain;
+}
+
 static const GskSlExpressionClass GSK_SL_EXPRESSION_SWIZZLE = {
   gsk_sl_expression_swizzle_free,
   gsk_sl_expression_swizzle_print,
   gsk_sl_expression_swizzle_is_assignable,
   gsk_sl_expression_swizzle_get_return_type,
   gsk_sl_expression_swizzle_get_constant,
-  gsk_sl_expression_swizzle_write_spv
+  gsk_sl_expression_swizzle_write_spv,
+  gsk_sl_expression_swizzle_get_spv_access_chain
 };
 
 /* NEGATION */
@@ -1230,7 +1330,8 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_NEGATION = {
   gsk_sl_expression_default_is_assignable,
   gsk_sl_expression_negation_get_return_type,
   gsk_sl_expression_negation_get_constant,
-  gsk_sl_expression_negation_write_spv
+  gsk_sl_expression_negation_write_spv,
+  gsk_sl_expression_default_get_spv_access_chain
 };
 
 /* CONSTANT */
@@ -1293,7 +1394,8 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_CONSTANT = {
   gsk_sl_expression_default_is_assignable,
   gsk_sl_expression_constant_get_return_type,
   gsk_sl_expression_constant_get_constant,
-  gsk_sl_expression_constant_write_spv
+  gsk_sl_expression_constant_write_spv,
+  gsk_sl_expression_default_get_spv_access_chain
 };
 
 /* If parsing fails completely, just assume 1.0 */
@@ -2487,6 +2589,7 @@ gsk_sl_expression_parse_assignment (GskSlScope        *scope,
 
   assign = gsk_sl_expression_new (GskSlExpressionAssignment, &GSK_SL_EXPRESSION_ASSIGNMENT);
   assign->binary = binary;
+  assign->type = gsk_sl_type_ref (result_type);
   assign->lvalue = lvalue;
   assign->rvalue = rvalue;
 
@@ -2556,4 +2659,3 @@ gsk_sl_expression_write_spv (const GskSlExpression *expression,
 {
   return expression->class->write_spv (expression, writer);
 }
-
diff --git a/gsk/gsksltypesprivate.h b/gsk/gsksltypesprivate.h
index c1f34b9..478dc27 100644
--- a/gsk/gsksltypesprivate.h
+++ b/gsk/gsksltypesprivate.h
@@ -36,6 +36,7 @@ typedef struct _GskSlType               GskSlType;
 typedef struct _GskSlValue              GskSlValue;
 typedef struct _GskSlVariable           GskSlVariable;
 
+typedef struct _GskSpvAccessChain       GskSpvAccessChain;
 typedef struct _GskSpvWriter            GskSpvWriter;
 typedef void (* GskSpvWriterFunc)       (GskSpvWriter *, gpointer);
 
diff --git a/gsk/gskslvariable.c b/gsk/gskslvariable.c
index aed2d21..ee81141 100644
--- a/gsk/gskslvariable.c
+++ b/gsk/gskslvariable.c
@@ -122,6 +122,12 @@ gsk_sl_variable_get_type (const GskSlVariable *variable)
   return variable->type;
 }
 
+const GskSlQualifier *
+gsk_sl_variable_get_qualifier (const GskSlVariable *variable)
+{
+  return &variable->qualifier;
+}
+
 const char *
 gsk_sl_variable_get_name (const GskSlVariable *variable)
 {
diff --git a/gsk/gskslvariableprivate.h b/gsk/gskslvariableprivate.h
index 0c55aaa..f60b3c5 100644
--- a/gsk/gskslvariableprivate.h
+++ b/gsk/gskslvariableprivate.h
@@ -37,6 +37,7 @@ void                    gsk_sl_variable_print                   (const GskSlVari
                                                                  GskSlPrinter           *printer);
 
 GskSlType *             gsk_sl_variable_get_type                (const GskSlVariable    *variable);
+const GskSlQualifier *  gsk_sl_variable_get_qualifier           (const GskSlVariable    *variable);
 const char *            gsk_sl_variable_get_name                (const GskSlVariable    *variable);
 const GskSlValue *      gsk_sl_variable_get_initial_value       (const GskSlVariable    *variable);
 gboolean                gsk_sl_variable_is_constant             (const GskSlVariable    *variable);
diff --git a/gsk/gskspvwriter.c b/gsk/gskspvwriter.c
index 427ab46..fedfe48 100644
--- a/gsk/gskspvwriter.c
+++ b/gsk/gskspvwriter.c
@@ -21,6 +21,7 @@
 #include "gskspvwriterprivate.h"
 
 #include "gskslfunctionprivate.h"
+#include "gskslqualifierprivate.h"
 #include "gsksltypeprivate.h"
 #include "gskslvalueprivate.h"
 #include "gskslvariableprivate.h"
@@ -661,3 +662,183 @@ gsk_spv_writer_convert (GskSpvWriter *writer,
       g_return_val_if_reached (id);
     }
 }
+
+struct _GskSpvAccessChain
+{
+  GskSpvWriter *writer;
+  GskSlVariable *variable;
+  GskSlType *type;
+  GArray *chain;
+  guint32 swizzle[4];
+  guint swizzle_length;
+};
+
+GskSpvAccessChain *
+gsk_spv_access_chain_new (GskSpvWriter  *writer,
+                          GskSlVariable *variable)
+{
+  GskSpvAccessChain *chain;
+
+  chain = g_slice_new0 (GskSpvAccessChain);
+
+  chain->writer = gsk_spv_writer_ref (writer);
+  chain->variable = gsk_sl_variable_ref (variable);
+  chain->type = gsk_sl_type_ref (gsk_sl_variable_get_type (variable));
+
+  return chain;
+}
+
+void
+gsk_spv_access_chain_free (GskSpvAccessChain *chain)
+{
+  if (chain->chain)
+    g_array_free (chain->chain, TRUE);
+  gsk_sl_type_unref (chain->type);
+  gsk_sl_variable_unref (chain->variable);
+  gsk_spv_writer_unref (chain->writer);
+
+  g_slice_free (GskSpvAccessChain, chain);
+}
+
+void
+gsk_spv_access_chain_add_index (GskSpvAccessChain *chain,
+                                GskSlType         *type,
+                                guint32            index_id)
+{
+  if (chain->chain == NULL)
+    chain->chain = g_array_new (FALSE, FALSE, sizeof (guint32));
+  gsk_sl_type_unref (chain->type);
+  chain->type = gsk_sl_type_ref (type);
+
+  g_array_append_val (chain->chain, index_id);
+}
+
+void
+gsk_spv_access_chain_swizzle (GskSpvAccessChain *chain,
+                              const guint       *indexes,
+                              guint              length)
+{
+  guint tmp[4];
+  guint i;
+
+  if (chain->swizzle_length != 0)
+    {
+      g_assert (length <= chain->swizzle_length);
+
+      for (i = 0; i < length; i++)
+        {
+          tmp[i] = chain->swizzle[indexes[i]];
+        }
+      indexes = tmp;
+    }
+
+  /* Mean trick to do optimization: We only assign a swizzle_length
+   * If something is actually swizzled. If we're doing an identity
+   * swizzle, ignore it.
+   */
+  if (length < gsk_sl_type_get_n_components (chain->type))
+    chain->swizzle_length = length;
+  else
+    chain->swizzle_length = 0;
+
+  for (i = 0; i < length; i++)
+    {
+      chain->swizzle[i] = indexes[i];
+      if (indexes[i] != i)
+        chain->swizzle_length = length;
+    }
+}
+
+static guint32
+gsk_spv_access_get_variable (GskSpvAccessChain *chain)
+{
+  guint32 variable_id;
+    
+  variable_id = gsk_spv_writer_get_id_for_variable (chain->writer,
+                                                    chain->variable);
+
+  if (chain->chain)
+    variable_id = gsk_spv_writer_access_chain (chain->writer,
+                                               chain->type,
+                                               gsk_sl_qualifier_get_storage_class 
(gsk_sl_variable_get_qualifier (chain->variable)),
+                                               variable_id,
+                                               (guint32 *) chain->chain->data,
+                                               chain->chain->len);
+
+  return variable_id;
+}
+
+static GskSlType *
+gsk_spv_access_chain_get_swizzle_type (GskSpvAccessChain *chain)
+{
+  g_assert (chain->swizzle_length != 0);
+
+  if (chain->swizzle_length == 1)
+    return gsk_sl_type_get_scalar (gsk_sl_type_get_scalar_type (chain->type));
+  else
+    return gsk_sl_type_get_vector (gsk_sl_type_get_scalar_type (chain->type), chain->swizzle_length);
+}
+
+guint32
+gsk_spv_access_chain_load (GskSpvAccessChain *chain)
+{
+  guint result_id;
+  
+  result_id = gsk_spv_writer_load (chain->writer,
+                                   chain->type,
+                                   gsk_spv_access_get_variable (chain),
+                                   0);
+
+  if (chain->swizzle_length)
+    result_id = gsk_spv_writer_vector_shuffle (chain->writer,
+                                               gsk_spv_access_chain_get_swizzle_type (chain),
+                                               result_id,
+                                               result_id,
+                                               chain->swizzle,
+                                               chain->swizzle_length);
+
+  return result_id;
+}
+
+void
+gsk_spv_access_chain_store (GskSpvAccessChain *chain,
+                            guint32            value)
+{
+  guint32 chain_id;
+  
+  chain_id = gsk_spv_access_get_variable (chain);
+
+  if (chain->swizzle_length)
+    {
+      guint32 indexes[4] = { 0, };
+      guint32 merge;
+      guint i, n;
+      
+      merge = gsk_spv_writer_load (chain->writer,
+                                   chain->type,
+                                   chain_id,
+                                   0);
+
+      n = gsk_sl_type_get_n_components (chain->type);
+      for (i = 0; i < n; i++)
+        {
+          if (i < chain->swizzle_length)
+            indexes[chain->swizzle[i]] = n + i;
+          if (indexes[i] == 0)
+            indexes[i] = i;
+        }
+
+      value = gsk_spv_writer_vector_shuffle (chain->writer,
+                                             chain->type,
+                                             merge,
+                                             value,
+                                             indexes,
+                                             n);
+    }
+
+  gsk_spv_writer_store (chain->writer,
+                        chain_id,
+                        value,
+                        0);
+}
+
diff --git a/gsk/gskspvwriterprivate.h b/gsk/gskspvwriterprivate.h
index dedf337..48b4eb9 100644
--- a/gsk/gskspvwriterprivate.h
+++ b/gsk/gskspvwriterprivate.h
@@ -91,6 +91,19 @@ void                    gsk_spv_writer_commit_code_block        (GskSpvWriter
 
 guint32                 gsk_spv_code_block_get_label            (GskSpvCodeBlock        *block);
 
+GskSpvAccessChain *     gsk_spv_access_chain_new                (GskSpvWriter           *writer,
+                                                                 GskSlVariable          *variable);
+void                    gsk_spv_access_chain_free               (GskSpvAccessChain      *chain);
+void                    gsk_spv_access_chain_add_index          (GskSpvAccessChain      *chain,
+                                                                 GskSlType              *type,
+                                                                 guint32                 index_id);
+void                    gsk_spv_access_chain_swizzle            (GskSpvAccessChain      *chain,
+                                                                 const guint            *indexes,
+                                                                 guint                   n_indexes);
+guint32                 gsk_spv_access_chain_load               (GskSpvAccessChain      *chain);
+void                    gsk_spv_access_chain_store              (GskSpvAccessChain      *chain,
+                                                                 guint32                 value);
+
 #include "gskspvwritergeneratedprivate.h"
 
 G_END_DECLS


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