[gtk+/wip/otte/shader: 12/150] gskslnode: Add builtin constructors
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/shader: 12/150] gskslnode: Add builtin constructors
- Date: Sat, 21 Oct 2017 02:27:11 +0000 (UTC)
commit cd3bb39e2ba91d27d4b6b501fb502e7fd767e17e
Author: Benjamin Otte <otte redhat com>
Date: Mon Sep 18 18:03:40 2017 +0200
gskslnode: Add builtin constructors
Do this by implementing function call nodes and adding GskSlFunction,
which is meant to be used for anything that is callable.
gsk/gskslfunction.c | 192 ++++++++++++++++++++++++++++++++
gsk/gskslfunctionprivate.h | 64 +++++++++++
gsk/gskslnode.c | 263 +++++++++++++++++++++++++++++++++++++++++---
gsk/gsksltypesprivate.h | 1 +
gsk/meson.build | 1 +
5 files changed, 506 insertions(+), 15 deletions(-)
---
diff --git a/gsk/gskslfunction.c b/gsk/gskslfunction.c
new file mode 100644
index 0000000..111ba6e
--- /dev/null
+++ b/gsk/gskslfunction.c
@@ -0,0 +1,192 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright © 2017 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gskslfunctionprivate.h"
+
+#include "gsksltypeprivate.h"
+
+static GskSlFunction *
+gsk_sl_function_alloc (const GskSlFunctionClass *klass,
+ gsize size)
+{
+ GskSlFunction *function;
+
+ function = g_slice_alloc0 (size);
+
+ function->class = klass;
+ function->ref_count = 1;
+
+ return function;
+}
+#define gsk_sl_function_new(_name, _klass) ((_name *) gsk_sl_function_alloc ((_klass), sizeof (_name)))
+
+/* BUILTIN CONSTRUCTOR */
+
+typedef struct _GskSlFunctionConstructor GskSlFunctionConstructor;
+
+struct _GskSlFunctionConstructor {
+ GskSlFunction parent;
+
+ GskSlType *type;
+};
+
+static void
+gsk_sl_function_constructor_free (GskSlFunction *function)
+{
+ GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function;
+
+ gsk_sl_type_unref (constructor->type);
+
+ g_slice_free (GskSlFunctionConstructor, constructor);
+}
+
+static GskSlType *
+gsk_sl_function_constructor_get_return_type (GskSlFunction *function)
+{
+ GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function;
+
+ return constructor->type;
+}
+
+static void
+gsk_sl_function_constructor_print_name (GskSlFunction *function,
+ GString *string)
+{
+ GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function;
+
+ gsk_sl_type_print (constructor->type, string);
+}
+
+
+static guint
+gsk_sl_function_builtin_get_args_by_type (const GskSlType *type)
+{
+ if (gsk_sl_type_is_scalar (type))
+ return 1;
+ else if (gsk_sl_type_is_vector (type))
+ return gsk_sl_type_get_length (type);
+ else if (gsk_sl_type_is_matrix (type))
+ return gsk_sl_type_get_length (type) * gsk_sl_function_builtin_get_args_by_type
(gsk_sl_type_get_index_type (type));
+ else
+ return 0;
+}
+
+static gboolean
+gsk_sl_function_constructor_matches (GskSlFunction *function,
+ GskSlType **arguments,
+ gsize n_arguments,
+ GError **error)
+{
+ GskSlFunctionConstructor *constructor = (GskSlFunctionConstructor *) function;
+ guint needed, provided;
+ gsize i;
+
+ if (n_arguments == 1 && gsk_sl_type_is_scalar (arguments[0]))
+ return TRUE;
+
+ needed = gsk_sl_function_builtin_get_args_by_type (constructor->type);
+
+ for (i = 0; i < n_arguments; i++)
+ {
+ if (needed == 0)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Too many arguments given to constructor,
only the first %"G_GSIZE_FORMAT" are necessary.", i);
+ return FALSE;
+ }
+
+ provided = gsk_sl_function_builtin_get_args_by_type (arguments[i]);
+ if (provided == 0)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "Invalid type for constructor in argument
%"G_GSIZE_FORMAT, i + 1);
+ return FALSE;
+ }
+
+ needed -= MIN (needed, provided);
+ }
+
+ return TRUE;
+}
+
+static const GskSlFunctionClass GSK_SL_FUNCTION_CONSTRUCTOR = {
+ gsk_sl_function_constructor_free,
+ gsk_sl_function_constructor_get_return_type,
+ gsk_sl_function_constructor_print_name,
+ gsk_sl_function_constructor_matches,
+};
+
+/* API */
+
+GskSlFunction *
+gsk_sl_function_new_constructor (GskSlType *type)
+{
+ GskSlFunctionConstructor *constructor;
+
+ constructor = gsk_sl_function_new (GskSlFunctionConstructor, &GSK_SL_FUNCTION_CONSTRUCTOR);
+
+ constructor->type = gsk_sl_type_ref (type);
+
+ return &constructor->parent;
+}
+
+GskSlFunction *
+gsk_sl_function_ref (GskSlFunction *function)
+{
+ g_return_val_if_fail (function != NULL, NULL);
+
+ function->ref_count += 1;
+
+ return function;
+}
+
+void
+gsk_sl_function_unref (GskSlFunction *function)
+{
+ if (function == NULL)
+ return;
+
+ function->ref_count -= 1;
+ if (function->ref_count > 0)
+ return;
+
+ function->class->free (function);
+}
+
+GskSlType *
+gsk_sl_function_get_return_type (GskSlFunction *function)
+{
+ return function->class->get_return_type (function);
+}
+
+void
+gsk_sl_function_print_name (GskSlFunction *function,
+ GString *string)
+{
+ function->class->print_name (function, string);
+}
+
+gboolean
+gsk_sl_function_matches (GskSlFunction *function,
+ GskSlType **arguments,
+ gsize n_arguments,
+ GError **error)
+{
+ return function->class->matches (function, arguments, n_arguments, error);
+}
+
diff --git a/gsk/gskslfunctionprivate.h b/gsk/gskslfunctionprivate.h
new file mode 100644
index 0000000..7005fd9
--- /dev/null
+++ b/gsk/gskslfunctionprivate.h
@@ -0,0 +1,64 @@
+/* GTK - The GIMP Toolkit
+ *
+ * Copyright © 2017 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GSK_SL_FUNCTION_PRIVATE_H__
+#define __GSK_SL_FUNCTION_PRIVATE_H__
+
+#include <glib.h>
+
+#include "gsksltypesprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskSlFunctionClass GskSlFunctionClass;
+
+struct _GskSlFunction
+{
+ const GskSlFunctionClass *class;
+
+ int ref_count;
+};
+
+struct _GskSlFunctionClass {
+ void (* free) (GskSlFunction *function);
+
+ GskSlType * (* get_return_type) (GskSlFunction *function);
+ void (* print_name) (GskSlFunction *function,
+ GString *string);
+ gboolean (* matches) (GskSlFunction *function,
+ GskSlType **arguments,
+ gsize n_arguments,
+ GError **error);
+};
+
+GskSlFunction * gsk_sl_function_new_constructor (GskSlType *type);
+
+GskSlFunction * gsk_sl_function_ref (GskSlFunction *function);
+void gsk_sl_function_unref (GskSlFunction *function);
+
+void gsk_sl_function_print_name (GskSlFunction *function,
+ GString *string);
+GskSlType * gsk_sl_function_get_return_type (GskSlFunction *function);
+gboolean gsk_sl_function_matches (GskSlFunction *function,
+ GskSlType **arguments,
+ gsize n_arguments,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GSK_SL_FUNCTION_PRIVATE_H__ */
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index 7eb8384..24e484d 100644
--- a/gsk/gskslnode.c
+++ b/gsk/gskslnode.c
@@ -21,6 +21,7 @@
#include "gskslnodeprivate.h"
#include "gskslpreprocessorprivate.h"
+#include "gskslfunctionprivate.h"
#include "gskslscopeprivate.h"
#include "gsksltokenizerprivate.h"
#include "gsksltypeprivate.h"
@@ -77,7 +78,11 @@ gsk_sl_node_program_print (GskSlNode *node,
gsk_sl_node_print (l->data, string);
for (l = program->functions; l; l = l->next)
- gsk_sl_node_print (l->data, string);
+ {
+ if (l != program->functions || program->declarations != NULL)
+ g_string_append (string, "\n");
+ gsk_sl_node_print (l->data, string);
+ }
}
static GskSlType *
@@ -832,6 +837,76 @@ static const GskSlNodeClass GSK_SL_NODE_REFERENCE = {
gsk_sl_node_reference_is_constant
};
+/* FUNCTION_CALL */
+
+typedef struct _GskSlNodeFunctionCall GskSlNodeFunctionCall;
+
+struct _GskSlNodeFunctionCall {
+ GskSlNode parent;
+
+ GskSlFunction *function;
+ GskSlNode **arguments;
+ guint n_arguments;
+};
+
+static void
+gsk_sl_node_function_call_free (GskSlNode *node)
+{
+ GskSlNodeFunctionCall *function_call = (GskSlNodeFunctionCall *) node;
+ guint i;
+
+ for (i = 0; i < function_call->n_arguments; i++)
+ {
+ gsk_sl_node_unref (function_call->arguments[i]);
+ }
+ g_free (function_call->arguments);
+
+ gsk_sl_function_unref (function_call->function);
+
+ g_slice_free (GskSlNodeFunctionCall, function_call);
+}
+
+static void
+gsk_sl_node_function_call_print (GskSlNode *node,
+ GString *string)
+{
+ GskSlNodeFunctionCall *function_call = (GskSlNodeFunctionCall *) node;
+ guint i;
+
+ gsk_sl_function_print_name (function_call->function, string);
+ g_string_append (string, " (");
+
+ for (i = 0; i < function_call->n_arguments; i++)
+ {
+ if (i > 0)
+ g_string_append (string, ", ");
+ gsk_sl_node_print (function_call->arguments[i], string);
+ }
+
+ g_string_append (string, ")");
+}
+
+static GskSlType *
+gsk_sl_node_function_call_get_return_type (GskSlNode *node)
+{
+ GskSlNodeFunctionCall *function_call = (GskSlNodeFunctionCall *) node;
+
+ return gsk_sl_function_get_return_type (function_call->function);
+}
+
+static gboolean
+gsk_sl_node_function_call_is_constant (GskSlNode *node)
+{
+ return FALSE;
+}
+
+static const GskSlNodeClass GSK_SL_NODE_FUNCTION_CALL = {
+ gsk_sl_node_function_call_free,
+ gsk_sl_node_function_call_print,
+ gsk_sl_node_function_call_get_return_type,
+ gsk_sl_node_function_call_is_constant
+};
+
/* CONSTANT */
typedef struct _GskSlNodeConstant GskSlNodeConstant;
@@ -970,6 +1045,89 @@ gsk_sl_node_parse_function_prototype (GskSlNodeProgram *program,
}
static GskSlNode *
+gsk_sl_node_parse_assignment_expression (GskSlNodeProgram *program,
+ GskSlScope *scope,
+ GskSlPreprocessor *stream);
+
+static GskSlNode *
+gsk_sl_node_parse_constructor_call (GskSlNodeProgram *program,
+ GskSlScope *scope,
+ GskSlPreprocessor *stream,
+ GskSlType *type)
+{
+ GskSlNodeFunctionCall *call;
+ const GskSlToken *token;
+ GskSlType **types;
+ GError *error = NULL;
+ gboolean fail = FALSE;
+ guint i;
+
+ call = gsk_sl_node_new (GskSlNodeFunctionCall, &GSK_SL_NODE_FUNCTION_CALL);
+ call->function = gsk_sl_function_new_constructor (type);
+ g_assert (call->function);
+
+ token = gsk_sl_preprocessor_get (stream);
+ if (!gsk_sl_token_is (token, GSK_SL_TOKEN_LEFT_PAREN))
+ {
+ gsk_sl_preprocessor_error (stream, "Expected opening \"(\" when calling constructor");
+ gsk_sl_node_unref ((GskSlNode *) call);
+ return NULL;
+ }
+ gsk_sl_preprocessor_consume (stream, (GskSlNode *) call);
+
+ token = gsk_sl_preprocessor_get (stream);
+ if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
+ {
+ GPtrArray *arguments;
+
+ arguments = g_ptr_array_new ();
+ while (TRUE)
+ {
+ GskSlNode *node = gsk_sl_node_parse_assignment_expression (program, scope, stream);
+
+ if (node != NULL)
+ g_ptr_array_add (arguments, node);
+ else
+ fail = TRUE;
+
+ token = gsk_sl_preprocessor_get (stream);
+ if (!gsk_sl_token_is (token, GSK_SL_TOKEN_COMMA))
+ break;
+ gsk_sl_preprocessor_consume (stream, (GskSlNode *) call);
+ }
+
+ call->n_arguments = arguments->len;
+ call->arguments = (GskSlNode **) g_ptr_array_free (arguments, FALSE);
+ }
+
+ types = g_newa (GskSlType *, call->n_arguments);
+ for (i = 0; i < call->n_arguments; i++)
+ types[i] = gsk_sl_node_get_return_type (call->arguments[i]);
+ if (!gsk_sl_function_matches (call->function, types, call->n_arguments, &error))
+ {
+ gsk_sl_preprocessor_error (stream, "%s", error->message);
+ g_clear_error (&error);
+ fail = TRUE;
+ }
+
+ if (!gsk_sl_token_is (token, GSK_SL_TOKEN_RIGHT_PAREN))
+ {
+ gsk_sl_preprocessor_error (stream, "Expected closing \")\" after arguments.");
+ gsk_sl_node_unref ((GskSlNode *) call);
+ return NULL;
+ }
+ gsk_sl_preprocessor_consume (stream, (GskSlNode *) call);
+
+ if (fail)
+ {
+ gsk_sl_node_unref ((GskSlNode *) call);
+ return NULL;
+ }
+
+ return (GskSlNode *) call;
+}
+
+static GskSlNode *
gsk_sl_node_parse_primary_expression (GskSlNodeProgram *program,
GskSlScope *scope,
GskSlPreprocessor *stream)
@@ -1035,6 +1193,61 @@ gsk_sl_node_parse_primary_expression (GskSlNodeProgram *program,
gsk_sl_preprocessor_consume (stream, (GskSlNode *) constant);
return (GskSlNode *) constant;
+ case GSK_SL_TOKEN_VOID:
+ case GSK_SL_TOKEN_FLOAT:
+ case GSK_SL_TOKEN_DOUBLE:
+ case GSK_SL_TOKEN_INT:
+ case GSK_SL_TOKEN_UINT:
+ case GSK_SL_TOKEN_BOOL:
+ case GSK_SL_TOKEN_BVEC2:
+ case GSK_SL_TOKEN_BVEC3:
+ case GSK_SL_TOKEN_BVEC4:
+ case GSK_SL_TOKEN_IVEC2:
+ case GSK_SL_TOKEN_IVEC3:
+ case GSK_SL_TOKEN_IVEC4:
+ case GSK_SL_TOKEN_UVEC2:
+ case GSK_SL_TOKEN_UVEC3:
+ case GSK_SL_TOKEN_UVEC4:
+ case GSK_SL_TOKEN_VEC2:
+ case GSK_SL_TOKEN_VEC3:
+ case GSK_SL_TOKEN_VEC4:
+ case GSK_SL_TOKEN_DVEC2:
+ case GSK_SL_TOKEN_DVEC3:
+ case GSK_SL_TOKEN_DVEC4:
+ case GSK_SL_TOKEN_MAT2:
+ case GSK_SL_TOKEN_MAT3:
+ case GSK_SL_TOKEN_MAT4:
+ case GSK_SL_TOKEN_DMAT2:
+ case GSK_SL_TOKEN_DMAT3:
+ case GSK_SL_TOKEN_DMAT4:
+ case GSK_SL_TOKEN_MAT2X2:
+ case GSK_SL_TOKEN_MAT2X3:
+ case GSK_SL_TOKEN_MAT2X4:
+ case GSK_SL_TOKEN_MAT3X2:
+ case GSK_SL_TOKEN_MAT3X3:
+ case GSK_SL_TOKEN_MAT3X4:
+ case GSK_SL_TOKEN_MAT4X2:
+ case GSK_SL_TOKEN_MAT4X3:
+ case GSK_SL_TOKEN_MAT4X4:
+ case GSK_SL_TOKEN_DMAT2X2:
+ case GSK_SL_TOKEN_DMAT2X3:
+ case GSK_SL_TOKEN_DMAT2X4:
+ case GSK_SL_TOKEN_DMAT3X2:
+ case GSK_SL_TOKEN_DMAT3X3:
+ case GSK_SL_TOKEN_DMAT3X4:
+ case GSK_SL_TOKEN_DMAT4X2:
+ case GSK_SL_TOKEN_DMAT4X3:
+ case GSK_SL_TOKEN_DMAT4X4:
+ {
+ GskSlType *type;
+
+ type = gsk_sl_type_new_parse (stream);
+ if (type == NULL)
+ return NULL;
+
+ return gsk_sl_node_parse_constructor_call (program, scope, stream, type);
+ }
+
default:
gsk_sl_preprocessor_error (stream, "Expected an expression.");
gsk_sl_preprocessor_consume (stream, (GskSlNode *) program);
@@ -1043,11 +1256,19 @@ gsk_sl_node_parse_primary_expression (GskSlNodeProgram *program,
}
static GskSlNode *
+gsk_sl_node_parse_postfix_expression (GskSlNodeProgram *program,
+ GskSlScope *scope,
+ GskSlPreprocessor *stream)
+{
+ return gsk_sl_node_parse_primary_expression (program, scope, stream);
+}
+
+static GskSlNode *
gsk_sl_node_parse_unary_expression (GskSlNodeProgram *program,
GskSlScope *scope,
GskSlPreprocessor *stream)
{
- return gsk_sl_node_parse_primary_expression (program, scope, stream);
+ return gsk_sl_node_parse_postfix_expression (program, scope, stream);
}
static GskSlNode *
@@ -1693,18 +1914,14 @@ gsk_sl_node_parse_expression (GskSlNodeProgram *program,
static GskSlNode *
gsk_sl_node_parse_declaration (GskSlNodeProgram *program,
GskSlScope *scope,
- GskSlPreprocessor *stream)
+ GskSlPreprocessor *stream,
+ GskSlType *type)
{
GskSlNodeDeclaration *declaration;
const GskSlToken *token;
- GskSlType *type;
-
- type = gsk_sl_type_new_parse (stream);
- if (type == NULL)
- return FALSE;
declaration = gsk_sl_node_new (GskSlNodeDeclaration, &GSK_SL_NODE_DECLARATION);
- declaration->type = type;
+ declaration->type = gsk_sl_type_ref (type);
token = gsk_sl_preprocessor_get (stream);
if (!gsk_sl_token_is (token, GSK_SL_TOKEN_IDENTIFIER))
@@ -1817,11 +2034,27 @@ gsk_sl_node_parse_function_definition (GskSlNodeProgram *program,
case GSK_SL_TOKEN_DMAT4X2:
case GSK_SL_TOKEN_DMAT4X3:
case GSK_SL_TOKEN_DMAT4X4:
- node = gsk_sl_node_parse_declaration (program, function->scope, stream);
- if (node)
- {
- function->statements = g_slist_append (function->statements, node);
- }
+ {
+ GskSlType *type;
+
+ type = gsk_sl_type_new_parse (stream);
+ if (type == NULL)
+ return FALSE;
+
+ token = gsk_sl_preprocessor_get (stream);
+
+ if (token->type == GSK_SL_TOKEN_LEFT_BRACE)
+ node = gsk_sl_node_parse_constructor_call (program, function->scope, stream, type);
+ else
+ node = gsk_sl_node_parse_declaration (program, function->scope, stream, type);
+
+ gsk_sl_type_unref (type);
+
+ if (node)
+ {
+ function->statements = g_slist_append (function->statements, node);
+ }
+ }
break;
default:
@@ -1837,7 +2070,7 @@ gsk_sl_node_parse_function_definition (GskSlNodeProgram *program,
out:
gsk_sl_preprocessor_consume (stream, (GskSlNode *) function);
- program->functions = g_slist_prepend (program->functions, function);
+ program->functions = g_slist_append (program->functions, function);
return result;
}
diff --git a/gsk/gsksltypesprivate.h b/gsk/gsksltypesprivate.h
index c5db6a5..cfe3f5c 100644
--- a/gsk/gsksltypesprivate.h
+++ b/gsk/gsksltypesprivate.h
@@ -21,6 +21,7 @@
#include <gsk/gsktypes.h>
+typedef struct _GskSlFunction GskSlFunction;
typedef struct _GskSlNode GskSlNode;
typedef struct _GskSlPreprocessor GskSlPreprocessor;
typedef struct _GskSlScope GskSlScope;
diff --git a/gsk/meson.build b/gsk/meson.build
index 1a14a2d..2feca68 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -32,6 +32,7 @@ gsk_private_sources = files([
'gskprivate.c',
'gskprofiler.c',
'gskshaderbuilder.c',
+ 'gskslfunction.c',
'gskslnode.c',
'gskslpreprocessor.c',
'gskslscope.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]