diff options
-rw-r--r-- | src/glsl/linker.cpp | 81 | ||||
-rw-r--r-- | src/glsl/main.cpp | 22 | ||||
-rw-r--r-- | 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 eb10f90a91..e70fa31a2b 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 dd43d12474..8b0bccdcb7 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 c636d69aba..8945e9b3b4 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); |