[gtk+/wip/otte/shader: 132/151] gsksl: Add support for stages



commit 39baeff8e69bfb3c0c4a1391d22c445f8d51e84a
Author: Benjamin Otte <otte redhat com>
Date:   Tue Oct 17 03:04:26 2017 +0200

    gsksl: Add support for stages
    
    The stage is just passed to everywhere it's needed. The compiler does
    not keep a stage property, instead it requires passing the stage as an
    argument to every compilation.
    
    As a side effect, environment treatment has changed:
    Environments now allow creating "similar" (for lack of a better term)
    environments with different version/profile.
    We use this to pass the stage as part of the environment.

 gsk/gskenums.h                |   12 +++++++++
 gsk/gskpixelshader.c          |    2 +-
 gsk/gskslcompiler.c           |   25 ++++++++++++-------
 gsk/gskslcompiler.h           |    2 +
 gsk/gskslenvironment.c        |   23 ++++++++++++++++-
 gsk/gskslenvironmentprivate.h |    8 +++++-
 gsk/gskslpreprocessor.c       |   37 ++++++++++------------------
 gsk/gskslprogram.c            |    4 ++-
 gsk/gskspvwriter.c            |   22 +++++++++++++++-
 gsk/gskspvwriterprivate.h     |    2 +-
 gtk/glsl.c                    |   54 +++++++++++++++++++++++++++++++++++++++-
 testsuite/gsksl/test-error.c  |   24 +++++++++++++++++-
 12 files changed, 171 insertions(+), 44 deletions(-)
---
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index ddca9b2..6d53824 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -192,4 +192,16 @@ typedef enum {
   GSK_SL_PROFILE_ES,
 } GskSlProfile;
 
+/**
+ * GskSlShaderStage:
+ * @GSK_SL_SHADER_VERTEX: The vertex shader stage
+ * @GSK_SL_SHADER_FRAGMENT: The fragment shader stage
+ *
+ * The shader stage associated with a GLSL program.
+ */
+typedef enum {
+  GSK_SL_SHADER_VERTEX,
+  GSK_SL_SHADER_FRAGMENT
+} GskSlShaderStage;
+
 #endif /* __GSK_TYPES_H__ */
diff --git a/gsk/gskpixelshader.c b/gsk/gskpixelshader.c
index a0cadd5..4ec43cf 100644
--- a/gsk/gskpixelshader.c
+++ b/gsk/gskpixelshader.c
@@ -151,7 +151,7 @@ gsk_pixel_shader_new_for_data (GBytes             *source,
   g_return_val_if_fail (source != NULL, NULL);
 
   compiler = gsk_sl_compiler_new ();
-  program = gsk_sl_compiler_compile_bytes (compiler, source);
+  program = gsk_sl_compiler_compile_bytes (compiler, GSK_SL_SHADER_FRAGMENT, source);
   g_object_unref (compiler);
   if (program == NULL)
     return NULL;
diff --git a/gsk/gskslcompiler.c b/gsk/gskslcompiler.c
index 8af9579..4d8de43 100644
--- a/gsk/gskslcompiler.c
+++ b/gsk/gskslcompiler.c
@@ -22,6 +22,7 @@
 
 #include "gskcodesourceprivate.h"
 #include "gsksldefineprivate.h"
+#include "gskslenvironmentprivate.h"
 #include "gskslpreprocessorprivate.h"
 #include "gskslprogramprivate.h"
 #include "gsksltokenizerprivate.h"
@@ -231,15 +232,19 @@ gsk_sl_compiler_resolve_include (GskSlCompiler  *compiler,
 }
 
 static GskSlProgram *
-gsk_sl_compiler_compile (GskSlCompiler *compiler,
-                         GskCodeSource *source)
+gsk_sl_compiler_compile (GskSlCompiler    *compiler,
+                         GskSlShaderStage  stage,
+                         GskCodeSource    *source)
 {
   GskSlPreprocessor *preproc;
+  GskSlEnvironment *environment;
   GskSlProgram *program;
 
   program = g_object_new (GSK_TYPE_SL_PROGRAM, NULL);
 
-  preproc = gsk_sl_preprocessor_new (compiler, NULL, source);
+  environment = gsk_sl_environment_new (stage, GSK_SL_PROFILE_CORE, 150);
+  preproc = gsk_sl_preprocessor_new (compiler, environment, source);
+  gsk_sl_environment_unref (environment);
 
   gsk_sl_program_parse (program, preproc);
 
@@ -255,8 +260,9 @@ gsk_sl_compiler_compile (GskSlCompiler *compiler,
 }
 
 GskSlProgram *
-gsk_sl_compiler_compile_file (GskSlCompiler *compiler,
-                              GFile         *file)
+gsk_sl_compiler_compile_file (GskSlCompiler    *compiler,
+                              GskSlShaderStage  stage,
+                              GFile            *file)
 {
   GskSlProgram *program;
   GskCodeSource *source;
@@ -266,7 +272,7 @@ gsk_sl_compiler_compile_file (GskSlCompiler *compiler,
 
   source = gsk_code_source_new_for_file (file);
 
-  program = gsk_sl_compiler_compile (compiler, source);
+  program = gsk_sl_compiler_compile (compiler, stage, source);
 
   g_object_unref (source);
 
@@ -274,8 +280,9 @@ gsk_sl_compiler_compile_file (GskSlCompiler *compiler,
 }
 
 GskSlProgram *
-gsk_sl_compiler_compile_bytes (GskSlCompiler *compiler,
-                               GBytes        *bytes)
+gsk_sl_compiler_compile_bytes (GskSlCompiler    *compiler,
+                               GskSlShaderStage  stage,
+                               GBytes           *bytes)
 {
   GskSlProgram *program;
   GskCodeSource *source;
@@ -285,7 +292,7 @@ gsk_sl_compiler_compile_bytes (GskSlCompiler *compiler,
 
   source = gsk_code_source_new_for_bytes ("<program>", bytes);
 
-  program = gsk_sl_compiler_compile (compiler, source);
+  program = gsk_sl_compiler_compile (compiler, stage, source);
 
   g_object_unref (source);
 
diff --git a/gsk/gskslcompiler.h b/gsk/gskslcompiler.h
index 6746e56..532f94d 100644
--- a/gsk/gskslcompiler.h
+++ b/gsk/gskslcompiler.h
@@ -74,9 +74,11 @@ void                    gsk_sl_compiler_remove_define           (GskSlCompiler
 
 GDK_AVAILABLE_IN_3_92
 GskSlProgram *          gsk_sl_compiler_compile_file            (GskSlCompiler       *compiler,
+                                                                 GskSlShaderStage     stage,
                                                                  GFile               *file);
 GDK_AVAILABLE_IN_3_92
 GskSlProgram *          gsk_sl_compiler_compile_bytes           (GskSlCompiler       *compiler,
+                                                                 GskSlShaderStage     stage,
                                                                  GBytes              *bytes);
 
 G_END_DECLS
diff --git a/gsk/gskslenvironment.c b/gsk/gskslenvironment.c
index f9c5ef2..6b5a0e3 100644
--- a/gsk/gskslenvironment.c
+++ b/gsk/gskslenvironment.c
@@ -29,19 +29,22 @@ struct _GskSlEnvironment
 {
   int ref_count;
 
+  GskSlShaderStage stage;
   GskSlProfile profile;
   guint version;
 };
 
 GskSlEnvironment *
-gsk_sl_environment_new (GskSlProfile profile,
-                        guint        version)
+gsk_sl_environment_new (GskSlShaderStage stage,
+                        GskSlProfile     profile,
+                        guint            version)
 {
   GskSlEnvironment *environment;
   
   environment = g_slice_new0 (GskSlEnvironment);
   environment->ref_count = 1;
 
+  environment->stage = stage;
   environment->profile = profile;
   environment->version = version;
 
@@ -49,6 +52,17 @@ gsk_sl_environment_new (GskSlProfile profile,
 }
 
 GskSlEnvironment *
+gsk_sl_environment_new_similar (GskSlEnvironment  *environment,
+                                GskSlProfile       profile,
+                                guint              version,
+                                GError           **error)
+{
+  return gsk_sl_environment_new (environment->stage,
+                                 profile == GSK_SL_PROFILE_NONE ? environment->profile : profile,
+                                 version);
+}
+
+GskSlEnvironment *
 gsk_sl_environment_ref (GskSlEnvironment *environment)
 {
   g_return_val_if_fail (environment != NULL, NULL);
@@ -71,6 +85,11 @@ gsk_sl_environment_unref (GskSlEnvironment *environment)
   g_slice_free (GskSlEnvironment, environment);
 }
 
+GskSlShaderStage
+gsk_sl_environment_get_stage (GskSlEnvironment *environment)
+{
+  return environment->stage;
+}
 
 GskSlProfile
 gsk_sl_environment_get_profile (GskSlEnvironment *environment)
diff --git a/gsk/gskslenvironmentprivate.h b/gsk/gskslenvironmentprivate.h
index 5e73f1c..ea63a95 100644
--- a/gsk/gskslenvironmentprivate.h
+++ b/gsk/gskslenvironmentprivate.h
@@ -25,12 +25,18 @@
 
 G_BEGIN_DECLS
 
-GskSlEnvironment *      gsk_sl_environment_new                  (GskSlProfile          profile,
+GskSlEnvironment *      gsk_sl_environment_new                  (GskSlShaderStage      stage,
+                                                                 GskSlProfile          profile,
                                                                  guint                 version);
+GskSlEnvironment *      gsk_sl_environment_new_similar          (GskSlEnvironment     *environment,
+                                                                 GskSlProfile          profile,
+                                                                 guint                 version,
+                                                                 GError              **error);
 
 GskSlEnvironment *      gsk_sl_environment_ref                  (GskSlEnvironment     *environment);
 void                    gsk_sl_environment_unref                (GskSlEnvironment     *environment);
 
+GskSlShaderStage        gsk_sl_environment_get_stage            (GskSlEnvironment     *environment);
 GskSlProfile            gsk_sl_environment_get_profile          (GskSlEnvironment     *environment);
 guint                   gsk_sl_environment_get_version          (GskSlEnvironment     *environment);
 
diff --git a/gsk/gskslpreprocessor.c b/gsk/gskslpreprocessor.c
index e7e3de2..5487b50 100644
--- a/gsk/gskslpreprocessor.c
+++ b/gsk/gskslpreprocessor.c
@@ -164,7 +164,9 @@ gsk_sl_preprocessor_handle_version (GskSlPreprocessor *preproc,
                                     const char        *profile_name,
                                     gboolean           first_token_ever)
 {
-  G_GNUC_UNUSED GskSlProfile profile;
+  GskSlEnvironment *new_environment;
+  GskSlProfile profile;
+  GError *error = NULL;
 
   if (version <= 0)
     {
@@ -189,29 +191,18 @@ gsk_sl_preprocessor_handle_version (GskSlPreprocessor *preproc,
       gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, location, "#version directive must be first in 
compilation.");
       return;
     }
-  if (preproc->environment)
+
+  new_environment = gsk_sl_environment_new_similar (preproc->environment, profile, version, &error);
+  if (new_environment == NULL)
     {
-      if (gsk_sl_environment_get_profile (preproc->environment) == profile &&
-          gsk_sl_environment_get_version (preproc->environment) == version)
-        {
-          gsk_sl_preprocessor_warn_full (preproc, VERSION, location,
-                                         "#version directive should not be used, but it matches predefined 
version.");
-          return;
-        }
-      else
-        {
-          GskSlProfile env_profile = gsk_sl_environment_get_profile (preproc->environment);
-          gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, location,
-                                          "#version directive not allowed. This compilation uses %u %s.",
-                                          gsk_sl_environment_get_version (preproc->environment),
-                                          env_profile == GSK_SL_PROFILE_ES ? "es" :
-                                          env_profile == GSK_SL_PROFILE_COMPATIBILITY ? "compatibility" :
-                                          "core");
-          return;
-        }
+      gsk_sl_preprocessor_emit_error (preproc, TRUE, location, error);
+      g_clear_error (&error);
+    }
+  else
+    {
+      gsk_sl_environment_unref (preproc->environment);
+      preproc->environment = new_environment;
     }
-
-  preproc->environment = gsk_sl_environment_new (profile, version);
 }
 
 static gboolean
@@ -737,8 +728,6 @@ gsk_sl_preprocessor_new (GskSlCompiler    *compiler,
       gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline);
       gsk_sl_preprocessor_handle_token (preproc, &pp, TRUE, FALSE);
     }
-  if (preproc->environment == NULL)
-    preproc->environment = gsk_sl_environment_new (GSK_SL_PROFILE_CORE, 150);
 
   return preproc;
 }
diff --git a/gsk/gskslprogram.c b/gsk/gskslprogram.c
index e5a1066..8ca5d39 100644
--- a/gsk/gskslprogram.c
+++ b/gsk/gskslprogram.c
@@ -33,6 +33,7 @@
 struct _GskSlProgram {
   GObject parent_instance;
 
+  GskSlShaderStage stage;
   GskSlScope *scope;
   GSList *declarations;
 };
@@ -70,6 +71,7 @@ gsk_sl_program_parse (GskSlProgram      *program,
   GskSlDeclaration *declaration;
   const GskSlToken *token;
 
+  program->stage = gsk_sl_environment_get_stage (gsk_sl_preprocessor_get_environment (preproc));
   program->scope = gsk_sl_environment_create_scope (gsk_sl_preprocessor_get_environment (preproc));
 
   for (token = gsk_sl_preprocessor_get (preproc);
@@ -153,7 +155,7 @@ gsk_sl_program_to_spirv (GskSlProgram *program)
 
   g_return_val_if_fail (GSK_IS_SL_PROGRAM (program), NULL);
 
-  writer = gsk_spv_writer_new ();
+  writer = gsk_spv_writer_new (program->stage);
 
   bytes = gsk_spv_writer_write (writer,
                                 gsk_sl_program_get_entry_point (program),
diff --git a/gsk/gskspvwriter.c b/gsk/gskspvwriter.c
index 57e5b38..f9d5920 100644
--- a/gsk/gskspvwriter.c
+++ b/gsk/gskspvwriter.c
@@ -49,6 +49,8 @@ struct _GskSpvWriter
 {
   int ref_count;
 
+  GskSlShaderStage stage;
+
   guint32 last_id;
   guint extended_instructions_id;
   GArray *code[GSK_SPV_WRITER_N_GLOBAL_SECTIONS];
@@ -122,13 +124,14 @@ pointer_type_free (gpointer data)
 }
 
 GskSpvWriter *
-gsk_spv_writer_new (void)
+gsk_spv_writer_new (GskSlShaderStage stage)
 {
   GskSpvWriter *writer;
   guint i;
   
   writer = g_slice_new0 (GskSpvWriter);
   writer->ref_count = 1;
+  writer->stage = stage;
 
   for (i = 0; i < GSK_SPV_WRITER_N_GLOBAL_SECTIONS; i++)
     {
@@ -266,6 +269,21 @@ gsk_spv_writer_collect_entry_point_interfaces (GskSpvWriter *writer,
   return (guint32 *) g_array_free (interfaces, FALSE);
 }
 
+static GskSpvExecutionModel
+gsk_spv_writer_get_execution_model (GskSpvWriter *writer)
+{
+  switch (writer->stage)
+  {
+    case GSK_SL_SHADER_VERTEX:
+      return GSK_SPV_EXECUTION_MODEL_VERTEX;
+    case GSK_SL_SHADER_FRAGMENT:
+      return GSK_SPV_EXECUTION_MODEL_FRAGMENT;
+    default:
+      g_assert_not_reached ();
+      return GSK_SPV_EXECUTION_MODEL_FRAGMENT;
+  }
+}
+
 static void
 gsk_spv_writer_do_write (GskSpvWriter     *writer,
                          GskSlFunction    *entry_point,
@@ -295,7 +313,7 @@ gsk_spv_writer_do_write (GskSpvWriter     *writer,
   interfaces = gsk_spv_writer_collect_entry_point_interfaces (writer,
                                                               &n_interfaces);
   gsk_spv_writer_entry_point (writer,
-                              GSK_SPV_EXECUTION_MODEL_FRAGMENT,
+                              gsk_spv_writer_get_execution_model (writer),
                               entry_point_id,
                               "main",
                               interfaces,
diff --git a/gsk/gskspvwriterprivate.h b/gsk/gskspvwriterprivate.h
index f745362..74937df 100644
--- a/gsk/gskspvwriterprivate.h
+++ b/gsk/gskspvwriterprivate.h
@@ -47,7 +47,7 @@ typedef enum {
 #define GSK_SPV_WRITER_N_GLOBAL_SECTIONS GSK_SPV_WRITER_SECTION_BLOCK_FIRST
 #define GSK_SPV_WRITER_N_BLOCK_SECTIONS (GSK_SPV_WRITER_N_SECTIONS - GSK_SPV_WRITER_N_GLOBAL_SECTIONS)
 
-GskSpvWriter *          gsk_spv_writer_new                      (void);
+GskSpvWriter *          gsk_spv_writer_new                      (GskSlShaderStage        stage);
 
 GskSpvWriter *          gsk_spv_writer_ref                      (GskSpvWriter           *writer);
 void                    gsk_spv_writer_unref                    (GskSpvWriter           *writer);
diff --git a/gtk/glsl.c b/gtk/glsl.c
index 840ab53..9df168f 100644
--- a/gtk/glsl.c
+++ b/gtk/glsl.c
@@ -41,7 +41,9 @@ compile (GskSlCompiler *compiler,
 
   file = g_file_new_for_commandline_arg (filename);
 
-  program = gsk_sl_compiler_compile_file (compiler, file);
+  program = gsk_sl_compiler_compile_file (compiler,
+                                          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (compiler), 
"shader-stage")),
+                                          file);
   g_object_unref (file);
   if (program == NULL)
     return FALSE;
@@ -74,7 +76,9 @@ dump (GskSlCompiler *compiler,
 
   file = g_file_new_for_commandline_arg (filename);
 
-  program = gsk_sl_compiler_compile_file (compiler, file);
+  program = gsk_sl_compiler_compile_file (compiler,
+                                          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (compiler), 
"shader-stage")),
+                                          file);
   g_object_unref (file);
   if (program == NULL)
     return FALSE;
@@ -141,6 +145,50 @@ undefine (const gchar *option_name,
   return TRUE;
 }
 
+static gboolean
+stage (const gchar *option_name,
+       const gchar *value,
+       gpointer data,
+       GError **error)
+{
+  static const struct {
+    const char *name;
+    GskSlShaderStage stage;
+  } stage_names[] = {
+    { "f", GSK_SL_SHADER_FRAGMENT },
+    { "frag", GSK_SL_SHADER_FRAGMENT },
+    { "fragment", GSK_SL_SHADER_FRAGMENT },
+    { "v", GSK_SL_SHADER_VERTEX },
+    { "vert", GSK_SL_SHADER_VERTEX },
+    { "vertex", GSK_SL_SHADER_VERTEX }
+  };
+  GskSlCompiler *compiler = data;
+  GString *str;
+  gsize i;
+
+  for (i = 0; i < G_N_ELEMENTS (stage_names); i++)
+    {
+      if (g_ascii_strcasecmp (stage_names[i].name, value) == 0)
+        {
+          g_object_set_data (G_OBJECT (compiler), "shader-stage", GUINT_TO_POINTER (stage_names[i].stage));
+          return TRUE;
+        }
+    }
+
+  str = g_string_new ("");
+  for (i = 0; i < G_N_ELEMENTS (stage_names); i++)
+    {
+      if (i > 0)
+        g_string_append (str, ", ");
+      g_string_append (str, stage_names[i].name);
+    }
+  g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+               "Unknown value given for shader stage. Valid options are: %s",
+               str->str);
+  g_string_free (str, TRUE);
+  return FALSE;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -152,6 +200,7 @@ main (int argc, char *argv[])
     { "define", 'D', 0, G_OPTION_ARG_CALLBACK, define, "Add a preprocssor definition", "NAME[=VALUE]" },
     { "undef", 'U', 0, G_OPTION_ARG_CALLBACK, undefine, "Cancel previous preprocessor definition", "NAME" },
     { "print", 'p', 0, G_OPTION_ARG_NONE, &print, "Print instead of compiling", NULL },
+    { "stage", 's', 0, G_OPTION_ARG_CALLBACK, stage, "Set the shader stage", "STAGE" },
     { "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, }
@@ -168,6 +217,7 @@ main (int argc, char *argv[])
   gtk_init ();
 
   compiler = gsk_sl_compiler_new ();
+  g_object_set_data (G_OBJECT (compiler), "shader-stage", GUINT_TO_POINTER (GSK_SL_SHADER_FRAGMENT));
   ctx = g_option_context_new (NULL);
   group = g_option_group_new (NULL, NULL, NULL, g_object_ref (compiler), g_object_unref);
   g_option_group_add_entries (group, entries);
diff --git a/testsuite/gsksl/test-error.c b/testsuite/gsksl/test-error.c
index b957270..01b69e0 100644
--- a/testsuite/gsksl/test-error.c
+++ b/testsuite/gsksl/test-error.c
@@ -27,12 +27,34 @@
 
 static GskSlCompiler *compiler;
 
+static GskSlShaderStage
+shader_stage_from_filename (GFile *file)
+{
+  GskSlShaderStage stage;
+  char *base;
+
+  base = g_file_get_basename (file);
+
+  if (g_str_has_suffix (base, ".vert"))
+    stage = GSK_SL_SHADER_VERTEX;
+  else if (g_str_has_suffix (base, ".frag"))
+    stage = GSK_SL_SHADER_FRAGMENT;
+  else
+    stage = GSK_SL_SHADER_FRAGMENT;
+
+  g_free (base);
+
+  return stage;
+}
+
 static void
 test_glsl_file (GFile *file)
 {
   GskSlProgram *program;
 
-  program = gsk_sl_compiler_compile_file (compiler, file);
+  program = gsk_sl_compiler_compile_file (compiler,
+                                          shader_stage_from_filename (file),
+                                          file);
   if (program != NULL)
     {
       g_object_unref (program);


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