diff options
Diffstat (limited to 'src/mesa/shader/slang/slang_link.c')
-rw-r--r-- | src/mesa/shader/slang/slang_link.c | 132 |
1 files changed, 115 insertions, 17 deletions
diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c index f98434892b6..e2daf72e7de 100644 --- a/src/mesa/shader/slang/slang_link.c +++ b/src/mesa/shader/slang/slang_link.c @@ -534,6 +534,106 @@ _slang_update_inputs_outputs(struct gl_program *prog) } + + + +/** + * Return a new shader whose source code is the concatenation of + * all the shader sources of the given type. + */ +static struct gl_shader * +concat_shaders(struct gl_shader_program *shProg, GLenum shaderType) +{ + struct gl_shader *newShader; + const struct gl_shader *firstShader = NULL; + GLuint shaderLengths[100]; + GLchar *source; + GLuint totalLen = 0, len = 0; + GLuint i; + + /* compute total size of new shader source code */ + for (i = 0; i < shProg->NumShaders; i++) { + const struct gl_shader *shader = shProg->Shaders[i]; + if (shader->Type == shaderType) { + shaderLengths[i] = _mesa_strlen(shader->Source); + totalLen += shaderLengths[i]; + if (!firstShader) + firstShader = shader; + } + } + + source = (GLchar *) _mesa_malloc(totalLen + 1); + if (!source) + return NULL; + + /* concatenate shaders */ + for (i = 0; i < shProg->NumShaders; i++) { + const struct gl_shader *shader = shProg->Shaders[i]; + if (shader->Type == shaderType) { + _mesa_memcpy(source + len, shader->Source, shaderLengths[i]); + len += shaderLengths[i]; + } + } + source[len] = '\0'; + /* + _mesa_printf("---NEW CONCATENATED SHADER---:\n%s\n------------\n", source); + */ + + newShader = CALLOC_STRUCT(gl_shader); + newShader->Type = shaderType; + newShader->Source = source; + newShader->Pragmas = firstShader->Pragmas; + + return newShader; +} + + +/** + * Search the shader program's list of shaders to find the one that + * defines main(). + * This will involve shader concatenation and recompilation if needed. + */ +static struct gl_shader * +get_main_shader(GLcontext *ctx, + struct gl_shader_program *shProg, GLenum type) +{ + struct gl_shader *shader = NULL; + GLuint i; + + /* + * Look for a shader that defines main() and has no unresolved references. + */ + for (i = 0; i < shProg->NumShaders; i++) { + shader = shProg->Shaders[i]; + if (shader->Type == type && + shader->Main && + !shader->UnresolvedRefs) { + /* All set! */ + return shader; + } + } + + /* + * There must have been unresolved references during the original + * compilation. Try concatenating all the shaders of the given type + * and recompile that. + */ + shader = concat_shaders(shProg, type); + + _slang_compile(ctx, shader); + + /* Finally, check if recompiling failed */ + if (!shader->CompileStatus || + !shader->Main || + shader->UnresolvedRefs) { + link_error(shProg, "Unresolved symbols"); + return NULL; + } + + return shader; +} + + /** * Shader linker. Currently: * @@ -557,6 +657,9 @@ _slang_link(GLcontext *ctx, _mesa_clear_shader_program_data(ctx, shProg); + /* Initialize LinkStatus to "success". Will be cleared if error. */ + shProg->LinkStatus = GL_TRUE; + /* check that all programs compiled successfully */ for (i = 0; i < shProg->NumShaders; i++) { if (!shProg->Shaders[i]->CompileStatus) { @@ -568,24 +671,19 @@ _slang_link(GLcontext *ctx, shProg->Uniforms = _mesa_new_uniform_list(); shProg->Varying = _mesa_new_parameter_list(); - /** - * Find attached vertex, fragment shaders defining main() + /* + * Find the vertex and fragment shaders which define main() */ - vertProg = NULL; - fragProg = NULL; - for (i = 0; i < shProg->NumShaders; i++) { - struct gl_shader *shader = shProg->Shaders[i]; - if (shader->Type == GL_VERTEX_SHADER) { - if (shader->Main) - vertProg = vertex_program(shader->Program); - } - else if (shader->Type == GL_FRAGMENT_SHADER) { - if (shader->Main) - fragProg = fragment_program(shader->Program); - } - else { - _mesa_problem(ctx, "unexpected shader target in slang_link()"); - } + { + struct gl_shader *vertShader, *fragShader; + vertShader = get_main_shader(ctx, shProg, GL_VERTEX_SHADER); + fragShader = get_main_shader(ctx, shProg, GL_FRAGMENT_SHADER); + if (vertShader) + vertProg = vertex_program(vertShader->Program); + if (fragShader) + fragProg = fragment_program(fragShader->Program); + if (!shProg->LinkStatus) + return; } #if FEATURE_es2_glsl |