summaryrefslogtreecommitdiff
path: root/src/mesa/shader
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/shader')
-rw-r--r--src/mesa/shader/prog_instruction.c17
-rw-r--r--src/mesa/shader/prog_instruction.h3
-rw-r--r--src/mesa/shader/prog_uniform.c157
-rw-r--r--src/mesa/shader/prog_uniform.h91
-rw-r--r--src/mesa/shader/program.c62
-rw-r--r--src/mesa/shader/program.h2
-rw-r--r--src/mesa/shader/programopt.c96
-rw-r--r--src/mesa/shader/programopt.h2
-rw-r--r--src/mesa/shader/shader_api.c308
-rw-r--r--src/mesa/shader/slang/slang_compile.c15
-rw-r--r--src/mesa/shader/slang/slang_link.c192
11 files changed, 666 insertions, 279 deletions
diff --git a/src/mesa/shader/prog_instruction.c b/src/mesa/shader/prog_instruction.c
index 066129037a..bea5d0551e 100644
--- a/src/mesa/shader/prog_instruction.c
+++ b/src/mesa/shader/prog_instruction.c
@@ -119,6 +119,23 @@ _mesa_copy_instructions(struct prog_instruction *dest,
/**
+ * Free an array of instructions
+ */
+void
+_mesa_free_instructions(struct prog_instruction *inst, GLuint count)
+{
+ GLuint i;
+ for (i = 0; i < count; i++) {
+ if (inst[i].Data)
+ _mesa_free(inst[i].Data);
+ if (inst[i].Comment)
+ _mesa_free((char *) inst[i].Comment);
+ }
+ _mesa_free(inst);
+}
+
+
+/**
* Basic info about each instruction
*/
struct instruction_info
diff --git a/src/mesa/shader/prog_instruction.h b/src/mesa/shader/prog_instruction.h
index e8a2407ea8..711166f9dd 100644
--- a/src/mesa/shader/prog_instruction.h
+++ b/src/mesa/shader/prog_instruction.h
@@ -439,6 +439,9 @@ extern struct prog_instruction *
_mesa_copy_instructions(struct prog_instruction *dest,
const struct prog_instruction *src, GLuint n);
+extern void
+_mesa_free_instructions(struct prog_instruction *inst, GLuint count);
+
extern GLuint
_mesa_num_inst_src_regs(gl_inst_opcode opcode);
diff --git a/src/mesa/shader/prog_uniform.c b/src/mesa/shader/prog_uniform.c
new file mode 100644
index 0000000000..20e004b350
--- /dev/null
+++ b/src/mesa/shader/prog_uniform.c
@@ -0,0 +1,157 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2008 Brian Paul 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file prog_uniform.c
+ * Shader uniform functions.
+ * \author Brian Paul
+ */
+
+#include "main/imports.h"
+#include "main/mtypes.h"
+#include "prog_uniform.h"
+
+
+struct gl_uniform_list *
+_mesa_new_uniform_list(void)
+{
+ return CALLOC_STRUCT(gl_uniform_list);
+}
+
+
+void
+_mesa_free_uniform_list(struct gl_uniform_list *list)
+{
+ GLuint i;
+ for (i = 0; i < list->NumUniforms; i++) {
+ _mesa_free((void *) list->Uniforms[i].Name);
+ }
+ _mesa_free(list->Uniforms);
+ _mesa_free(list);
+}
+
+
+GLboolean
+_mesa_append_uniform(struct gl_uniform_list *list,
+ const char *name, GLenum target, GLuint progPos)
+{
+ const GLuint oldNum = list->NumUniforms;
+ GLint index;
+
+ assert(target == GL_VERTEX_PROGRAM_ARB ||
+ target == GL_FRAGMENT_PROGRAM_ARB);
+
+ index = _mesa_lookup_uniform(list, name);
+ if (index < 0) {
+ /* not found - append to list */
+
+ if (oldNum + 1 > list->Size) {
+ /* Need to grow the list array (alloc some extra) */
+ list->Size += 4;
+
+ /* realloc arrays */
+ list->Uniforms = (struct gl_uniform *)
+ _mesa_realloc(list->Uniforms,
+ oldNum * sizeof(struct gl_uniform),
+ list->Size * sizeof(struct gl_uniform));
+ }
+
+ if (!list->Uniforms) {
+ /* out of memory */
+ list->NumUniforms = 0;
+ list->Size = 0;
+ return GL_FALSE;
+ }
+
+ list->Uniforms[oldNum].Name = _mesa_strdup(name);
+ list->Uniforms[oldNum].VertPos = -1;
+ list->Uniforms[oldNum].FragPos = -1;
+ index = oldNum;
+ list->NumUniforms++;
+ }
+
+ /* update position for the vertex or fragment program */
+ if (target == GL_VERTEX_PROGRAM_ARB) {
+ if (list->Uniforms[index].VertPos != -1) {
+ /* this uniform is already in the list - that shouldn't happen */
+ return GL_FALSE;
+ }
+ list->Uniforms[index].VertPos = progPos;
+ }
+ else {
+ if (list->Uniforms[index].FragPos != -1) {
+ /* this uniform is already in the list - that shouldn't happen */
+ return GL_FALSE;
+ }
+ list->Uniforms[index].FragPos = progPos;
+ }
+
+ return GL_TRUE;
+}
+
+
+/**
+ * Return the location/index of the named uniform in the uniform list,
+ * or -1 if not found.
+ */
+GLint
+_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name)
+{
+ GLuint i;
+ for (i = 0; i < list->NumUniforms; i++) {
+ if (!_mesa_strcmp(list->Uniforms[i].Name, name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+GLint
+_mesa_longest_uniform_name(const struct gl_uniform_list *list)
+{
+ GLint max = 0;
+ GLuint i;
+ for (i = 0; i < list->NumUniforms; i++) {
+ GLuint len = _mesa_strlen(list->Uniforms[i].Name);
+ if (len > max)
+ max = len;
+ }
+ return max;
+}
+
+
+void
+_mesa_print_uniforms(const struct gl_uniform_list *list)
+{
+ GLuint i;
+ printf("Uniform list %p:\n", (void *) list);
+ for (i = 0; i < list->NumUniforms; i++) {
+ printf("%d: %s %d %d\n",
+ i,
+ list->Uniforms[i].Name,
+ list->Uniforms[i].VertPos,
+ list->Uniforms[i].FragPos);
+ }
+}
diff --git a/src/mesa/shader/prog_uniform.h b/src/mesa/shader/prog_uniform.h
new file mode 100644
index 0000000000..735de28705
--- /dev/null
+++ b/src/mesa/shader/prog_uniform.h
@@ -0,0 +1,91 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 7.1
+ *
+ * Copyright (C) 1999-2008 Brian Paul 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file prog_uniform.c
+ * Shader uniform functions.
+ * \author Brian Paul
+ */
+
+#ifndef PROG_UNIFORM_H
+#define PROG_UNIFORM_H
+
+#include "main/mtypes.h"
+#include "prog_statevars.h"
+
+
+/**
+ * Shader program uniform variable.
+ * The glGetUniformLocation() and glUniform() commands will use this
+ * information.
+ * Note that a uniform such as "binormal" might be used in both the
+ * vertex shader and the fragment shader. When glUniform() is called to
+ * set the uniform's value, it must be updated in both the vertex and
+ * fragment shaders. The uniform may be in different locations in the
+ * two shaders so we keep track of that here.
+ */
+struct gl_uniform
+{
+ const char *Name; /**< Null-terminated string */
+ GLint VertPos;
+ GLint FragPos;
+#if 0
+ GLenum DataType; /**< GL_FLOAT, GL_FLOAT_VEC2, etc */
+ GLuint Size; /**< Number of components (1..4) */
+#endif
+};
+
+
+/**
+ * List of gl_uniforms
+ */
+struct gl_uniform_list
+{
+ GLuint Size; /**< allocated size of Uniforms array */
+ GLuint NumUniforms; /**< number of uniforms in the array */
+ struct gl_uniform *Uniforms; /**< Array [Size] */
+};
+
+
+extern struct gl_uniform_list *
+_mesa_new_uniform_list(void);
+
+extern void
+_mesa_free_uniform_list(struct gl_uniform_list *list);
+
+extern GLboolean
+_mesa_append_uniform(struct gl_uniform_list *list,
+ const char *name, GLenum target, GLuint progPos);
+
+extern GLint
+_mesa_lookup_uniform(const struct gl_uniform_list *list, const char *name);
+
+extern GLint
+_mesa_longest_uniform_name(const struct gl_uniform_list *list);
+
+extern void
+_mesa_print_uniforms(const struct gl_uniform_list *list);
+
+
+#endif /* PROG_UNIFORM_H */
diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c
index 09a8494bd3..0ed7f833d2 100644
--- a/src/mesa/shader/program.c
+++ b/src/mesa/shader/program.c
@@ -287,16 +287,7 @@ _mesa_delete_program(GLcontext *ctx, struct gl_program *prog)
if (prog->String)
_mesa_free(prog->String);
- if (prog->Instructions) {
- GLuint i;
- for (i = 0; i < prog->NumInstructions; i++) {
- if (prog->Instructions[i].Data)
- _mesa_free(prog->Instructions[i].Data);
- if (prog->Instructions[i].Comment)
- _mesa_free((char *) prog->Instructions[i].Comment);
- }
- _mesa_free(prog->Instructions);
- }
+ _mesa_free_instructions(prog->Instructions, prog->NumInstructions);
if (prog->Parameters) {
_mesa_free_parameter_list(prog->Parameters);
@@ -361,6 +352,7 @@ _mesa_clone_program(GLcontext *ctx, const struct gl_program *prog)
prog->NumInstructions);
clone->InputsRead = prog->InputsRead;
clone->OutputsWritten = prog->OutputsWritten;
+ clone->SamplersUsed = prog->SamplersUsed;
memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed));
if (prog->Parameters)
@@ -414,6 +406,55 @@ _mesa_clone_program(GLcontext *ctx, const struct gl_program *prog)
}
+/**
+ * Insert 'count' NOP instructions at 'start' in the given program.
+ * Adjust branch targets accordingly.
+ */
+GLboolean
+_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count)
+{
+ const GLuint origLen = prog->NumInstructions;
+ const GLuint newLen = origLen + count;
+ struct prog_instruction *newInst;
+ GLuint i;
+
+ /* adjust branches */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->BranchTarget > 0) {
+ if (inst->BranchTarget >= start) {
+ inst->BranchTarget += count;
+ }
+ }
+ }
+
+ /* Alloc storage for new instructions */
+ newInst = _mesa_alloc_instructions(newLen);
+ if (!newInst) {
+ return GL_FALSE;
+ }
+
+ /* Copy 'start' instructions into new instruction buffer */
+ _mesa_copy_instructions(newInst, prog->Instructions, start);
+
+ /* init the new instructions */
+ _mesa_init_instructions(newInst + start, count);
+
+ /* Copy the remaining/tail instructions to new inst buffer */
+ _mesa_copy_instructions(newInst + start + count,
+ prog->Instructions + start,
+ origLen - start);
+
+ /* free old instructions */
+ _mesa_free_instructions(prog->Instructions, origLen);
+
+ /* install new instructions */
+ prog->Instructions = newInst;
+ prog->NumInstructions = newLen;
+
+ return GL_TRUE;
+}
+
/**
* Search instructions for registers that match (oldFile, oldIndex),
@@ -537,6 +578,7 @@ _mesa_combine_programs(GLcontext *ctx,
}
newProg->InputsRead = progA->InputsRead | inputsB;
newProg->OutputsWritten = progB->OutputsWritten;
+ newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed;
}
else {
/* vertex program */
diff --git a/src/mesa/shader/program.h b/src/mesa/shader/program.h
index 4b7297e4c6..414a57d39c 100644
--- a/src/mesa/shader/program.h
+++ b/src/mesa/shader/program.h
@@ -87,6 +87,8 @@ _mesa_lookup_program(GLcontext *ctx, GLuint id);
extern struct gl_program *
_mesa_clone_program(GLcontext *ctx, const struct gl_program *prog);
+extern GLboolean
+_mesa_insert_instructions(struct gl_program *prog, GLuint start, GLuint count);
extern struct gl_program *
_mesa_combine_programs(GLcontext *ctx,
diff --git a/src/mesa/shader/programopt.c b/src/mesa/shader/programopt.c
index 9eeb71db1b..7d560c74a5 100644
--- a/src/mesa/shader/programopt.c
+++ b/src/mesa/shader/programopt.c
@@ -35,6 +35,7 @@
#include "context.h"
#include "prog_parameter.h"
#include "prog_statevars.h"
+#include "program.h"
#include "programopt.h"
#include "prog_instruction.h"
@@ -102,7 +103,7 @@ _mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog)
_mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
/* free old instructions */
- _mesa_free(vprog->Base.Instructions);
+ _mesa_free_instructions(vprog->Base.Instructions, origLen);
/* install new instructions */
vprog->Base.Instructions = newInst;
@@ -274,7 +275,7 @@ _mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog)
inst++;
/* free old instructions */
- _mesa_free(fprog->Base.Instructions);
+ _mesa_free_instructions(fprog->Base.Instructions, origLen);
/* install new instructions */
fprog->Base.Instructions = newInst;
@@ -364,3 +365,94 @@ _mesa_count_texture_instructions(struct gl_program *prog)
}
}
+
+/**
+ * Scan/rewrite program to remove reads of varying (output) registers.
+ * In GLSL vertex shaders, varying vars can be read and written.
+ * Normally, vertex varying vars are implemented as output registers.
+ * On some hardware, trying to read an output register causes trouble.
+ * So, rewrite the program to use a temporary register in this case.
+ */
+void
+_mesa_remove_varying_reads(struct gl_program *prog)
+{
+ GLuint i;
+ GLint outputMap[VERT_RESULT_MAX];
+ GLuint numVaryingReads = 0;
+
+ assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
+
+ for (i = 0; i < VERT_RESULT_MAX; i++)
+ outputMap[i] = -1;
+
+ /* look for instructions which read from varying vars */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ GLuint j;
+ for (j = 0; j < numSrc; j++) {
+ if (inst->SrcReg[j].File == PROGRAM_VARYING) {
+ /* replace the read with a temp reg */
+ const GLuint var = inst->SrcReg[j].Index;
+ if (outputMap[var] == -1) {
+ numVaryingReads++;
+ outputMap[var] = _mesa_find_free_register(prog,
+ PROGRAM_TEMPORARY);
+ }
+ inst->SrcReg[j].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[j].Index = outputMap[var];
+ }
+ }
+ }
+
+ if (numVaryingReads == 0)
+ return; /* nothing to be done */
+
+ /* look for instructions which write to the varying vars identified above */
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
+ GLuint j;
+ for (j = 0; j < numSrc; j++) {
+ if (inst->DstReg.File == PROGRAM_VARYING &&
+ outputMap[inst->DstReg.Index] >= 0) {
+ /* change inst to write to the temp reg, instead of the varying */
+ inst->DstReg.File = PROGRAM_TEMPORARY;
+ inst->DstReg.Index = outputMap[inst->DstReg.Index];
+ }
+ }
+ }
+
+ /* insert new instructions to copy the temp vars to the varying vars */
+ {
+ struct prog_instruction *inst;
+ GLint endPos, var;
+
+ /* Look for END instruction and insert the new varying writes */
+ endPos = -1;
+ for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ if (inst->Opcode == OPCODE_END) {
+ endPos = i;
+ _mesa_insert_instructions(prog, i, numVaryingReads);
+ break;
+ }
+ }
+
+ assert(endPos >= 0);
+
+ /* insert new MOV instructions here */
+ inst = prog->Instructions + endPos;
+ for (var = 0; var < VERT_RESULT_MAX; var++) {
+ if (outputMap[var] >= 0) {
+ /* MOV VAR[var], TEMP[tmp]; */
+ inst->Opcode = OPCODE_MOV;
+ inst->DstReg.File = PROGRAM_VARYING;
+ inst->DstReg.Index = var;
+ inst->SrcReg[0].File = PROGRAM_TEMPORARY;
+ inst->SrcReg[0].Index = outputMap[var];
+ inst++;
+ }
+ }
+ }
+}
diff --git a/src/mesa/shader/programopt.h b/src/mesa/shader/programopt.h
index ce63644bbf..47ff2f0c7b 100644
--- a/src/mesa/shader/programopt.h
+++ b/src/mesa/shader/programopt.h
@@ -39,5 +39,7 @@ _mesa_count_texture_indirections(struct gl_program *prog);
extern void
_mesa_count_texture_instructions(struct gl_program *prog);
+extern void
+_mesa_remove_varying_reads(struct gl_program *prog);
#endif /* PROGRAMOPT_H */
diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c
index 4cb8bb8ed1..9c419c9903 100644
--- a/src/mesa/shader/shader_api.c
+++ b/src/mesa/shader/shader_api.c
@@ -43,6 +43,7 @@
#include "prog_parameter.h"
#include "prog_print.h"
#include "prog_statevars.h"
+#include "prog_uniform.h"
#include "shader/shader_api.h"
#include "shader/slang/slang_compile.h"
#include "shader/slang/slang_link.h"
@@ -75,25 +76,25 @@ _mesa_clear_shader_program_data(GLcontext *ctx,
struct gl_shader_program *shProg)
{
if (shProg->VertexProgram) {
- if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
- /* to prevent a double-free in the next call */
- shProg->VertexProgram->Base.Parameters = NULL;
- }
+ /* Set ptr to NULL since the param list is shared with the
+ * original/unlinked program.
+ */
+ shProg->VertexProgram->Base.Parameters = NULL;
ctx->Driver.DeleteProgram(ctx, &shProg->VertexProgram->Base);
shProg->VertexProgram = NULL;
}
if (shProg->FragmentProgram) {
- if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
- /* to prevent a double-free in the next call */
- shProg->FragmentProgram->Base.Parameters = NULL;
- }
+ /* Set ptr to NULL since the param list is shared with the
+ * original/unlinked program.
+ */
+ shProg->FragmentProgram->Base.Parameters = NULL;
ctx->Driver.DeleteProgram(ctx, &shProg->FragmentProgram->Base);
shProg->FragmentProgram = NULL;
}
if (shProg->Uniforms) {
- _mesa_free_parameter_list(shProg->Uniforms);
+ _mesa_free_uniform_list(shProg->Uniforms);
shProg->Uniforms = NULL;
}
@@ -673,39 +674,43 @@ _mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
GLsizei maxLength, GLsizei *length, GLint *size,
GLenum *type, GLchar *nameOut)
{
- struct gl_shader_program *shProg
+ const struct gl_shader_program *shProg
= _mesa_lookup_shader_program(ctx, program);
- GLuint ind, j;
+ const struct gl_program *prog;
+ GLint progPos;
if (!shProg) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
return;
}
- if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
+ if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
return;
}
- ind = 0;
- for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
- if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
- shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
- if (ind == index) {
- /* found it */
- copy_string(nameOut, maxLength, length,
- shProg->Uniforms->Parameters[j].Name);
- if (size)
- *size = shProg->Uniforms->Parameters[j].Size;
- if (type)
- *type = shProg->Uniforms->Parameters[j].DataType;
- return;
- }
- ind++;
+ progPos = shProg->Uniforms->Uniforms[index].VertPos;
+ if (progPos >= 0) {
+ prog = &shProg->VertexProgram->Base;
+ }
+ else {
+ progPos = shProg->Uniforms->Uniforms[index].FragPos;
+ if (progPos >= 0) {
+ prog = &shProg->FragmentProgram->Base;
}
}
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
+ if (!prog || progPos < 0)
+ return; /* should never happen */
+
+ if (nameOut)
+ copy_string(nameOut, maxLength, length,
+ prog->Parameters->Parameters[progPos].Name);
+ if (size)
+ *size = prog->Parameters->Parameters[progPos].Size;
+
+ if (type)
+ *type = prog->Parameters->Parameters[progPos].DataType;
}
@@ -792,14 +797,10 @@ _mesa_get_programiv(GLcontext *ctx, GLuint program,
PROGRAM_INPUT) + 1;
break;
case GL_ACTIVE_UNIFORMS:
- *params
- = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
- + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
+ *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
break;
case GL_ACTIVE_UNIFORM_MAX_LENGTH:
- *params = MAX2(
- _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
- _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
+ *params = _mesa_longest_uniform_name(shProg->Uniforms);
if (*params > 0)
(*params)++; /* add one for terminating zero */
break;
@@ -896,10 +897,23 @@ _mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
struct gl_shader_program *shProg
= _mesa_lookup_shader_program(ctx, program);
if (shProg) {
- GLint i;
- if (location >= 0 && location < shProg->Uniforms->NumParameters) {
- for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
- params[i] = shProg->Uniforms->ParameterValues[location][i];
+ if (location < shProg->Uniforms->NumUniforms) {
+ GLint progPos, i;
+ const struct gl_program *prog;
+
+ progPos = shProg->Uniforms->Uniforms[location].VertPos;
+ if (progPos >= 0) {
+ prog = &shProg->VertexProgram->Base;
+ }
+ else {
+ progPos = shProg->Uniforms->Uniforms[location].FragPos;
+ if (progPos >= 0) {
+ prog = &shProg->FragmentProgram->Base;
+ }
+ }
+
+ for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
+ params[i] = prog->Parameters->ParameterValues[progPos][i];
}
}
else {
@@ -920,23 +934,10 @@ _mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
{
struct gl_shader_program *shProg
= _mesa_lookup_shader_program(ctx, program);
- if (shProg) {
- GLuint loc;
- for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
- const struct gl_program_parameter *u
- = shProg->Uniforms->Parameters + loc;
- /* XXX this is a temporary simplification / short-cut.
- * We need to handle things like "e.c[0].b" as seen in the
- * GLSL orange book, page 189.
- */
- if ((u->Type == PROGRAM_UNIFORM ||
- u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
- return loc;
- }
- }
- }
- return -1;
+ if (!shProg)
+ return -1;
+ return _mesa_lookup_uniform(shProg->Uniforms, name);
}
@@ -1068,6 +1069,78 @@ update_textures_used(struct gl_program *prog)
/**
+ * Set the value of a program's uniform variable.
+ * \param program the program whose uniform to update
+ * \param location the location/index of the uniform
+ * \param type the datatype of the uniform
+ * \param count the number of uniforms to set
+ * \param elems number of elements per uniform
+ * \param values the new values
+ */
+static void
+set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
+ GLenum type, GLint count, GLint elems, const void *values)
+{
+ if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
+ /* This controls which texture unit which is used by a sampler */
+ GLuint texUnit, sampler;
+
+ /* data type for setting samplers must be int */
+ if (type != GL_INT || count != 1) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUniform(only glUniform1i can be used "
+ "to set sampler uniforms)");
+ return;
+ }
+
+ sampler = (GLuint) program->Parameters->ParameterValues[location][0];
+ texUnit = ((GLuint *) values)[0];
+
+ /* check that the sampler (tex unit index) is legal */
+ if (texUnit >= ctx->Const.MaxTextureImageUnits) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glUniform1(invalid sampler/tex unit index)");
+ return;
+ }
+
+ /* This maps a sampler to a texture unit: */
+ program->SamplerUnits[sampler] = texUnit;
+ update_textures_used(program);
+
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+ }
+ else {
+ /* ordinary uniform variable */
+ GLint k, i;
+
+ if (count * elems > program->Parameters->Parameters[location].Size) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
+ return;
+ }
+
+ for (k = 0; k < count; k++) {
+ GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
+ if (type == GL_INT ||
+ type == GL_INT_VEC2 ||
+ type == GL_INT_VEC3 ||
+ type == GL_INT_VEC4) {
+ const GLint *iValues = ((const GLint *) values) + k * elems;
+ for (i = 0; i < elems; i++) {
+ uniformVal[i] = (GLfloat) iValues[i];
+ }
+ }
+ else {
+ const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
+ for (i = 0; i < elems; i++) {
+ uniformVal[i] = fValues[i];
+ }
+ }
+ }
+ }
+}
+
+
+/**
* Called via ctx->Driver.Uniform().
*/
static void
@@ -1075,20 +1148,18 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
const GLvoid *values, GLenum type)
{
struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
- GLint elems, i, k;
+ GLint elems;
if (!shProg || !shProg->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
return;
}
- if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
+ if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
return;
}
- FLUSH_VERTICES(ctx, _NEW_PROGRAM);
-
if (count < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
return;
@@ -1116,63 +1187,54 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
return;
}
- if (count * elems > shProg->Uniforms->Parameters[location].Size) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
- return;
- }
-
- if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
- /* This controls which texture unit which is used by a sampler */
- GLuint texUnit, sampler;
-
- /* data type for setting samplers must be int */
- if (type != GL_INT || count != 1) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniform(only glUniform1i can be used "
- "to set sampler uniforms)");
- return;
- }
-
- sampler = (GLuint) shProg->Uniforms->ParameterValues[location][0];
- texUnit = ((GLuint *) values)[0];
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- /* check that the sampler (tex unit index) is legal */
- if (texUnit >= ctx->Const.MaxTextureImageUnits) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glUniform1(invalid sampler/tex unit index)");
- return;
+ /* A uniform var may be used by both a vertex shader and a fragment
+ * shader. We may need to update one or both shader's uniform here:
+ */
+ if (shProg->VertexProgram) {
+ GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
+ if (loc >= 0) {
+ set_program_uniform(ctx, &shProg->VertexProgram->Base,
+ loc, type, count, elems, values);
}
+ }
- if (shProg->VertexProgram) {
- shProg->VertexProgram->Base.SamplerUnits[sampler] = texUnit;
- update_textures_used(&shProg->VertexProgram->Base);
- }
- if (shProg->FragmentProgram) {
- shProg->FragmentProgram->Base.SamplerUnits[sampler] = texUnit;
- update_textures_used(&shProg->FragmentProgram->Base);
+ if (shProg->FragmentProgram) {
+ GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
+ if (loc >= 0) {
+ set_program_uniform(ctx, &shProg->FragmentProgram->Base,
+ loc, type, count, elems, values);
}
+ }
+}
- FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+static void
+set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
+ GLuint location, GLuint rows, GLuint cols,
+ GLboolean transpose, const GLfloat *values)
+{
+ /*
+ * Note: the _columns_ of a matrix are stored in program registers, not
+ * the rows.
+ */
+ /* XXXX need to test 3x3 and 2x2 matrices... */
+ if (transpose) {
+ GLuint row, col;
+ for (col = 0; col < cols; col++) {
+ GLfloat *v = program->Parameters->ParameterValues[location + col];
+ for (row = 0; row < rows; row++) {
+ v[row] = values[row * cols + col];
+ }
+ }
}
else {
- /* ordinary uniform variable */
- for (k = 0; k < count; k++) {
- GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
- if (type == GL_INT ||
- type == GL_INT_VEC2 ||
- type == GL_INT_VEC3 ||
- type == GL_INT_VEC4) {
- const GLint *iValues = ((const GLint *) values) + k * elems;
- for (i = 0; i < elems; i++) {
- uniformVal[i] = (GLfloat) iValues[i];
- }
- }
- else {
- const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
- for (i = 0; i < elems; i++) {
- uniformVal[i] = fValues[i];
- }
+ GLuint row, col;
+ for (col = 0; col < cols; col++) {
+ GLfloat *v = program->Parameters->ParameterValues[location + col];
+ for (row = 0; row < rows; row++) {
+ v[row] = values[col * rows + row];
}
}
}
@@ -1193,7 +1255,7 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
"glUniformMatrix(program not linked)");
return;
}
- if (location < 0 || location >= shProg->Uniforms->NumParameters) {
+ if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
return;
}
@@ -1204,27 +1266,19 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
FLUSH_VERTICES(ctx, _NEW_PROGRAM);
- /*
- * Note: the _columns_ of a matrix are stored in program registers, not
- * the rows.
- */
- /* XXXX need to test 3x3 and 2x2 matrices... */
- if (transpose) {
- GLuint row, col;
- for (col = 0; col < cols; col++) {
- GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
- for (row = 0; row < rows; row++) {
- v[row] = values[row * cols + col];
- }
+ if (shProg->VertexProgram) {
+ GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
+ if (loc >= 0) {
+ set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
+ loc, rows, cols, transpose, values);
}
}
- else {
- GLuint row, col;
- for (col = 0; col < cols; col++) {
- GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
- for (row = 0; row < rows; row++) {
- v[row] = values[col * rows + row];
- }
+
+ if (shProg->FragmentProgram) {
+ GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
+ if (loc >= 0) {
+ set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
+ loc, rows, cols, transpose, values);
}
}
}
diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c
index bfb9ca4db6..0df673085b 100644
--- a/src/mesa/shader/slang/slang_compile.c
+++ b/src/mesa/shader/slang/slang_compile.c
@@ -31,6 +31,8 @@
#include "main/imports.h"
#include "main/context.h"
#include "shader/program.h"
+#include "shader/programopt.h"
+#include "shader/prog_print.h"
#include "shader/prog_parameter.h"
#include "shader/grammar/grammar_mesa.h"
#include "slang_codegen.h"
@@ -2186,6 +2188,19 @@ _slang_compile(GLcontext *ctx, struct gl_shader *shader)
_slang_delete_mempool((slang_mempool *) ctx->Shader.MemPool);
ctx->Shader.MemPool = NULL;
+ if (shader->Type == GL_VERTEX_SHADER) {
+ /* remove any reads of varying (output) registers */
+#if 0
+ printf("Pre-remove output reads:\n");
+ _mesa_print_program(shader->Programs[0]);
+#endif
+ _mesa_remove_varying_reads(shader->Programs[0]);
+#if 0
+ printf("Post-remove output reads:\n");
+ _mesa_print_program(shader->Programs[0]);
+#endif
+ }
+
return success;
}
diff --git a/src/mesa/shader/slang/slang_link.c b/src/mesa/shader/slang/slang_link.c
index 390ae56aa5..addff20421 100644
--- a/src/mesa/shader/slang/slang_link.c
+++ b/src/mesa/shader/slang/slang_link.c
@@ -37,12 +37,17 @@
#include "shader/prog_parameter.h"
#include "shader/prog_print.h"
#include "shader/prog_statevars.h"
+#include "shader/prog_uniform.h"
#include "shader/shader_api.h"
#include "slang_link.h"
-
+/**
+ * Linking varying vars involves rearranging varying vars so that the
+ * vertex program's output varyings matches the order of the fragment
+ * program's input varyings.
+ */
static GLboolean
link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog)
{
@@ -132,148 +137,53 @@ link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog)
}
-static GLboolean
-is_uniform(GLuint file)
-{
- return (file == PROGRAM_ENV_PARAM ||
- file == PROGRAM_STATE_VAR ||
- file == PROGRAM_NAMED_PARAM ||
- file == PROGRAM_CONSTANT ||
- file == PROGRAM_SAMPLER ||
- file == PROGRAM_UNIFORM);
-}
-
-
-static GLuint shProg_NumSamplers = 0; /** XXX temporary */
-
-
-static GLboolean
-link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
+/**
+ * Build the shProg->Uniforms list.
+ * This is basically a list/index of all uniforms found in either/both of
+ * the vertex and fragment shaders.
+ */
+static void
+link_uniform_vars(struct gl_shader_program *shProg,
+ struct gl_program *prog,
+ GLuint *numSamplers)
{
- GLuint *map, i;
GLuint samplerMap[MAX_SAMPLERS];
+ GLuint 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; /* incr below*/) {
- /* see if this uniform is in the linked uniform list */
+ for (i = 0; i < prog->Parameters->NumParameters; i++) {
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));
-
- /* See if this uniform is already in the linked program's list */
- if (p->Name) {
- /* this is a named uniform */
- j = _mesa_lookup_parameter_index(shProg->Uniforms, -1, p->Name);
- }
- else {
- /* this is an unnamed constant */
- /*GLuint swizzle;*/
- ASSERT(p->Type == PROGRAM_CONSTANT);
- if (_mesa_lookup_parameter_constant(shProg->Uniforms, pVals,
- p->Size, &j, NULL)) {
- assert(j >= 0);
- }
- else {
- j = -1;
- }
- }
-
- if (j >= 0) {
- /* already in linked program's list */
- /* check size XXX check this */
-#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(shProg->Uniforms, p->Name, pVals);
- break;
- case PROGRAM_CONSTANT:
- j = _mesa_add_named_constant(shProg->Uniforms, p->Name, pVals, p->Size);
- break;
- case PROGRAM_STATE_VAR:
- j = _mesa_add_state_reference(shProg->Uniforms, p->StateIndexes);
- break;
- case PROGRAM_UNIFORM:
- j = _mesa_add_uniform(shProg->Uniforms, p->Name, p->Size, p->DataType);
- break;
- case PROGRAM_SAMPLER:
- {
- GLuint sampNum = shProg_NumSamplers++;
- GLuint oldSampNum;
- j = _mesa_add_sampler(shProg->Uniforms, p->Name,
- p->DataType, sampNum);
- oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0];
- assert(oldSampNum < MAX_SAMPLERS);
- samplerMap[oldSampNum] = sampNum;
- }
- break;
- default:
- _mesa_problem(NULL, "bad parameter type in link_uniform_vars()");
- return GL_FALSE;
- }
+ /*
+ * XXX FIX NEEDED HERE
+ * We should also be adding a uniform if p->Type == PROGRAM_STATE_VAR.
+ * For example, modelview matrix, light pos, etc.
+ * Also, we need to update the state-var name-generator code to
+ * generate GLSL-style names, like "gl_LightSource[0].position".
+ * Furthermore, we'll need to fix the state-var's size/datatype info.
+ */
+
+ if (p->Type == PROGRAM_UNIFORM ||
+ p->Type == PROGRAM_SAMPLER) {
+ _mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i);
}
- ASSERT(j >= 0);
-
- size = p->Size;
- while (size > 0) {
- map[i] = j;
- i++;
- j++;
- size -= 4;
+ if (p->Type == PROGRAM_SAMPLER) {
+ /* Allocate a new sampler index */
+ GLuint sampNum = *numSamplers;
+ GLuint oldSampNum = (GLuint) prog->Parameters->ParameterValues[i][0];
+ assert(oldSampNum < MAX_SAMPLERS);
+ samplerMap[oldSampNum] = sampNum;
+ (*numSamplers)++;
}
-
}
-#if 0
- printf("================ post link uniforms ===============\n");
- _mesa_print_parameter_list(shProg->Uniforms);
-#endif
-
-#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,
+ /* OK, now scan the program/shader instructions looking for sampler vars,
* replacing the old index with the new index.
*/
prog->SamplersUsed = 0x0;
for (i = 0; i < prog->NumInstructions; i++) {
struct prog_instruction *inst = prog->Instructions + i;
- GLuint j;
-
- if (is_uniform(inst->DstReg.File)) {
- inst->DstReg.Index = map[ inst->DstReg.Index ];
- }
-
- for (j = 0; j < 3; j++) {
- if (is_uniform(inst->SrcReg[j].File)) {
- inst->SrcReg[j].Index = map[ inst->SrcReg[j].Index ];
- }
- }
-
if (_mesa_is_tex_instruction(inst->Opcode)) {
/*
printf("====== remap sampler from %d to %d\n",
@@ -286,9 +196,6 @@ link_uniform_vars(struct gl_shader_program *shProg, struct gl_program *prog)
}
}
- free(map);
-
- return GL_TRUE;
}
@@ -476,13 +383,12 @@ _slang_link(GLcontext *ctx,
{
const struct gl_vertex_program *vertProg;
const struct gl_fragment_program *fragProg;
+ GLuint numSamplers = 0;
GLuint i;
- shProg_NumSamplers = 0; /** XXX temporary */
-
_mesa_clear_shader_program_data(ctx, shProg);
- shProg->Uniforms = _mesa_new_parameter_list();
+ shProg->Uniforms = _mesa_new_uniform_list();
shProg->Varying = _mesa_new_parameter_list();
/**
@@ -519,24 +425,30 @@ _slang_link(GLcontext *ctx,
shProg->FragmentProgram = NULL;
}
+ /* link varying vars */
if (shProg->VertexProgram)
link_varying_vars(shProg, &shProg->VertexProgram->Base);
if (shProg->FragmentProgram)
link_varying_vars(shProg, &shProg->FragmentProgram->Base);
+ /* link uniform vars */
if (shProg->VertexProgram)
- link_uniform_vars(shProg, &shProg->VertexProgram->Base);
+ link_uniform_vars(shProg, &shProg->VertexProgram->Base, &numSamplers);
if (shProg->FragmentProgram)
- link_uniform_vars(shProg, &shProg->FragmentProgram->Base);
+ link_uniform_vars(shProg, &shProg->FragmentProgram->Base, &numSamplers);
+
+ /*_mesa_print_uniforms(shProg->Uniforms);*/
- /* The vertex and fragment programs share a common set of uniforms now */
if (shProg->VertexProgram) {
- _mesa_free_parameter_list(shProg->VertexProgram->Base.Parameters);
- shProg->VertexProgram->Base.Parameters = shProg->Uniforms;
+ /* Rather than cloning the parameter list here, just share it.
+ * We need to be careful _mesa_clear_shader_program_data() in
+ * to avoid double-freeing.
+ */
+ shProg->VertexProgram->Base.Parameters = vertProg->Base.Parameters;
}
if (shProg->FragmentProgram) {
- _mesa_free_parameter_list(shProg->FragmentProgram->Base.Parameters);
- shProg->FragmentProgram->Base.Parameters = shProg->Uniforms;
+ /* see comment just above */
+ shProg->FragmentProgram->Base.Parameters = fragProg->Base.Parameters;
}
if (shProg->VertexProgram) {