Mesa (glsl2): linker: Stub-out intrastage linker

Ian Romanick idr at kemper.freedesktop.org
Mon Jul 12 22:23:37 UTC 2010


Module: Mesa
Branch: glsl2
Commit: 3fb878722ed53d79eedb9fe68972ef32b79575d4
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=3fb878722ed53d79eedb9fe68972ef32b79575d4

Author: Ian Romanick <ian.d.romanick at intel.com>
Date:   Fri Jul  9 14:09:34 2010 -0700

linker: Stub-out intrastage linker

---

 src/glsl/linker.cpp            |   81 +++++++++++++++++++++++++++++++++-------
 src/glsl/main.cpp              |   22 +++++++++++
 src/mesa/shader/ir_to_mesa.cpp |    9 +---
 3 files changed, 92 insertions(+), 20 deletions(-)

diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index eb10f90..e70fa31 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -77,9 +77,8 @@ extern "C" {
 #include "ir.h"
 #include "ir_optimization.h"
 #include "program.h"
-extern "C" {
 #include "hash_table.h"
-}
+#include "shader_api.h"
 
 /**
  * Visitor that determines whether or not a variable is ever written.
@@ -399,6 +398,53 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
 }
 
 
+/**
+ * Populates a shaders symbol table with all global declarations
+ */
+static void
+populate_symbol_table(gl_shader *sh)
+{
+   sh->symbols = new(sh) glsl_symbol_table;
+
+   foreach_list(node, sh->ir) {
+      ir_instruction *const inst = (ir_instruction *) node;
+      ir_variable *var;
+      ir_function *func;
+
+      if ((func = inst->as_function()) != NULL) {
+	 sh->symbols->add_function(func->name, func);
+      } else if ((var = inst->as_variable()) != NULL) {
+	 sh->symbols->add_variable(var->name, var);
+      }
+   }
+}
+
+
+/**
+ * Combine a group of shaders for a single stage to generate a linked shader
+ *
+ * \note
+ * If this function is supplied a single shader, it is cloned, and the new
+ * shader is returned.
+ */
+static struct gl_shader *
+link_intrastage_shaders(struct gl_shader_program *prog,
+			struct gl_shader **shader_list,
+			unsigned num_shaders)
+{
+   (void) prog;
+   assert(num_shaders == 1);
+
+   gl_shader *const linked = _mesa_new_shader(NULL, 0, shader_list[0]->Type);
+   linked->ir = new(linked) exec_list;
+   clone_ir_list(linked->ir, shader_list[0]->ir);
+
+   populate_symbol_table(linked);
+
+   return linked;
+}
+
+
 struct uniform_node {
    exec_node link;
    struct gl_uniform *u;
@@ -807,25 +853,32 @@ link_shaders(struct gl_shader_program *prog)
    }
 
    /* FINISHME: Implement intra-stage linking. */
-   assert(num_vert_shaders <= 1);
-   assert(num_frag_shaders <= 1);
-
-   /* Verify that each of the per-target executables is valid.
-    */
-   if (!validate_vertex_shader_executable(prog, vert_shader_list[0])
-       || !validate_fragment_shader_executable(prog, frag_shader_list[0]))
-      goto done;
+   prog->_NumLinkedShaders = 0;
+   if (num_vert_shaders > 0) {
+      gl_shader *const sh =
+	 link_intrastage_shaders(prog, vert_shader_list, num_vert_shaders);
 
+      if (sh == NULL)
+	 goto done;
 
-   prog->_NumLinkedShaders = 0;
+      if (!validate_vertex_shader_executable(prog, sh))
+	  goto done;
 
-   if (num_vert_shaders > 0) {
-      prog->_LinkedShaders[prog->_NumLinkedShaders] = vert_shader_list[0];
+      prog->_LinkedShaders[prog->_NumLinkedShaders] = sh;
       prog->_NumLinkedShaders++;
    }
 
    if (num_frag_shaders > 0) {
-      prog->_LinkedShaders[prog->_NumLinkedShaders] = frag_shader_list[0];
+      gl_shader *const sh =
+	 link_intrastage_shaders(prog, frag_shader_list, num_frag_shaders);
+
+      if (sh == NULL)
+	 goto done;
+
+      if (!validate_fragment_shader_executable(prog, sh))
+	  goto done;
+
+      prog->_LinkedShaders[prog->_NumLinkedShaders] = sh;
       prog->_NumLinkedShaders++;
    }
 
diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp
index dd43d12..8b0bccd 100644
--- a/src/glsl/main.cpp
+++ b/src/glsl/main.cpp
@@ -36,6 +36,25 @@
 #include "ir_print_visitor.h"
 #include "program.h"
 
+extern "C" struct gl_shader *
+_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type);
+
+/* Copied from shader_api.c for the stand-alone compiler.
+ */
+struct gl_shader *
+_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
+{
+   struct gl_shader *shader;
+   assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
+   shader = talloc_zero(NULL, struct gl_shader);
+   if (shader) {
+      shader->Type = type;
+      shader->Name = name;
+      shader->RefCount = 1;
+   }
+   return shader;
+}
+
 /* Returned string will have 'ctx' as its talloc owner. */
 static char *
 load_text_file(void *ctx, const char *file_name)
@@ -271,6 +290,9 @@ main(int argc, char **argv)
 	 printf("Info log for linking:\n%s\n", whole_program->InfoLog);
    }
 
+   for (unsigned i = 0; i < whole_program->_NumLinkedShaders; i++)
+      talloc_free(whole_program->_LinkedShaders[i]);
+
    talloc_free(whole_program);
    _mesa_glsl_release_types();
 
diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp
index c636d69..8945e9b 100644
--- a/src/mesa/shader/ir_to_mesa.cpp
+++ b/src/mesa/shader/ir_to_mesa.cpp
@@ -1998,20 +1998,17 @@ _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog)
       prog->Uniforms = _mesa_new_uniform_list();
    }
 
-   prog->LinkStatus = prog->LinkStatus;
-
-   /* FINISHME: This should use the linker-generated code */
    if (prog->LinkStatus) {
-      for (i = 0; i < prog->NumShaders; i++) {
+      for (i = 0; i < prog->_NumLinkedShaders; i++) {
 	 struct gl_program *linked_prog;
 
 	 linked_prog = get_mesa_program(ctx, prog,
-					prog->Shaders[i]);
+					prog->_LinkedShaders[i]);
 	 count_resources(linked_prog);
 
 	 link_uniforms_to_shared_uniform_list(prog->Uniforms, linked_prog);
 
-	 switch (prog->Shaders[i]->Type) {
+	 switch (prog->_LinkedShaders[i]->Type) {
 	 case GL_VERTEX_SHADER:
 	    _mesa_reference_vertprog(ctx, &prog->VertexProgram,
 				     (struct gl_vertex_program *)linked_prog);




More information about the mesa-commit mailing list