[gtk+/wip/otte/shader: 89/175] gsksl: Implement skeleton SPIRV output
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/shader: 89/175] gsksl: Implement skeleton SPIRV output
- Date: Sun, 8 Oct 2017 03:38:12 +0000 (UTC)
commit 5d1a5e1a66ee4a1071c9f3486f6e9312f541431a
Author: Benjamin Otte <otte redhat com>
Date: Thu Sep 21 20:33:57 2017 +0200
gsksl: Implement skeleton SPIRV output
gsk/gskslnode.c | 398 ++++++++++++++++++++++++++++++++++-------
gsk/gskslnodeprivate.h | 7 +
gsk/gskslpointertype.c | 52 ++++++
gsk/gskslpointertypeprivate.h | 9 +
gsk/gskslpreprocessor.c | 121 ++++++++++++-
gsk/gsksltokenizer.c | 30 +++-
gsk/gsksltokenizerprivate.h | 2 +
gsk/gsksltype.c | 142 ++++++++++++++-
gsk/gsksltypeprivate.h | 7 +
gsk/gsksltypesprivate.h | 2 +
gsk/gskspvwriter.c | 241 +++++++++++++++++++++++++
gsk/gskspvwriterprivate.h | 200 +++++++++++++++++++++
gsk/meson.build | 3 +-
gtk/glsl.c | 53 +++++-
14 files changed, 1172 insertions(+), 95 deletions(-)
---
diff --git a/gsk/gskslnode.c b/gsk/gskslnode.c
index 9e04c9c..89e41ed 100644
--- a/gsk/gskslnode.c
+++ b/gsk/gskslnode.c
@@ -26,6 +26,7 @@
#include "gskslscopeprivate.h"
#include "gsksltokenizerprivate.h"
#include "gsksltypeprivate.h"
+#include "gskspvwriterprivate.h"
#include <string.h>
@@ -44,67 +45,6 @@ gsk_sl_node_alloc (const GskSlNodeClass *klass,
}
#define gsk_sl_node_new(_name, _klass) ((_name *) gsk_sl_node_alloc ((_klass), sizeof (_name)))
-/* PROGRAM */
-
-typedef struct _GskSlNodeProgram GskSlNodeProgram;
-
-struct _GskSlNodeProgram {
- GskSlNode parent;
-
- GskSlScope *scope;
- GSList *declarations;
- GSList *functions;
-};
-
-static void
-gsk_sl_node_program_free (GskSlNode *node)
-{
- GskSlNodeProgram *program = (GskSlNodeProgram *) node;
-
- g_slist_free (program->declarations);
- g_slist_free (program->functions);
- gsk_sl_scope_unref (program->scope);
-
- g_slice_free (GskSlNodeProgram, program);
-}
-
-static void
-gsk_sl_node_program_print (GskSlNode *node,
- GString *string)
-{
- GskSlNodeProgram *program = (GskSlNodeProgram *) node;
- GSList *l;
-
- for (l = program->declarations; l; l = l->next)
- gsk_sl_node_print (l->data, string);
-
- for (l = program->functions; l; l = l->next)
- {
- if (l != program->functions || program->declarations != NULL)
- g_string_append (string, "\n");
- gsk_sl_node_print (l->data, string);
- }
-}
-
-static GskSlType *
-gsk_sl_node_program_get_return_type (GskSlNode *node)
-{
- return NULL;
-}
-
-static gboolean
-gsk_sl_node_program_is_constant (GskSlNode *node)
-{
- return TRUE;
-}
-
-static const GskSlNodeClass GSK_SL_NODE_PROGRAM = {
- gsk_sl_node_program_free,
- gsk_sl_node_program_print,
- gsk_sl_node_program_get_return_type,
- gsk_sl_node_program_is_constant
-};
-
/* FUNCTION */
typedef struct _GskSlNodeFunction GskSlNodeFunction;
@@ -171,11 +111,142 @@ gsk_sl_node_function_is_constant (GskSlNode *node)
return TRUE;
}
+static guint32
+gsk_sl_node_function_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ GskSlNodeFunction *function = (GskSlNodeFunction *) node;
+ guint32 return_type_id, function_type_id, function_id, label_id;
+ GSList *l;
+
+ /* declare type of function */
+ return_type_id = gsk_spv_writer_get_id_for_type (writer, function->return_type);
+ function_type_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 3, GSK_SPV_OP_TYPE_FUNCTION,
+ (guint32[2]) { function_type_id,
+ return_type_id });
+
+ /* add debug info */
+ /* FIXME */
+
+ /* add function body */
+ function_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_CODE,
+ 5, GSK_SPV_OP_FUNCTION,
+ (guint32[4]) { return_type_id,
+ function_id,
+ 0,
+ function_type_id });
+ label_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_CODE,
+ 2, GSK_SPV_OP_LABEL,
+ (guint32[4]) { label_id });
+
+ for (l = function->statements; l; l = l->next)
+ {
+ gsk_sl_node_write_spv (l->data, writer);
+ }
+
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_CODE,
+ 1, GSK_SPV_OP_FUNCTION_END,
+ NULL);
+ return function_id;
+}
+
static const GskSlNodeClass GSK_SL_NODE_FUNCTION = {
gsk_sl_node_function_free,
gsk_sl_node_function_print,
gsk_sl_node_function_get_return_type,
- gsk_sl_node_function_is_constant
+ gsk_sl_node_function_is_constant,
+ gsk_sl_node_function_write_spv
+};
+
+/* PROGRAM */
+
+typedef struct _GskSlNodeProgram GskSlNodeProgram;
+
+struct _GskSlNodeProgram {
+ GskSlNode parent;
+
+ GskSlScope *scope;
+ GSList *declarations;
+ GSList *functions;
+};
+
+static void
+gsk_sl_node_program_free (GskSlNode *node)
+{
+ GskSlNodeProgram *program = (GskSlNodeProgram *) node;
+
+ g_slist_free (program->declarations);
+ g_slist_free (program->functions);
+ gsk_sl_scope_unref (program->scope);
+
+ g_slice_free (GskSlNodeProgram, program);
+}
+
+static void
+gsk_sl_node_program_print (GskSlNode *node,
+ GString *string)
+{
+ GskSlNodeProgram *program = (GskSlNodeProgram *) node;
+ GSList *l;
+
+ for (l = program->declarations; l; l = l->next)
+ gsk_sl_node_print (l->data, string);
+
+ for (l = program->functions; l; l = l->next)
+ {
+ if (l != program->functions || program->declarations != NULL)
+ g_string_append (string, "\n");
+ gsk_sl_node_print (l->data, string);
+ }
+}
+
+static GskSlType *
+gsk_sl_node_program_get_return_type (GskSlNode *node)
+{
+ return NULL;
+}
+
+static gboolean
+gsk_sl_node_program_is_constant (GskSlNode *node)
+{
+ return TRUE;
+}
+
+static guint32
+gsk_sl_node_program_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ GskSlNodeProgram *program = (GskSlNodeProgram *) node;
+ GSList *l;
+
+ for (l = program->declarations; l; l = l->next)
+ gsk_sl_node_write_spv (l->data, writer);
+
+ for (l = program->functions; l; l = l->next)
+ {
+ guint32 id = gsk_sl_node_write_spv (l->data, writer);
+
+ if (g_str_equal (((GskSlNodeFunction *) l->data)->name, "main"))
+ gsk_spv_writer_set_entry_point (writer, id);
+ }
+
+ return 0;
+}
+
+static const GskSlNodeClass GSK_SL_NODE_PROGRAM = {
+ gsk_sl_node_program_free,
+ gsk_sl_node_program_print,
+ gsk_sl_node_program_get_return_type,
+ gsk_sl_node_program_is_constant,
+ gsk_sl_node_program_write_spv
};
/* ASSIGNMENT */
@@ -268,11 +339,21 @@ gsk_sl_node_assignment_is_constant (GskSlNode *node)
return FALSE;
}
+static guint32
+gsk_sl_node_assignment_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ g_assert_not_reached ();
+
+ return 0;
+}
+
static const GskSlNodeClass GSK_SL_NODE_ASSIGNMENT = {
gsk_sl_node_assignment_free,
gsk_sl_node_assignment_print,
gsk_sl_node_assignment_get_return_type,
- gsk_sl_node_assignment_is_constant
+ gsk_sl_node_assignment_is_constant,
+ gsk_sl_node_assignment_write_spv
};
/* BINARY */
@@ -710,11 +791,21 @@ gsk_sl_node_operation_is_constant (GskSlNode *node)
&& gsk_sl_node_is_constant (operation->right);
}
+static guint32
+gsk_sl_node_operation_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ g_assert_not_reached ();
+
+ return 0;
+}
+
static const GskSlNodeClass GSK_SL_NODE_OPERATION = {
gsk_sl_node_operation_free,
gsk_sl_node_operation_print,
gsk_sl_node_operation_get_return_type,
- gsk_sl_node_operation_is_constant
+ gsk_sl_node_operation_is_constant,
+ gsk_sl_node_operation_write_spv
};
/* DECLARATION */
@@ -778,11 +869,41 @@ gsk_sl_node_declaration_is_constant (GskSlNode *node)
return declaration->constant;
}
+static guint32
+gsk_sl_node_declaration_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ GskSlNodeDeclaration *declaration = (GskSlNodeDeclaration *) node;
+ guint32 pointer_type_id, declaration_id;
+
+ pointer_type_id = gsk_spv_writer_get_id_for_pointer_type (writer, declaration->type);
+ declaration_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_CODE,
+ 4, GSK_SPV_OP_VARIABLE,
+ (guint32[3]) { pointer_type_id,
+ declaration_id,
+ gsk_sl_pointer_type_get_storage_class (declaration->type)});
+ gsk_spv_writer_set_id_for_declaration (writer, (GskSlNode *) node, declaration_id);
+
+ if (declaration->initial)
+ {
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_CODE,
+ 3, GSK_SPV_OP_STORE,
+ (guint32[2]) { declaration_id,
+ gsk_sl_node_write_spv (declaration->initial, writer)});
+ }
+
+ return declaration_id;
+}
+
static const GskSlNodeClass GSK_SL_NODE_DECLARATION = {
gsk_sl_node_declaration_free,
gsk_sl_node_declaration_print,
gsk_sl_node_declaration_get_return_type,
- gsk_sl_node_declaration_is_constant
+ gsk_sl_node_declaration_is_constant,
+ gsk_sl_node_declaration_write_spv
};
/* REFERENCE */
@@ -832,11 +953,32 @@ gsk_sl_node_reference_is_constant (GskSlNode *node)
return gsk_sl_node_is_constant (reference->declaration);
}
+static guint32
+gsk_sl_node_reference_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ GskSlNodeReference *reference = (GskSlNodeReference *) node;
+ guint32 declaration_id, result_id, type_id;
+
+ type_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_node_get_return_type (reference->declaration));
+ declaration_id = gsk_spv_writer_get_id_for_declaration (writer, reference->declaration);
+ result_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_CODE,
+ 4, GSK_SPV_OP_LOAD,
+ (guint32[3]) { type_id,
+ result_id,
+ declaration_id });
+
+ return result_id;
+}
+
static const GskSlNodeClass GSK_SL_NODE_REFERENCE = {
gsk_sl_node_reference_free,
gsk_sl_node_reference_print,
gsk_sl_node_reference_get_return_type,
- gsk_sl_node_reference_is_constant
+ gsk_sl_node_reference_is_constant,
+ gsk_sl_node_reference_write_spv
};
/* FUNCTION_CALL */
@@ -902,11 +1044,21 @@ gsk_sl_node_function_call_is_constant (GskSlNode *node)
return FALSE;
}
+static guint32
+gsk_sl_node_function_call_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ g_assert_not_reached ();
+
+ return 0;
+}
+
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
+ gsk_sl_node_function_call_is_constant,
+ gsk_sl_node_function_call_write_spv
};
/* RETURN */
@@ -966,11 +1118,21 @@ gsk_sl_node_return_is_constant (GskSlNode *node)
return TRUE;
}
+static guint32
+gsk_sl_node_return_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ g_assert_not_reached ();
+
+ return 0;
+}
+
static const GskSlNodeClass GSK_SL_NODE_RETURN = {
gsk_sl_node_return_free,
gsk_sl_node_return_print,
gsk_sl_node_return_get_return_type,
- gsk_sl_node_return_is_constant
+ gsk_sl_node_return_is_constant,
+ gsk_sl_node_return_write_spv
};
/* CONSTANT */
@@ -1055,11 +1217,85 @@ gsk_sl_node_constant_is_constant (GskSlNode *node)
return TRUE;
}
+static guint32
+gsk_sl_node_constant_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ GskSlNodeConstant *constant = (GskSlNodeConstant *) node;
+ guint32 type_id, result_id;
+
+ switch (constant->type)
+ {
+ case GSK_SL_FLOAT:
+ type_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_scalar (GSK_SL_FLOAT));
+ result_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 4, GSK_SPV_OP_CONSTANT,
+ (guint32[3]) { type_id,
+ result_id,
+ *(guint32 *) &constant->f });
+ break;
+
+ case GSK_SL_DOUBLE:
+ type_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_scalar (GSK_SL_DOUBLE));
+ result_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 5, GSK_SPV_OP_CONSTANT,
+ (guint32[4]) { type_id,
+ result_id,
+ *(guint32 *) &constant->d,
+ *(((guint32 *) &constant->d) + 1) });
+ break;
+
+ case GSK_SL_INT:
+ type_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_scalar (GSK_SL_INT));
+ result_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 4, GSK_SPV_OP_CONSTANT,
+ (guint32[3]) { type_id,
+ result_id,
+ constant->i32 });
+ break;
+
+ case GSK_SL_UINT:
+ type_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_scalar (GSK_SL_UINT));
+ result_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 4, GSK_SPV_OP_CONSTANT,
+ (guint32[3]) { type_id,
+ result_id,
+ constant->u32 });
+ break;
+
+ case GSK_SL_BOOL:
+ type_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_scalar (GSK_SL_BOOL));
+ result_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 3, constant->b ? GSK_SPV_OP_CONSTANT_TRUE : GSK_SPV_OP_CONSTANT_FALSE,
+ (guint32[2]) { type_id,
+ result_id });
+ break;
+
+ case GSK_SL_VOID:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return result_id;
+}
+
static const GskSlNodeClass GSK_SL_NODE_CONSTANT = {
gsk_sl_node_constant_free,
gsk_sl_node_constant_print,
gsk_sl_node_constant_get_return_type,
- gsk_sl_node_constant_is_constant
+ gsk_sl_node_constant_is_constant,
+ gsk_sl_node_constant_write_spv
};
/* API */
@@ -2277,6 +2513,22 @@ gsk_sl_node_print (GskSlNode *node,
node->class->print (node, string);
}
+GBytes *
+gsk_sl_node_compile (GskSlNode *node)
+{
+ GskSpvWriter *writer;
+ GBytes *bytes;
+
+ writer = gsk_spv_writer_new ();
+
+ gsk_sl_node_write_spv (node, writer);
+ bytes = gsk_spv_writer_write (writer);
+
+ gsk_spv_writer_unref (writer);
+
+ return bytes;
+}
+
GskSlType *
gsk_sl_node_get_return_type (GskSlNode *node)
{
@@ -2288,3 +2540,11 @@ gsk_sl_node_is_constant (GskSlNode *node)
{
return node->class->is_constant (node);
}
+
+guint32
+gsk_sl_node_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer)
+{
+ return node->class->write_spv (node, writer);
+}
+
diff --git a/gsk/gskslnodeprivate.h b/gsk/gskslnodeprivate.h
index 6df9bb6..43e7d54 100644
--- a/gsk/gskslnodeprivate.h
+++ b/gsk/gskslnodeprivate.h
@@ -39,6 +39,8 @@ struct _GskSlNodeClass {
GString *string);
GskSlType * (* get_return_type) (GskSlNode *node);
gboolean (* is_constant) (GskSlNode *node);
+ guint32 (* write_spv) (const GskSlNode *node,
+ GskSpvWriter *writer);
};
GDK_AVAILABLE_IN_3_92
@@ -52,9 +54,14 @@ void gsk_sl_node_unref (GskSlNode
GDK_AVAILABLE_IN_3_92
void gsk_sl_node_print (GskSlNode *node,
GString *string);
+GDK_AVAILABLE_IN_3_92
+GBytes * gsk_sl_node_compile (GskSlNode *node);
GskSlType * gsk_sl_node_get_return_type (GskSlNode *node);
gboolean gsk_sl_node_is_constant (GskSlNode *node);
+guint32 gsk_sl_node_write_spv (const GskSlNode *node,
+ GskSpvWriter *writer);
+
G_END_DECLS
#endif /* __GSK_SL_NODE_PRIVATE_H__ */
diff --git a/gsk/gskslpointertype.c b/gsk/gskslpointertype.c
index 07b09f2..42ca9f3 100644
--- a/gsk/gskslpointertype.c
+++ b/gsk/gskslpointertype.c
@@ -23,6 +23,7 @@
#include "gskslpreprocessorprivate.h"
#include "gsksltokenizerprivate.h"
#include "gsksltypeprivate.h"
+#include "gskspvwriterprivate.h"
struct _GskSlPointerType {
int ref_count;
@@ -384,3 +385,54 @@ gsk_sl_pointer_type_is_writeonly (const GskSlPointerType *type)
{
return type->flags & GSK_SL_POINTER_TYPE_WRITEONLY ? TRUE : FALSE;
}
+
+GskSpvStorageClass
+gsk_sl_pointer_type_get_storage_class (const GskSlPointerType *type)
+{
+ if (type->flags & GSK_SL_POINTER_TYPE_LOCAL)
+ return GSK_SPV_STORAGE_CLASS_FUNCTION;
+
+ return GSK_SPV_STORAGE_CLASS_PRIVATE;
+}
+
+gboolean
+gsk_sl_pointer_type_equal (gconstpointer a,
+ gconstpointer b)
+{
+ const GskSlPointerType *typea = a;
+ const GskSlPointerType *typeb = b;
+
+ if (!gsk_sl_type_equal (typea->type, typeb->type))
+ return FALSE;
+
+ return gsk_sl_pointer_type_get_storage_class (typea)
+ == gsk_sl_pointer_type_get_storage_class (typeb);
+}
+
+guint
+gsk_sl_pointer_type_hash (gconstpointer t)
+{
+ const GskSlPointerType *type = t;
+
+ return gsk_sl_type_hash (type->type)
+ ^ gsk_sl_pointer_type_get_storage_class (type);
+}
+
+guint32
+gsk_sl_pointer_type_write_spv (const GskSlPointerType *type,
+ GskSpvWriter *writer)
+{
+ guint32 type_id, result_id;
+
+ type_id = gsk_spv_writer_get_id_for_type (writer, type->type);
+ result_id = gsk_spv_writer_next_id (writer);
+
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 4, GSK_SPV_OP_TYPE_POINTER,
+ (guint32[3]) { result_id,
+ gsk_sl_pointer_type_get_storage_class (type),
+ type_id });
+
+ return result_id;
+}
diff --git a/gsk/gskslpointertypeprivate.h b/gsk/gskslpointertypeprivate.h
index f0b5614..cb4af80 100644
--- a/gsk/gskslpointertypeprivate.h
+++ b/gsk/gskslpointertypeprivate.h
@@ -22,6 +22,7 @@
#include <glib.h>
#include "gsksltypesprivate.h"
+#include "gskspvwriterprivate.h"
G_BEGIN_DECLS
@@ -71,6 +72,14 @@ gboolean gsk_sl_pointer_type_is_restrict (const G
gboolean gsk_sl_pointer_type_is_readonly (const GskSlPointerType *type);
gboolean gsk_sl_pointer_type_is_writeonly (const GskSlPointerType *type);
+gboolean gsk_sl_pointer_type_equal (gconstpointer a,
+ gconstpointer b);
+guint gsk_sl_pointer_type_hash (gconstpointer type);
+
+GskSpvStorageClass gsk_sl_pointer_type_get_storage_class (const GskSlPointerType *type);
+guint32 gsk_sl_pointer_type_write_spv (const GskSlPointerType *type,
+ GskSpvWriter *writer);
+
G_END_DECLS
#endif /* __GSK_SL_POINTER_TYPE_PRIVATE_H__ */
diff --git a/gsk/gskslpreprocessor.c b/gsk/gskslpreprocessor.c
index f0fb716..c633a7f 100644
--- a/gsk/gskslpreprocessor.c
+++ b/gsk/gskslpreprocessor.c
@@ -93,29 +93,132 @@ static gboolean
gsk_sl_token_is_skipped (const GskSlToken *token)
{
return gsk_sl_token_is (token, GSK_SL_TOKEN_ERROR)
+ || gsk_sl_token_is (token, GSK_SL_TOKEN_NEWLINE)
|| gsk_sl_token_is (token, GSK_SL_TOKEN_WHITESPACE)
|| gsk_sl_token_is (token, GSK_SL_TOKEN_COMMENT)
|| gsk_sl_token_is (token, GSK_SL_TOKEN_SINGLE_LINE_COMMENT);
}
-static void
-gsk_sl_token_ensure (GskSlPreprocessor *preproc)
+static gboolean
+gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc)
{
- if (!gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_EOF))
- return;
-
+ gboolean was_newline;
+
do
{
preproc->location = *gsk_sl_tokenizer_get_location (preproc->tokenizer);
+ was_newline = gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_NEWLINE);
gsk_sl_tokenizer_read_token (preproc->tokenizer, &preproc->token);
}
while (gsk_sl_token_is_skipped (&preproc->token));
+
+ return was_newline;
+}
+
+static void
+gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
+{
+ gboolean was_newline = gsk_sl_preprocessor_next_token (preproc);
+
+ /* empty # line */
+ if (was_newline)
+ return;
+
+ if (gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_IDENTIFIER))
+ {
+ if (g_str_equal (preproc->token.str, "define"))
+ {
+ gsk_sl_preprocessor_error (preproc, "Unknown preprocessor directive #define.");
+ }
+#if 0
+ else if (g_str_equal (preproc->token.str, "else"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "elif"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "endif"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "error"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "extension"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "if"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "ifdef"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "ifndef"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "line"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "pragma"))
+ {
+ }
+ else if (g_str_equal (preproc->token.str, "version"))
+ {
+ }
+#endif
+ else
+ {
+ gsk_sl_preprocessor_error (preproc, "Unknown preprocessor directive #%s.", preproc->token.str);
+ }
+ }
+ else if (gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_ELSE))
+ {
+ gsk_sl_preprocessor_error (preproc, "Unknown preprocessor directive #else.");
+ }
+ else
+ {
+ gsk_sl_preprocessor_error (preproc, "Missing identifier for preprocessor directive.");
+ }
+
+ while (!gsk_sl_preprocessor_next_token (preproc));
+}
+
+static void
+gsk_sl_preprocessor_ensure (GskSlPreprocessor *preproc)
+{
+ gboolean was_newline = FALSE;
+
+ if (!gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_EOF))
+ return;
+
+ was_newline = gsk_sl_preprocessor_next_token (preproc);
+
+ while (TRUE)
+ {
+ if (gsk_sl_token_is (&preproc->token, GSK_SL_TOKEN_HASH))
+ {
+ if (!was_newline &&
+ preproc->location.bytes != 0)
+ {
+ gsk_sl_preprocessor_error (preproc, "Unexpected \"#\" - preprocessor directives must be at
start of line.");
+ was_newline = gsk_sl_preprocessor_next_token (preproc);
+ }
+ else
+ {
+ gsk_sl_preprocessor_handle_preprocessor_directive (preproc);
+ was_newline = TRUE;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
}
const GskSlToken *
gsk_sl_preprocessor_get (GskSlPreprocessor *preproc)
{
- gsk_sl_token_ensure (preproc);
+ gsk_sl_preprocessor_ensure (preproc);
return &preproc->token;
}
@@ -123,7 +226,7 @@ gsk_sl_preprocessor_get (GskSlPreprocessor *preproc)
const GskCodeLocation *
gsk_sl_preprocessor_get_location (GskSlPreprocessor *preproc)
{
- gsk_sl_token_ensure (preproc);
+ gsk_sl_preprocessor_ensure (preproc);
return &preproc->location;
}
@@ -132,7 +235,7 @@ void
gsk_sl_preprocessor_consume (GskSlPreprocessor *preproc,
GskSlNode *consumer)
{
- gsk_sl_token_ensure (preproc);
+ gsk_sl_preprocessor_ensure (preproc);
gsk_sl_token_clear (&preproc->token);
}
@@ -152,7 +255,7 @@ gsk_sl_preprocessor_error (GskSlPreprocessor *preproc,
args);
va_end (args);
- gsk_sl_token_ensure (preproc);
+ gsk_sl_preprocessor_ensure (preproc);
gsk_sl_preprocessor_error_func (preproc->tokenizer,
TRUE,
&preproc->location,
diff --git a/gsk/gsksltokenizer.c b/gsk/gsksltokenizer.c
index fa9a071..aa9c343 100644
--- a/gsk/gsksltokenizer.c
+++ b/gsk/gsksltokenizer.c
@@ -90,6 +90,7 @@ gsk_sl_token_clear (GskSlToken *token)
case GSK_SL_TOKEN_EOF:
case GSK_SL_TOKEN_ERROR:
+ case GSK_SL_TOKEN_NEWLINE:
case GSK_SL_TOKEN_WHITESPACE:
case GSK_SL_TOKEN_COMMENT:
case GSK_SL_TOKEN_SINGLE_LINE_COMMENT:
@@ -296,6 +297,7 @@ gsk_sl_token_clear (GskSlToken *token)
case GSK_SL_TOKEN_CARET:
case GSK_SL_TOKEN_AMPERSAND:
case GSK_SL_TOKEN_QUESTION:
+ case GSK_SL_TOKEN_HASH:
case GSK_SL_TOKEN_INVARIANT:
case GSK_SL_TOKEN_PRECISE:
case GSK_SL_TOKEN_HIGH_PRECISION:
@@ -487,6 +489,7 @@ gsk_sl_token_print (const GskSlToken *token,
case GSK_SL_TOKEN_SINGLE_LINE_COMMENT:
break;
+ case GSK_SL_TOKEN_NEWLINE:
case GSK_SL_TOKEN_WHITESPACE:
g_string_append (string, " ");
break;
@@ -864,6 +867,10 @@ gsk_sl_token_print (const GskSlToken *token,
g_string_append_c (string, '?');
break;
+ case GSK_SL_TOKEN_HASH:
+ g_string_append_c (string, '#');
+ break;
+
default:
g_assert_not_reached ();
break;
@@ -979,8 +986,7 @@ is_whitespace (char c)
return c == ' '
|| c == '\t'
|| c == '\f'
- || c == '\n'
- || c == '\r';
+ || is_newline (c);
}
static inline gsize
@@ -1187,11 +1193,18 @@ static void
gsk_sl_token_reader_read_whitespace (GskSlTokenReader *reader,
GskSlToken *token)
{
- do {
- gsk_sl_token_reader_consume (reader, 1);
- } while (is_whitespace (gsk_sl_token_reader_get (reader, 0)));
+ gboolean has_newline = FALSE;
+ char c;
- gsk_sl_token_init (token, GSK_SL_TOKEN_WHITESPACE);
+ for (c = gsk_sl_token_reader_get (reader, 0);
+ is_whitespace (c);
+ c = gsk_sl_token_reader_get (reader, 0))
+ {
+ has_newline |= is_newline (c);
+ gsk_sl_token_reader_consume (reader, 1);
+ }
+
+ gsk_sl_token_init (token, has_newline ? GSK_SL_TOKEN_NEWLINE : GSK_SL_TOKEN_WHITESPACE);
}
static gboolean
@@ -1798,6 +1811,11 @@ gsk_sl_tokenizer_read_token (GskSlTokenizer *tokenizer,
gsk_sl_token_reader_consume (&reader, 1);
break;
+ case '#':
+ gsk_sl_token_init (token, GSK_SL_TOKEN_HASH);
+ gsk_sl_token_reader_consume (&reader, 1);
+ break;
+
case ',':
gsk_sl_token_init (token, GSK_SL_TOKEN_COMMA);
gsk_sl_token_reader_consume (&reader, 1);
diff --git a/gsk/gsksltokenizerprivate.h b/gsk/gsksltokenizerprivate.h
index ea769fc..ec2fc92 100644
--- a/gsk/gsksltokenizerprivate.h
+++ b/gsk/gsksltokenizerprivate.h
@@ -25,6 +25,7 @@ G_BEGIN_DECLS
typedef enum {
GSK_SL_TOKEN_EOF = 0,
GSK_SL_TOKEN_ERROR,
+ GSK_SL_TOKEN_NEWLINE,
GSK_SL_TOKEN_WHITESPACE,
GSK_SL_TOKEN_COMMENT,
GSK_SL_TOKEN_SINGLE_LINE_COMMENT,
@@ -232,6 +233,7 @@ typedef enum {
GSK_SL_TOKEN_CARET,
GSK_SL_TOKEN_AMPERSAND,
GSK_SL_TOKEN_QUESTION,
+ GSK_SL_TOKEN_HASH,
GSK_SL_TOKEN_INVARIANT,
GSK_SL_TOKEN_PRECISE,
GSK_SL_TOKEN_HIGH_PRECISION,
diff --git a/gsk/gsksltype.c b/gsk/gsksltype.c
index b295872..6259efe 100644
--- a/gsk/gsksltype.c
+++ b/gsk/gsksltype.c
@@ -22,6 +22,7 @@
#include "gsksltokenizerprivate.h"
#include "gskslpreprocessorprivate.h"
+#include "gskspvwriterprivate.h"
#include <string.h>
@@ -45,6 +46,8 @@ struct _GskSlTypeClass {
guint (* get_length) (const GskSlType *type);
gboolean (* can_convert) (const GskSlType *target,
const GskSlType *source);
+ guint32 (* write_spv) (const GskSlType *type,
+ GskSpvWriter *writer);
};
/* SCALAR */
@@ -121,13 +124,85 @@ gsk_sl_type_scalar_can_convert (const GskSlType *target,
return gsk_sl_scalar_type_can_convert (target_scalar->scalar, source_scalar->scalar);
}
+static guint32
+gsk_sl_type_scalar_write_spv (const GskSlType *type,
+ GskSpvWriter *writer)
+{
+ GskSlTypeScalar *scalar = (GskSlTypeScalar *) type;
+ guint32 result;
+
+ switch (scalar->scalar)
+ {
+ case GSK_SL_VOID:
+ result = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 2, GSK_SPV_OP_TYPE_VOID,
+ (guint32[1]) { result });
+ break;
+
+ case GSK_SL_FLOAT:
+ result = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 3, GSK_SPV_OP_TYPE_FLOAT,
+ (guint32[2]) { result,
+ 32 });
+ break;
+
+ case GSK_SL_DOUBLE:
+ result = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 3, GSK_SPV_OP_TYPE_FLOAT,
+ (guint32[2]) { result,
+ 64 });
+ break;
+
+ case GSK_SL_INT:
+ result = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 4, GSK_SPV_OP_TYPE_INT,
+ (guint32[3]) { result,
+ 32,
+ 1 });
+ break;
+
+ case GSK_SL_UINT:
+ result = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 4, GSK_SPV_OP_TYPE_INT,
+ (guint32[3]) { result,
+ 32,
+ 0 });
+ break;
+
+ case GSK_SL_BOOL:
+ result = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 2, GSK_SPV_OP_TYPE_BOOL,
+ (guint32[1]) { result });
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return result;
+}
+
static const GskSlTypeClass GSK_SL_TYPE_SCALAR = {
gsk_sl_type_scalar_free,
gsk_sl_type_scalar_get_name,
gsk_sl_type_scalar_get_scalar_type,
gsk_sl_type_scalar_get_index_type,
gsk_sl_type_scalar_get_length,
- gsk_sl_type_scalar_can_convert
+ gsk_sl_type_scalar_can_convert,
+ gsk_sl_type_scalar_write_spv
};
/* VECTOR */
@@ -196,13 +271,33 @@ gsk_sl_type_vector_can_convert (const GskSlType *target,
return gsk_sl_scalar_type_can_convert (target_vector->scalar, source_vector->scalar);
}
+static guint32
+gsk_sl_type_vector_write_spv (const GskSlType *type,
+ GskSpvWriter *writer)
+{
+ GskSlTypeVector *vector = (GskSlTypeVector *) type;
+ guint32 result_id, scalar_id;
+
+ scalar_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_scalar (vector->scalar));
+ result_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 4, GSK_SPV_OP_TYPE_VECTOR,
+ (guint32[3]) { result_id,
+ scalar_id,
+ vector->length });
+
+ return result_id;
+}
+
static const GskSlTypeClass GSK_SL_TYPE_VECTOR = {
gsk_sl_type_vector_free,
gsk_sl_type_vector_get_name,
gsk_sl_type_vector_get_scalar_type,
gsk_sl_type_vector_get_index_type,
gsk_sl_type_vector_get_length,
- gsk_sl_type_vector_can_convert
+ gsk_sl_type_vector_can_convert,
+ gsk_sl_type_vector_write_spv
};
/* MATRIX */
@@ -273,13 +368,33 @@ gsk_sl_type_matrix_can_convert (const GskSlType *target,
return gsk_sl_scalar_type_can_convert (target_matrix->scalar, source_matrix->scalar);
}
+static guint32
+gsk_sl_type_matrix_write_spv (const GskSlType *type,
+ GskSpvWriter *writer)
+{
+ GskSlTypeMatrix *matrix = (GskSlTypeMatrix *) type;
+ guint32 result_id, vector_id;
+
+ vector_id = gsk_spv_writer_get_id_for_type (writer, gsk_sl_type_get_index_type (type));
+ result_id = gsk_spv_writer_next_id (writer);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ 4, GSK_SPV_OP_TYPE_MATRIX,
+ (guint32[3]) { result_id,
+ vector_id,
+ matrix->columns });
+
+ return result_id;
+}
+
static const GskSlTypeClass GSK_SL_TYPE_MATRIX = {
gsk_sl_type_matrix_free,
gsk_sl_type_matrix_get_name,
gsk_sl_type_matrix_get_scalar_type,
gsk_sl_type_matrix_get_index_type,
gsk_sl_type_matrix_get_length,
- gsk_sl_type_matrix_can_convert
+ gsk_sl_type_matrix_can_convert,
+ gsk_sl_type_matrix_write_spv
};
GskSlType *
@@ -634,3 +749,24 @@ gsk_sl_type_can_convert (const GskSlType *target,
{
return target->class->can_convert (target, source);
}
+
+gboolean
+gsk_sl_type_equal (gconstpointer a,
+ gconstpointer b)
+{
+ return a == b;
+}
+
+guint
+gsk_sl_type_hash (gconstpointer type)
+{
+ return GPOINTER_TO_UINT (type);
+}
+
+guint32
+gsk_sl_type_write_spv (const GskSlType *type,
+ GskSpvWriter *writer)
+{
+ return type->class->write_spv (type, writer);
+}
+
diff --git a/gsk/gsksltypeprivate.h b/gsk/gsksltypeprivate.h
index 3fd84c3..bcf80e7 100644
--- a/gsk/gsksltypeprivate.h
+++ b/gsk/gsksltypeprivate.h
@@ -58,6 +58,13 @@ gboolean gsk_sl_scalar_type_can_convert (GskSlScalarType
gboolean gsk_sl_type_can_convert (const GskSlType *target,
const GskSlType *source);
+gboolean gsk_sl_type_equal (gconstpointer a,
+ gconstpointer b);
+guint gsk_sl_type_hash (gconstpointer type);
+
+guint32 gsk_sl_type_write_spv (const GskSlType *type,
+ GskSpvWriter *writer);
+
G_END_DECLS
#endif /* __GSK_SL_TYPE_PRIVATE_H__ */
diff --git a/gsk/gsksltypesprivate.h b/gsk/gsksltypesprivate.h
index d160d62..f9d82ea 100644
--- a/gsk/gsksltypesprivate.h
+++ b/gsk/gsksltypesprivate.h
@@ -29,4 +29,6 @@ typedef struct _GskSlScope GskSlScope;
typedef struct _GskSlToken GskSlToken;
typedef struct _GskSlType GskSlType;
+typedef struct _GskSpvWriter GskSpvWriter;
+
#endif /* __GSK_SL_TYPES_H__ */
diff --git a/gsk/gskspvwriter.c b/gsk/gskspvwriter.c
new file mode 100644
index 0000000..dda6402
--- /dev/null
+++ b/gsk/gskspvwriter.c
@@ -0,0 +1,241 @@
+/* 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 "gskspvwriterprivate.h"
+
+#include "gskslnodeprivate.h"
+#include "gskslpointertypeprivate.h"
+#include "gsksltypeprivate.h"
+
+struct _GskSpvWriter
+{
+ int ref_count;
+
+ guint32 last_id;
+ GArray *code[GSK_SPV_WRITER_N_SECTIONS];
+
+ guint32 entry_point;
+ GHashTable *types;
+ GHashTable *pointer_types;
+ GHashTable *declarations;
+};
+
+GskSpvWriter *
+gsk_spv_writer_new (void)
+{
+ GskSpvWriter *writer;
+ guint i;
+
+ writer = g_slice_new0 (GskSpvWriter);
+ writer->ref_count = 1;
+
+ for (i = 0; i < GSK_SPV_WRITER_N_SECTIONS; i++)
+ {
+ writer->code[i] = g_array_new (FALSE, FALSE, sizeof (guint32));
+ }
+
+ writer->types = g_hash_table_new_full (gsk_sl_type_hash, gsk_sl_type_equal,
+ (GDestroyNotify) gsk_sl_type_unref, NULL);
+ writer->pointer_types = g_hash_table_new_full (gsk_sl_pointer_type_hash, gsk_sl_pointer_type_equal,
+ (GDestroyNotify) gsk_sl_pointer_type_unref, NULL);
+ writer->declarations = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ (GDestroyNotify) gsk_sl_node_unref, NULL);
+ /* the ID 1 is reserved for the GLSL instruction set (for now) */
+ writer->last_id = 1;
+
+ return writer;
+}
+
+GskSpvWriter *
+gsk_spv_writer_ref (GskSpvWriter *writer)
+{
+ g_return_val_if_fail (writer != NULL, NULL);
+
+ writer->ref_count += 1;
+
+ return writer;
+}
+
+void
+gsk_spv_writer_unref (GskSpvWriter *writer)
+{
+ guint i;
+
+ if (writer == NULL)
+ return;
+
+ writer->ref_count -= 1;
+ if (writer->ref_count > 0)
+ return;
+
+ for (i = 0; i < GSK_SPV_WRITER_N_SECTIONS; i++)
+ {
+ g_array_free (writer->code[i], TRUE);
+ }
+
+ g_hash_table_destroy (writer->pointer_types);
+ g_hash_table_destroy (writer->types);
+ g_hash_table_destroy (writer->declarations);
+
+ g_slice_free (GskSpvWriter, writer);
+}
+
+#define STRING(s, offset) ((guint32) ((s)[offset + 0] | ((s)[offset + 1] << 8) | ((s)[offset + 2] << 16) |
((s)[offset + 3] << 24)))
+static void
+gsk_spv_writer_write_header (GskSpvWriter *writer)
+{
+ guchar instruction_set[] = "\0\0\0\0GLSL.std.450\0\0\0\0";
+
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_HEADER,
+ 2, GSK_SPV_OP_CAPABILITY,
+ (guint32[1]) { GSK_SPV_CAPABILITY_SHADER });
+ *(guint32 *) instruction_set = 1;
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_HEADER,
+ 1 + sizeof (instruction_set) / 4, GSK_SPV_OP_EXT_INST_IMPORT,
+ (guint32 *) instruction_set);
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_HEADER,
+ 3, GSK_SPV_OP_MEMORY_MODEL,
+ (guint32[2]) { GSK_SPV_ADDRESSING_LOGICAL,
+ GSK_SPV_MEMORY_GLSL450 });
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_HEADER,
+ 5, GSK_SPV_OP_ENTRY_POINT,
+ (guint32[4]) { GSK_SPV_EXECUTION_MODEL_FRAGMENT,
+ writer->entry_point,
+ STRING ("main", 0),
+ 0 });
+ gsk_spv_writer_add (writer,
+ GSK_SPV_WRITER_SECTION_HEADER,
+ 3, GSK_SPV_OP_EXECUTION_MODE,
+ (guint32[4]) { writer->entry_point,
+ GSK_SPV_EXECUTION_MODE_ORIGIN_UPPER_LEFT });
+}
+
+static void
+gsk_spv_writer_clear_header (GskSpvWriter *writer)
+{
+ g_array_set_size (writer->code[GSK_SPV_WRITER_SECTION_HEADER], 0);
+}
+
+GBytes *
+gsk_spv_writer_write (GskSpvWriter *writer)
+{
+ GArray *array;
+ gsize size;
+ guint i;
+
+ gsk_spv_writer_write_header (writer);
+
+ array = g_array_new (FALSE, FALSE, sizeof (guint32));
+
+ g_array_append_val (array, (guint32) { GSK_SPV_MAGIC_NUMBER });
+ g_array_append_val (array, (guint32) { (GSK_SPV_VERSION_MAJOR << 16) | (GSK_SPV_VERSION_MINOR << 8) });
+ g_array_append_val (array, (guint32) { GSK_SPV_GENERATOR });
+ g_array_append_val (array, (guint32) { writer->last_id + 1 });
+ g_array_append_val (array, (guint32) { 0 });
+
+ for (i = 0; i < GSK_SPV_WRITER_N_SECTIONS; i++)
+ {
+ g_array_append_vals (array, writer->code[i]->data, writer->code[i]->len);
+ }
+
+ gsk_spv_writer_clear_header (writer);
+
+ size = array->len * sizeof (guint32);
+ return g_bytes_new_take (g_array_free (array, FALSE), size);
+}
+
+guint32
+gsk_spv_writer_get_id_for_type (GskSpvWriter *writer,
+ GskSlType *type)
+{
+ guint32 result;
+
+ result = GPOINTER_TO_UINT (g_hash_table_lookup (writer->types, type));
+ if (result != 0)
+ return result;
+
+ result = gsk_sl_type_write_spv (type, writer);
+ g_hash_table_insert (writer->types, gsk_sl_type_ref (type), GUINT_TO_POINTER (result));
+ return result;
+}
+
+guint32
+gsk_spv_writer_get_id_for_pointer_type (GskSpvWriter *writer,
+ GskSlPointerType *type)
+{
+ guint32 result;
+
+ result = GPOINTER_TO_UINT (g_hash_table_lookup (writer->pointer_types, type));
+ if (result != 0)
+ return result;
+
+ result = gsk_sl_pointer_type_write_spv (type, writer);
+ g_hash_table_insert (writer->pointer_types, gsk_sl_pointer_type_ref (type), GUINT_TO_POINTER (result));
+ return result;
+}
+
+guint32
+gsk_spv_writer_get_id_for_declaration (GskSpvWriter *writer,
+ GskSlNode *node)
+{
+ return GPOINTER_TO_UINT (g_hash_table_lookup (writer->declarations, node));
+}
+
+void
+gsk_spv_writer_set_id_for_declaration (GskSpvWriter *writer,
+ GskSlNode *node,
+ guint32 id)
+{
+ g_hash_table_insert (writer->declarations, gsk_sl_node_ref (node), GUINT_TO_POINTER (id));
+}
+
+guint32
+gsk_spv_writer_next_id (GskSpvWriter *writer)
+{
+ writer->last_id++;
+
+ return writer->last_id;
+}
+
+void
+gsk_spv_writer_set_entry_point (GskSpvWriter *writer,
+ guint32 entry_point)
+{
+ writer->entry_point = entry_point;
+}
+
+void
+gsk_spv_writer_add (GskSpvWriter *writer,
+ GskSpvWriterSection section,
+ guint16 word_count,
+ guint16 opcode,
+ guint32 *words)
+{
+ guint32 word;
+
+ word = word_count << 16 | opcode;
+ g_array_append_val (writer->code[section], word);
+ g_array_append_vals (writer->code[section], words, word_count - 1);
+}
+
diff --git a/gsk/gskspvwriterprivate.h b/gsk/gskspvwriterprivate.h
new file mode 100644
index 0000000..39d561a
--- /dev/null
+++ b/gsk/gskspvwriterprivate.h
@@ -0,0 +1,200 @@
+/* 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_SPV_WRITER_PRIVATE_H__
+#define __GSK_SPV_WRITER_PRIVATE_H__
+
+#include <glib.h>
+
+#include "gsksltypesprivate.h"
+
+G_BEGIN_DECLS
+
+#define GSK_SPV_MAGIC_NUMBER 0x07230203
+#define GSK_SPV_VERSION_MAJOR 1
+#define GSK_SPV_VERSION_MINOR 0
+#define GSK_SPV_GENERATOR 0
+
+typedef enum {
+ GSK_SPV_OP_NOP = 0,
+ GSK_SPV_OP_UNDEF = 1,
+ GSK_SPV_OP_SOURCE_CONTINUED = 2,
+ GSK_SPV_OP_SOURCE = 3,
+ GSK_SPV_OP_SOURCE_EXTENSION = 4,
+ GSK_SPV_OP_NAME = 5,
+ GSK_SPV_OP_MEMBER_NAME = 6,
+ GSK_SPV_OP_STRING = 7,
+ GSK_SPV_OP_LINE = 8,
+ GSK_SPV_OP_EXTENSION = 10,
+ GSK_SPV_OP_EXT_INST_IMPORT = 11,
+ GSK_SPV_OP_EXT_INST = 12,
+ GSK_SPV_OP_MEMORY_MODEL = 14,
+ GSK_SPV_OP_ENTRY_POINT = 15,
+ GSK_SPV_OP_EXECUTION_MODE = 16,
+ GSK_SPV_OP_CAPABILITY = 17,
+ GSK_SPV_OP_TYPE_VOID = 19,
+ GSK_SPV_OP_TYPE_BOOL = 20,
+ GSK_SPV_OP_TYPE_INT = 21,
+ GSK_SPV_OP_TYPE_FLOAT = 22,
+ GSK_SPV_OP_TYPE_VECTOR = 23,
+ GSK_SPV_OP_TYPE_MATRIX = 24,
+ GSK_SPV_OP_TYPE_IMAGE = 25,
+ GSK_SPV_OP_TYPE_SAMPLER = 26,
+ GSK_SPV_OP_TYPE_SAMPLED_IMAGE = 27,
+ GSK_SPV_OP_TYPE_ARRAY = 28,
+ GSK_SPV_OP_TYPE_RUNTIME_ARRAY = 29,
+ GSK_SPV_OP_TYPE_STRUCT = 30,
+ GSK_SPV_OP_TYPE_OPAQUE = 31,
+ GSK_SPV_OP_TYPE_POINTER = 32,
+ GSK_SPV_OP_TYPE_FUNCTION = 33,
+ GSK_SPV_OP_TYPE_EVENT = 34,
+ GSK_SPV_OP_TYPE_DEVICE_EVENT = 35,
+ GSK_SPV_OP_TYPE_RESERVE_ID = 36,
+ GSK_SPV_OP_TYPE_QUEUE = 37,
+ GSK_SPV_OP_TYPE_PIPE = 38,
+ GSK_SPV_OP_TYPE_FORWARD_POINTER = 39,
+ GSK_SPV_OP_CONSTANT_TRUE = 41,
+ GSK_SPV_OP_CONSTANT_FALSE = 42,
+ GSK_SPV_OP_CONSTANT = 43,
+ GSK_SPV_OP_CONSTANT_COMPOSITE = 44,
+ GSK_SPV_OP_CONSTANT_SAMPLER = 45,
+ GSK_SPV_OP_CONSTANT_NULL = 46,
+ GSK_SPV_OP_SPEC_CONSTANT_TRUE = 48,
+ GSK_SPV_OP_SPEC_CONSTANT_FALSE = 49,
+ GSK_SPV_OP_SPEC_CONSTANT = 50,
+ GSK_SPV_OP_SPEC_CONSTANT_COMPOSITE = 51,
+ GSK_SPV_OP_SPEC_CONSTANT_OP = 52,
+ GSK_SPV_OP_FUNCTION = 54,
+ GSK_SPV_OP_FUNCTION_PARAMETER = 55,
+ GSK_SPV_OP_FUNCTION_END = 56,
+ GSK_SPV_OP_FUNCTION_CALL = 57,
+ GSK_SPV_OP_VARIABLE = 59,
+ GSK_SPV_OP_IMAGE_TEXEL_POINTER = 60,
+ GSK_SPV_OP_LOAD = 61,
+ GSK_SPV_OP_STORE = 62,
+ GSK_SPV_OP_COPY_MEMORY = 63,
+ GSK_SPV_OP_COPY_MEMORY_SIZED = 64,
+ GSK_SPV_OP_ACCESS_CHAIN = 65,
+ GSK_SPV_OP_IN_BOUNDS_ACCESS_CHAIN = 66,
+ GSK_SPV_OP_PTR_ACCESS_CHAIN = 67,
+ GSK_SPV_OP_ARRAY_LENGTH = 68,
+ GSK_SPV_OP_GENERIC_PTR_MEM_SEMANTICS = 69,
+ GSK_SPV_OP_IN_BOUNDS_PTR_ACCESS_CHAIN = 70,
+ GSK_SPV_OP_PHI = 245,
+ GSK_SPV_OP_LOOP_MERGE = 246,
+ GSK_SPV_OP_SELECTION_MERGE = 247,
+ GSK_SPV_OP_LABEL = 248,
+ GSK_SPV_OP_BRANCH = 249,
+ GSK_SPV_OP_BRANCH_CONDITIONAL = 250,
+ GSK_SPV_OP_SWITCH = 251,
+ GSK_SPV_OP_KILL = 252,
+ GSK_SPV_OP_RETURN = 253,
+ GSK_SPV_OP_RETURN_VALUE = 254,
+ GSK_SPV_OP_UNREACHABLE = 255,
+ GSK_SPV_OP_LIFETIME_START = 256,
+ GSK_SPV_OP_LIFETIME_STOP = 257,
+ GSK_SPV_OP_SIZE_OF = 321,
+ GSK_SPV_OP_TYPE_PIPE_STORAGE = 322,
+ GSK_SPV_OP_TYPE_NAMED_BARRIER = 327
+} GskSpvOpcode;
+
+typedef enum {
+ GSK_SPV_CAPABILITY_MATRIX = 0,
+ GSK_SPV_CAPABILITY_SHADER = 1
+} GskSpvCapability;
+
+typedef enum {
+ GSK_SPV_ADDRESSING_LOGICAL = 0,
+ GSK_SPV_ADDRESSING_PHYSICAL32 = 1,
+ GSK_SPV_ADDRESSING_PHYSICAL64 = 2,
+} GskSpvAddressingModel;
+
+typedef enum {
+ GSK_SPV_MEMORY_SIMPLE = 0,
+ GSK_SPV_MEMORY_GLSL450 = 1,
+ GSK_SPV_MEMORY_OPEN_CL = 2
+} GskSpvMemoryModel;
+
+typedef enum {
+ GSK_SPV_EXECUTION_MODEL_VERTEX = 0,
+ GSK_SPV_EXECUTION_MODEL_TESSELATION_CONTROL = 1,
+ GSK_SPV_EXECUTION_MODEL_TESSELATION_EVALUATION = 2,
+ GSK_SPV_EXECUTION_MODEL_GEOMETRY = 3,
+ GSK_SPV_EXECUTION_MODEL_FRAGMENT = 4,
+ GSK_SPV_EXECUTION_MODEL_GL_COMPUTE = 5,
+ GSK_SPV_EXECUTION_MODEL_KERNEL = 6,
+} GskSpvExecutionModel;
+
+typedef enum {
+ GSK_SPV_EXECUTION_MODE_ORIGIN_UPPER_LEFT = 7
+} GskSpvExecutionMode;
+
+typedef enum {
+ GSK_SPV_STORAGE_CLASS_UNIFORM_CONSTANT = 0,
+ GSK_SPV_STORAGE_CLASS_INPUT = 1,
+ GSK_SPV_STORAGE_CLASS_UNIFORM = 2,
+ GSK_SPV_STORAGE_CLASS_OUTPUT = 3,
+ GSK_SPV_STORAGE_CLASS_WORKGROUP = 4,
+ GSK_SPV_STORAGE_CLASS_CROSS_WORKGROUP = 5,
+ GSK_SPV_STORAGE_CLASS_PRIVATE = 6,
+ GSK_SPV_STORAGE_CLASS_FUNCTION = 7,
+ GSK_SPV_STORAGE_CLASS_GENERIC = 8,
+ GSK_SPV_STORAGE_CLASS_PUSH_CONSTANT = 9,
+ GSK_SPV_STORAGE_CLASS_ATOMIC_COUNTER = 10,
+ GSK_SPV_STORAGE_CLASS_IMAGE = 11,
+ GSK_SPV_STORAGE_CLASS_STORAGE_BUFFER = 12
+} GskSpvStorageClass;
+
+typedef enum {
+ GSK_SPV_WRITER_SECTION_HEADER,
+ GSK_SPV_WRITER_SECTION_DEBUG,
+ GSK_SPV_WRITER_SECTION_DECLARE,
+ GSK_SPV_WRITER_SECTION_CODE,
+ /* add more */
+ GSK_SPV_WRITER_N_SECTIONS
+} GskSpvWriterSection;
+
+GskSpvWriter * gsk_spv_writer_new (void);
+
+GskSpvWriter * gsk_spv_writer_ref (GskSpvWriter *writer);
+void gsk_spv_writer_unref (GskSpvWriter *writer);
+
+GBytes * gsk_spv_writer_write (GskSpvWriter *writer);
+void gsk_spv_writer_set_entry_point (GskSpvWriter *writer,
+ guint32 entry_point);
+
+guint32 gsk_spv_writer_get_id_for_type (GskSpvWriter *writer,
+ GskSlType *type);
+guint32 gsk_spv_writer_get_id_for_pointer_type (GskSpvWriter *writer,
+ GskSlPointerType *type);
+guint32 gsk_spv_writer_get_id_for_declaration (GskSpvWriter *writer,
+ GskSlNode *node);
+void gsk_spv_writer_set_id_for_declaration (GskSpvWriter *writer,
+ GskSlNode *node,
+ guint32 id);
+
+guint32 gsk_spv_writer_next_id (GskSpvWriter *writer);
+void gsk_spv_writer_add (GskSpvWriter *writer,
+ GskSpvWriterSection section,
+ guint16 word_count,
+ guint16 opcode,
+ guint32 *words);
+
+G_END_DECLS
+
+#endif /* __GSK_SPV_WRITER_PRIVATE_H__ */
diff --git a/gsk/meson.build b/gsk/meson.build
index 5b4f2ae..77fdfd5 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -38,7 +38,8 @@ gsk_private_sources = files([
'gskslpointertype.c',
'gskslscope.c',
'gsksltokenizer.c',
- 'gsksltype.c'
+ 'gsksltype.c',
+ 'gskspvwriter.c'
])
gsk_public_headers = files([
diff --git a/gtk/glsl.c b/gtk/glsl.c
index 4e7f9d1..ec5c0ee 100644
--- a/gtk/glsl.c
+++ b/gtk/glsl.c
@@ -46,7 +46,44 @@ bytes_new_from_file (const char *filename,
return g_bytes_new_take (data, length);
}
-gboolean
+static gboolean
+compile (GOutputStream *output,
+ const char *filename)
+{
+ GBytes *bytes;
+ GskSlNode *program;
+ GError *error = NULL;
+
+ bytes = bytes_new_from_file (filename, &error);
+ if (bytes == NULL)
+ {
+ g_print (error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+
+ program = gsk_sl_node_new_program (bytes, NULL);
+ g_bytes_unref (bytes);
+ if (program == NULL)
+ return FALSE;
+
+ bytes = gsk_sl_node_compile (program);
+ if (!g_output_stream_write_all (output, g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL,
NULL, &error))
+ {
+ g_print (error->message);
+ g_error_free (error);
+ g_bytes_unref (bytes);
+ gsk_sl_node_unref (program);
+ return FALSE;
+ }
+
+ g_bytes_unref (bytes);
+ gsk_sl_node_unref (program);
+
+ return TRUE;
+}
+
+static gboolean
dump (GOutputStream *output,
const char *filename)
{
@@ -64,6 +101,7 @@ dump (GOutputStream *output,
}
program = gsk_sl_node_new_program (bytes, NULL);
+ g_bytes_unref (bytes);
if (program == NULL)
return FALSE;
@@ -100,7 +138,9 @@ main (int argc, char *argv[])
GOptionContext *ctx;
char **filenames = NULL;
char *output_file = NULL;
+ gboolean print = FALSE;
const GOptionEntry entries[] = {
+ { "print", 'p', 0, G_OPTION_ARG_NONE, &print, "Print instead of compiling", NULL },
{ "output", 'o', 0, G_OPTION_ARG_FILENAME, &output_file, "Output filename", "FILE" },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, "List of input files", "FILE
[FILE...]" },
{ NULL, }
@@ -161,13 +201,12 @@ main (int argc, char *argv[])
}
}
- for (i = 0; filenames[i] != NULL; i++)
+ for (i = 0; success && filenames[i] != NULL; i++)
{
- if (!dump (output, filenames[i]))
- {
- success = FALSE;
- break;
- }
+ if (print)
+ success = dump (output, filenames[i]);
+ else
+ success = compile (output, filenames[i]);
}
if (!g_output_stream_close (output, NULL, &error))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]