summaryrefslogtreecommitdiff
path: root/src/mesa/shader/slang/slang_link.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/shader/slang/slang_link.c')
-rw-r--r--src/mesa/shader/slang/slang_link.c271
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);