diff --git a/gsk/gskslexpression.c b/gsk/gskslexpression.c index ea99319d1f..9c9de365f0 100644 --- a/gsk/gskslexpression.c +++ b/gsk/gskslexpression.c @@ -1055,6 +1055,142 @@ static const GskSlExpressionClass GSK_SL_EXPRESSION_SWIZZLE = { gsk_sl_expression_swizzle_write_spv }; +/* NEGATION */ + +typedef struct _GskSlExpressionNegation GskSlExpressionNegation; + +struct _GskSlExpressionNegation { + GskSlExpression parent; + + GskSlExpression *expr; +}; + +static void +gsk_sl_expression_negation_free (GskSlExpression *expression) +{ + GskSlExpressionNegation *negation = (GskSlExpressionNegation *) expression; + + gsk_sl_expression_unref (negation->expr); + + g_slice_free (GskSlExpressionNegation, negation); +} + +static void +gsk_sl_expression_negation_print (const GskSlExpression *expression, + GString *string) +{ + const GskSlExpressionNegation *negation = (const GskSlExpressionNegation *) expression; + + g_string_append (string, "-"); + gsk_sl_expression_print (negation->expr, string); +} + +static GskSlType * +gsk_sl_expression_negation_get_return_type (const GskSlExpression *expression) +{ + const GskSlExpressionNegation *negation = (const GskSlExpressionNegation *) expression; + + return gsk_sl_expression_get_return_type (negation->expr); +} + +#define GSK_SL_OPERATION_FUNC(func,type,...) \ +static void \ +func (gpointer value, gpointer unused) \ +{ \ + type x = *(type *) value; \ + __VA_ARGS__ \ + *(type *) value = x; \ +} +GSK_SL_OPERATION_FUNC(gsk_sl_expression_negation_int, gint32, x = -x;) +GSK_SL_OPERATION_FUNC(gsk_sl_expression_negation_uint, guint32, x = -x;) +GSK_SL_OPERATION_FUNC(gsk_sl_expression_negation_float, float, x = -x;) +GSK_SL_OPERATION_FUNC(gsk_sl_expression_negation_double, double, x = -x;) + +static GskSlValue * +gsk_sl_expression_negation_get_constant (const GskSlExpression *expression) +{ + const GskSlExpressionNegation *negation = (const GskSlExpressionNegation *) expression; + GskSlValue *value; + + value = gsk_sl_expression_get_constant (negation->expr); + if (value == NULL) + return NULL; + + switch (gsk_sl_type_get_scalar_type (gsk_sl_value_get_type (value))) + { + case GSK_SL_INT: + gsk_sl_value_componentwise (value, gsk_sl_expression_negation_int, NULL); + break; + case GSK_SL_UINT: + gsk_sl_value_componentwise (value, gsk_sl_expression_negation_uint, NULL); + break; + case GSK_SL_FLOAT: + gsk_sl_value_componentwise (value, gsk_sl_expression_negation_float, NULL); + break; + case GSK_SL_DOUBLE: + gsk_sl_value_componentwise (value, gsk_sl_expression_negation_double, NULL); + break; + case GSK_SL_VOID: + case GSK_SL_BOOL: + default: + g_assert_not_reached (); + break; + } + + return value; +} + +static guint32 +gsk_sl_expression_negation_write_spv (const GskSlExpression *expression, + GskSpvWriter *writer) +{ + const GskSlExpressionNegation *negation = (const GskSlExpressionNegation *) expression; + guint type_id, expr_id, result_id; + GskSlType *type; + + type = gsk_sl_expression_get_return_type (negation->expr); + type_id = gsk_spv_writer_get_id_for_type (writer, type); + expr_id = gsk_sl_expression_write_spv (negation->expr, writer); + result_id = gsk_spv_writer_next_id (writer); + + switch (gsk_sl_type_get_scalar_type (type)) + { + case GSK_SL_INT: + case GSK_SL_UINT: + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 4, GSK_SPV_OP_S_NEGATE, + (guint32[3]) { type_id, + result_id, + expr_id }); + break; + case GSK_SL_FLOAT: + case GSK_SL_DOUBLE: + gsk_spv_writer_add (writer, + GSK_SPV_WRITER_SECTION_CODE, + 4, GSK_SPV_OP_F_NEGATE, + (guint32[3]) { type_id, + result_id, + expr_id }); + break; + case GSK_SL_VOID: + case GSK_SL_BOOL: + default: + g_assert_not_reached (); + break; + } + + return result_id; +} + +static const GskSlExpressionClass GSK_SL_EXPRESSION_NEGATION = { + gsk_sl_expression_negation_free, + gsk_sl_expression_negation_print, + gsk_sl_expression_negation_get_return_type, + gsk_sl_expression_negation_get_constant, + gsk_sl_expression_negation_write_spv +}; + /* CONSTANT */ typedef struct _GskSlExpressionConstant GskSlExpressionConstant; @@ -1071,6 +1207,8 @@ gsk_sl_expression_constant_free (GskSlExpression *expression) GskSlExpressionConstant *constant = (GskSlExpressionConstant *) expression; gsk_sl_value_free (constant->value); + + g_slice_free (GskSlExpressionConstant, constant); } static void @@ -1496,9 +1634,48 @@ gsk_sl_expression_parse_postfix (GskSlScope *scope, static GskSlExpression * gsk_sl_expression_parse_unary (GskSlScope *scope, - GskSlPreprocessor *stream) + GskSlPreprocessor *preproc) { - return gsk_sl_expression_parse_postfix (scope, stream); + const GskSlToken *token; + GskSlType *type; + + token = gsk_sl_preprocessor_get (preproc); + + if (gsk_sl_token_is (token, GSK_SL_TOKEN_DASH)) + { + GskSlExpressionNegation *negation = gsk_sl_expression_new (GskSlExpressionNegation, &GSK_SL_EXPRESSION_NEGATION); + GskSlExpression *expr; + + gsk_sl_preprocessor_consume (preproc, negation); + negation->expr = gsk_sl_expression_parse_unary (scope, preproc); + type = gsk_sl_expression_get_return_type (negation->expr); + if (!gsk_sl_type_is_scalar (type) && !gsk_sl_type_is_vector (type) && !gsk_sl_type_is_matrix (type)) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Negation only works on scalars, vectors and matrices, not on %s.", + gsk_sl_type_get_name (type)); + expr = gsk_sl_expression_ref (negation->expr); + gsk_sl_expression_unref ((GskSlExpression *) negation); + return expr; + } + else if (gsk_sl_type_get_scalar_type (type) == GSK_SL_BOOL) + { + gsk_sl_preprocessor_error (preproc, TYPE_MISMATCH, + "Negation does not work on boolean types like %s.", + gsk_sl_type_get_name (type)); + expr = gsk_sl_expression_ref (negation->expr); + gsk_sl_expression_unref ((GskSlExpression *) negation); + return expr; + } + else + { + return (GskSlExpression *) negation; + } + } + else + { + return gsk_sl_expression_parse_postfix (scope, preproc); + } } static GskSlExpression * diff --git a/gsk/gskslvalue.c b/gsk/gskslvalue.c index 6972ff7c72..304fafeca1 100644 --- a/gsk/gskslvalue.c +++ b/gsk/gskslvalue.c @@ -194,6 +194,25 @@ gsk_sl_value_free (GskSlValue *value) g_slice_free (GskSlValue, value); } +void +gsk_sl_value_componentwise (GskSlValue *value, + void (* func) (gpointer, gpointer), + gpointer user_data) +{ + gsize stride; + gsize i, n; + + g_return_if_fail (gsk_sl_type_is_scalar (value->type) || gsk_sl_type_is_vector (value->type) || gsk_sl_type_is_matrix (value->type)); + + stride = gsk_sl_type_get_size (gsk_sl_type_get_scalar (gsk_sl_type_get_scalar_type (value->type))); + n = gsk_sl_type_get_size (value->type) / stride; + + for (i = 0; i < n; i++) + { + func ((guchar *) value->data + stride * i, user_data); + } +} + void gsk_sl_value_print (const GskSlValue *value, GString *string) diff --git a/gsk/gskslvalueprivate.h b/gsk/gskslvalueprivate.h index c4e7c595ec..3a314a6dc7 100644 --- a/gsk/gskslvalueprivate.h +++ b/gsk/gskslvalueprivate.h @@ -35,6 +35,9 @@ GskSlValue * gsk_sl_value_new_member (GskSlValue GskSlValue * gsk_sl_value_copy (const GskSlValue *source); void gsk_sl_value_free (GskSlValue *value); +void gsk_sl_value_componentwise (GskSlValue *value, + void (* func) (gpointer, gpointer), + gpointer user_data); void gsk_sl_value_print (const GskSlValue *value, GString *string); diff --git a/gsk/gskspvwriterprivate.h b/gsk/gskspvwriterprivate.h index c0f3d5c159..81b2af1df7 100644 --- a/gsk/gskspvwriterprivate.h +++ b/gsk/gskspvwriterprivate.h @@ -119,6 +119,33 @@ typedef enum { GSK_SPV_OP_GENERIC_CAST_TO_PTR = 122, GSK_SPV_OP_GENERIC_CAST_TO_PTR_EXPLICIT = 123, GSK_SPV_OP_BITCAST = 124, + GSK_SPV_OP_S_NEGATE = 126, + GSK_SPV_OP_F_NEGATE = 127, + GSK_SPV_OP_I_ADD = 128, + GSK_SPV_OP_F_ADD = 129, + GSK_SPV_OP_I_SUB = 130, + GSK_SPV_OP_F_SUB = 131, + GSK_SPV_OP_I_MUL = 132, + GSK_SPV_OP_F_MUL = 133, + GSK_SPV_OP_U_DIV = 134, + GSK_SPV_OP_S_DIV = 135, + GSK_SPV_OP_F_DIV = 136, + GSK_SPV_OP_U_MOD = 137, + GSK_SPV_OP_S_REM = 138, + GSK_SPV_OP_S_MOD = 139, + GSK_SPV_OP_F_REM = 140, + GSK_SPV_OP_F_MOD = 141, + GSK_SPV_OP_VECTOR_TIMES_SCALAR = 142, + GSK_SPV_OP_MATRIX_TIMES_SCALAR = 143, + GSK_SPV_OP_VECTOR_TIMES_MATRIX = 144, + GSK_SPV_OP_MATRIX_TIMES_VECTOR = 145, + GSK_SPV_OP_MATRIX_TIMES_MATRIX = 146, + GSK_SPV_OP_OUTER_PRODUCT = 147, + GSK_SPV_OP_DOT = 148, + GSK_SPV_OP_I_ADD_CARRY = 149, + GSK_SPV_OP_I_SUB_BORROW = 150, + GSK_SPV_OP_U_MUL_EXTENDED = 151, + GSK_SPV_OP_S_MUL_EXTENDED = 152, GSK_SPV_OP_PHI = 245, GSK_SPV_OP_LOOP_MERGE = 246, GSK_SPV_OP_SELECTION_MERGE = 247,