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 branchtags/mesa_7_1_rc1
| @@ -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 */ | |||
| @@ -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 */ | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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[] */ | |||
| @@ -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; | |||
| }; | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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, | |||
| @@ -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 (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]; | |||
| 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 | |||
| 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,55 +1100,121 @@ _mesa_use_program(GLcontext *ctx, GLuint program) | |||
| } | |||
| /** | |||
| * Called via ctx->Driver.Uniform(). | |||
| * Update the vertex and fragment program's TexturesUsed arrays. | |||
| */ | |||
| void | |||
| _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, | |||
| const GLvoid *values, GLenum type) | |||
| static void | |||
| update_textures_used(struct gl_program *prog) | |||
| { | |||
| struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; | |||
| GLint elems, i, k; | |||
| GLenum uType; | |||
| GLsizei maxCount; | |||
| GLuint s; | |||
| if (!shProg || !shProg->LinkStatus) { | |||
| _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)"); | |||
| return; | |||
| } | |||
| memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed)); | |||
| 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)"); | |||
| return; | |||
| 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); | |||
| } | |||
| } | |||
| } | |||
| 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; | |||
| /** | |||
| * 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 */ | |||
| unit = ((GLint *) values)[0]; | |||
| if (unit >= ctx->Const.MaxTextureImageUnits) { | |||
| 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(). | |||
| */ | |||
| void | |||
| _mesa_uniform(GLcontext *ctx, GLint location, GLsizei count, | |||
| const GLvoid *values, GLenum type) | |||
| { | |||
| struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; | |||
| GLint elems; | |||
| if (!shProg || !shProg->LinkStatus) { | |||
| _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)"); | |||
| return; | |||
| } | |||
| if (location == -1) | |||
| return; /* The standard specifies this as a no-op */ | |||
| if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) { | |||
| _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)"); | |||
| return; | |||
| } | |||
| if (count < 0) { | |||
| @@ -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. | |||
| FLUSH_VERTICES(ctx, _NEW_PROGRAM); | |||
| /* 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: | |||
| */ | |||
| 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; | |||
| 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->FragmentProgram) { | |||
| GLint loc = shProg->Uniforms->Uniforms[location].FragPos; | |||
| if (loc >= 0) { | |||
| set_program_uniform(ctx, &shProg->FragmentProgram->Base, | |||
| loc, type, count, elems, values); | |||
| } | |||
| } | |||
| } | |||
| /* 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. | |||
| 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. | |||
| */ | |||
| 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]; | |||
| /* 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 { | |||
| const GLfloat *fValues = ((const GLfloat *) values) + k * elems; | |||
| for (i = 0; i < elems; i++) { | |||
| uniformVal[i] = fValues[i]; | |||
| } | |||
| 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]; | |||
| } | |||
| } | |||
| 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->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); | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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) { | |||
| @@ -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; | |||
| } | |||
| @@ -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; | |||
| } | |||
| @@ -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) | |||
| { | |||
| return (file == PROGRAM_ENV_PARAM || | |||
| file == PROGRAM_STATE_VAR || | |||
| file == PROGRAM_NAMED_PARAM || | |||
| file == PROGRAM_CONSTANT || | |||
| file == PROGRAM_SAMPLER || | |||
| file == PROGRAM_UNIFORM); | |||
| } | |||
| 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; | |||
| #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; | |||
| GLuint samplerMap[MAX_SAMPLERS]; | |||
| GLuint i; | |||
| 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)); | |||
| 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 (j >= 0) { | |||
| /* already in list, check size XXX check this */ | |||
| #if 0 | |||
| assert(p->Size == shProg->Uniforms->Parameters[j].Size); | |||
| #endif | |||
| /* | |||
| * 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); | |||
| } | |||
| 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 (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 (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) { | |||
| @@ -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); | |||
| @@ -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; | |||
| @@ -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 \ | |||
| @@ -33,18 +33,19 @@ | |||
| /** | |||
| * 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); | |||
| const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current; | |||
| lambda = CLAMP(lambda, texObj->MinLod, texObj->MaxLod); | |||
| /* XXX use a float-valued TextureSample routine here!!! */ | |||
| swrast->TextureSample[unit](ctx, texObj, 1, (const GLfloat (*)[4]) texcoord, | |||
| &lambda, &rgba); | |||
| @@ -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; | |||
| } | |||
| @@ -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; | |||