[gtk+/wip/otte/shader: 38/176] gskslvariable: Allow storing an initializer value with a variable



commit 6a0ff0f164a02170ea594bd59ecb09ed72de2e40
Author: Benjamin Otte <otte redhat com>
Date:   Tue Sep 26 17:46:04 2017 +0200

    gskslvariable: Allow storing an initializer value with a variable
    
    This code requires the addition of gsk_sl_value_new_convert() so
    constants can be converted to the right type.

 gsk/gskslnode.c            |   56 +++++++++++++++---------
 gsk/gskslprogram.c         |    6 ++-
 gsk/gsksltype.c            |  102 +++++++++++++++++++++++++++++++++++++++++---
 gsk/gsksltypeprivate.h     |    4 ++
 gsk/gskslvalue.c           |   94 ++++++++++++++++++++++++++++++++++++++++
 gsk/gskslvalueprivate.h    |    2 +
 gsk/gskslvariable.c        |   18 +++++++-
 gsk/gskslvariableprivate.h |    4 +-
 8 files changed, 254 insertions(+), 32 deletions(-)
---
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index e145268..46a0150 100644
--- a/gsk/gskslnode.c
+++ b/gsk/gskslnode.c
@@ -27,6 +27,7 @@
 #include "gskslscopeprivate.h"
 #include "gsksltokenizerprivate.h"
 #include "gsksltypeprivate.h"
+#include "gskslvalueprivate.h"
 #include "gskslvariableprivate.h"
 #include "gskspvwriterprivate.h"
 
@@ -253,38 +254,51 @@ gsk_sl_node_parse_declaration (GskSlScope        *scope,
 {
   GskSlNodeDeclaration *declaration;
   GskSlPointerType *pointer_type;
+  GskSlValue *value = NULL;
   const GskSlToken *token;
+  char *name;
 
   declaration = gsk_sl_node_new (GskSlNodeDeclaration, &GSK_SL_NODE_DECLARATION);
   
-  pointer_type = gsk_sl_pointer_type_new (type, TRUE, 
decoration->values[GSK_SL_DECORATION_CALLER_ACCESS].value);
-  token = gsk_sl_preprocessor_get (stream);
-  if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
-    {
-      declaration->variable = gsk_sl_variable_new (pointer_type, NULL, 
decoration->values[GSK_SL_DECORATION_CONST].set);
-      gsk_sl_pointer_type_unref (pointer_type);
-      return (GskSlNode *) declaration;
-    }
-
-  declaration->variable = gsk_sl_variable_new (pointer_type, token->str, 
decoration->values[GSK_SL_DECORATION_CONST].set);
-  gsk_sl_preprocessor_consume (stream, (GskSlNode *) declaration);
-  gsk_sl_pointer_type_unref (pointer_type);
-
   token = gsk_sl_preprocessor_get (stream);
-  if (gsk_sl_token_is (token, GSK_SL_TOKEN_EQUAL))
+  if (gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
     {
+      name = g_strdup (token->str);
       gsk_sl_preprocessor_consume (stream, (GskSlNode *) declaration);
-      declaration->initial = gsk_sl_expression_parse_assignment (scope, stream);
-      if (!gsk_sl_type_can_convert (type, gsk_sl_expression_get_return_type (declaration->initial)))
+
+      token = gsk_sl_preprocessor_get (stream);
+      if (gsk_sl_token_is (token, GSK_SL_TOKEN_EQUAL))
         {
-          gsk_sl_preprocessor_error (stream, "Cannot convert from initializer type %s to variable type %s",
-                                             gsk_sl_type_get_name (gsk_sl_expression_get_return_type 
(declaration->initial)),
-                                             gsk_sl_type_get_name (type));
-          gsk_sl_node_unref ((GskSlNode *) declaration);
-          return NULL;
+          GskSlValue *unconverted;
+
+          gsk_sl_preprocessor_consume (stream, (GskSlNode *) declaration);
+          declaration->initial = gsk_sl_expression_parse_assignment (scope, stream);
+          if (!gsk_sl_type_can_convert (type, gsk_sl_expression_get_return_type (declaration->initial)))
+            {
+              gsk_sl_preprocessor_error (stream, "Cannot convert from initializer type %s to variable type 
%s",
+                                                 gsk_sl_type_get_name (gsk_sl_expression_get_return_type 
(declaration->initial)),
+                                                 gsk_sl_type_get_name (type));
+              gsk_sl_node_unref ((GskSlNode *) declaration);
+              return NULL;
+            }
+
+          unconverted = gsk_sl_expression_get_constant (declaration->initial);
+          if (unconverted)
+            {
+              value = gsk_sl_value_new_convert (unconverted, type);
+              gsk_sl_value_free (unconverted);
+            }
         }
     }
+  else
+    {
+      name = NULL;
+      value = NULL;
+    }
 
+  pointer_type = gsk_sl_pointer_type_new (type, TRUE, 
decoration->values[GSK_SL_DECORATION_CALLER_ACCESS].value);
+  declaration->variable = gsk_sl_variable_new (pointer_type, name, value, 
decoration->values[GSK_SL_DECORATION_CONST].set);
+  gsk_sl_pointer_type_unref (pointer_type);
   gsk_sl_scope_add_variable (scope, declaration->variable);
 
   return (GskSlNode *) declaration;
diff --git a/gsk/gskslprogram.c b/gsk/gskslprogram.c
index a0f405a..9845433 100644
--- a/gsk/gskslprogram.c
+++ b/gsk/gskslprogram.c
@@ -84,7 +84,7 @@ gsk_sl_program_parse_variable (GskSlProgram      *program,
   gsk_sl_preprocessor_consume (preproc, NULL);
 
   pointer_type = gsk_sl_pointer_type_new (type, FALSE, 
decoration->values[GSK_SL_DECORATION_CALLER_ACCESS].value);
-  variable = gsk_sl_variable_new (pointer_type, name, decoration->values[GSK_SL_DECORATION_CONST].set);
+  variable = gsk_sl_variable_new (pointer_type, g_strdup (name), NULL, 
decoration->values[GSK_SL_DECORATION_CONST].set);
   gsk_sl_pointer_type_unref (pointer_type);
       
   program->variables = g_slist_append (program->variables, variable);
@@ -121,7 +121,7 @@ gsk_sl_program_parse_declaration (GskSlProgram      *program,
       if (success)
         {
           GskSlPointerType *ptype = gsk_sl_pointer_type_new (type, FALSE, 
decoration.values[GSK_SL_DECORATION_CALLER_ACCESS].value);
-          GskSlVariable *variable = gsk_sl_variable_new (ptype, NULL, 
decoration.values[GSK_SL_DECORATION_CONST].set);
+          GskSlVariable *variable = gsk_sl_variable_new (ptype, NULL, NULL, 
decoration.values[GSK_SL_DECORATION_CONST].set);
           gsk_sl_pointer_type_unref (ptype);
           program->variables = g_slist_append (program->variables, variable);
           gsk_sl_preprocessor_consume (preproc, program);
@@ -159,6 +159,8 @@ gsk_sl_program_parse_declaration (GskSlProgram      *program,
       success &= gsk_sl_program_parse_variable (program, scope, preproc, &decoration, type, name);
     }
 
+  g_free (name);
+
   return success;
 }
 
diff --git a/gsk/gsksltype.c b/gsk/gsksltype.c
index fe927db..9510557 100644
--- a/gsk/gsksltype.c
+++ b/gsk/gsksltype.c
@@ -216,19 +216,100 @@ write_bool_spv (GskSpvWriter  *writer,
   return result_id;
 }
 
+#define SIMPLE_CONVERSION(source_name, target_name, source_type, target_type) \
+static void \
+source_name ## _to_ ## target_name (gpointer target, gconstpointer source) \
+{ \
+  *(target_type *) target = *(const source_type *) source; \
+}
+
+SIMPLE_CONVERSION(float, float, float, float);
+SIMPLE_CONVERSION(float, double, float, double);
+SIMPLE_CONVERSION(float, int, float, gint32);
+SIMPLE_CONVERSION(float, uint, float, guint32);
+static void
+float_to_bool (gpointer target, gconstpointer source)
+{
+  *(guint32 *) target = *(const float *) source ? TRUE : FALSE;
+}
+
+SIMPLE_CONVERSION(double, float, double, float);
+SIMPLE_CONVERSION(double, double, double, double);
+SIMPLE_CONVERSION(double, int, double, gint32);
+SIMPLE_CONVERSION(double, uint, double, guint32);
+static void
+double_to_bool (gpointer target, gconstpointer source)
+{
+  *(guint32 *) target = *(const double *) source ? TRUE : FALSE;
+}
+
+SIMPLE_CONVERSION(int, float, gint32, float);
+SIMPLE_CONVERSION(int, double, gint32, double);
+SIMPLE_CONVERSION(int, int, gint32, gint32);
+SIMPLE_CONVERSION(int, uint, gint32, guint32);
+static void
+int_to_bool (gpointer target, gconstpointer source)
+{
+  *(guint32 *) target = *(const gint32 *) source ? TRUE : FALSE;
+}
+
+SIMPLE_CONVERSION(uint, float, guint32, float);
+SIMPLE_CONVERSION(uint, double, guint32, double);
+SIMPLE_CONVERSION(uint, int, guint32, gint32);
+SIMPLE_CONVERSION(uint, uint, guint32, guint32);
+static void
+uint_to_bool (gpointer target, gconstpointer source)
+{
+  *(guint32 *) target = *(const guint32 *) source ? TRUE : FALSE;
+}
+
+static void
+bool_to_float (gpointer target, gconstpointer source)
+{
+  *(float *) target = *(const guint32 *) source ? 1.0 : 0.0;
+}
+
+static void
+bool_to_double (gpointer target, gconstpointer source)
+{
+  *(double *) target = *(const guint32 *) source ? 1.0 : 0.0;
+}
+
+static void
+bool_to_int (gpointer target, gconstpointer source)
+{
+  *(gint32 *) target = *(const guint32 *) source ? 1 : 0;
+}
+
+static void
+bool_to_uint (gpointer target, gconstpointer source)
+{
+  *(guint32 *) target = *(const guint32 *) source ? 1 : 0;
+}
+
+static void
+bool_to_bool (gpointer target, gconstpointer source)
+{
+  *(guint32 *) target = *(const guint32 *) source;
+}
+
+#define CONVERSIONS(name) { NULL, name ## _to_float, name ## _to_double, name ## _to_int, name ## _to_uint, 
name ## _to_bool }
 struct {
   const char *name;
   gsize size;
   void (* print_value) (GString *string, gconstpointer value);
+  void (* convert_value[N_SCALAR_TYPES]) (gpointer target, gconstpointer source);
   guint32 (* write_value_spv) (GskSpvWriter *writer, gconstpointer value);
 } scalar_infos[] = {
-  [GSK_SL_VOID] =   { "void",   0, print_void,   write_void_spv, },
-  [GSK_SL_FLOAT] =  { "float",  4, print_float,  write_float_spv },
-  [GSK_SL_DOUBLE] = { "double", 8, print_double, write_double_spv },
-  [GSK_SL_INT] =    { "int",    4, print_int,    write_int_spv },
-  [GSK_SL_UINT] =   { "uint",   4, print_uint,   write_uint_spv },
-  [GSK_SL_BOOL] =   { "bool",   4, print_bool,   write_bool_spv }
+  [GSK_SL_VOID] =   { "void",   0, print_void,   { NULL, },            write_void_spv, },
+  [GSK_SL_FLOAT] =  { "float",  4, print_float,  CONVERSIONS (float),  write_float_spv },
+  [GSK_SL_DOUBLE] = { "double", 8, print_double, CONVERSIONS (double), write_double_spv },
+  [GSK_SL_INT] =    { "int",    4, print_int,    CONVERSIONS (int),    write_int_spv },
+  [GSK_SL_UINT] =   { "uint",   4, print_uint,   CONVERSIONS (uint),   write_uint_spv },
+  [GSK_SL_BOOL] =   { "bool",   4, print_bool,   CONVERSIONS (bool),   write_bool_spv }
 };
+#undef SIMPLE_CONVERSION
+#undef CONVERSIONS
 
 /* SCALAR */
 
@@ -1081,6 +1162,15 @@ gsk_sl_scalar_type_can_convert (GskSlScalarType target,
   }
 }
 
+void
+gsk_sl_scalar_type_convert_value (GskSlScalarType target_type,
+                                  gpointer        target_value,
+                                  GskSlScalarType source_type,
+                                  gconstpointer   source_value)
+{
+  scalar_infos[source_type].convert_value[target_type] (target_value, source_value);
+}
+
 gboolean
 gsk_sl_type_can_convert (const GskSlType *target,
                          const GskSlType *source)
diff --git a/gsk/gsksltypeprivate.h b/gsk/gsksltypeprivate.h
index 309133f..efb8f85 100644
--- a/gsk/gsksltypeprivate.h
+++ b/gsk/gsksltypeprivate.h
@@ -72,6 +72,10 @@ void                    gsk_sl_type_print_value                 (const GskSlType
 guint32                 gsk_sl_type_write_value_spv             (GskSlType           *type,
                                                                  GskSpvWriter        *writer,
                                                                  gconstpointer        value);
+void                    gsk_sl_scalar_type_convert_value        (GskSlScalarType      target_type,
+                                                                 gpointer             target_value,
+                                                                 GskSlScalarType      source_type,
+                                                                 gconstpointer        source_value);
 
 G_END_DECLS
 
diff --git a/gsk/gskslvalue.c b/gsk/gskslvalue.c
index c70a438..ff52e3f 100644
--- a/gsk/gskslvalue.c
+++ b/gsk/gskslvalue.c
@@ -64,6 +64,100 @@ gsk_sl_value_new_for_data (GskSlType      *type,
   return value;
 }
 
+/**
+ * gsk_sl_value_new_convert:
+ * @source: value to convert
+ * @new_type: type to convert to
+ *
+ * Converts @source into the @new_type. This function uses the extended
+ * conversion rules for constructors. If you want to restrict yourself
+ * to the usual conversion rules, call this function after checking
+ * for compatibility via gsk_sl_type_can_convert().
+ *
+ * Returns: a new value containing the converted @source or %NULL
+ *     if the source cannot be converted to @type.
+ **/
+GskSlValue *
+gsk_sl_value_new_convert (GskSlValue *source,
+                          GskSlType  *new_type)
+{
+  GskSlValue *result;
+
+  if (gsk_sl_type_equal (source->type, new_type))
+    {
+      return gsk_sl_value_copy (source);
+    }
+  else if (gsk_sl_type_is_scalar (source->type))
+    {
+      if (!gsk_sl_type_is_scalar (new_type))
+        return NULL;
+
+      result = gsk_sl_value_new (new_type);
+      gsk_sl_scalar_type_convert_value (gsk_sl_type_get_scalar_type (new_type),
+                                        result->data,
+                                        gsk_sl_type_get_scalar_type (source->type),
+                                        source->data);
+      return result;
+    }
+  else if (gsk_sl_type_is_vector (source->type))
+    {
+      guchar *sdata, *ddata;
+      gsize sstride, dstride;
+      guint i, n;
+
+      if (!gsk_sl_type_is_vector (new_type) || 
+          gsk_sl_type_get_length (new_type) != gsk_sl_type_get_length (source->type))
+        return NULL;
+
+      n = gsk_sl_type_get_length (new_type);
+      result = gsk_sl_value_new (new_type);
+      sdata = source->data;
+      ddata = result->data;
+      sstride = gsk_sl_type_get_size (source->type) / n;
+      dstride = gsk_sl_type_get_size (new_type) / n;
+      for (i = 0; i < n; i++)
+        {
+          gsk_sl_scalar_type_convert_value (gsk_sl_type_get_scalar_type (new_type),
+                                            ddata + i * dstride,
+                                            gsk_sl_type_get_scalar_type (source->type),
+                                            sdata + i * sstride);
+        }
+
+      return result;
+    }
+  else if (gsk_sl_type_is_matrix (source->type))
+    {
+      guchar *sdata, *ddata;
+      gsize sstride, dstride;
+      guint i, n;
+
+      if (!gsk_sl_type_is_matrix (new_type) ||
+          gsk_sl_type_get_length (new_type) != gsk_sl_type_get_length (source->type) ||
+          gsk_sl_type_get_length (gsk_sl_type_get_index_type (new_type)) != gsk_sl_type_get_length 
(gsk_sl_type_get_index_type (source->type)))
+        return NULL;
+
+      n = gsk_sl_type_get_length (new_type) * gsk_sl_type_get_length (gsk_sl_type_get_index_type 
(source->type));
+      result = gsk_sl_value_new (new_type);
+      sdata = source->data;
+      ddata = result->data;
+      sstride = gsk_sl_type_get_size (source->type) / n;
+      dstride = gsk_sl_type_get_size (new_type) / n;
+      for (i = 0; i < n; i++)
+        {
+          gsk_sl_scalar_type_convert_value (gsk_sl_type_get_scalar_type (new_type),
+                                            ddata + i * dstride,
+                                            gsk_sl_type_get_scalar_type (source->type),
+                                            sdata + i * sstride);
+        }
+
+      return result;
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
 GskSlValue *
 gsk_sl_value_copy (const GskSlValue *source)
 {
diff --git a/gsk/gskslvalueprivate.h b/gsk/gskslvalueprivate.h
index a4fe651..afd81b5 100644
--- a/gsk/gskslvalueprivate.h
+++ b/gsk/gskslvalueprivate.h
@@ -28,6 +28,8 @@ GskSlValue *            gsk_sl_value_new_for_data               (GskSlType
                                                                  gpointer             data,
                                                                  GDestroyNotify       free_func,
                                                                  gpointer             user_data);
+GskSlValue *            gsk_sl_value_new_convert                (GskSlValue          *source,
+                                                                 GskSlType           *new_type);
 GskSlValue *            gsk_sl_value_copy                       (const GskSlValue    *source);
 void                    gsk_sl_value_free                       (GskSlValue          *value);
 
diff --git a/gsk/gskslvariable.c b/gsk/gskslvariable.c
index b84ccc0..9cedbc3 100644
--- a/gsk/gskslvariable.c
+++ b/gsk/gskslvariable.c
@@ -21,6 +21,8 @@
 #include "gskslvariableprivate.h"
 
 #include "gskslpointertypeprivate.h"
+#include "gsksltypeprivate.h"
+#include "gskslvalueprivate.h"
 #include "gskspvwriterprivate.h"
 
 struct _GskSlVariable {
@@ -28,21 +30,25 @@ struct _GskSlVariable {
 
   GskSlPointerType *type;
   char *name;
+  GskSlValue *initial_value;
   gboolean constant;
 };
 
 GskSlVariable *
 gsk_sl_variable_new (GskSlPointerType *type,
-                     const char       *name,
+                     char             *name,
+                     GskSlValue       *initial_value,
                      gboolean          constant)
 {
   GskSlVariable *variable;
 
+  g_return_val_if_fail (initial_value == NULL || gsk_sl_type_equal (gsk_sl_pointer_type_get_type (type), 
gsk_sl_value_get_type (initial_value)), NULL);
   variable = g_slice_new0 (GskSlVariable);
 
   variable->ref_count = 1;
   variable->type = gsk_sl_pointer_type_ref (type);
-  variable->name = g_strdup (name);
+  variable->name = name;
+  variable->initial_value = initial_value;
   variable->constant = constant;
 
   return variable;
@@ -68,6 +74,8 @@ gsk_sl_variable_unref (GskSlVariable *variable)
   if (variable->ref_count > 0)
     return;
 
+  if (variable->initial_value)
+    gsk_sl_value_free (variable->initial_value);
   gsk_sl_pointer_type_unref (variable->type);
   g_free (variable->name);
 
@@ -100,6 +108,12 @@ gsk_sl_variable_get_name (const GskSlVariable *variable)
   return variable->name;
 }
 
+const GskSlValue *
+gsk_sl_variable_get_initial_value (const GskSlVariable *variable)
+{
+  return variable->initial_value;
+}
+
 gboolean
 gsk_sl_variable_is_constant (const GskSlVariable *variable)
 {
diff --git a/gsk/gskslvariableprivate.h b/gsk/gskslvariableprivate.h
index f909d22..92f8de0 100644
--- a/gsk/gskslvariableprivate.h
+++ b/gsk/gskslvariableprivate.h
@@ -26,7 +26,8 @@
 G_BEGIN_DECLS
 
 GskSlVariable *         gsk_sl_variable_new                     (GskSlPointerType       *type,
-                                                                 const char             *name,
+                                                                 char                   *name,
+                                                                 GskSlValue             *initial_value,
                                                                  gboolean                constant);
 
 GskSlVariable *         gsk_sl_variable_ref                     (GskSlVariable          *variable);
@@ -37,6 +38,7 @@ void                    gsk_sl_variable_print                   (const GskSlVari
 
 GskSlPointerType *      gsk_sl_variable_get_type                (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);
 
 guint32                 gsk_sl_variable_write_spv               (const GskSlVariable    *variable,


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