diff options
Diffstat (limited to 'src/mesa/shader/slang/slang_link.c')
-rw-r--r-- | src/mesa/shader/slang/slang_link.c | 271 |
1 files changed, 218 insertions, 53 deletions
diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c index c6d5cc0566..169c07f8ce 100644 --- a/src/mesa/shader/slang/slang_link.c +++ b/src/mesa/shader/slang/slang_link.c @@ -40,6 +40,7 @@ #include "shader/prog_statevars.h" #include "shader/prog_uniform.h" #include "shader/shader_api.h" +#include "slang_builtin.h" #include "slang_link.h" @@ -97,7 +98,8 @@ bits_agree(GLbitfield flags1, GLbitfield flags2, GLbitfield bit) * which inputs are centroid-sampled, invariant, etc. */ static GLboolean -link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog) +link_varying_vars(GLcontext *ctx, + struct gl_shader_program *shProg, struct gl_program *prog) { GLuint *map, i, firstVarying, newFile; GLbitfield *inOutFlags; @@ -156,8 +158,12 @@ link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog) var->Flags); } + if (shProg->Varying->NumParameters > ctx->Const.MaxVarying) { + link_error(shProg, "Too many varying variables"); + return GL_FALSE; + } + /* Map varying[i] to varying[j]. - * Plus, set prog->Input/OutputFlags[] as described above. * Note: the loop here takes care of arrays or large (sz>4) vars. */ { @@ -282,6 +288,7 @@ link_uniform_vars(GLcontext *ctx, for (i = 0; i < prog->NumInstructions; i++) { struct prog_instruction *inst = prog->Instructions + i; if (_mesa_is_tex_instruction(inst->Opcode)) { + /* here, inst->TexSrcUnit is really the sampler unit */ const GLint oldSampNum = inst->TexSrcUnit; #if 0 @@ -289,12 +296,14 @@ link_uniform_vars(GLcontext *ctx, inst->TexSrcUnit, samplerMap[ inst->TexSrcUnit ]); #endif - /* here, texUnit is really samplerUnit */ if (oldSampNum < Elements(samplerMap)) { const GLuint newSampNum = samplerMap[oldSampNum]; inst->TexSrcUnit = newSampNum; prog->SamplerTargets[newSampNum] = inst->TexSrcTarget; prog->SamplersUsed |= (1 << newSampNum); + if (inst->TexShadow) { + prog->ShadowSamplers |= (1 << newSampNum); + } } } } @@ -316,9 +325,10 @@ _slang_resolve_attributes(struct gl_shader_program *shProg, const struct gl_program *origProg, struct gl_program *linkedProg) { - GLint attribMap[MAX_VERTEX_ATTRIBS]; + GLint attribMap[MAX_VERTEX_GENERIC_ATTRIBS]; GLuint i, j; - GLbitfield usedAttributes; + GLbitfield usedAttributes; /* generics only, not legacy attributes */ + GLbitfield inputsRead = 0x0; assert(origProg != linkedProg); assert(origProg->Target == GL_VERTEX_PROGRAM_ARB); @@ -342,8 +352,17 @@ _slang_resolve_attributes(struct gl_shader_program *shProg, usedAttributes |= (1 << attr); } + /* If gl_Vertex is used, that actually counts against the limit + * on generic vertex attributes. This avoids the ambiguity of + * whether glVertexAttrib4fv(0, v) sets legacy attribute 0 (vert pos) + * or generic attribute[0]. If gl_Vertex is used, we want the former. + */ + if (origProg->InputsRead & VERT_BIT_POS) { + usedAttributes |= 0x1; + } + /* initialize the generic attribute map entries to -1 */ - for (i = 0; i < MAX_VERTEX_ATTRIBS; i++) { + for (i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) { attribMap[i] = -1; } @@ -353,6 +372,10 @@ _slang_resolve_attributes(struct gl_shader_program *shProg, for (i = 0; i < linkedProg->NumInstructions; i++) { struct prog_instruction *inst = linkedProg->Instructions + i; for (j = 0; j < 3; j++) { + if (inst->SrcReg[j].File == PROGRAM_INPUT) { + inputsRead |= (1 << inst->SrcReg[j].Index); + } + if (inst->SrcReg[j].File == PROGRAM_INPUT && inst->SrcReg[j].Index >= VERT_ATTRIB_GENERIC0) { /* @@ -384,11 +407,11 @@ _slang_resolve_attributes(struct gl_shader_program *shProg, * Start at 1 since generic attribute 0 always aliases * glVertex/position. */ - for (attr = 1; attr < MAX_VERTEX_ATTRIBS; attr++) { + for (attr = 0; attr < MAX_VERTEX_GENERIC_ATTRIBS; attr++) { if (((1 << attr) & usedAttributes) == 0) break; } - if (attr == MAX_VERTEX_ATTRIBS) { + if (attr == MAX_VERTEX_GENERIC_ATTRIBS) { link_error(shProg, "Too many vertex attributes"); return GL_FALSE; } @@ -414,6 +437,20 @@ _slang_resolve_attributes(struct gl_shader_program *shProg, } } + /* Handle pre-defined attributes here (gl_Vertex, gl_Normal, etc). + * When the user queries the active attributes we need to include both + * the user-defined attributes and the built-in ones. + */ + for (i = VERT_ATTRIB_POS; i < VERT_ATTRIB_GENERIC0; i++) { + if (inputsRead & (1 << i)) { + _mesa_add_attribute(linkedProg->Attributes, + _slang_vert_attrib_name(i), + 4, /* size in floats */ + _slang_vert_attrib_type(i), + -1 /* attrib/input */); + } + } + return GL_TRUE; } @@ -467,37 +504,152 @@ _slang_update_inputs_outputs(struct gl_program *prog) for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].File == PROGRAM_INPUT) { prog->InputsRead |= 1 << inst->SrcReg[j].Index; - if (prog->Target == GL_FRAGMENT_PROGRAM_ARB && - inst->SrcReg[j].Index == FRAG_ATTRIB_FOGC) { - /* The fragment shader FOGC input is used for fog, - * front-facing and sprite/point coord. - */ - struct gl_fragment_program *fp = fragment_program(prog); - const GLint swz = GET_SWZ(inst->SrcReg[j].Swizzle, 0); - if (swz == SWIZZLE_X) - fp->UsesFogFragCoord = GL_TRUE; - else if (swz == SWIZZLE_Y) - fp->UsesFrontFacing = GL_TRUE; - else if (swz == SWIZZLE_Z || swz == SWIZZLE_W) - fp->UsesPointCoord = GL_TRUE; - } } else if (inst->SrcReg[j].File == PROGRAM_ADDRESS) { maxAddrReg = MAX2(maxAddrReg, (GLuint) (inst->SrcReg[j].Index + 1)); } } + if (inst->DstReg.File == PROGRAM_OUTPUT) { prog->OutputsWritten |= 1 << inst->DstReg.Index; + if (inst->DstReg.RelAddr) { + /* If the output attribute is indexed with relative addressing + * we know that it must be a varying or texcoord such as + * gl_TexCoord[i] = v; In this case, mark all the texcoords + * or varying outputs as being written. It's not an error if + * a vertex shader writes varying vars that aren't used by the + * fragment shader. But it is an error for a fragment shader + * to use varyings that are not written by the vertex shader. + */ + if (prog->Target == GL_VERTEX_PROGRAM_ARB) { + if (inst->DstReg.Index == VERT_RESULT_TEX0) { + /* mark all texcoord outputs as written */ + const GLbitfield mask = + ((1 << MAX_TEXTURE_COORD_UNITS) - 1) << VERT_RESULT_TEX0; + prog->OutputsWritten |= mask; + } + else if (inst->DstReg.Index == VERT_RESULT_VAR0) { + /* mark all generic varying outputs as written */ + const GLbitfield mask = + ((1 << MAX_VARYING) - 1) << VERT_RESULT_VAR0; + prog->OutputsWritten |= mask; + } + } + } } else if (inst->DstReg.File == PROGRAM_ADDRESS) { maxAddrReg = MAX2(maxAddrReg, inst->DstReg.Index + 1); } } - prog->NumAddressRegs = maxAddrReg; } + + + +/** + * 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; + } + } + + if (totalLen == 0) + return NULL; + + 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); + + if (shader) { + _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: * @@ -514,13 +666,16 @@ _slang_link(GLcontext *ctx, GLhandleARB programObj, struct gl_shader_program *shProg) { - const struct gl_vertex_program *vertProg; - const struct gl_fragment_program *fragProg; + const struct gl_vertex_program *vertProg = NULL; + const struct gl_fragment_program *fragProg = NULL; GLuint numSamplers = 0; GLuint i; _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) { @@ -532,24 +687,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 @@ -573,6 +723,8 @@ _slang_link(GLcontext *ctx, struct gl_vertex_program *linked_vprog = vertex_program(_mesa_clone_program(ctx, &vertProg->Base)); shProg->VertexProgram = linked_vprog; /* refcount OK */ + /* vertex program ID not significant; just set Id for debugging purposes */ + shProg->VertexProgram->Base.Id = shProg->Name; ASSERT(shProg->VertexProgram->Base.RefCount == 1); } @@ -581,16 +733,18 @@ _slang_link(GLcontext *ctx, struct gl_fragment_program *linked_fprog = fragment_program(_mesa_clone_program(ctx, &fragProg->Base)); shProg->FragmentProgram = linked_fprog; /* refcount OK */ + /* vertex program ID not significant; just set Id for debugging purposes */ + shProg->FragmentProgram->Base.Id = shProg->Name; ASSERT(shProg->FragmentProgram->Base.RefCount == 1); } /* link varying vars */ if (shProg->VertexProgram) { - if (!link_varying_vars(shProg, &shProg->VertexProgram->Base)) + if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) return; } if (shProg->FragmentProgram) { - if (!link_varying_vars(shProg, &shProg->FragmentProgram->Base)) + if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) return; } @@ -650,7 +804,7 @@ _slang_link(GLcontext *ctx, /* check that gl_FragColor and gl_FragData are not both written to */ if (shProg->FragmentProgram) { GLbitfield outputsWritten = shProg->FragmentProgram->Base.OutputsWritten; - if ((outputsWritten & ((1 << FRAG_RESULT_COLR))) && + if ((outputsWritten & ((1 << FRAG_RESULT_COLOR))) && (outputsWritten >= (1 << FRAG_RESULT_DATA0))) { link_error(shProg, "Fragment program cannot write both gl_FragColor" " and gl_FragData[].\n"); @@ -666,12 +820,12 @@ _slang_link(GLcontext *ctx, /* notify driver that a new fragment program has been compiled/linked */ ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, &shProg->FragmentProgram->Base); - if (MESA_VERBOSE & VERBOSE_GLSL_DUMP) { - printf("Mesa original fragment program:\n"); + if (ctx->Shader.Flags & GLSL_DUMP) { + _mesa_printf("Mesa pre-link fragment program:\n"); _mesa_print_program(&fragProg->Base); _mesa_print_program_parameters(ctx, &fragProg->Base); - printf("Mesa post-link fragment program:\n"); + _mesa_printf("Mesa post-link fragment program:\n"); _mesa_print_program(&shProg->FragmentProgram->Base); _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base); } @@ -684,20 +838,31 @@ _slang_link(GLcontext *ctx, /* notify driver that a new vertex program has been compiled/linked */ ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, &shProg->VertexProgram->Base); - if (MESA_VERBOSE & VERBOSE_GLSL_DUMP) { - printf("Mesa original vertex program:\n"); + if (ctx->Shader.Flags & GLSL_DUMP) { + _mesa_printf("Mesa pre-link vertex program:\n"); _mesa_print_program(&vertProg->Base); _mesa_print_program_parameters(ctx, &vertProg->Base); - printf("Mesa post-link vertex program:\n"); + _mesa_printf("Mesa post-link vertex program:\n"); _mesa_print_program(&shProg->VertexProgram->Base); _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base); } } - if (MESA_VERBOSE & VERBOSE_GLSL_DUMP) { - printf("Varying vars:\n"); + /* Debug: */ + if (0) { + if (shProg->VertexProgram) + _mesa_postprocess_program(ctx, &shProg->VertexProgram->Base); + if (shProg->FragmentProgram) + _mesa_postprocess_program(ctx, &shProg->FragmentProgram->Base); + } + + if (ctx->Shader.Flags & GLSL_DUMP) { + _mesa_printf("Varying vars:\n"); _mesa_print_parameter_list(shProg->Varying); + if (shProg->InfoLog) { + _mesa_printf("Info Log: %s\n", shProg->InfoLog); + } } shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); |