Updated GLSL uniform/sampler handling from gallium-0.1 branch

Previously, the shader linker combined the uniforms used by the vertex and
fragment shaders into a combined set of uniforms.  This made the implementation
of glUniform*() simple, but was rather inefficient otherwise.  Now each shader
gets its own set of uniforms (no more modelview matrix showing up in the
fragment shader uniforms, for example).

cherry-picked by hand from gallium-0.1 branch
This commit is contained in:
Brian Paul
2008-05-14 16:09:46 -06:00
parent c807c1a23f
commit ade508312c
17 changed files with 341 additions and 416 deletions

View File

@@ -188,6 +188,7 @@
#define MAX_PROGRAM_ADDRESS_REGS 2
#define MAX_UNIFORMS 128
#define MAX_VARYING 8
#define MAX_SAMPLERS 8
/*@}*/
/** For GL_NV_vertex_program */

View File

@@ -1863,6 +1863,7 @@ enum register_file
/** Vertex and fragment instructions */
struct prog_instruction;
struct gl_program_parameter_list;
struct gl_uniform_list;
/**
@@ -1882,6 +1883,7 @@ struct gl_program
GLbitfield InputsRead; /**< Bitmask of which input regs are read */
GLbitfield OutputsWritten; /**< Bitmask of which output regs are written to */
GLbitfield TexturesUsed[MAX_TEXTURE_IMAGE_UNITS]; /**< TEXTURE_x_BIT bitmask */
GLbitfield SamplersUsed; /**< Bitfield of which samplers are used */
GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */
/** Named parameters, constants, etc. from program text */
@@ -1894,6 +1896,11 @@ struct gl_program
/** Vertex program user-defined attributes */
struct gl_program_parameter_list *Attributes;
/** Map from sampler unit to texture unit (set by glUniform1i()) */
GLubyte SamplerUnits[MAX_SAMPLERS];
/** Which texture target is being sampled (TEXTURE_1D/2D/3D/etc_INDEX) */
GLubyte SamplerTargets[MAX_SAMPLERS];
/** Logical counts */
/*@{*/
GLuint NumInstructions;
@@ -2086,7 +2093,7 @@ struct gl_query_state
/**
* A GLSL shader object.
* A GLSL vertex or fragment shader object.
*/
struct gl_shader
{
@@ -2104,7 +2111,8 @@ struct gl_shader
/**
* A GLSL program object. Basically a linked collection of "shaders".
* A GLSL program object.
* Basically a linked collection of vertex and fragment shaders.
*/
struct gl_shader_program
{
@@ -2119,7 +2127,7 @@ struct gl_shader_program
/* post-link info: */
struct gl_vertex_program *VertexProgram; /**< Linked vertex program */
struct gl_fragment_program *FragmentProgram; /**< Linked fragment prog */
struct gl_program_parameter_list *Uniforms; /**< Plus constants, etc */
struct gl_uniform_list *Uniforms;
struct gl_program_parameter_list *Varying;
struct gl_program_parameter_list *Attributes; /**< Vertex attributes */
GLboolean LinkStatus; /**< GL_LINK_STATUS */

View File

@@ -310,6 +310,8 @@ fetch_texel(GLcontext *ctx,
const GLfloat texcoord[4], GLfloat lodBias,
GLfloat color[4])
{
const GLuint unit = machine->Samplers[inst->TexSrcUnit];
/* Note: we only have the right derivatives for fragment input attribs.
*/
if (machine->NumDeriv > 0 &&
@@ -320,12 +322,10 @@ fetch_texel(GLcontext *ctx,
machine->FetchTexelDeriv(ctx, texcoord,
machine->DerivX[attr],
machine->DerivY[attr],
lodBias,
inst->TexSrcUnit, color);
lodBias, unit, color);
}
else {
machine->FetchTexelLod(ctx, texcoord, lodBias,
inst->TexSrcUnit, color);
machine->FetchTexelLod(ctx, texcoord, lodBias, unit, color);
}
}

View File

@@ -63,6 +63,8 @@ struct gl_program_machine
GLuint CondCodes[4]; /**< COND_* value for x/y/z/w */
GLint AddressReg[MAX_PROGRAM_ADDRESS_REGS][4];
const GLubyte *Samplers; /** Array mapping sampler var to tex unit */
GLuint CallStack[MAX_PROGRAM_CALL_DEPTH]; /**< For CAL/RET instructions */
GLuint StackDepth; /**< Index/ptr to top of CallStack[] */

View File

@@ -413,12 +413,13 @@ struct prog_instruction
*/
GLint BranchTarget;
#if 0
/**
* For TEX instructions in shaders, the sampler to use for the
* texture lookup.
*/
GLint Sampler;
#endif
const char *Comment;
};

View File

@@ -282,22 +282,25 @@ _mesa_add_uniform(struct gl_program_parameter_list *paramList,
* Add a sampler to the parameter list.
* \param name uniform's name
* \param datatype GL_SAMPLER_2D, GL_SAMPLER_2D_RECT_ARB, etc.
* \param index the sampler number (as seen in TEX instructions)
*/
GLint
_mesa_add_sampler(struct gl_program_parameter_list *paramList,
const char *name, GLenum datatype)
const char *name, GLenum datatype, GLuint index)
{
GLint i = _mesa_lookup_parameter_index(paramList, -1, name);
if (i >= 0 && paramList->Parameters[i].Type == PROGRAM_SAMPLER) {
ASSERT(paramList->Parameters[i].Size == 1);
ASSERT(paramList->Parameters[i].DataType == datatype);
ASSERT(paramList->ParameterValues[i][0] == index);
/* already in list */
return i;
}
else {
GLfloat indexf = index;
const GLint size = 1; /* a sampler is basically a texture unit number */
i = _mesa_add_parameter(paramList, PROGRAM_SAMPLER, name,
size, datatype, NULL, NULL);
size, datatype, &indexf, NULL);
return i;
}
}

View File

@@ -114,7 +114,7 @@ _mesa_add_uniform(struct gl_program_parameter_list *paramList,
extern GLint
_mesa_add_sampler(struct gl_program_parameter_list *paramList,
const char *name, GLenum datatype);
const char *name, GLenum datatype, GLuint index);
extern GLint
_mesa_add_varying(struct gl_program_parameter_list *paramList,

View File

@@ -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,23 +76,23 @@ _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;
_mesa_reference_vertprog(ctx, &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;
_mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
}
if (shProg->Uniforms) {
_mesa_free_parameter_list(shProg->Uniforms);
_mesa_free_uniform_list(shProg->Uniforms);
shProg->Uniforms = NULL;
}
@@ -680,9 +681,9 @@ _mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
shProg->Attributes->Parameters[index].Name);
sz = shProg->Attributes->Parameters[index].Size;
if (size)
*size = 1; /* attributes may not be arrays */
if (type && sz > 0 && sz <= 4) /* XXX this is a temporary hack */
*type = vec_types[sz - 1];
*size = sz;
if (type)
*type = vec_types[sz]; /* XXX this is a temporary hack */
}
@@ -696,41 +697,41 @@ _mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
{
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) {
GLuint uSize = shProg->Uniforms->Parameters[j].Size;
GLenum uType = shProg->Uniforms->Parameters[j].DataType;
/* found it */
copy_string(nameOut, maxLength, length,
shProg->Uniforms->Parameters[j].Name);
if (size) {
/* convert from floats to 'type' (eg: sizeof(mat4x4)=1) */
*size = uSize / sizeof_glsl_type(uType);
}
if (type)
*type = uType;
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;
}
@@ -848,14 +849,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;
@@ -952,42 +949,24 @@ _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) {
GLuint uSize;
GLenum uType;
GLint rows = 0;
uType = shProg->Uniforms->Parameters[location].DataType;
uSize = sizeof_glsl_type(uType);
/* Matrix types need special handling, because they span several
* parameters, and may also not be fully packed.
*/
switch (shProg->Uniforms->Parameters[location].DataType) {
case GL_FLOAT_MAT2:
case GL_FLOAT_MAT3x2:
case GL_FLOAT_MAT4x2:
rows = 2;
break;
case GL_FLOAT_MAT2x3:
case GL_FLOAT_MAT3:
case GL_FLOAT_MAT4x3:
rows = 3;
break;
case GL_FLOAT_MAT2x4:
case GL_FLOAT_MAT3x4:
case GL_FLOAT_MAT4:
rows = 4;
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;
}
if (rows != 0) {
GLint r, c;
for (c = 0, i = 0; c * 4 < uSize; c++)
for (r = 0; r < rows; r++, i++)
params[i] = shProg->Uniforms->ParameterValues[location + c][r];
}
else
for (i = 0; i < uSize; i++) {
params[i] = shProg->Uniforms->ParameterValues[location][i];
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 {
_mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
@@ -1007,23 +986,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);
}
@@ -1134,6 +1100,100 @@ _mesa_use_program(GLcontext *ctx, GLuint program)
}
/**
* Update the vertex and fragment program's TexturesUsed arrays.
*/
static void
update_textures_used(struct gl_program *prog)
{
GLuint s;
memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
for (s = 0; s < MAX_SAMPLERS; s++) {
if (prog->SamplersUsed & (1 << s)) {
GLuint u = prog->SamplerUnits[s];
GLuint t = prog->SamplerTargets[s];
assert(u < MAX_TEXTURE_IMAGE_UNITS);
prog->TexturesUsed[u] |= (1 << t);
}
}
}
/**
* 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().
*/
@@ -1142,9 +1202,7 @@ _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;
GLenum uType;
GLsizei maxCount;
GLint elems;
if (!shProg || !shProg->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
@@ -1154,37 +1212,11 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
if (location == -1)
return; /* The standard specifies this as a no-op */
/* The spec says this is GL_INVALID_OPERATION, although it seems like it
* ought to be GL_INVALID_VALUE
*/
if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
return;
}
FLUSH_VERTICES(ctx, _NEW_PROGRAM);
uType = shProg->Uniforms->Parameters[location].DataType;
/*
* If we're setting a sampler, we must use glUniformi1()!
*/
if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
GLint unit;
if (type != GL_INT || count != 1) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glUniform(only glUniform1i can be used "
"to set sampler uniforms)");
return;
}
/* check that the sampler (tex unit index) is legal */
unit = ((GLint *) values)[0];
if (unit >= ctx->Const.MaxTextureImageUnits) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glUniform1(invalid sampler/tex unit index)");
return;
}
}
if (count < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
return;
@@ -1212,69 +1244,56 @@ _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
return;
}
/* OpenGL requires types to match exactly, except that one can convert
* float or int array to boolean array.
*/
switch (uType)
{
case GL_BOOL:
case GL_BOOL_VEC2:
case GL_BOOL_VEC3:
case GL_BOOL_VEC4:
if (elems != sizeof_glsl_type(uType)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)");
}
break;
case PROGRAM_SAMPLER:
break;
default:
if (shProg->Uniforms->Parameters[location].Type != PROGRAM_SAMPLER
&& uType != type) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
}
break;
}
FLUSH_VERTICES(ctx, _NEW_PROGRAM);
/* XXX if this is a base type, then count must equal 1. However, we
* don't have enough information from the compiler to distinguish a
* base type from a 1-element array of that type. The standard allows
* count to overrun an array, in which case the overflow is ignored.
/* 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:
*/
maxCount = shProg->Uniforms->Parameters[location].Size / elems;
if (count > maxCount) count = maxCount;
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];
}
}
if (uType == GL_BOOL ||
uType == GL_BOOL_VEC2 ||
uType == GL_BOOL_VEC3 ||
uType == GL_BOOL_VEC4) {
for (i = 0; i < elems; i++)
uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
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->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
if (shProg->VertexProgram)
_slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
if (shProg->FragmentProgram)
_slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
FLUSH_VERTICES(ctx, _NEW_TEXTURE);
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);
}
}
}
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 {
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];
}
}
}
}
@@ -1287,62 +1306,42 @@ _mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
GLenum matrixType, GLint location, GLsizei count,
GLboolean transpose, const GLfloat *values)
{
GLsizei maxCount, i;
struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
if (!shProg || !shProg->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glUniformMatrix(program not linked)");
return;
}
if (location == -1)
return; /* The standard specifies this as a no-op */
/* The spec says this is GL_INVALID_OPERATION, although it seems like it
* ought to be GL_INVALID_VALUE
*/
if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
return;
}
if (values == NULL) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
return;
}
if (count < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(count < 0)");
return;
}
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... */
maxCount = shProg->Uniforms->Parameters[location].Size / (4 * cols);
if (count > maxCount)
count = maxCount;
for (i = 0; i < count; i++) {
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);
}
location += cols;
values += rows * cols;
}
}

View File

@@ -2836,14 +2836,14 @@ _slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var,
const GLint texIndex = sampler_to_texture_index(var->type.specifier.type);
if (texIndex != -1) {
/* Texture sampler:
/* This is a texture sampler variable...
* store->File = PROGRAM_SAMPLER
* store->Index = sampler uniform location
* store->Index = sampler number (0..7, typically)
* store->Size = texture type index (1D, 2D, 3D, cube, etc)
*/
GLint samplerUniform
= _mesa_add_sampler(prog->Parameters, varName, datatype);
store = _slang_new_ir_storage(PROGRAM_SAMPLER, samplerUniform, texIndex);
const GLint sampNum = A->numSamplers++;
_mesa_add_sampler(prog->Parameters, varName, datatype, sampNum);
store = _slang_new_ir_storage(PROGRAM_SAMPLER, sampNum, texIndex);
if (dbg) printf("SAMPLER ");
}
else if (var->type.qualifier == SLANG_QUAL_UNIFORM) {

View File

@@ -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"
@@ -1618,6 +1620,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
A.program = O->program;
A.vartable = O->vartable;
A.curFuncEndLabel = NULL;
A.numSamplers = 0;
if (!_slang_codegen_global_variable(&A, var, C->type))
return 0;
}
@@ -1640,6 +1643,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O,
A.space.funcs = O->funs;
A.space.structs = O->structs;
A.space.vars = O->vars;
A.numSamplers = 0;
if (!initialize_global(&A, var))
return 0;
}
@@ -1773,6 +1777,7 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition,
A.program = O->program;
A.vartable = O->vartable;
A.log = C->L;
A.numSamplers = 0;
_slang_codegen_function(&A, *parsed_func_ret);
}
@@ -2180,6 +2185,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;
}

View File

@@ -922,11 +922,15 @@ emit_tex(slang_emit_info *emitInfo, slang_ir_node *n)
assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
assert(n->Children[0]->Store->Size <= TEXTURE_RECT_INDEX);
inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
inst->TexSrcTarget = n->Children[0]->Store->Size;
#if 0
inst->TexSrcUnit = 27; /* Dummy value; the TexSrcUnit will be computed at
* link time, using the sampler uniform's value.
*/
inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
#else
inst->TexSrcUnit = n->Children[0]->Store->Index; /* i.e. uniform's index */
#endif
return inst;
}

View File

@@ -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,145 +137,65 @@ link_varying_vars(struct gl_shader_program *shProg, struct gl_program *prog)
}
static GLboolean
is_uniform(GLuint file)
/**
* 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)
{
return (file == PROGRAM_ENV_PARAM ||
file == PROGRAM_STATE_VAR ||
file == PROGRAM_NAMED_PARAM ||
file == PROGRAM_CONSTANT ||
file == PROGRAM_SAMPLER ||
file == PROGRAM_UNIFORM);
}
GLuint samplerMap[MAX_SAMPLERS];
GLuint i;
static GLboolean
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; /* 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));
/*
* 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->Name) {
j = _mesa_lookup_parameter_index(shProg->Uniforms, -1, p->Name);
}
else {
/*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 (p->Type == PROGRAM_UNIFORM ||
p->Type == PROGRAM_SAMPLER) {
_mesa_append_uniform(shProg->Uniforms, p->Name, prog->Target, i);
}
if (j >= 0) {
/* already in list, check size XXX check this */
#if 0
assert(p->Size == shProg->Uniforms->Parameters[j].Size);
#endif
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)++;
}
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:
j = _mesa_add_sampler(shProg->Uniforms, p->Name, p->DataType);
break;
default:
_mesa_problem(NULL, "bad parameter type in link_uniform_vars()");
return GL_FALSE;
}
}
ASSERT(j >= 0);
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
#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 (inst->Opcode == OPCODE_TEX ||
inst->Opcode == OPCODE_TXB ||
inst->Opcode == OPCODE_TXP) {
if (_mesa_is_tex_instruction(inst->Opcode)) {
/*
printf("====== remap sampler from %d to %d\n",
inst->Sampler, map[ inst->Sampler ]);
*/
inst->Sampler = map[ inst->Sampler ];
/* here, texUnit is really samplerUnit */
inst->TexSrcUnit = samplerMap[inst->TexSrcUnit];
prog->SamplerTargets[inst->TexSrcUnit] = inst->TexSrcTarget;
prog->SamplersUsed |= (1 << inst->TexSrcUnit);
}
}
free(map);
return GL_TRUE;
}
@@ -329,10 +254,8 @@ _slang_resolve_attributes(struct gl_shader_program *shProg,
* glVertex/position.
*/
for (attr = 1; attr < MAX_VERTEX_ATTRIBS; attr++) {
if (((1 << attr) & usedAttributes) == 0) {
usedAttributes |= (1 << attr);
if (((1 << attr) & usedAttributes) == 0)
break;
}
}
if (attr == MAX_VERTEX_ATTRIBS) {
/* too many! XXX record error log */
@@ -406,36 +329,6 @@ _slang_remap_attribute(struct gl_program *prog, GLuint oldAttrib, GLuint newAttr
/**
* 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);
}
}
}
/** cast wrapper */
static struct gl_vertex_program *
vertex_program(struct gl_program *prog)
@@ -476,12 +369,9 @@ link_error(struct gl_shader_program *shProg, const char *msg)
* 2. Varying vars in the two shaders are combined so their locations
* agree between the vertex and fragment stages. They're treated as
* vertex program output attribs and as fragment program input attribs.
* 3. Uniform vars (including state references, constants, etc) from the
* vertex and fragment shaders are merged into one group. Recall that
* GLSL uniforms are shared by all linked shaders.
* 4. The vertex and fragment programs are cloned and modified to update
* src/dst register references so they use the new, linked uniform/
* varying storage locations.
* 3. The vertex and fragment programs are cloned and modified to update
* src/dst register references so they use the new, linked varying
* storage locations.
*/
void
_slang_link(GLcontext *ctx,
@@ -490,11 +380,12 @@ _slang_link(GLcontext *ctx,
{
const struct gl_vertex_program *vertProg;
const struct gl_fragment_program *fragProg;
GLuint numSamplers = 0;
GLuint i;
_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();
/**
@@ -531,33 +422,30 @@ _slang_link(GLcontext *ctx,
_mesa_reference_fragprog(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);
/* 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;
assert(shProg->Uniforms);
}
if (shProg->FragmentProgram) {
_mesa_free_parameter_list(shProg->FragmentProgram->Base.Parameters);
shProg->FragmentProgram->Base.Parameters = shProg->Uniforms;
assert(shProg->Uniforms);
}
/*_mesa_print_uniforms(shProg->Uniforms);*/
if (shProg->VertexProgram) {
_slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
/* 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) {
_slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
/* see comment just above */
shProg->FragmentProgram->Base.Parameters = fragProg->Base.Parameters;
}
if (shProg->VertexProgram) {

View File

@@ -32,10 +32,6 @@ extern void
_slang_link(GLcontext *ctx, GLhandleARB h,
struct gl_shader_program *shProg);
extern void
_slang_resolve_samplers(struct gl_shader_program *shProg,
struct gl_program *prog);
extern void
_slang_remap_attribute(struct gl_program *prog, GLuint oldAttrib,
GLuint newAttrib);

View File

@@ -65,6 +65,7 @@ typedef struct slang_assemble_ctx_
struct slang_label_ *curFuncEndLabel;
struct slang_ir_node_ *CurLoop;
struct slang_function_ *CurFunction;
GLuint numSamplers;
} slang_assemble_ctx;

View File

@@ -165,6 +165,7 @@ SHADER_SOURCES = \
shader/prog_parameter.c \
shader/prog_print.c \
shader/prog_statevars.c \
shader/prog_uniform.c \
shader/programopt.c \
shader/shader_api.c \

View File

@@ -33,11 +33,12 @@
/**
* Fetch a texel.
* Fetch a texel with given lod.
* Called via machine->FetchTexelLod()
*/
static void
fetch_texel( GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda,
GLuint unit, GLfloat color[4] )
fetch_texel_lod( GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda,
GLuint unit, GLfloat color[4] )
{
GLchan rgba[4];
SWcontext *swrast = SWRAST_CONTEXT(ctx);
@@ -58,6 +59,7 @@ fetch_texel( GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda,
/**
* Fetch a texel with the given partial derivatives to compute a level
* of detail in the mipmap.
* Called via machine->FetchTexelDeriv()
*/
static void
fetch_texel_deriv( GLcontext *ctx, const GLfloat texcoord[4],
@@ -117,6 +119,8 @@ init_machine(GLcontext *ctx, struct gl_program_machine *machine,
machine->DerivY = (GLfloat (*)[4]) span->attrStepY;
machine->NumDeriv = FRAG_ATTRIB_MAX;
machine->Samplers = program->Base.SamplerUnits;
/* if running a GLSL program (not ARB_fragment_program) */
if (ctx->Shader.CurrentProgram) {
/* Store front/back facing value in register FOGC.Y */
@@ -134,7 +138,7 @@ init_machine(GLcontext *ctx, struct gl_program_machine *machine,
/* init call stack */
machine->StackDepth = 0;
machine->FetchTexelLod = fetch_texel;
machine->FetchTexelLod = fetch_texel_lod;
machine->FetchTexelDeriv = fetch_texel_deriv;
}

View File

@@ -1401,7 +1401,6 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span)
* Write to renderbuffers
*/
{
const struct gl_fragment_program *fp = ctx->FragmentProgram._Current;
const GLuint numBuffers = fb->_NumColorDrawBuffers;
const GLboolean multiFragOutputs = numBuffers > 1;
GLuint buf;