/*
* Mesa 3-D graphics library
- * Version: 7.2
+ * Version: 7.3
*
* Copyright (C) 2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
}
if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_CENTROID)) {
char msg[100];
- snprintf(msg, sizeof(msg),
- "centroid modifier mismatch for '%s'", var->Name);
+ _mesa_snprintf(msg, sizeof(msg),
+ "centroid modifier mismatch for '%s'", var->Name);
link_error(shProg, msg);
return GL_FALSE;
}
if (!bits_agree(var->Flags, v->Flags, PROG_PARAM_BIT_INVARIANT)) {
char msg[100];
- snprintf(msg, sizeof(msg),
- "invariant modifier mismatch for '%s'", var->Name);
+ _mesa_snprintf(msg, sizeof(msg),
+ "invariant modifier mismatch for '%s'", var->Name);
link_error(shProg, msg);
return GL_FALSE;
}
* Build the shProg->Uniforms list.
* This is basically a list/index of all uniforms found in either/both of
* the vertex and fragment shaders.
+ *
+ * About uniforms:
+ * Each uniform has two indexes, one that points into the vertex
+ * program's parameter array and another that points into the fragment
+ * program's parameter array. When the user changes a uniform's value
+ * we have to change the value in the vertex and/or fragment program's
+ * parameter array.
+ *
+ * This function will be called twice to set up the two uniform->parameter
+ * mappings.
+ *
+ * If a uniform is only present in the vertex program OR fragment program
+ * then the fragment/vertex parameter index, respectively, will be -1.
*/
-static void
-link_uniform_vars(struct gl_shader_program *shProg,
+static GLboolean
+link_uniform_vars(GLcontext *ctx,
+ struct gl_shader_program *shProg,
struct gl_program *prog,
GLuint *numSamplers)
{
- GLuint samplerMap[MAX_SAMPLERS];
+ GLuint samplerMap[200]; /* max number of samplers declared, not used */
GLuint i;
for (i = 0; i < prog->Parameters->NumParameters; i++) {
* Furthermore, we'll need to fix the state-var's size/datatype info.
*/
- if ((p->Type == PROGRAM_UNIFORM && p->Used) ||
- p->Type == PROGRAM_SAMPLER) {
+ if ((p->Type == PROGRAM_UNIFORM || p->Type == PROGRAM_SAMPLER)
+ && p->Used) {
+ /* add this uniform, indexing into the target's Parameters list */
struct gl_uniform *uniform =
_mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i);
if (uniform)
uniform->Initialized = p->Initialized;
}
- if (p->Type == PROGRAM_SAMPLER) {
+ /* The samplerMap[] table we build here is used to remap/re-index
+ * sampler references by TEX instructions.
+ */
+ if (p->Type == PROGRAM_SAMPLER && p->Used) {
/* Allocate a new sampler index */
- GLuint sampNum = *numSamplers;
GLuint oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0];
- assert(oldSampNum < MAX_SAMPLERS);
- samplerMap[oldSampNum] = sampNum;
+ GLuint newSampNum = *numSamplers;
+ if (newSampNum >= ctx->Const.MaxTextureImageUnits) {
+ char s[100];
+ _mesa_sprintf(s, "Too many texture samplers (%u, max is %u)",
+ newSampNum, ctx->Const.MaxTextureImageUnits);
+ link_error(shProg, s);
+ return GL_FALSE;
+ }
+ /* save old->new mapping in the table */
+ if (oldSampNum < Elements(samplerMap))
+ samplerMap[oldSampNum] = newSampNum;
+ /* update parameter's sampler index */
+ prog->Parameters->ParameterValues[i][0] = (GLfloat) newSampNum;
(*numSamplers)++;
}
}
-
- /* OK, now scan the program/shader instructions looking for sampler vars,
- * replacing the old index with the new index.
+ /* OK, now scan the program/shader instructions looking for texture
+ * instructions using sampler vars. Replace old sampler indexes with
+ * new ones.
*/
prog->SamplersUsed = 0x0;
for (i = 0; i < prog->NumInstructions; i++) {
struct prog_instruction *inst = prog->Instructions + i;
if (_mesa_is_tex_instruction(inst->Opcode)) {
- /*
+ const GLint oldSampNum = inst->TexSrcUnit;
+
+#if 0
printf("====== remap sampler from %d to %d\n",
- inst->Sampler, map[ inst->Sampler ]);
- */
+ inst->TexSrcUnit, samplerMap[ inst->TexSrcUnit ]);
+#endif
+
/* here, texUnit is really samplerUnit */
- assert(inst->TexSrcUnit < MAX_SAMPLERS);
- inst->TexSrcUnit = samplerMap[inst->TexSrcUnit];
- prog->SamplerTargets[inst->TexSrcUnit] = inst->TexSrcTarget;
- prog->SamplersUsed |= (1 << inst->TexSrcUnit);
+ if (oldSampNum < Elements(samplerMap)) {
+ const GLuint newSampNum = samplerMap[oldSampNum];
+ inst->TexSrcUnit = newSampNum;
+ prog->SamplerTargets[newSampNum] = inst->TexSrcTarget;
+ prog->SamplersUsed |= (1 << newSampNum);
+ }
}
}
+ return GL_TRUE;
}
{
GLint attribMap[MAX_VERTEX_ATTRIBS];
GLuint i, j;
- GLbitfield usedAttributes;
+ GLbitfield usedAttributes; /* generics only, not legacy attributes */
assert(origProg != linkedProg);
assert(origProg->Target == GL_VERTEX_PROGRAM_ARB);
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++) {
attribMap[i] = -1;
* 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_ATTRIBS; attr++) {
if (((1 << attr) & usedAttributes) == 0)
break;
}
}
/* link uniform vars */
- if (shProg->VertexProgram)
- link_uniform_vars(shProg, &shProg->VertexProgram->Base, &numSamplers);
- if (shProg->FragmentProgram)
- link_uniform_vars(shProg, &shProg->FragmentProgram->Base, &numSamplers);
+ if (shProg->VertexProgram) {
+ if (!link_uniform_vars(ctx, shProg, &shProg->VertexProgram->Base,
+ &numSamplers)) {
+ return;
+ }
+ }
+ if (shProg->FragmentProgram) {
+ if (!link_uniform_vars(ctx, shProg, &shProg->FragmentProgram->Base,
+ &numSamplers)) {
+ return;
+ }
+ }
/*_mesa_print_uniforms(shProg->Uniforms);*/
}
}
+ /* 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))) &&
+ (outputsWritten >= (1 << FRAG_RESULT_DATA0))) {
+ link_error(shProg, "Fragment program cannot write both gl_FragColor"
+ " and gl_FragData[].\n");
+ return;
+ }
+ }
+
if (fragProg && shProg->FragmentProgram) {
/* Compute initial program's TexturesUsed info */
/* 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);
}
/* 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");
+ 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);