/*
* Mesa 3-D graphics library
- * Version: 6.6
+ * Version: 6.5.3
*
* Copyright (C) 2006 Brian Paul All Rights Reserved.
*
*/
/**
- * \file slang_link.c
- * slang linker
- * \author Michal Krol
+ * \file slang_link2.c
+ * GLSL linker
+ * \author Brian Paul
*/
#include "imports.h"
#include "prog_instruction.h"
#include "prog_parameter.h"
#include "prog_print.h"
-#include "shaderobjects.h"
+#include "shader_api.h"
#include "slang_link.h"
static GLboolean
-link_varying_vars(struct gl_linked_program *linked, struct gl_program *prog)
+link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog)
{
GLuint *map, i, firstVarying, newFile;
GLbitfield varsWritten, varsRead;
const struct gl_program_parameter *var
= prog->Varying->Parameters + i;
- GLint j = _mesa_lookup_parameter_index(linked->Varying, -1, var->Name);
+ GLint j = _mesa_lookup_parameter_index(shProg->Varying, -1, var->Name);
if (j >= 0) {
/* already in list, check size */
- if (var->Size != linked->Varying->Parameters[j].Size) {
+ if (var->Size != shProg->Varying->Parameters[j].Size) {
/* error */
return GL_FALSE;
}
}
else {
/* not already in linked list */
- j = _mesa_add_varying(linked->Varying, var->Name, var->Size);
+ j = _mesa_add_varying(shProg->Varying, var->Name, var->Size);
}
ASSERT(j >= 0);
file == PROGRAM_STATE_VAR ||
file == PROGRAM_NAMED_PARAM ||
file == PROGRAM_CONSTANT ||
+ file == PROGRAM_SAMPLER ||
file == PROGRAM_UNIFORM);
}
static GLboolean
-link_uniform_vars(struct gl_linked_program *linked, struct gl_program *prog)
+link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
{
GLuint *map, i;
+#if 0
+ printf("================ pre link uniforms ===============\n");
+ _mesa_print_parameter_list(shProg->Uniforms);
+#endif
+
map = (GLuint *) malloc(prog->Parameters->NumParameters * sizeof(GLuint));
if (!map)
return GL_FALSE;
- for (i = 0; i < prog->Parameters->NumParameters; i++) {
+ for (i = 0; i < prog->Parameters->NumParameters; /* incr below*/) {
/* see if this uniform is in the linked uniform list */
const struct gl_program_parameter *p = prog->Parameters->Parameters + i;
const GLfloat *pVals = prog->Parameters->ParameterValues[i];
GLint j;
+ GLint size;
/* sanity check */
assert(is_uniform(p->Type));
if (p->Name) {
- j = _mesa_lookup_parameter_index(linked->Uniforms, -1, p->Name);
+ j = _mesa_lookup_parameter_index(shProg->Uniforms, -1, p->Name);
}
else {
GLuint swizzle;
ASSERT(p->Type == PROGRAM_CONSTANT);
- if (_mesa_lookup_parameter_constant(linked->Uniforms, pVals,
+ if (_mesa_lookup_parameter_constant(shProg->Uniforms, pVals,
p->Size, &j, &swizzle)) {
assert(j >= 0);
}
if (j >= 0) {
/* already in list, check size XXX check this */
- assert(p->Size == linked->Uniforms->Parameters[j].Size);
+#if 0
+ assert(p->Size == shProg->Uniforms->Parameters[j].Size);
+#endif
}
else {
/* not already in linked list */
switch (p->Type) {
case PROGRAM_ENV_PARAM:
- j = _mesa_add_named_parameter(linked->Uniforms, p->Name, pVals);
+ j = _mesa_add_named_parameter(shProg->Uniforms, p->Name, pVals);
+ break;
case PROGRAM_CONSTANT:
- j = _mesa_add_named_constant(linked->Uniforms, p->Name, pVals, p->Size);
+ j = _mesa_add_named_constant(shProg->Uniforms, p->Name, pVals, p->Size);
break;
case PROGRAM_STATE_VAR:
- j = _mesa_add_state_reference(linked->Uniforms, (const GLint *) p->StateIndexes);
+ j = _mesa_add_state_reference(shProg->Uniforms, (const GLint *) p->StateIndexes);
break;
case PROGRAM_UNIFORM:
- j = _mesa_add_uniform(linked->Uniforms, p->Name, p->Size);
+ j = _mesa_add_uniform(shProg->Uniforms, p->Name, p->Size);
+ break;
+ case PROGRAM_SAMPLER:
+ j = _mesa_add_sampler(shProg->Uniforms, p->Name);
break;
default:
abort();
}
ASSERT(j >= 0);
- map[i] = j;
+ size = p->Size;
+ while (size > 0) {
+ map[i] = j;
+ i++;
+ j++;
+ size -= 4;
+ }
+
}
+#if 0
+ printf("================ post link uniforms ===============\n");
+ _mesa_print_parameter_list(shProg->Uniforms);
+#endif
- /* OK, now scan the program/shader instructions looking for varying vars,
+#if 0
+ {
+ GLuint i;
+ for (i = 0; i < prog->Parameters->NumParameters; i++) {
+ printf("map[%d] = %d\n", i, map[i]);
+ }
+ _mesa_print_parameter_list(shProg->Uniforms);
+ }
+#endif
+
+ /* OK, now scan the program/shader instructions looking for uniform vars,
* replacing the old index with the new index.
*/
for (i = 0; i < prog->NumInstructions; i++) {
inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ];
}
}
- /* XXX update program OutputsWritten, InputsRead */
+
+ if (inst->Opcode == OPCODE_TEX ||
+ inst->Opcode == OPCODE_TXB ||
+ inst->Opcode == OPCODE_TXP) {
+ printf("====== remap sampler from %d to %d\n",
+ inst->Sampler, map[ inst->Sampler ]);
+ inst->Sampler = map[ inst->Sampler ];
+ }
}
free(map);
}
+/**
+ * XXX Temporary
+ */
static void
-free_linked_program_data(GLcontext *ctx, struct gl_linked_program *linked)
+_slang_resolve_branches(struct gl_program *prog)
{
- if (linked->VertexProgram) {
- if (linked->VertexProgram->Base.Parameters == linked->Uniforms) {
- /* to prevent a double-free in the next call */
- linked->VertexProgram->Base.Parameters = NULL;
+ struct target {
+ const char *Name;
+ GLuint Pos;
+ };
+ struct target targets[500];
+ GLuint numTargets = 0;
+ GLuint i, j;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->Opcode == OPCODE_NOP && inst->Comment) {
+ targets[numTargets].Name = inst->Comment;
+ targets[numTargets].Pos = i;
+ numTargets++;
}
- _mesa_delete_program(ctx, &linked->VertexProgram->Base);
- linked->VertexProgram = NULL;
}
- if (linked->FragmentProgram) {
- if (linked->FragmentProgram->Base.Parameters == linked->Uniforms) {
- /* to prevent a double-free in the next call */
- linked->FragmentProgram->Base.Parameters = NULL;
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->Opcode == OPCODE_BRA) {
+ for (j = 0; j < numTargets; j++) {
+ if (!strcmp(inst->Comment, targets[j].Name)) {
+ inst->BranchTarget = targets[j].Pos;
+ break;
+ }
+ }
+ if (j == numTargets) {
+ abort();
+ }
}
- _mesa_delete_program(ctx, &linked->FragmentProgram->Base);
- linked->FragmentProgram = NULL;
}
+}
- if (linked->Uniforms) {
- _mesa_free_parameter_list(linked->Uniforms);
- linked->Uniforms = NULL;
+/**
+ * Scan program for texture instructions, lookup sampler/uniform's value
+ * to determine which texture unit to use.
+ * Also, update the program's TexturesUsed[] array.
+ */
+void
+_slang_resolve_samplers(struct gl_shader_program *shProg,
+ struct gl_program *prog)
+{
+ GLuint i;
+
+ for (i = 0; i < MAX_TEXTURE_IMAGE_UNITS; i++)
+ prog->TexturesUsed[i] = 0;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->Opcode == OPCODE_TEX ||
+ inst->Opcode == OPCODE_TXB ||
+ inst->Opcode == OPCODE_TXP) {
+ GLint sampleUnit = (GLint) shProg->Uniforms->ParameterValues[inst->Sampler][0];
+ assert(sampleUnit < MAX_TEXTURE_IMAGE_UNITS);
+ inst->TexSrcUnit = sampleUnit;
+
+ prog->TexturesUsed[inst->TexSrcUnit] |= (1 << inst->TexSrcTarget);
+ }
}
+}
- if (linked->Varying) {
- _mesa_free_parameter_list(linked->Varying);
- linked->Varying = NULL;
+
+/**
+ * Scan program instructions to update the program's InputsRead and
+ * OutputsWritten fields.
+ */
+static void
+_slang_update_inputs_outputs(struct gl_program *prog)
+{
+ GLuint i, j;
+
+ prog->InputsRead = 0x0;
+ prog->OutputsWritten = 0x0;
+
+ for (i = 0; i < prog->NumInstructions; i++) {
+ const struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_INPUT) {
+ prog->InputsRead |= 1 << inst->SrcReg[j].Index;
+ }
+ }
+ if (inst->DstReg.File == PROGRAM_OUTPUT) {
+ prog->OutputsWritten |= 1 << inst->DstReg.Index;
+ }
}
}
+
+/** cast wrapper */
+static struct gl_vertex_program *
+vertex_program(struct gl_program *prog)
+{
+ assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
+ return (struct gl_vertex_program *) prog;
+}
+
+
+/** cast wrapper */
+static struct gl_fragment_program *
+fragment_program(struct gl_program *prog)
+{
+ assert(prog->Target == GL_FRAGMENT_PROGRAM_ARB);
+ return (struct gl_fragment_program *) prog;
+}
+
+
/**
* Shader linker. Currently:
*
void
_slang_link2(GLcontext *ctx,
GLhandleARB programObj,
- struct gl_linked_program *linked)
+ struct gl_shader_program *shProg)
{
struct gl_vertex_program *vertProg;
struct gl_fragment_program *fragProg;
GLuint i;
- free_linked_program_data(ctx, linked);
+ _mesa_free_shader_program_data(ctx, shProg);
- linked->Uniforms = _mesa_new_parameter_list();
- linked->Varying = _mesa_new_parameter_list();
+ shProg->Uniforms = _mesa_new_parameter_list();
+ shProg->Varying = _mesa_new_parameter_list();
/**
* Find attached vertex shader, fragment shader
*/
vertProg = NULL;
fragProg = NULL;
- for (i = 0; i < linked->NumShaders; i++) {
- if (linked->Shaders[i]->Target == GL_VERTEX_PROGRAM_ARB)
- vertProg = (struct gl_vertex_program *) linked->Shaders[i];
- else if (linked->Shaders[i]->Target == GL_FRAGMENT_PROGRAM_ARB)
- fragProg = (struct gl_fragment_program *) linked->Shaders[i];
+ for (i = 0; i < shProg->NumShaders; i++) {
+ if (shProg->Shaders[i]->Type == GL_VERTEX_SHADER)
+ vertProg = vertex_program(shProg->Shaders[i]->Programs[0]);
+ else if (shProg->Shaders[i]->Type == GL_FRAGMENT_SHADER)
+ fragProg = fragment_program(shProg->Shaders[i]->Programs[0]);
else
_mesa_problem(ctx, "unexpected shader target in slang_link2()");
}
if (!vertProg || !fragProg) {
/* XXX is it legal to have one but not the other?? */
/* XXX record error */
- linked->LinkStatus = GL_FALSE;
+ shProg->LinkStatus = GL_FALSE;
return;
}
+ if (!vertProg->Base.Varying || !fragProg->Base.Varying) {
+ /* temporary */
+ _mesa_problem(ctx, "vertex/fragment program lacks varying list!");
+ shProg->LinkStatus = GL_FALSE;
+ return;
+ }
+
/*
* Make copies of the vertex/fragment programs now since we'll be
* changing src/dst registers after merging the uniforms and varying vars.
*/
- linked->VertexProgram = (struct gl_vertex_program *)
- _mesa_clone_program(ctx, &vertProg->Base);
- linked->FragmentProgram = (struct gl_fragment_program *)
- _mesa_clone_program(ctx, &fragProg->Base);
-
-#if 1
- printf("************** orig program\n");
- _mesa_print_program(&fragProg->Base);
- _mesa_print_program_parameters(ctx, &fragProg->Base);
-#endif
+ shProg->VertexProgram
+ = vertex_program(_mesa_clone_program(ctx, &vertProg->Base));
+ shProg->FragmentProgram
+ = fragment_program(_mesa_clone_program(ctx, &fragProg->Base));
- link_varying_vars(linked, &linked->VertexProgram->Base);
- link_varying_vars(linked, &linked->FragmentProgram->Base);
+ link_varying_vars(shProg, &shProg->VertexProgram->Base);
+ link_varying_vars(shProg, &shProg->FragmentProgram->Base);
- link_uniform_vars(linked, &linked->VertexProgram->Base);
- link_uniform_vars(linked, &linked->FragmentProgram->Base);
+ link_uniform_vars(shProg, &shProg->VertexProgram->Base);
+ link_uniform_vars(shProg, &shProg->FragmentProgram->Base);
/* The vertex and fragment programs share a common set of uniforms now */
- _mesa_free_parameter_list(linked->VertexProgram->Base.Parameters);
- _mesa_free_parameter_list(linked->FragmentProgram->Base.Parameters);
- linked->VertexProgram->Base.Parameters = linked->Uniforms;
- linked->FragmentProgram->Base.Parameters = linked->Uniforms;
+ _mesa_free_parameter_list(shProg->VertexProgram->Base.Parameters);
+ _mesa_free_parameter_list(shProg->FragmentProgram->Base.Parameters);
+ shProg->VertexProgram->Base.Parameters = shProg->Uniforms;
+ shProg->FragmentProgram->Base.Parameters = shProg->Uniforms;
+
+ _slang_resolve_branches(&shProg->VertexProgram->Base);
+ _slang_resolve_branches(&shProg->FragmentProgram->Base);
+#if 1
+ _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
+ _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
+#endif
+ _slang_update_inputs_outputs(&shProg->VertexProgram->Base);
+ _slang_update_inputs_outputs(&shProg->FragmentProgram->Base);
#if 1
- printf("************** linked/cloned\n");
- _mesa_print_program(&linked->FragmentProgram->Base);
- _mesa_print_program_parameters(ctx, &linked->FragmentProgram->Base);
+ printf("************** original fragment program\n");
+ _mesa_print_program(&fragProg->Base);
+ _mesa_print_program_parameters(ctx, &fragProg->Base);
+#endif
+#if 1
+ printf("************** linked fragment prog\n");
+ _mesa_print_program(&shProg->FragmentProgram->Base);
+ _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base);
+#endif
+#if 1
+ printf("************** original vertex program\n");
+ _mesa_print_program(&vertProg->Base);
+ _mesa_print_program_parameters(ctx, &fragProg->Base);
+#endif
+#if 1
+ printf("************** linked vertex prog\n");
+ _mesa_print_program(&shProg->VertexProgram->Base);
+ _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base);
#endif
- linked->LinkStatus = (linked->VertexProgram && linked->FragmentProgram);
+ shProg->LinkStatus = (shProg->VertexProgram && shProg->FragmentProgram);
}