linker: Link built-in functions instead of including them in every shader
authorIan Romanick <ian.d.romanick@intel.com>
Tue, 20 Jul 2010 18:29:46 +0000 (11:29 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Wed, 21 Jul 2010 22:52:58 +0000 (15:52 -0700)
This is an invasive set of changes.  Each user shader tracks a set of other
shaders that contain built-in functions.  During compilation, function
prototypes are imported from these shaders.  During linking, the
shaders are linked with these built-in-function shaders just like with
any other shader.

src/glsl/builtin_function.cpp
src/glsl/builtins/110_vs/ftransform
src/glsl/builtins/tools/generate_builtins.pl
src/glsl/glsl_parser_extras.h
src/glsl/ir.h
src/glsl/linker.cpp
src/glsl/main.cpp
src/mesa/main/mtypes.h
src/mesa/shader/ir_to_mesa.cpp

index 967bcd0c40d68a5f4b142875390cd24fb6476170..10e59e491e47a02d069fa6d3cecb88dece66eee9 100644 (file)
 #include <stdio.h>
 #include "glsl_parser_extras.h"
 #include "ir_reader.h"
+#include "program.h"
 
-void
-read_builtins(_mesa_glsl_parse_state *st, exec_list *instructions,
-             const char **functions, unsigned count)
+extern "C" struct gl_shader *
+_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type);
+
+gl_shader *
+read_builtins(GLenum target, const char **functions, unsigned count)
 {
-   if (st->error)
-      return;
+   gl_shader *sh = _mesa_new_shader(NULL, 0, target);
+   struct _mesa_glsl_parse_state *st =
+      new(sh) _mesa_glsl_parse_state(NULL, target, sh);
+
+   st->language_version = 130;
+   st->ARB_texture_rectangle_enable = true;
+   st->EXT_texture_array_enable = true;
+   _mesa_glsl_initialize_types(st);
+
+   sh->ir = new(sh) exec_list;
+   sh->symbols = st->symbols;
 
    for (unsigned i = 0; i < count; i++) {
-      _mesa_glsl_read_ir(st, instructions, functions[i]);
+      _mesa_glsl_read_ir(st, sh->ir, functions[i]);
 
       if (st->error) {
         printf("error reading builtin: %.35s ...\n", functions[i]);
-         return;
+        delete st;
+        talloc_free(sh);
+         return NULL;
       }
    }
+
+   reparent_ir(sh->ir, sh);
+   delete st;
+
+   return sh;
 }
 
 /* 110 builtins */
@@ -2580,7 +2599,9 @@ static const char *functions_for_110_fs [] = {
 /* 110_vs builtins */
 
 static const char *builtins_110_vs_ftransform = {
-   "((function ftransform\n"
+   "((declare (uniform) mat4 gl_ModelViewProjectionMatrix)\n"
+   " (declare (in) vec4 gl_Vertex)\n"
+   " (function ftransform\n"
    "   (signature vec4\n"
    "     (parameters)\n"
    "    ((return (expression vec4 *\n"
@@ -4760,53 +4781,146 @@ static const char *functions_for_EXT_texture_array_fs [] = {
 #define Elements(x) (sizeof(x)/sizeof(*(x)))
 #endif
 
+void *builtin_mem_ctx = NULL;
+
+void
+_mesa_glsl_release_functions(void)
+{
+    talloc_free(builtin_mem_ctx);
+}
+
 void
 _mesa_glsl_initialize_functions(exec_list *instructions,
                                struct _mesa_glsl_parse_state *state)
 {
-   if (state->language_version >= 110)
-      read_builtins(state, instructions,
-                    functions_for_110,
-                    Elements(functions_for_110));
-
-   if (state->target == fragment_shader && state->language_version >= 110)
-      read_builtins(state, instructions,
-                    functions_for_110_fs,
-                    Elements(functions_for_110_fs));
-
-   if (state->target == vertex_shader && state->language_version >= 110)
-      read_builtins(state, instructions,
-                    functions_for_110_vs,
-                    Elements(functions_for_110_vs));
-
-   if (state->language_version >= 120)
-      read_builtins(state, instructions,
-                    functions_for_120,
-                    Elements(functions_for_120));
-
-   if (state->language_version >= 130)
-      read_builtins(state, instructions,
-                    functions_for_130,
-                    Elements(functions_for_130));
-
-   if (state->target == fragment_shader && state->language_version >= 130)
-      read_builtins(state, instructions,
-                    functions_for_130_fs,
-                    Elements(functions_for_130_fs));
-
-   if (state->ARB_texture_rectangle_enable)
-      read_builtins(state, instructions,
-                    functions_for_ARB_texture_rectangle,
-                    Elements(functions_for_ARB_texture_rectangle));
-
-   if (state->EXT_texture_array_enable)
-      read_builtins(state, instructions,
-                    functions_for_EXT_texture_array,
-                    Elements(functions_for_EXT_texture_array));
-
-   if (state->target == fragment_shader && state->EXT_texture_array_enable)
-      read_builtins(state, instructions,
-                    functions_for_EXT_texture_array_fs,
-                    Elements(functions_for_EXT_texture_array_fs));
+   if (builtin_mem_ctx == NULL)
+      builtin_mem_ctx = talloc_init("GLSL built-in functions");
+
+   state->num_builtins_to_link = 0;
+   if (state->language_version >= 110) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_110,
+                           Elements(functions_for_110));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
+
+   if (state->target == fragment_shader && state->language_version >= 110) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_110_fs,
+                           Elements(functions_for_110_fs));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
+
+   if (state->target == vertex_shader && state->language_version >= 110) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_110_vs,
+                           Elements(functions_for_110_vs));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
+
+   if (state->language_version >= 120) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_120,
+                           Elements(functions_for_120));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
+
+   if (state->language_version >= 130) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_130,
+                           Elements(functions_for_130));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
+
+   if (state->target == fragment_shader && state->language_version >= 130) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_130_fs,
+                           Elements(functions_for_130_fs));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
+
+   if (state->ARB_texture_rectangle_enable) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_ARB_texture_rectangle,
+                           Elements(functions_for_ARB_texture_rectangle));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
+
+   if (state->EXT_texture_array_enable) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_EXT_texture_array,
+                           Elements(functions_for_EXT_texture_array));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
+
+   if (state->target == fragment_shader && state->EXT_texture_array_enable) {
+      static gl_shader *sh = NULL;
+
+      if (sh == NULL) {
+        sh = read_builtins(GL_VERTEX_SHADER, functions_for_EXT_texture_array_fs,
+                           Elements(functions_for_EXT_texture_array_fs));
+        talloc_steal(builtin_mem_ctx, sh);
+      }
+
+      import_prototypes(sh->ir, instructions, state->symbols, state);
+      state->builtins_to_link[state->num_builtins_to_link] = sh;
+      state->num_builtins_to_link++;
+   }
 
 }
index 3a5e8ccecfcc813926cc12eecbfa62853da161e8..9ca63dc1e34b922880b7461b0d25466a341deda4 100644 (file)
@@ -1,4 +1,6 @@
-((function ftransform
+((declare (uniform) mat4 gl_ModelViewProjectionMatrix)
+ (declare (in) vec4 gl_Vertex)
+ (function ftransform
    (signature vec4
      (parameters)
     ((return (expression vec4 *
index a0b5c1f421c5df135099176b954dcbce68927ea9..61d511da1d49fa164ea7bacb35117f1e4b05f005 100755 (executable)
@@ -64,22 +64,41 @@ print << 'EOF';
 #include <stdio.h>
 #include "glsl_parser_extras.h"
 #include "ir_reader.h"
+#include "program.h"
 
-void
-read_builtins(_mesa_glsl_parse_state *st, exec_list *instructions,
-             const char **functions, unsigned count)
+extern "C" struct gl_shader *
+_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type);
+
+gl_shader *
+read_builtins(GLenum target, const char **functions, unsigned count)
 {
-   if (st->error)
-      return;
+   gl_shader *sh = _mesa_new_shader(NULL, 0, target);
+   struct _mesa_glsl_parse_state *st =
+      new(sh) _mesa_glsl_parse_state(NULL, target, sh);
+
+   st->language_version = 130;
+   st->ARB_texture_rectangle_enable = true;
+   st->EXT_texture_array_enable = true;
+   _mesa_glsl_initialize_types(st);
+
+   sh->ir = new(sh) exec_list;
+   sh->symbols = st->symbols;
 
    for (unsigned i = 0; i < count; i++) {
-      _mesa_glsl_read_ir(st, instructions, functions[i]);
+      _mesa_glsl_read_ir(st, sh->ir, functions[i]);
 
       if (st->error) {
         printf("error reading builtin: %.35s ...\n", functions[i]);
-         return;
+        delete st;
+        talloc_free(sh);
+         return NULL;
       }
    }
+
+   reparent_ir(sh->ir, sh);
+   delete st;
+
+   return sh;
 }
 
 EOF
@@ -95,10 +114,22 @@ print << 'EOF';
 #define Elements(x) (sizeof(x)/sizeof(*(x)))
 #endif
 
+void *builtin_mem_ctx = NULL;
+
+void
+_mesa_glsl_release_functions(void)
+{
+    talloc_free(builtin_mem_ctx);
+}
+
 void
 _mesa_glsl_initialize_functions(exec_list *instructions,
                                struct _mesa_glsl_parse_state *state)
 {
+   if (builtin_mem_ctx == NULL)
+      builtin_mem_ctx = talloc_init("GLSL built-in functions");
+
+   state->num_builtins_to_link = 0;
 EOF
 
 foreach $version_xs (@versions) {
@@ -117,10 +148,20 @@ foreach $version_xs (@versions) {
       # Not a version...an extension name
       $check = "${check}state->${version}_enable";
    }
-   print "   if ($check)\n";
-   print "      read_builtins(state, instructions,\n";
-   print "                    functions_for_$version_xs,\n";
-   print "                    Elements(functions_for_$version_xs));\n\n"
+   print "   if ($check) {\n";
+   print "      static gl_shader *sh = NULL;\n";
+   print "\n";
+   print "      if (sh == NULL) {\n";
+   print "      sh = read_builtins(GL_VERTEX_SHADER, functions_for_$version_xs,\n";
+   print "                         Elements(functions_for_$version_xs));\n";
+   print "      talloc_steal(builtin_mem_ctx, sh);\n";
+   print "      }\n";
+   print "\n";
+   print "      import_prototypes(sh->ir, instructions, state->symbols, state);\n";
+   print "      state->builtins_to_link[state->num_builtins_to_link] = sh;\n";
+   print "      state->num_builtins_to_link++;\n";
+   print "   }\n";
+   print "\n";
 }
 
 print "}\n";
index b50d9eea67625a822b92b2bbd953925abed31666..56f6e18e0bd990d6892b6837d9a2c61e4d78a10e 100644 (file)
@@ -125,6 +125,10 @@ struct _mesa_glsl_parse_state {
 
    /** Extensions supported by the OpenGL implementation. */
    const struct gl_extensions *extensions;
+
+   /** Shaders containing built-in functions that are used for linking. */
+   struct gl_shader *builtins_to_link[16];
+   unsigned num_builtins_to_link;
 };
 
 typedef struct YYLTYPE {
index 38b10f5b06d18a2cd12c023b7c947c6c483269b7..3a643fc5807e08d396b070d1d5bd35a05537c956 100644 (file)
@@ -1315,6 +1315,9 @@ extern void
 _mesa_glsl_initialize_functions(exec_list *instructions,
                                struct _mesa_glsl_parse_state *state);
 
+extern void
+_mesa_glsl_release_functions(void);
+
 extern void
 reparent_ir(exec_list *list, void *mem_ctx);
 
index 640e6eee8e09d7fc42a07e7f33c519fc2b6ef29c..7c30a40a6ce1fb89bb16489637e9989c35b26a52 100644 (file)
@@ -739,7 +739,28 @@ link_intrastage_shaders(struct gl_shader_program *prog,
 
    /* Resolve initializers for global variables in the linked shader.
     */
-   link_function_calls(prog, linked, shader_list, num_shaders);
+   unsigned num_linking_shaders = num_shaders;
+   for (unsigned i = 0; i < num_shaders; i++)
+      num_linking_shaders += shader_list[i]->num_builtins_to_link;
+
+   gl_shader **linking_shaders =
+      (gl_shader **) calloc(num_linking_shaders, sizeof(gl_shader *));
+
+   memcpy(linking_shaders, shader_list,
+         sizeof(linking_shaders[0]) * num_shaders);
+
+   unsigned idx = num_shaders;
+   for (unsigned i = 0; i < num_shaders; i++) {
+      memcpy(&linking_shaders[idx], shader_list[i]->builtins_to_link,
+            sizeof(linking_shaders[0]) * shader_list[i]->num_builtins_to_link);
+      idx += shader_list[i]->num_builtins_to_link;
+   }
+
+   assert(idx == num_linking_shaders);
+
+   link_function_calls(prog, linked, linking_shaders, num_linking_shaders);
+
+   free(linking_shaders);
 
    return linked;
 }
index cf9a5157857d3d6b3975b261d504d25edb1d9cb3..2ecf57f8ce2e3f1567363ecf5b1b1666e64754a0 100644 (file)
@@ -219,6 +219,9 @@ compile_shader(struct gl_shader *shader)
    shader->symbols = state->symbols;
    shader->CompileStatus = !state->error;
    shader->Version = state->language_version;
+   memcpy(shader->builtins_to_link, state->builtins_to_link,
+         sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
+   shader->num_builtins_to_link = state->num_builtins_to_link;
 
    if (shader->InfoLog)
       talloc_free(shader->InfoLog);
@@ -305,6 +308,7 @@ main(int argc, char **argv)
 
    talloc_free(whole_program);
    _mesa_glsl_release_types();
+   _mesa_glsl_release_functions();
 
    return status;
 }
index 729c2eaf0fdd0fa47ed273f4ad5a82678171e849..f8257d565bf48ca535dba1058c48f21ee2410daf 100644 (file)
@@ -1971,6 +1971,10 @@ struct gl_shader
 
    struct exec_list *ir;
    struct glsl_symbol_table *symbols;
+
+   /** Shaders containing built-in functions that are used for linking. */
+   struct gl_shader *builtins_to_link[16];
+   unsigned num_builtins_to_link;
 };
 
 
index a2b2eb95c82cde307efdf4f0e9a8f9396544eb6b..bfb8e3201ac961b085979f8c1680bafc4fddf2bd 100644 (file)
@@ -2207,6 +2207,9 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader)
    shader->CompileStatus = !state->error;
    shader->InfoLog = state->info_log;
    shader->Version = state->language_version;
+   memcpy(shader->builtins_to_link, state->builtins_to_link,
+         sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
+   shader->num_builtins_to_link = state->num_builtins_to_link;
 
    /* Retain any live IR, but trash the rest. */
    reparent_ir(shader->ir, shader);