diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c index e1452681e3..46a0150894 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 a0f405a9da..9845433dfa 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 fe927db0c5..9510557314 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 309133f64b..efb8f8539a 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 c70a438062..ff52e3fb30 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 a4fe651665..afd81b5a52 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 b84ccc0df8..9cedbc327f 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 f909d22fc4..92f8de0f25 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,