diff options
-rw-r--r-- | src/mesa/main/mtypes.h | 1 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 19 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.h | 1 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_compile.c | 2 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 7 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_link.c | 132 |
6 files changed, 139 insertions, 23 deletions
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index a5d3be3543..e77dd1d226 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1974,6 +1974,7 @@ struct gl_shader GLboolean DeletePending; GLboolean CompileStatus; GLboolean Main; /**< shader defines main() */ + GLboolean UnresolvedRefs; const GLchar *Source; /**< Source code string */ struct gl_program *Program; /**< Post-compile assembly code */ GLchar *InfoLog; diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index a7cfc45e6f..6d693c9027 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -2199,12 +2199,13 @@ _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name, name); return NULL; } + if (!fun->body) { - slang_info_log_error(A->log, - "Function '%s' prototyped but not defined. " - "Separate compilation units not supported.", - name); - return NULL; + /* The function body may be in another compilation unit. + * We'll try concatenating the shaders and recompile at link time. + */ + A->UnresolvedRefs = GL_TRUE; + return new_node1(IR_NOP, NULL); } /* type checking to be sure function's return type matches 'dest' type */ @@ -4648,6 +4649,14 @@ _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun) printf("************* End codegen function ************\n\n"); #endif + if (A->UnresolvedRefs) { + /* Can't codegen at this time. + * At link time we'll concatenate all the vertex shaders and/or all + * the fragment shaders and try recompiling. + */ + return GL_TRUE; + } + /* Emit program instructions */ success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_TRUE, A->log); _slang_free_ir_tree(n); diff --git a/src/mesa/shader/slang/slang_codegen.h b/src/mesa/shader/slang/slang_codegen.h index e812c1f7ea..d80013ad34 100644 --- a/src/mesa/shader/slang/slang_codegen.h +++ b/src/mesa/shader/slang/slang_codegen.h @@ -43,6 +43,7 @@ typedef struct slang_assemble_ctx_ struct slang_ir_node_ *CurLoop; struct slang_function_ *CurFunction; GLuint UnrollLoop; + GLboolean UnresolvedRefs; } slang_assemble_ctx; diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index fb7128841c..6348f799aa 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -2435,6 +2435,8 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, _slang_codegen_function(&A, mainFunc); shader->Main = GL_TRUE; /* this shader defines main() */ + + shader->UnresolvedRefs = A.UnresolvedRefs; } _slang_pop_var_table(o.vartable); diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index 1b1edb4460..8493c490fb 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -62,6 +62,8 @@ typedef struct GLuint MaxInstructions; /**< size of prog->Instructions[] buffer */ + GLboolean UnresolvedFunctions; + /* code-gen options */ GLboolean EmitHighLevelInstructions; GLboolean EmitCondCodes; @@ -872,6 +874,7 @@ emit_compare(slang_emit_info *emitInfo, slang_ir_node *n) emit(emitInfo, n->Children[1]); if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) { + /* XXX this error should have been caught in slang_codegen.c */ slang_info_log_error(emitInfo->log, "invalid operands to == or !="); n->Store = NULL; return NULL; @@ -1356,7 +1359,8 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n) inst = emit(emitInfo, n->Children[1]); if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) { - if (!emitInfo->log->text) { + if (!emitInfo->log->text && !emitInfo->UnresolvedFunctions) { + /* XXX this error should have been caught in slang_codegen.c */ slang_info_log_error(emitInfo->log, "invalid assignment"); } return NULL; @@ -2155,6 +2159,7 @@ emit_var_ref(slang_emit_info *emitInfo, slang_ir_node *n) if (index < 0) { /* error */ char s[100]; + /* XXX isn't this really an out of memory/resources error? */ _mesa_snprintf(s, sizeof(s), "Undefined variable '%s'", (char *) n->Var->a_name); slang_info_log_error(emitInfo->log, s); diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c index f98434892b..e2daf72e7d 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 |