aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/main
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa/main')
-rw-r--r--mesalib/src/mesa/main/bufferobj.c1
-rw-r--r--mesalib/src/mesa/main/context.c18
-rw-r--r--mesalib/src/mesa/main/context.h24
-rw-r--r--mesalib/src/mesa/main/ff_fragment_shader.cpp1504
-rw-r--r--mesalib/src/mesa/main/get.c12
-rw-r--r--mesalib/src/mesa/main/mtypes.h22
-rw-r--r--mesalib/src/mesa/main/queryobj.c1
-rw-r--r--mesalib/src/mesa/main/shaderapi.c5
-rw-r--r--mesalib/src/mesa/main/shaderobj.c828
-rw-r--r--mesalib/src/mesa/main/state.c25
-rw-r--r--mesalib/src/mesa/main/state.h39
-rw-r--r--mesalib/src/mesa/main/texenvprogram.c1618
-rw-r--r--mesalib/src/mesa/main/texenvprogram.h2
-rw-r--r--mesalib/src/mesa/main/uniforms.c3398
14 files changed, 3717 insertions, 3780 deletions
diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c
index afb7999de..ce3bf86fb 100644
--- a/mesalib/src/mesa/main/bufferobj.c
+++ b/mesalib/src/mesa/main/bufferobj.c
@@ -749,6 +749,7 @@ _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
GET_CURRENT_CONTEXT(ctx);
GLsizei i;
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ FLUSH_VERTICES(ctx, 0);
if (n < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c
index 8db8ed865..d5baf4a29 100644
--- a/mesalib/src/mesa/main/context.c
+++ b/mesalib/src/mesa/main/context.c
@@ -486,7 +486,6 @@ init_program_limits(GLenum type, struct gl_program_constants *prog)
prog->MaxTemps = MAX_PROGRAM_TEMPS;
prog->MaxEnvParams = MAX_PROGRAM_ENV_PARAMS;
prog->MaxLocalParams = MAX_PROGRAM_LOCAL_PARAMS;
- prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
prog->MaxAddressOffset = MAX_PROGRAM_LOCAL_PARAMS;
switch (type) {
@@ -494,23 +493,19 @@ init_program_limits(GLenum type, struct gl_program_constants *prog)
prog->MaxParameters = MAX_VERTEX_PROGRAM_PARAMS;
prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
+ prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
break;
case GL_FRAGMENT_PROGRAM_ARB:
prog->MaxParameters = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
prog->MaxAttribs = MAX_NV_FRAGMENT_PROGRAM_INPUTS;
prog->MaxAddressRegs = MAX_FRAGMENT_PROGRAM_ADDRESS_REGS;
+ prog->MaxUniformComponents = 4 * MAX_UNIFORMS;
break;
case MESA_GEOMETRY_PROGRAM:
prog->MaxParameters = MAX_NV_VERTEX_PROGRAM_PARAMS;
prog->MaxAttribs = MAX_NV_VERTEX_PROGRAM_INPUTS;
prog->MaxAddressRegs = MAX_VERTEX_PROGRAM_ADDRESS_REGS;
-
- prog->MaxGeometryTextureImageUnits = MAX_GEOMETRY_TEXTURE_IMAGE_UNITS;
- prog->MaxGeometryVaryingComponents = MAX_GEOMETRY_VARYING_COMPONENTS;
- prog->MaxVertexVaryingComponents = MAX_VERTEX_VARYING_COMPONENTS;
- prog->MaxGeometryUniformComponents = MAX_GEOMETRY_UNIFORM_COMPONENTS;
- prog->MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
- prog->MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
+ prog->MaxUniformComponents = MAX_GEOMETRY_UNIFORM_COMPONENTS;
break;
default:
assert(0 && "Bad program type in init_program_limits()");
@@ -619,6 +614,13 @@ _mesa_init_constants(struct gl_context *ctx)
ctx->Const.MaxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS;
ctx->Const.MaxVarying = MAX_VARYING;
#endif
+#if FEATURE_ARB_geometry_shader4
+ ctx->Const.MaxGeometryTextureImageUnits = MAX_GEOMETRY_TEXTURE_IMAGE_UNITS;
+ ctx->Const.MaxVertexVaryingComponents = MAX_VERTEX_VARYING_COMPONENTS;
+ ctx->Const.MaxGeometryVaryingComponents = MAX_GEOMETRY_VARYING_COMPONENTS;
+ ctx->Const.MaxGeometryOutputVertices = MAX_GEOMETRY_OUTPUT_VERTICES;
+ ctx->Const.MaxGeometryTotalOutputComponents = MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS;
+#endif
/* Shading language version */
if (ctx->API == API_OPENGL) {
diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h
index 160e795f7..ae4d6f7da 100644
--- a/mesalib/src/mesa/main/context.h
+++ b/mesalib/src/mesa/main/context.h
@@ -286,28 +286,4 @@ do { \
-/**
- * Is the secondary color needed?
- */
-#define NEED_SECONDARY_COLOR(CTX) \
- (((CTX)->Light.Enabled && \
- (CTX)->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) \
- || (CTX)->Fog.ColorSumEnabled \
- || ((CTX)->VertexProgram._Current && \
- ((CTX)->VertexProgram._Current != (CTX)->VertexProgram._TnlProgram) && \
- ((CTX)->VertexProgram._Current->Base.InputsRead & VERT_BIT_COLOR1)) \
- || ((CTX)->FragmentProgram._Current && \
- ((CTX)->FragmentProgram._Current != (CTX)->FragmentProgram._TexEnvProgram) && \
- ((CTX)->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL1)) \
- )
-
-
-/**
- * Is RGBA LogicOp enabled?
- */
-#define RGBA_LOGICOP_ENABLED(CTX) \
- ((CTX)->Color.ColorLogicOpEnabled || \
- ((CTX)->Color.BlendEnabled && (CTX)->Color.Blend[0].EquationRGB == GL_LOGIC_OP))
-
-
#endif /* CONTEXT_H */
diff --git a/mesalib/src/mesa/main/ff_fragment_shader.cpp b/mesalib/src/mesa/main/ff_fragment_shader.cpp
new file mode 100644
index 000000000..ed513397a
--- /dev/null
+++ b/mesalib/src/mesa/main/ff_fragment_shader.cpp
@@ -0,0 +1,1504 @@
+/**************************************************************************
+ *
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * Copyright 2009 VMware, Inc. All Rights Reserved.
+ * Copyright © 2010 Intel Corporation
+ *
+ * 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
+ *
+ **************************************************************************/
+
+extern "C" {
+#include "glheader.h"
+#include "imports.h"
+#include "mtypes.h"
+#include "main/uniforms.h"
+#include "main/macros.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
+#include "program/prog_cache.h"
+#include "program/prog_instruction.h"
+#include "program/prog_print.h"
+#include "program/prog_statevars.h"
+#include "program/programopt.h"
+#include "texenvprogram.h"
+}
+#include "../glsl/glsl_types.h"
+#include "../glsl/ir.h"
+#include "../glsl/glsl_symbol_table.h"
+#include "../glsl/glsl_parser_extras.h"
+#include "../glsl/ir_optimization.h"
+#include "../glsl/ir_print_visitor.h"
+#include "../program/ir_to_mesa.h"
+
+/*
+ * Note on texture units:
+ *
+ * The number of texture units supported by fixed-function fragment
+ * processing is MAX_TEXTURE_COORD_UNITS, not MAX_TEXTURE_IMAGE_UNITS.
+ * That's because there's a one-to-one correspondence between texture
+ * coordinates and samplers in fixed-function processing.
+ *
+ * Since fixed-function vertex processing is limited to MAX_TEXTURE_COORD_UNITS
+ * sets of texcoords, so is fixed-function fragment processing.
+ *
+ * We can safely use ctx->Const.MaxTextureUnits for loop bounds.
+ */
+
+
+struct texenvprog_cache_item
+{
+ GLuint hash;
+ void *key;
+ struct gl_shader_program *data;
+ struct texenvprog_cache_item *next;
+};
+
+static GLboolean
+texenv_doing_secondary_color(struct gl_context *ctx)
+{
+ if (ctx->Light.Enabled &&
+ (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))
+ return GL_TRUE;
+
+ if (ctx->Fog.ColorSumEnabled)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+struct mode_opt {
+#ifdef __GNUC__
+ __extension__ GLubyte Source:4; /**< SRC_x */
+ __extension__ GLubyte Operand:3; /**< OPR_x */
+#else
+ GLubyte Source; /**< SRC_x */
+ GLubyte Operand; /**< OPR_x */
+#endif
+};
+
+struct state_key {
+ GLuint nr_enabled_units:8;
+ GLuint enabled_units:8;
+ GLuint separate_specular:1;
+ GLuint fog_enabled:1;
+ GLuint fog_mode:2; /**< FOG_x */
+ GLuint inputs_available:12;
+ GLuint num_draw_buffers:4;
+
+ /* NOTE: This array of structs must be last! (see "keySize" below) */
+ struct {
+ GLuint enabled:1;
+ GLuint source_index:3; /**< TEXTURE_x_INDEX */
+ GLuint shadow:1;
+ GLuint ScaleShiftRGB:2;
+ GLuint ScaleShiftA:2;
+
+ GLuint NumArgsRGB:3; /**< up to MAX_COMBINER_TERMS */
+ GLuint ModeRGB:5; /**< MODE_x */
+
+ GLuint NumArgsA:3; /**< up to MAX_COMBINER_TERMS */
+ GLuint ModeA:5; /**< MODE_x */
+
+ struct mode_opt OptRGB[MAX_COMBINER_TERMS];
+ struct mode_opt OptA[MAX_COMBINER_TERMS];
+ } unit[MAX_TEXTURE_UNITS];
+};
+
+#define FOG_LINEAR 0
+#define FOG_EXP 1
+#define FOG_EXP2 2
+#define FOG_UNKNOWN 3
+
+static GLuint translate_fog_mode( GLenum mode )
+{
+ switch (mode) {
+ case GL_LINEAR: return FOG_LINEAR;
+ case GL_EXP: return FOG_EXP;
+ case GL_EXP2: return FOG_EXP2;
+ default: return FOG_UNKNOWN;
+ }
+}
+
+#define OPR_SRC_COLOR 0
+#define OPR_ONE_MINUS_SRC_COLOR 1
+#define OPR_SRC_ALPHA 2
+#define OPR_ONE_MINUS_SRC_ALPHA 3
+#define OPR_ZERO 4
+#define OPR_ONE 5
+#define OPR_UNKNOWN 7
+
+static GLuint translate_operand( GLenum operand )
+{
+ switch (operand) {
+ case GL_SRC_COLOR: return OPR_SRC_COLOR;
+ case GL_ONE_MINUS_SRC_COLOR: return OPR_ONE_MINUS_SRC_COLOR;
+ case GL_SRC_ALPHA: return OPR_SRC_ALPHA;
+ case GL_ONE_MINUS_SRC_ALPHA: return OPR_ONE_MINUS_SRC_ALPHA;
+ case GL_ZERO: return OPR_ZERO;
+ case GL_ONE: return OPR_ONE;
+ default:
+ assert(0);
+ return OPR_UNKNOWN;
+ }
+}
+
+#define SRC_TEXTURE 0
+#define SRC_TEXTURE0 1
+#define SRC_TEXTURE1 2
+#define SRC_TEXTURE2 3
+#define SRC_TEXTURE3 4
+#define SRC_TEXTURE4 5
+#define SRC_TEXTURE5 6
+#define SRC_TEXTURE6 7
+#define SRC_TEXTURE7 8
+#define SRC_CONSTANT 9
+#define SRC_PRIMARY_COLOR 10
+#define SRC_PREVIOUS 11
+#define SRC_ZERO 12
+#define SRC_UNKNOWN 15
+
+static GLuint translate_source( GLenum src )
+{
+ switch (src) {
+ case GL_TEXTURE: return SRC_TEXTURE;
+ case GL_TEXTURE0:
+ case GL_TEXTURE1:
+ case GL_TEXTURE2:
+ case GL_TEXTURE3:
+ case GL_TEXTURE4:
+ case GL_TEXTURE5:
+ case GL_TEXTURE6:
+ case GL_TEXTURE7: return SRC_TEXTURE0 + (src - GL_TEXTURE0);
+ case GL_CONSTANT: return SRC_CONSTANT;
+ case GL_PRIMARY_COLOR: return SRC_PRIMARY_COLOR;
+ case GL_PREVIOUS: return SRC_PREVIOUS;
+ case GL_ZERO:
+ return SRC_ZERO;
+ default:
+ assert(0);
+ return SRC_UNKNOWN;
+ }
+}
+
+#define MODE_REPLACE 0 /* r = a0 */
+#define MODE_MODULATE 1 /* r = a0 * a1 */
+#define MODE_ADD 2 /* r = a0 + a1 */
+#define MODE_ADD_SIGNED 3 /* r = a0 + a1 - 0.5 */
+#define MODE_INTERPOLATE 4 /* r = a0 * a2 + a1 * (1 - a2) */
+#define MODE_SUBTRACT 5 /* r = a0 - a1 */
+#define MODE_DOT3_RGB 6 /* r = a0 . a1 */
+#define MODE_DOT3_RGB_EXT 7 /* r = a0 . a1 */
+#define MODE_DOT3_RGBA 8 /* r = a0 . a1 */
+#define MODE_DOT3_RGBA_EXT 9 /* r = a0 . a1 */
+#define MODE_MODULATE_ADD_ATI 10 /* r = a0 * a2 + a1 */
+#define MODE_MODULATE_SIGNED_ADD_ATI 11 /* r = a0 * a2 + a1 - 0.5 */
+#define MODE_MODULATE_SUBTRACT_ATI 12 /* r = a0 * a2 - a1 */
+#define MODE_ADD_PRODUCTS 13 /* r = a0 * a1 + a2 * a3 */
+#define MODE_ADD_PRODUCTS_SIGNED 14 /* r = a0 * a1 + a2 * a3 - 0.5 */
+#define MODE_BUMP_ENVMAP_ATI 15 /* special */
+#define MODE_UNKNOWN 16
+
+/**
+ * Translate GL combiner state into a MODE_x value
+ */
+static GLuint translate_mode( GLenum envMode, GLenum mode )
+{
+ switch (mode) {
+ case GL_REPLACE: return MODE_REPLACE;
+ case GL_MODULATE: return MODE_MODULATE;
+ case GL_ADD:
+ if (envMode == GL_COMBINE4_NV)
+ return MODE_ADD_PRODUCTS;
+ else
+ return MODE_ADD;
+ case GL_ADD_SIGNED:
+ if (envMode == GL_COMBINE4_NV)
+ return MODE_ADD_PRODUCTS_SIGNED;
+ else
+ return MODE_ADD_SIGNED;
+ case GL_INTERPOLATE: return MODE_INTERPOLATE;
+ case GL_SUBTRACT: return MODE_SUBTRACT;
+ case GL_DOT3_RGB: return MODE_DOT3_RGB;
+ case GL_DOT3_RGB_EXT: return MODE_DOT3_RGB_EXT;
+ case GL_DOT3_RGBA: return MODE_DOT3_RGBA;
+ case GL_DOT3_RGBA_EXT: return MODE_DOT3_RGBA_EXT;
+ case GL_MODULATE_ADD_ATI: return MODE_MODULATE_ADD_ATI;
+ case GL_MODULATE_SIGNED_ADD_ATI: return MODE_MODULATE_SIGNED_ADD_ATI;
+ case GL_MODULATE_SUBTRACT_ATI: return MODE_MODULATE_SUBTRACT_ATI;
+ case GL_BUMP_ENVMAP_ATI: return MODE_BUMP_ENVMAP_ATI;
+ default:
+ assert(0);
+ return MODE_UNKNOWN;
+ }
+}
+
+
+/**
+ * Do we need to clamp the results of the given texture env/combine mode?
+ * If the inputs to the mode are in [0,1] we don't always have to clamp
+ * the results.
+ */
+static GLboolean
+need_saturate( GLuint mode )
+{
+ switch (mode) {
+ case MODE_REPLACE:
+ case MODE_MODULATE:
+ case MODE_INTERPOLATE:
+ return GL_FALSE;
+ case MODE_ADD:
+ case MODE_ADD_SIGNED:
+ case MODE_SUBTRACT:
+ case MODE_DOT3_RGB:
+ case MODE_DOT3_RGB_EXT:
+ case MODE_DOT3_RGBA:
+ case MODE_DOT3_RGBA_EXT:
+ case MODE_MODULATE_ADD_ATI:
+ case MODE_MODULATE_SIGNED_ADD_ATI:
+ case MODE_MODULATE_SUBTRACT_ATI:
+ case MODE_ADD_PRODUCTS:
+ case MODE_ADD_PRODUCTS_SIGNED:
+ case MODE_BUMP_ENVMAP_ATI:
+ return GL_TRUE;
+ default:
+ assert(0);
+ return GL_FALSE;
+ }
+}
+
+
+
+/**
+ * Translate TEXTURE_x_BIT to TEXTURE_x_INDEX.
+ */
+static GLuint translate_tex_src_bit( GLbitfield bit )
+{
+ ASSERT(bit);
+ return _mesa_ffs(bit) - 1;
+}
+
+
+#define VERT_BIT_TEX_ANY (0xff << VERT_ATTRIB_TEX0)
+#define VERT_RESULT_TEX_ANY (0xff << VERT_RESULT_TEX0)
+
+/**
+ * Identify all possible varying inputs. The fragment program will
+ * never reference non-varying inputs, but will track them via state
+ * constants instead.
+ *
+ * This function figures out all the inputs that the fragment program
+ * has access to. The bitmask is later reduced to just those which
+ * are actually referenced.
+ */
+static GLbitfield get_fp_input_mask( struct gl_context *ctx )
+{
+ /* _NEW_PROGRAM */
+ const GLboolean vertexShader =
+ (ctx->Shader.CurrentVertexProgram &&
+ ctx->Shader.CurrentVertexProgram->LinkStatus &&
+ ctx->Shader.CurrentVertexProgram->VertexProgram);
+ const GLboolean vertexProgram = ctx->VertexProgram._Enabled;
+ GLbitfield fp_inputs = 0x0;
+
+ if (ctx->VertexProgram._Overriden) {
+ /* Somebody's messing with the vertex program and we don't have
+ * a clue what's happening. Assume that it could be producing
+ * all possible outputs.
+ */
+ fp_inputs = ~0;
+ }
+ else if (ctx->RenderMode == GL_FEEDBACK) {
+ /* _NEW_RENDERMODE */
+ fp_inputs = (FRAG_BIT_COL0 | FRAG_BIT_TEX0);
+ }
+ else if (!(vertexProgram || vertexShader) ||
+ !ctx->VertexProgram._Current) {
+ /* Fixed function vertex logic */
+ /* _NEW_ARRAY */
+ GLbitfield varying_inputs = ctx->varying_vp_inputs;
+
+ /* These get generated in the setup routine regardless of the
+ * vertex program:
+ */
+ /* _NEW_POINT */
+ if (ctx->Point.PointSprite)
+ varying_inputs |= FRAG_BITS_TEX_ANY;
+
+ /* First look at what values may be computed by the generated
+ * vertex program:
+ */
+ /* _NEW_LIGHT */
+ if (ctx->Light.Enabled) {
+ fp_inputs |= FRAG_BIT_COL0;
+
+ if (texenv_doing_secondary_color(ctx))
+ fp_inputs |= FRAG_BIT_COL1;
+ }
+
+ /* _NEW_TEXTURE */
+ fp_inputs |= (ctx->Texture._TexGenEnabled |
+ ctx->Texture._TexMatEnabled) << FRAG_ATTRIB_TEX0;
+
+ /* Then look at what might be varying as a result of enabled
+ * arrays, etc:
+ */
+ if (varying_inputs & VERT_BIT_COLOR0)
+ fp_inputs |= FRAG_BIT_COL0;
+ if (varying_inputs & VERT_BIT_COLOR1)
+ fp_inputs |= FRAG_BIT_COL1;
+
+ fp_inputs |= (((varying_inputs & VERT_BIT_TEX_ANY) >> VERT_ATTRIB_TEX0)
+ << FRAG_ATTRIB_TEX0);
+
+ }
+ else {
+ /* calculate from vp->outputs */
+ struct gl_vertex_program *vprog;
+ GLbitfield64 vp_outputs;
+
+ /* Choose GLSL vertex shader over ARB vertex program. Need this
+ * since vertex shader state validation comes after fragment state
+ * validation (see additional comments in state.c).
+ */
+ if (vertexShader)
+ vprog = ctx->Shader.CurrentVertexProgram->VertexProgram;
+ else
+ vprog = ctx->VertexProgram.Current;
+
+ vp_outputs = vprog->Base.OutputsWritten;
+
+ /* These get generated in the setup routine regardless of the
+ * vertex program:
+ */
+ /* _NEW_POINT */
+ if (ctx->Point.PointSprite)
+ vp_outputs |= FRAG_BITS_TEX_ANY;
+
+ if (vp_outputs & (1 << VERT_RESULT_COL0))
+ fp_inputs |= FRAG_BIT_COL0;
+ if (vp_outputs & (1 << VERT_RESULT_COL1))
+ fp_inputs |= FRAG_BIT_COL1;
+
+ fp_inputs |= (((vp_outputs & VERT_RESULT_TEX_ANY) >> VERT_RESULT_TEX0)
+ << FRAG_ATTRIB_TEX0);
+ }
+
+ return fp_inputs;
+}
+
+
+/**
+ * Examine current texture environment state and generate a unique
+ * key to identify it.
+ */
+static GLuint make_state_key( struct gl_context *ctx, struct state_key *key )
+{
+ GLuint i, j;
+ GLbitfield inputs_referenced = FRAG_BIT_COL0;
+ const GLbitfield inputs_available = get_fp_input_mask( ctx );
+ GLuint keySize;
+
+ memset(key, 0, sizeof(*key));
+
+ /* _NEW_TEXTURE */
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
+ const struct gl_texture_object *texObj = texUnit->_Current;
+ const struct gl_tex_env_combine_state *comb = texUnit->_CurrentCombine;
+ GLenum format;
+
+ if (!texUnit->_ReallyEnabled || !texUnit->Enabled)
+ continue;
+
+ format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat;
+
+ key->unit[i].enabled = 1;
+ key->enabled_units |= (1<<i);
+ key->nr_enabled_units = i + 1;
+ inputs_referenced |= FRAG_BIT_TEX(i);
+
+ key->unit[i].source_index =
+ translate_tex_src_bit(texUnit->_ReallyEnabled);
+
+ key->unit[i].shadow = ((texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE) &&
+ ((format == GL_DEPTH_COMPONENT) ||
+ (format == GL_DEPTH_STENCIL_EXT)));
+
+ key->unit[i].NumArgsRGB = comb->_NumArgsRGB;
+ key->unit[i].NumArgsA = comb->_NumArgsA;
+
+ key->unit[i].ModeRGB =
+ translate_mode(texUnit->EnvMode, comb->ModeRGB);
+ key->unit[i].ModeA =
+ translate_mode(texUnit->EnvMode, comb->ModeA);
+
+ key->unit[i].ScaleShiftRGB = comb->ScaleShiftRGB;
+ key->unit[i].ScaleShiftA = comb->ScaleShiftA;
+
+ for (j = 0; j < MAX_COMBINER_TERMS; j++) {
+ key->unit[i].OptRGB[j].Operand = translate_operand(comb->OperandRGB[j]);
+ key->unit[i].OptA[j].Operand = translate_operand(comb->OperandA[j]);
+ key->unit[i].OptRGB[j].Source = translate_source(comb->SourceRGB[j]);
+ key->unit[i].OptA[j].Source = translate_source(comb->SourceA[j]);
+ }
+
+ if (key->unit[i].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
+ /* requires some special translation */
+ key->unit[i].NumArgsRGB = 2;
+ key->unit[i].ScaleShiftRGB = 0;
+ key->unit[i].OptRGB[0].Operand = OPR_SRC_COLOR;
+ key->unit[i].OptRGB[0].Source = SRC_TEXTURE;
+ key->unit[i].OptRGB[1].Operand = OPR_SRC_COLOR;
+ key->unit[i].OptRGB[1].Source = texUnit->BumpTarget - GL_TEXTURE0 + SRC_TEXTURE0;
+ }
+ }
+
+ /* _NEW_LIGHT | _NEW_FOG */
+ if (texenv_doing_secondary_color(ctx)) {
+ key->separate_specular = 1;
+ inputs_referenced |= FRAG_BIT_COL1;
+ }
+
+ /* _NEW_FOG */
+ if (ctx->Fog.Enabled) {
+ key->fog_enabled = 1;
+ key->fog_mode = translate_fog_mode(ctx->Fog.Mode);
+ inputs_referenced |= FRAG_BIT_FOGC; /* maybe */
+ }
+
+ /* _NEW_BUFFERS */
+ key->num_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers;
+
+ key->inputs_available = (inputs_available & inputs_referenced);
+
+ /* compute size of state key, ignoring unused texture units */
+ keySize = sizeof(*key) - sizeof(key->unit)
+ + key->nr_enabled_units * sizeof(key->unit[0]);
+
+ return keySize;
+}
+
+
+/** State used to build the fragment program:
+ */
+struct texenv_fragment_program {
+ struct gl_shader_program *shader_program;
+ struct gl_shader *shader;
+ struct gl_fragment_program *program;
+ exec_list *instructions;
+ exec_list *top_instructions;
+ void *mem_ctx;
+ struct state_key *state;
+
+ GLbitfield alu_temps; /**< Track texture indirections, see spec. */
+ GLbitfield temps_output; /**< Track texture indirections, see spec. */
+ GLbitfield temp_in_use; /**< Tracks temporary regs which are in use. */
+ GLboolean error;
+
+ ir_variable *src_texture[MAX_TEXTURE_COORD_UNITS];
+ /* Reg containing each texture unit's sampled texture color,
+ * else undef.
+ */
+
+ /* Texcoord override from bumpmapping. */
+ struct ir_variable *texcoord_tex[MAX_TEXTURE_COORD_UNITS];
+
+ /* Reg containing texcoord for a texture unit,
+ * needed for bump mapping, else undef.
+ */
+
+ ir_rvalue *src_previous; /**< Reg containing color from previous
+ * stage. May need to be decl'd.
+ */
+
+ GLuint last_tex_stage; /**< Number of last enabled texture unit */
+};
+
+static ir_rvalue *
+get_source(struct texenv_fragment_program *p,
+ GLuint src, GLuint unit)
+{
+ ir_variable *var;
+ ir_dereference *deref;
+
+ switch (src) {
+ case SRC_TEXTURE:
+ return new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
+
+ case SRC_TEXTURE0:
+ case SRC_TEXTURE1:
+ case SRC_TEXTURE2:
+ case SRC_TEXTURE3:
+ case SRC_TEXTURE4:
+ case SRC_TEXTURE5:
+ case SRC_TEXTURE6:
+ case SRC_TEXTURE7:
+ return new(p->mem_ctx)
+ ir_dereference_variable(p->src_texture[src - SRC_TEXTURE0]);
+
+ case SRC_CONSTANT:
+ var = p->shader->symbols->get_variable("gl_TextureEnvColor");
+ assert(var);
+ deref = new(p->mem_ctx) ir_dereference_variable(var);
+ var->max_array_access = MAX2(var->max_array_access, unit);
+ return new(p->mem_ctx) ir_dereference_array(deref,
+ new(p->mem_ctx) ir_constant(unit));
+
+ case SRC_PRIMARY_COLOR:
+ var = p->shader->symbols->get_variable("gl_Color");
+ assert(var);
+ return new(p->mem_ctx) ir_dereference_variable(var);
+
+ case SRC_ZERO:
+ return new(p->mem_ctx) ir_constant(0.0f);
+
+ case SRC_PREVIOUS:
+ if (!p->src_previous) {
+ var = p->shader->symbols->get_variable("gl_Color");
+ assert(var);
+ return new(p->mem_ctx) ir_dereference_variable(var);
+ } else {
+ return p->src_previous->clone(p->mem_ctx, NULL);
+ }
+
+ default:
+ assert(0);
+ return NULL;
+ }
+}
+
+static ir_rvalue *
+emit_combine_source(struct texenv_fragment_program *p,
+ GLuint unit,
+ GLuint source,
+ GLuint operand)
+{
+ ir_rvalue *src;
+
+ src = get_source(p, source, unit);
+
+ switch (operand) {
+ case OPR_ONE_MINUS_SRC_COLOR:
+ return new(p->mem_ctx) ir_expression(ir_binop_sub,
+ new(p->mem_ctx) ir_constant(1.0f),
+ src);
+
+ case OPR_SRC_ALPHA:
+ return new(p->mem_ctx) ir_swizzle(src, 3, 3, 3, 3, 1);
+
+ case OPR_ONE_MINUS_SRC_ALPHA:
+ return new(p->mem_ctx) ir_expression(ir_binop_sub,
+ new(p->mem_ctx) ir_constant(1.0f),
+ new(p->mem_ctx) ir_swizzle(src,
+ 3, 3,
+ 3, 3, 1));
+ case OPR_ZERO:
+ return new(p->mem_ctx) ir_constant(0.0f);
+ case OPR_ONE:
+ return new(p->mem_ctx) ir_constant(1.0f);
+ case OPR_SRC_COLOR:
+ return src;
+ default:
+ assert(0);
+ return src;
+ }
+}
+
+/**
+ * Check if the RGB and Alpha sources and operands match for the given
+ * texture unit's combinder state. When the RGB and A sources and
+ * operands match, we can emit fewer instructions.
+ */
+static GLboolean args_match( const struct state_key *key, GLuint unit )
+{
+ GLuint i, numArgs = key->unit[unit].NumArgsRGB;
+
+ for (i = 0; i < numArgs; i++) {
+ if (key->unit[unit].OptA[i].Source != key->unit[unit].OptRGB[i].Source)
+ return GL_FALSE;
+
+ switch (key->unit[unit].OptA[i].Operand) {
+ case OPR_SRC_ALPHA:
+ switch (key->unit[unit].OptRGB[i].Operand) {
+ case OPR_SRC_COLOR:
+ case OPR_SRC_ALPHA:
+ break;
+ default:
+ return GL_FALSE;
+ }
+ break;
+ case OPR_ONE_MINUS_SRC_ALPHA:
+ switch (key->unit[unit].OptRGB[i].Operand) {
+ case OPR_ONE_MINUS_SRC_COLOR:
+ case OPR_ONE_MINUS_SRC_ALPHA:
+ break;
+ default:
+ return GL_FALSE;
+ }
+ break;
+ default:
+ return GL_FALSE; /* impossible */
+ }
+ }
+
+ return GL_TRUE;
+}
+
+static ir_rvalue *
+smear(struct texenv_fragment_program *p, ir_rvalue *val)
+{
+ if (!val->type->is_scalar())
+ return val;
+
+ return new(p->mem_ctx) ir_swizzle(val, 0, 0, 0, 0, 4);
+}
+
+static ir_rvalue *
+emit_combine(struct texenv_fragment_program *p,
+ GLuint unit,
+ GLuint nr,
+ GLuint mode,
+ const struct mode_opt *opt)
+{
+ ir_rvalue *src[MAX_COMBINER_TERMS];
+ ir_rvalue *tmp0, *tmp1;
+ GLuint i;
+
+ assert(nr <= MAX_COMBINER_TERMS);
+
+ for (i = 0; i < nr; i++)
+ src[i] = emit_combine_source( p, unit, opt[i].Source, opt[i].Operand );
+
+ switch (mode) {
+ case MODE_REPLACE:
+ return src[0];
+
+ case MODE_MODULATE:
+ return new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
+
+ case MODE_ADD:
+ return new(p->mem_ctx) ir_expression(ir_binop_add, src[0], src[1]);
+
+ case MODE_ADD_SIGNED:
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, src[0], src[1]);
+ return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
+ new(p->mem_ctx) ir_constant(-0.5f));
+
+ case MODE_INTERPOLATE:
+ /* Arg0 * (Arg2) + Arg1 * (1-Arg2) */
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
+
+ tmp1 = new(p->mem_ctx) ir_expression(ir_binop_sub,
+ new(p->mem_ctx) ir_constant(1.0f),
+ src[2]->clone(p->mem_ctx, NULL));
+ tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[1], tmp1);
+
+ return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
+
+ case MODE_SUBTRACT:
+ return new(p->mem_ctx) ir_expression(ir_binop_sub, src[0], src[1]);
+
+ case MODE_DOT3_RGBA:
+ case MODE_DOT3_RGBA_EXT:
+ case MODE_DOT3_RGB_EXT:
+ case MODE_DOT3_RGB: {
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0],
+ new(p->mem_ctx) ir_constant(2.0f));
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
+ new(p->mem_ctx) ir_constant(-1.0f));
+ tmp0 = new(p->mem_ctx) ir_swizzle(smear(p, tmp0), 0, 1, 2, 3, 3);
+
+ tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[1],
+ new(p->mem_ctx) ir_constant(2.0f));
+ tmp1 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp1,
+ new(p->mem_ctx) ir_constant(-1.0f));
+ tmp1 = new(p->mem_ctx) ir_swizzle(smear(p, tmp1), 0, 1, 2, 3, 3);
+
+ return new(p->mem_ctx) ir_expression(ir_binop_dot, tmp0, tmp1);
+ }
+ case MODE_MODULATE_ADD_ATI:
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
+ return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, src[1]);
+
+ case MODE_MODULATE_SIGNED_ADD_ATI:
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, src[1]);
+ return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
+ new(p->mem_ctx) ir_constant(-0.5f));
+
+ case MODE_MODULATE_SUBTRACT_ATI:
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[2]);
+ return new(p->mem_ctx) ir_expression(ir_binop_sub, tmp0, src[1]);
+
+ case MODE_ADD_PRODUCTS:
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
+ tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[2], src[3]);
+ return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
+
+ case MODE_ADD_PRODUCTS_SIGNED:
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[0], src[1]);
+ tmp1 = new(p->mem_ctx) ir_expression(ir_binop_mul, src[2], src[3]);
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add, tmp0, tmp1);
+ return new(p->mem_ctx) ir_expression(ir_binop_add, tmp0,
+ new(p->mem_ctx) ir_constant(-0.5f));
+
+ case MODE_BUMP_ENVMAP_ATI:
+ /* special - not handled here */
+ assert(0);
+ return src[0];
+ default:
+ assert(0);
+ return src[0];
+ }
+}
+
+static ir_rvalue *
+saturate(struct texenv_fragment_program *p, ir_rvalue *val)
+{
+ val = new(p->mem_ctx) ir_expression(ir_binop_min, val,
+ new(p->mem_ctx) ir_constant(1.0f));
+ return new(p->mem_ctx) ir_expression(ir_binop_max, val,
+ new(p->mem_ctx) ir_constant(0.0f));
+}
+
+/**
+ * Generate instructions for one texture unit's env/combiner mode.
+ */
+static ir_rvalue *
+emit_texenv(struct texenv_fragment_program *p, GLuint unit)
+{
+ const struct state_key *key = p->state;
+ GLboolean rgb_saturate, alpha_saturate;
+ GLuint rgb_shift, alpha_shift;
+
+ if (!key->unit[unit].enabled) {
+ return get_source(p, SRC_PREVIOUS, 0);
+ }
+ if (key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
+ /* this isn't really a env stage delivering a color and handled elsewhere */
+ return get_source(p, SRC_PREVIOUS, 0);
+ }
+
+ switch (key->unit[unit].ModeRGB) {
+ case MODE_DOT3_RGB_EXT:
+ alpha_shift = key->unit[unit].ScaleShiftA;
+ rgb_shift = 0;
+ break;
+ case MODE_DOT3_RGBA_EXT:
+ alpha_shift = 0;
+ rgb_shift = 0;
+ break;
+ default:
+ rgb_shift = key->unit[unit].ScaleShiftRGB;
+ alpha_shift = key->unit[unit].ScaleShiftA;
+ break;
+ }
+
+ /* If we'll do rgb/alpha shifting don't saturate in emit_combine().
+ * We don't want to clamp twice.
+ */
+ if (rgb_shift)
+ rgb_saturate = GL_FALSE; /* saturate after rgb shift */
+ else if (need_saturate(key->unit[unit].ModeRGB))
+ rgb_saturate = GL_TRUE;
+ else
+ rgb_saturate = GL_FALSE;
+
+ if (alpha_shift)
+ alpha_saturate = GL_FALSE; /* saturate after alpha shift */
+ else if (need_saturate(key->unit[unit].ModeA))
+ alpha_saturate = GL_TRUE;
+ else
+ alpha_saturate = GL_FALSE;
+
+ ir_variable *temp_var = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
+ "texenv_combine",
+ ir_var_temporary);
+ p->instructions->push_tail(temp_var);
+
+ ir_dereference *deref;
+ ir_assignment *assign;
+ ir_rvalue *val;
+
+ /* Emit the RGB and A combine ops
+ */
+ if (key->unit[unit].ModeRGB == key->unit[unit].ModeA &&
+ args_match(key, unit)) {
+ val = emit_combine(p, unit,
+ key->unit[unit].NumArgsRGB,
+ key->unit[unit].ModeRGB,
+ key->unit[unit].OptRGB);
+ val = smear(p, val);
+ if (rgb_saturate)
+ val = saturate(p, val);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
+ assign = new(p->mem_ctx) ir_assignment(deref, val, NULL);
+ p->instructions->push_tail(assign);
+ }
+ else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT ||
+ key->unit[unit].ModeRGB == MODE_DOT3_RGBA) {
+ ir_rvalue *val = emit_combine(p, unit,
+ key->unit[unit].NumArgsRGB,
+ key->unit[unit].ModeRGB,
+ key->unit[unit].OptRGB);
+ val = smear(p, val);
+ if (rgb_saturate)
+ val = saturate(p, val);
+ deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
+ assign = new(p->mem_ctx) ir_assignment(deref, val, NULL);
+ p->instructions->push_tail(assign);
+ }
+ else {
+ /* Need to do something to stop from re-emitting identical
+ * argument calculations here:
+ */
+ val = emit_combine(p, unit,
+ key->unit[unit].NumArgsRGB,
+ key->unit[unit].ModeRGB,
+ key->unit[unit].OptRGB);
+ val = smear(p, val);
+ val = new(p->mem_ctx) ir_swizzle(val, 0, 1, 2, 3, 3);
+ if (rgb_saturate)
+ val = saturate(p, val);
+ deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
+ assign = new(p->mem_ctx) ir_assignment(deref, val, NULL, WRITEMASK_XYZ);
+ p->instructions->push_tail(assign);
+
+ val = emit_combine(p, unit,
+ key->unit[unit].NumArgsA,
+ key->unit[unit].ModeA,
+ key->unit[unit].OptA);
+ val = smear(p, val);
+ val = new(p->mem_ctx) ir_swizzle(val, 3, 3, 3, 3, 1);
+ if (alpha_saturate)
+ val = saturate(p, val);
+ deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
+ assign = new(p->mem_ctx) ir_assignment(deref, val, NULL, WRITEMASK_W);
+ p->instructions->push_tail(assign);
+ }
+
+ deref = new(p->mem_ctx) ir_dereference_variable(temp_var);
+
+ /* Deal with the final shift:
+ */
+ if (alpha_shift || rgb_shift) {
+ ir_constant *shift;
+
+ if (rgb_shift == alpha_shift) {
+ shift = new(p->mem_ctx) ir_constant((float)(1 << rgb_shift));
+ }
+ else {
+ float const_data[4] = {
+ 1 << rgb_shift,
+ 1 << rgb_shift,
+ 1 << rgb_shift,
+ 1 << alpha_shift
+ };
+ shift = new(p->mem_ctx) ir_constant(glsl_type::vec4_type,
+ (ir_constant_data *)const_data);
+ }
+
+ return saturate(p, new(p->mem_ctx) ir_expression(ir_binop_mul,
+ deref, shift));
+ }
+ else
+ return deref;
+}
+
+
+/**
+ * Generate instruction for getting a texture source term.
+ */
+ static void load_texture( struct texenv_fragment_program *p, GLuint unit )
+ {
+ ir_dereference *deref;
+ ir_assignment *assign;
+
+ if (p->src_texture[unit])
+ return;
+
+ const GLuint texTarget = p->state->unit[unit].source_index;
+ ir_rvalue *texcoord;
+
+ if (p->texcoord_tex[unit]) {
+ texcoord = new(p->mem_ctx) ir_dereference_variable(p->texcoord_tex[unit]);
+ }
+ else {
+ ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord");
+ assert(tc_array);
+ texcoord = new(p->mem_ctx) ir_dereference_variable(tc_array);
+ ir_rvalue *index = new(p->mem_ctx) ir_constant(unit);
+ texcoord = new(p->mem_ctx) ir_dereference_array(texcoord, index);
+ tc_array->max_array_access = MAX2(tc_array->max_array_access, unit);
+ }
+
+ if (!p->state->unit[unit].enabled) {
+ p->src_texture[unit] = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
+ "dummy_tex",
+ ir_var_temporary);
+ p->instructions->push_tail(p->src_texture[unit]);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
+ assign = new(p->mem_ctx) ir_assignment(deref,
+ new(p->mem_ctx) ir_constant(0.0f),
+ NULL);
+ p->instructions->push_tail(assign);
+ return ;
+ }
+
+ const glsl_type *sampler_type = NULL;
+ int coords = 0;
+
+ switch (texTarget) {
+ case TEXTURE_1D_INDEX:
+ if (p->state->unit[unit].shadow)
+ sampler_type = p->shader->symbols->get_type("sampler1DShadow");
+ else
+ sampler_type = p->shader->symbols->get_type("sampler1D");
+ coords = 1;
+ break;
+ case TEXTURE_1D_ARRAY_INDEX:
+ if (p->state->unit[unit].shadow)
+ sampler_type = p->shader->symbols->get_type("sampler1DArrayShadow");
+ else
+ sampler_type = p->shader->symbols->get_type("sampler1DArray");
+ coords = 2;
+ break;
+ case TEXTURE_2D_INDEX:
+ if (p->state->unit[unit].shadow)
+ sampler_type = p->shader->symbols->get_type("sampler2DShadow");
+ else
+ sampler_type = p->shader->symbols->get_type("sampler2D");
+ coords = 2;
+ break;
+ case TEXTURE_2D_ARRAY_INDEX:
+ if (p->state->unit[unit].shadow)
+ sampler_type = p->shader->symbols->get_type("sampler2DArrayShadow");
+ else
+ sampler_type = p->shader->symbols->get_type("sampler2DArray");
+ coords = 3;
+ break;
+ case TEXTURE_RECT_INDEX:
+ if (p->state->unit[unit].shadow)
+ sampler_type = p->shader->symbols->get_type("sampler2DRectShadow");
+ else
+ sampler_type = p->shader->symbols->get_type("sampler2DRect");
+ coords = 2;
+ break;
+ case TEXTURE_3D_INDEX:
+ assert(!p->state->unit[unit].shadow);
+ sampler_type = p->shader->symbols->get_type("sampler3D");
+ coords = 3;
+ break;
+ case TEXTURE_CUBE_INDEX:
+ if (p->state->unit[unit].shadow)
+ sampler_type = p->shader->symbols->get_type("samplerCubeShadow");
+ else
+ sampler_type = p->shader->symbols->get_type("samplerCube");
+ coords = 3;
+ break;
+ }
+
+ p->src_texture[unit] = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
+ "tex",
+ ir_var_temporary);
+ p->instructions->push_tail(p->src_texture[unit]);
+
+ ir_texture *tex = new(p->mem_ctx) ir_texture(ir_tex);
+
+
+ char *sampler_name = ralloc_asprintf(p->mem_ctx, "sampler_%d", unit);
+ ir_variable *sampler = new(p->mem_ctx) ir_variable(sampler_type,
+ sampler_name,
+ ir_var_uniform);
+ p->top_instructions->push_head(sampler);
+ deref = new(p->mem_ctx) ir_dereference_variable(sampler);
+ tex->set_sampler(deref);
+
+ tex->coordinate = new(p->mem_ctx) ir_swizzle(texcoord, 0, 1, 2, 3, coords);
+
+ if (p->state->unit[unit].shadow) {
+ texcoord = texcoord->clone(p->mem_ctx, NULL);
+ tex->shadow_comparitor = new(p->mem_ctx) ir_swizzle(texcoord,
+ coords, 0, 0, 0,
+ 1);
+ coords++;
+ }
+
+ texcoord = texcoord->clone(p->mem_ctx, NULL);
+ tex->projector = new(p->mem_ctx) ir_swizzle(texcoord, 3, 0, 0, 0, 1);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(p->src_texture[unit]);
+ assign = new(p->mem_ctx) ir_assignment(deref, tex, NULL);
+ p->instructions->push_tail(assign);
+ }
+
+static void
+load_texenv_source(struct texenv_fragment_program *p,
+ GLuint src, GLuint unit)
+{
+ switch (src) {
+ case SRC_TEXTURE:
+ load_texture(p, unit);
+ break;
+
+ case SRC_TEXTURE0:
+ case SRC_TEXTURE1:
+ case SRC_TEXTURE2:
+ case SRC_TEXTURE3:
+ case SRC_TEXTURE4:
+ case SRC_TEXTURE5:
+ case SRC_TEXTURE6:
+ case SRC_TEXTURE7:
+ load_texture(p, src - SRC_TEXTURE0);
+ break;
+
+ default:
+ /* not a texture src - do nothing */
+ break;
+ }
+}
+
+
+/**
+ * Generate instructions for loading all texture source terms.
+ */
+static GLboolean
+load_texunit_sources( struct texenv_fragment_program *p, GLuint unit )
+{
+ const struct state_key *key = p->state;
+ GLuint i;
+
+ for (i = 0; i < key->unit[unit].NumArgsRGB; i++) {
+ load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit );
+ }
+
+ for (i = 0; i < key->unit[unit].NumArgsA; i++) {
+ load_texenv_source( p, key->unit[unit].OptA[i].Source, unit );
+ }
+
+ return GL_TRUE;
+}
+
+/**
+ * Generate instructions for loading bump map textures.
+ */
+static void
+load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit )
+{
+ const struct state_key *key = p->state;
+ GLuint bumpedUnitNr = key->unit[unit].OptRGB[1].Source - SRC_TEXTURE0;
+ ir_rvalue *bump;
+ ir_rvalue *texcoord;
+ ir_variable *rot_mat_0_var, *rot_mat_1_var;
+ ir_dereference_variable *rot_mat_0, *rot_mat_1;
+
+ rot_mat_0_var = p->shader->symbols->get_variable("gl_MESABumpRotMatrix0");
+ rot_mat_1_var = p->shader->symbols->get_variable("gl_MESABumpRotMatrix1");
+ rot_mat_0 = new(p->mem_ctx) ir_dereference_variable(rot_mat_0_var);
+ rot_mat_1 = new(p->mem_ctx) ir_dereference_variable(rot_mat_1_var);
+
+ ir_variable *tc_array = p->shader->symbols->get_variable("gl_TexCoord");
+ assert(tc_array);
+ texcoord = new(p->mem_ctx) ir_dereference_variable(tc_array);
+ ir_rvalue *index = new(p->mem_ctx) ir_constant(bumpedUnitNr);
+ texcoord = new(p->mem_ctx) ir_dereference_array(texcoord, index);
+ tc_array->max_array_access = MAX2(tc_array->max_array_access, unit);
+
+ load_texenv_source( p, unit + SRC_TEXTURE0, unit );
+
+ /* Apply rot matrix and add coords to be available in next phase.
+ * dest = Arg1 + (Arg0.xx * rotMat0) + (Arg0.yy * rotMat1)
+ * note only 2 coords are affected the rest are left unchanged (mul by 0)
+ */
+ ir_dereference *deref;
+ ir_assignment *assign;
+ ir_rvalue *bump_x, *bump_y;
+
+ texcoord = smear(p, texcoord);
+
+ /* bump_texcoord = texcoord */
+ ir_variable *bumped = new(p->mem_ctx) ir_variable(texcoord->type,
+ "bump_texcoord",
+ ir_var_temporary);
+ p->instructions->push_tail(bumped);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(bumped);
+ assign = new(p->mem_ctx) ir_assignment(deref, texcoord, NULL);
+ p->instructions->push_tail(assign);
+
+ /* bump_texcoord.xy += arg0.x * rotmat0 + arg0.y * rotmat1 */
+ bump = get_source(p, key->unit[unit].OptRGB[0].Source, unit);
+ bump_x = new(p->mem_ctx) ir_swizzle(bump, 0, 0, 0, 0, 1);
+ bump = bump->clone(p->mem_ctx, NULL);
+ bump_y = new(p->mem_ctx) ir_swizzle(bump, 1, 0, 0, 0, 1);
+
+ bump_x = new(p->mem_ctx) ir_expression(ir_binop_mul, bump_x, rot_mat_0);
+ bump_y = new(p->mem_ctx) ir_expression(ir_binop_mul, bump_y, rot_mat_1);
+
+ ir_expression *expr;
+ expr = new(p->mem_ctx) ir_expression(ir_binop_add, bump_x, bump_y);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(bumped);
+ expr = new(p->mem_ctx) ir_expression(ir_binop_add,
+ new(p->mem_ctx) ir_swizzle(deref,
+ 0, 1, 1, 1,
+ 2),
+ expr);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(bumped);
+ assign = new(p->mem_ctx) ir_assignment(deref, expr, NULL, WRITEMASK_XY);
+ p->instructions->push_tail(assign);
+
+ p->texcoord_tex[bumpedUnitNr] = bumped;
+}
+
+/**
+ * Applies the fog calculations.
+ *
+ * This is basically like the ARB_fragment_prorgam fog options. Note
+ * that ffvertex_prog.c produces fogcoord for us when
+ * GL_FOG_COORDINATE_EXT is set to GL_FRAGMENT_DEPTH_EXT.
+ */
+static ir_rvalue *
+emit_fog_instructions(struct texenv_fragment_program *p,
+ ir_rvalue *fragcolor)
+{
+ struct state_key *key = p->state;
+ ir_rvalue *f, *temp;
+ ir_variable *params, *oparams;
+ ir_variable *fogcoord;
+ ir_assignment *assign;
+
+ /* Temporary storage for the whole fog result. Fog calculations
+ * only affect rgb so we're hanging on to the .a value of fragcolor
+ * this way.
+ */
+ ir_variable *fog_result = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
+ "fog_result",
+ ir_var_auto);
+ p->instructions->push_tail(fog_result);
+ temp = new(p->mem_ctx) ir_dereference_variable(fog_result);
+ assign = new(p->mem_ctx) ir_assignment(temp, fragcolor, NULL);
+ p->instructions->push_tail(assign);
+
+ temp = new(p->mem_ctx) ir_dereference_variable(fog_result);
+ fragcolor = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3);
+
+ oparams = p->shader->symbols->get_variable("gl_MESAFogParamsOptimized");
+ fogcoord = p->shader->symbols->get_variable("gl_FogFragCoord");
+ params = p->shader->symbols->get_variable("gl_Fog");
+ f = new(p->mem_ctx) ir_dereference_variable(fogcoord);
+
+ ir_variable *f_var = new(p->mem_ctx) ir_variable(glsl_type::float_type,
+ "fog_factor", ir_var_auto);
+ p->instructions->push_tail(f_var);
+
+ switch (key->fog_mode) {
+ case FOG_LINEAR:
+ /* f = (end - z) / (end - start)
+ *
+ * gl_MesaFogParamsOptimized gives us (-1 / (end - start)) and
+ * (end / (end - start)) so we can generate a single MAD.
+ */
+ temp = new(p->mem_ctx) ir_dereference_variable(oparams);
+ temp = new(p->mem_ctx) ir_swizzle(temp, 0, 0, 0, 0, 1);
+ f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
+
+ temp = new(p->mem_ctx) ir_dereference_variable(oparams);
+ temp = new(p->mem_ctx) ir_swizzle(temp, 1, 0, 0, 0, 1);
+ f = new(p->mem_ctx) ir_expression(ir_binop_add, f, temp);
+ break;
+ case FOG_EXP:
+ /* f = e^(-(density * fogcoord))
+ *
+ * gl_MesaFogParamsOptimized gives us density/ln(2) so we can
+ * use EXP2 which is generally the native instruction without
+ * having to do any further math on the fog density uniform.
+ */
+ temp = new(p->mem_ctx) ir_dereference_variable(oparams);
+ temp = new(p->mem_ctx) ir_swizzle(temp, 2, 0, 0, 0, 1);
+ f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
+ f = new(p->mem_ctx) ir_expression(ir_unop_neg, f);
+ f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f);
+ break;
+ case FOG_EXP2:
+ /* f = e^(-(density * fogcoord)^2)
+ *
+ * gl_MesaFogParamsOptimized gives us density/sqrt(ln(2)) so we
+ * can do this like FOG_EXP but with a squaring after the
+ * multiply by density.
+ */
+ ir_variable *temp_var = new(p->mem_ctx) ir_variable(glsl_type::float_type,
+ "fog_temp",
+ ir_var_auto);
+ p->instructions->push_tail(temp_var);
+
+ temp = new(p->mem_ctx) ir_dereference_variable(oparams);
+ temp = new(p->mem_ctx) ir_swizzle(temp, 3, 0, 0, 0, 1);
+ f = new(p->mem_ctx) ir_expression(ir_binop_mul,
+ f, temp);
+
+ temp = new(p->mem_ctx) ir_dereference_variable(temp_var);
+ ir_assignment *assign = new(p->mem_ctx) ir_assignment(temp, f, NULL);
+ p->instructions->push_tail(assign);
+
+ f = new(p->mem_ctx) ir_dereference_variable(temp_var);
+ temp = new(p->mem_ctx) ir_dereference_variable(temp_var);
+ f = new(p->mem_ctx) ir_expression(ir_binop_mul, f, temp);
+ f = new(p->mem_ctx) ir_expression(ir_unop_neg, f);
+ f = new(p->mem_ctx) ir_expression(ir_unop_exp2, f);
+ break;
+ }
+
+ f = saturate(p, f);
+
+ temp = new(p->mem_ctx) ir_dereference_variable(f_var);
+ assign = new(p->mem_ctx) ir_assignment(temp, f, NULL);
+ p->instructions->push_tail(assign);
+
+ f = new(p->mem_ctx) ir_dereference_variable(f_var);
+ f = new(p->mem_ctx) ir_expression(ir_binop_sub,
+ new(p->mem_ctx) ir_constant(1.0f),
+ f);
+ temp = new(p->mem_ctx) ir_dereference_variable(params);
+ temp = new(p->mem_ctx) ir_dereference_record(temp, "color");
+ temp = new(p->mem_ctx) ir_swizzle(temp, 0, 1, 2, 3, 3);
+ temp = new(p->mem_ctx) ir_expression(ir_binop_mul, temp, f);
+
+ f = new(p->mem_ctx) ir_dereference_variable(f_var);
+ f = new(p->mem_ctx) ir_expression(ir_binop_mul, fragcolor, f);
+ f = new(p->mem_ctx) ir_expression(ir_binop_add, temp, f);
+
+ ir_dereference *deref = new(p->mem_ctx) ir_dereference_variable(fog_result);
+ assign = new(p->mem_ctx) ir_assignment(deref, f, NULL, WRITEMASK_XYZ);
+ p->instructions->push_tail(assign);
+
+ return new(p->mem_ctx) ir_dereference_variable(fog_result);
+}
+
+static void
+emit_instructions(struct texenv_fragment_program *p)
+{
+ struct state_key *key = p->state;
+ GLuint unit;
+
+ if (key->enabled_units) {
+ /* Zeroth pass - bump map textures first */
+ for (unit = 0; unit < key->nr_enabled_units; unit++) {
+ if (key->unit[unit].enabled &&
+ key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
+ load_texunit_bumpmap(p, unit);
+ }
+ }
+
+ /* First pass - to support texture_env_crossbar, first identify
+ * all referenced texture sources and emit texld instructions
+ * for each:
+ */
+ for (unit = 0; unit < key->nr_enabled_units; unit++)
+ if (key->unit[unit].enabled) {
+ load_texunit_sources(p, unit);
+ p->last_tex_stage = unit;
+ }
+
+ /* Second pass - emit combine instructions to build final color:
+ */
+ for (unit = 0; unit < key->nr_enabled_units; unit++) {
+ if (key->unit[unit].enabled) {
+ p->src_previous = emit_texenv(p, unit);
+ }
+ }
+ }
+
+ ir_rvalue *cf = get_source(p, SRC_PREVIOUS, 0);
+ ir_dereference_variable *deref;
+ ir_assignment *assign;
+
+ if (key->separate_specular) {
+ ir_rvalue *tmp0, *tmp1;
+ ir_variable *spec_result = new(p->mem_ctx) ir_variable(glsl_type::vec4_type,
+ "specular_add",
+ ir_var_temporary);
+
+ p->instructions->push_tail(spec_result);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
+ assign = new(p->mem_ctx) ir_assignment(deref, cf, NULL);
+ p->instructions->push_tail(assign);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
+ tmp0 = new(p->mem_ctx) ir_swizzle(deref, 0, 1, 2, 3, 3);
+
+ ir_variable *secondary =
+ p->shader->symbols->get_variable("gl_SecondaryColor");
+ assert(secondary);
+ deref = new(p->mem_ctx) ir_dereference_variable(secondary);
+ tmp1 = new(p->mem_ctx) ir_swizzle(deref, 0, 1, 2, 3, 3);
+
+ tmp0 = new(p->mem_ctx) ir_expression(ir_binop_add,
+ tmp0, tmp1);
+
+ deref = new(p->mem_ctx) ir_dereference_variable(spec_result);
+ assign = new(p->mem_ctx) ir_assignment(deref, tmp0, NULL, WRITEMASK_XYZ);
+ p->instructions->push_tail(assign);
+
+ cf = new(p->mem_ctx) ir_dereference_variable(spec_result);
+ }
+
+ if (key->fog_enabled) {
+ cf = emit_fog_instructions(p, cf);
+ }
+
+ ir_variable *frag_color = p->shader->symbols->get_variable("gl_FragColor");
+ assert(frag_color);
+ deref = new(p->mem_ctx) ir_dereference_variable(frag_color);
+ assign = new(p->mem_ctx) ir_assignment(deref, cf, NULL);
+ p->instructions->push_tail(assign);
+}
+
+/**
+ * Generate a new fragment program which implements the context's
+ * current texture env/combine mode.
+ */
+static struct gl_shader_program *
+create_new_program(struct gl_context *ctx, struct state_key *key)
+{
+ struct texenv_fragment_program p;
+ unsigned int unit;
+ _mesa_glsl_parse_state *state;
+
+ memset(&p, 0, sizeof(p));
+ p.mem_ctx = ralloc_context(NULL);
+ p.shader = ctx->Driver.NewShader(ctx, 0, GL_FRAGMENT_SHADER);
+ p.shader->ir = new(p.shader) exec_list;
+ state = new(p.shader) _mesa_glsl_parse_state(ctx, GL_FRAGMENT_SHADER,
+ p.shader);
+ p.shader->symbols = state->symbols;
+ p.top_instructions = p.shader->ir;
+ p.instructions = p.shader->ir;
+ p.state = key;
+ p.shader_program = ctx->Driver.NewShaderProgram(ctx, 0);
+
+ state->language_version = 120;
+ _mesa_glsl_initialize_types(state);
+ _mesa_glsl_initialize_variables(p.instructions, state);
+
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ p.src_texture[unit] = NULL;
+ p.texcoord_tex[unit] = NULL;
+ }
+
+ p.src_previous = NULL;
+
+ p.last_tex_stage = 0;
+
+ ir_function *main_f = new(p.mem_ctx) ir_function("main");
+ p.instructions->push_tail(main_f);
+ state->symbols->add_function(main_f);
+
+ ir_function_signature *main_sig =
+ new(p.mem_ctx) ir_function_signature(p.shader->symbols->get_type("void"));
+ main_sig->is_defined = true;
+ main_f->add_signature(main_sig);
+
+ p.instructions = &main_sig->body;
+ if (key->num_draw_buffers)
+ emit_instructions(&p);
+
+ validate_ir_tree(p.shader->ir);
+
+ while (do_common_optimization(p.shader->ir, false, 32))
+ ;
+ reparent_ir(p.shader->ir, p.shader->ir);
+
+ p.shader->CompileStatus = true;
+ p.shader->Version = state->language_version;
+ p.shader->num_builtins_to_link = state->num_builtins_to_link;
+ p.shader_program->Shaders =
+ (gl_shader **)malloc(sizeof(*p.shader_program->Shaders));
+ p.shader_program->Shaders[0] = p.shader;
+ p.shader_program->NumShaders = 1;
+
+ _mesa_glsl_link_shader(ctx, p.shader_program);
+
+ /* Set the sampler uniforms, and relink to get them into the linked
+ * program.
+ */
+ struct gl_fragment_program *fp = p.shader_program->FragmentProgram;
+ for (unsigned int i = 0; i < MAX_TEXTURE_UNITS; i++) {
+ char *name = ralloc_asprintf(p.mem_ctx, "sampler_%d", i);
+ int loc = _mesa_get_uniform_location(ctx, p.shader_program, name);
+ if (loc != -1) {
+ /* Avoid using _mesa_uniform() because it flags state
+ * updates, so if we're generating this shader_program in a
+ * state update, we end up recursing. Instead, just set the
+ * value, which is picked up at re-link.
+ */
+ loc = (loc & 0xffff) + (loc >> 16);
+ int sampler = fp->Base.Parameters->ParameterValues[loc][0];
+ fp->Base.SamplerUnits[sampler] = i;
+ }
+ }
+ _mesa_update_shader_textures_used(&fp->Base);
+ (void) ctx->Driver.ProgramStringNotify(ctx, fp->Base.Target, &fp->Base);
+
+ if (!p.shader_program->LinkStatus)
+ _mesa_problem(ctx, "Failed to link fixed function fragment shader: %s\n",
+ p.shader_program->InfoLog);
+
+ ralloc_free(p.mem_ctx);
+ return p.shader_program;
+}
+
+extern "C" {
+
+/**
+ * Return a fragment program which implements the current
+ * fixed-function texture, fog and color-sum operations.
+ */
+struct gl_shader_program *
+_mesa_get_fixed_func_fragment_program(struct gl_context *ctx)
+{
+ struct gl_shader_program *shader_program;
+ struct state_key key;
+ GLuint keySize;
+
+ keySize = make_state_key(ctx, &key);
+
+ shader_program = (struct gl_shader_program *)
+ _mesa_search_program_cache(ctx->FragmentProgram.Cache,
+ &key, keySize);
+
+ if (!shader_program) {
+ shader_program = create_new_program(ctx, &key);
+
+ _mesa_shader_cache_insert(ctx, ctx->FragmentProgram.Cache,
+ &key, keySize, shader_program);
+ }
+
+ return shader_program;
+}
+
+}
diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c
index 529285027..a3cae1cbc 100644
--- a/mesalib/src/mesa/main/get.c
+++ b/mesalib/src/mesa/main/get.c
@@ -1201,22 +1201,22 @@ static const struct value_desc values[] = {
/* GL_ARB_geometry_shader4 */
{ GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryTextureImageUnits),
+ CONTEXT_INT(Const.MaxGeometryTextureImageUnits),
extra_ARB_geometry_shader4 },
{ GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryOutputVertices),
+ CONTEXT_INT(Const.MaxGeometryOutputVertices),
extra_ARB_geometry_shader4 },
{ GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryTotalOutputComponents),
+ CONTEXT_INT(Const.MaxGeometryTotalOutputComponents),
extra_ARB_geometry_shader4 },
{ GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryUniformComponents),
+ CONTEXT_INT(Const.GeometryProgram.MaxUniformComponents),
extra_ARB_geometry_shader4 },
{ GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxGeometryVaryingComponents),
+ CONTEXT_INT(Const.MaxGeometryVaryingComponents),
extra_ARB_geometry_shader4 },
{ GL_MAX_VERTEX_VARYING_COMPONENTS_ARB,
- CONTEXT_INT(Const.GeometryProgram.MaxVertexVaryingComponents),
+ CONTEXT_INT(Const.MaxVertexVaryingComponents),
extra_ARB_geometry_shader4 },
/* GL_EXT_gpu_shader4 / GL 3.0 */
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 4e530a268..520d96689 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -2191,6 +2191,7 @@ struct gl_shader_state
struct gl_shader_program *CurrentVertexProgram;
struct gl_shader_program *CurrentGeometryProgram;
struct gl_shader_program *CurrentFragmentProgram;
+ struct gl_shader_program *_CurrentFragmentProgram;
/**
* Program used by glUniform calls.
@@ -2563,7 +2564,7 @@ struct gl_precision
/**
- * Limits for vertex and fragment programs/shaders.
+ * Limits for vertex, geometry and fragment programs/shaders.
*/
struct gl_program_constants
{
@@ -2589,14 +2590,7 @@ struct gl_program_constants
GLuint MaxNativeAddressRegs;
GLuint MaxNativeParameters;
/* For shaders */
- GLuint MaxUniformComponents;
- /* GL_ARB_geometry_shader4 */
- GLuint MaxGeometryTextureImageUnits;
- GLuint MaxGeometryVaryingComponents;
- GLuint MaxVertexVaryingComponents;
- GLuint MaxGeometryUniformComponents;
- GLuint MaxGeometryOutputVertices;
- GLuint MaxGeometryTotalOutputComponents;
+ GLuint MaxUniformComponents; /**< Usually == MaxParameters * 4 */
/* ES 2.0 and GL_ARB_ES2_compatibility */
struct gl_precision LowFloat, MediumFloat, HighFloat;
struct gl_precision LowInt, MediumInt, HighInt;
@@ -2619,6 +2613,7 @@ struct gl_constants
GLuint MaxTextureImageUnits;
GLuint MaxVertexTextureImageUnits;
GLuint MaxCombinedTextureImageUnits;
+ GLuint MaxGeometryTextureImageUnits;
GLuint MaxTextureUnits; /**< = MIN(CoordUnits, ImageUnits) */
GLfloat MaxTextureMaxAnisotropy; /**< GL_EXT_texture_filter_anisotropic */
GLfloat MaxTextureLodBias; /**< GL_EXT_texture_lod_bias */
@@ -2658,7 +2653,14 @@ struct gl_constants
GLuint MaxRenderbufferSize; /**< GL_EXT_framebuffer_object */
GLuint MaxSamples; /**< GL_ARB_framebuffer_object */
- GLuint MaxVarying; /**< Number of float[4] varying parameters */
+ /** Number of varying vectors between vertex and fragment shaders */
+ GLuint MaxVarying;
+ GLuint MaxVertexVaryingComponents; /**< Between vert and geom shader */
+ GLuint MaxGeometryVaryingComponents; /**< Between geom and frag shader */
+
+ /** GL_ARB_geometry_shader4 */
+ GLuint MaxGeometryOutputVertices;
+ GLuint MaxGeometryTotalOutputComponents;
GLuint GLSLVersion; /**< GLSL version supported (ex: 120 = 1.20) */
diff --git a/mesalib/src/mesa/main/queryobj.c b/mesalib/src/mesa/main/queryobj.c
index dc9f18a65..c3c1aa170 100644
--- a/mesalib/src/mesa/main/queryobj.c
+++ b/mesalib/src/mesa/main/queryobj.c
@@ -218,6 +218,7 @@ _mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
GLint i;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ FLUSH_VERTICES(ctx, 0);
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(ctx, "glDeleeteQueries(%d)\n", n);
diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c
index 252cda845..3609577b7 100644
--- a/mesalib/src/mesa/main/shaderapi.c
+++ b/mesalib/src/mesa/main/shaderapi.c
@@ -1236,6 +1236,7 @@ _mesa_DeleteObjectARB(GLhandleARB obj)
if (obj) {
GET_CURRENT_CONTEXT(ctx);
+ FLUSH_VERTICES(ctx, 0);
if (is_program(ctx, obj)) {
delete_shader_program(ctx, obj);
}
@@ -1254,6 +1255,7 @@ _mesa_DeleteProgram(GLuint name)
{
if (name) {
GET_CURRENT_CONTEXT(ctx);
+ FLUSH_VERTICES(ctx, 0);
delete_shader_program(ctx, name);
}
}
@@ -1264,6 +1266,7 @@ _mesa_DeleteShader(GLuint name)
{
if (name) {
GET_CURRENT_CONTEXT(ctx);
+ FLUSH_VERTICES(ctx, 0);
delete_shader(ctx, name);
}
}
@@ -1729,7 +1732,7 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname,
switch (pname) {
case GL_GEOMETRY_VERTICES_OUT_ARB:
if (value < 1 ||
- (unsigned) value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) {
+ (unsigned) value > ctx->Const.MaxGeometryOutputVertices) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
value);
diff --git a/mesalib/src/mesa/main/shaderobj.c b/mesalib/src/mesa/main/shaderobj.c
index 1d7584559..06a2f53af 100644
--- a/mesalib/src/mesa/main/shaderobj.c
+++ b/mesalib/src/mesa/main/shaderobj.c
@@ -1,413 +1,415 @@
-/*
- * Mesa 3-D graphics library
- *
- * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009-2010 VMware, Inc. 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 shaderobj.c
- * \author Brian Paul
- *
- */
-
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/hash.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "main/shaderobj.h"
-#include "program/program.h"
-#include "program/prog_parameter.h"
-#include "program/prog_uniform.h"
-#include "ralloc.h"
-
-/**********************************************************************/
-/*** Shader object functions ***/
-/**********************************************************************/
-
-
-/**
- * Set ptr to point to sh.
- * If ptr is pointing to another shader, decrement its refcount (and delete
- * if refcount hits zero).
- * Then set ptr to point to sh, incrementing its refcount.
- */
-void
-_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
- struct gl_shader *sh)
-{
- assert(ptr);
- if (*ptr == sh) {
- /* no-op */
- return;
- }
- if (*ptr) {
- /* Unreference the old shader */
- GLboolean deleteFlag = GL_FALSE;
- struct gl_shader *old = *ptr;
-
- ASSERT(old->RefCount > 0);
- old->RefCount--;
- /*printf("SHADER DECR %p (%d) to %d\n",
- (void*) old, old->Name, old->RefCount);*/
- deleteFlag = (old->RefCount == 0);
-
- if (deleteFlag) {
- _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
- ctx->Driver.DeleteShader(ctx, old);
- }
-
- *ptr = NULL;
- }
- assert(!*ptr);
-
- if (sh) {
- /* reference new */
- sh->RefCount++;
- /*printf("SHADER INCR %p (%d) to %d\n",
- (void*) sh, sh->Name, sh->RefCount);*/
- *ptr = sh;
- }
-}
-
-void
-_mesa_init_shader(struct gl_context *ctx, struct gl_shader *shader)
-{
- shader->RefCount = 1;
-}
-
-/**
- * Allocate a new gl_shader object, initialize it.
- * Called via ctx->Driver.NewShader()
- */
-struct gl_shader *
-_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
-{
- struct gl_shader *shader;
- assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER ||
- type == GL_GEOMETRY_SHADER_ARB);
- shader = rzalloc(NULL, struct gl_shader);
- if (shader) {
- shader->Type = type;
- shader->Name = name;
- _mesa_init_shader(ctx, shader);
- }
- return shader;
-}
-
-
-/**
- * Delete a shader object.
- * Called via ctx->Driver.DeleteShader().
- */
-static void
-_mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
-{
- if (sh->Source)
- free((void *) sh->Source);
- _mesa_reference_program(ctx, &sh->Program, NULL);
- ralloc_free(sh);
-}
-
-
-/**
- * Lookup a GLSL shader object.
- */
-struct gl_shader *
-_mesa_lookup_shader(struct gl_context *ctx, GLuint name)
-{
- if (name) {
- struct gl_shader *sh = (struct gl_shader *)
- _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
- /* Note that both gl_shader and gl_shader_program objects are kept
- * in the same hash table. Check the object's type to be sure it's
- * what we're expecting.
- */
- if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
- return NULL;
- }
- return sh;
- }
- return NULL;
-}
-
-
-/**
- * As above, but record an error if shader is not found.
- */
-struct gl_shader *
-_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
-{
- if (!name) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
- return NULL;
- }
- else {
- struct gl_shader *sh = (struct gl_shader *)
- _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
- if (!sh) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
- return NULL;
- }
- if (sh->Type == GL_SHADER_PROGRAM_MESA) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
- return NULL;
- }
- return sh;
- }
-}
-
-
-
-/**********************************************************************/
-/*** Shader Program object functions ***/
-/**********************************************************************/
-
-
-/**
- * Set ptr to point to shProg.
- * If ptr is pointing to another object, decrement its refcount (and delete
- * if refcount hits zero).
- * Then set ptr to point to shProg, incrementing its refcount.
- */
-void
-_mesa_reference_shader_program(struct gl_context *ctx,
- struct gl_shader_program **ptr,
- struct gl_shader_program *shProg)
-{
- assert(ptr);
- if (*ptr == shProg) {
- /* no-op */
- return;
- }
- if (*ptr) {
- /* Unreference the old shader program */
- GLboolean deleteFlag = GL_FALSE;
- struct gl_shader_program *old = *ptr;
-
- ASSERT(old->RefCount > 0);
- old->RefCount--;
-#if 0
- printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
- (void *) old, old->Name, old->RefCount);
-#endif
- deleteFlag = (old->RefCount == 0);
-
- if (deleteFlag) {
- _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
- ctx->Driver.DeleteShaderProgram(ctx, old);
- }
-
- *ptr = NULL;
- }
- assert(!*ptr);
-
- if (shProg) {
- shProg->RefCount++;
-#if 0
- printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
- (void *) shProg, shProg->Name, shProg->RefCount);
-#endif
- *ptr = shProg;
- }
-}
-
-void
-_mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog)
-{
- prog->Type = GL_SHADER_PROGRAM_MESA;
- prog->RefCount = 1;
- prog->Attributes = _mesa_new_parameter_list();
-#if FEATURE_ARB_geometry_shader4
- prog->Geom.VerticesOut = 0;
- prog->Geom.InputType = GL_TRIANGLES;
- prog->Geom.OutputType = GL_TRIANGLE_STRIP;
-#endif
-}
-
-/**
- * Allocate a new gl_shader_program object, initialize it.
- * Called via ctx->Driver.NewShaderProgram()
- */
-static struct gl_shader_program *
-_mesa_new_shader_program(struct gl_context *ctx, GLuint name)
-{
- struct gl_shader_program *shProg;
- shProg = rzalloc(NULL, struct gl_shader_program);
- if (shProg) {
- shProg->Name = name;
- _mesa_init_shader_program(ctx, shProg);
- }
- return shProg;
-}
-
-
-/**
- * Clear (free) the shader program state that gets produced by linking.
- */
-void
-_mesa_clear_shader_program_data(struct gl_context *ctx,
- struct gl_shader_program *shProg)
-{
- _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
- _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
- _mesa_reference_geomprog(ctx, &shProg->GeometryProgram, NULL);
-
- if (shProg->Uniforms) {
- _mesa_free_uniform_list(shProg->Uniforms);
- shProg->Uniforms = NULL;
- }
-
- if (shProg->Varying) {
- _mesa_free_parameter_list(shProg->Varying);
- shProg->Varying = NULL;
- }
-}
-
-
-/**
- * Free all the data that hangs off a shader program object, but not the
- * object itself.
- */
-void
-_mesa_free_shader_program_data(struct gl_context *ctx,
- struct gl_shader_program *shProg)
-{
- GLuint i;
- gl_shader_type sh;
-
- assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
-
- _mesa_clear_shader_program_data(ctx, shProg);
-
- if (shProg->Attributes) {
- _mesa_free_parameter_list(shProg->Attributes);
- shProg->Attributes = NULL;
- }
-
- /* detach shaders */
- for (i = 0; i < shProg->NumShaders; i++) {
- _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
- }
- shProg->NumShaders = 0;
-
- if (shProg->Shaders) {
- free(shProg->Shaders);
- shProg->Shaders = NULL;
- }
-
- if (shProg->InfoLog) {
- ralloc_free(shProg->InfoLog);
- shProg->InfoLog = NULL;
- }
-
- /* Transform feedback varying vars */
- for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
- free(shProg->TransformFeedback.VaryingNames[i]);
- }
- free(shProg->TransformFeedback.VaryingNames);
- shProg->TransformFeedback.VaryingNames = NULL;
- shProg->TransformFeedback.NumVarying = 0;
-
-
- for (sh = 0; sh < MESA_SHADER_TYPES; sh++) {
- if (shProg->_LinkedShaders[sh] != NULL) {
- ctx->Driver.DeleteShader(ctx, shProg->_LinkedShaders[sh]);
- shProg->_LinkedShaders[sh] = NULL;
- }
- }
-}
-
-
-/**
- * Free/delete a shader program object.
- * Called via ctx->Driver.DeleteShaderProgram().
- */
-static void
-_mesa_delete_shader_program(struct gl_context *ctx, struct gl_shader_program *shProg)
-{
- _mesa_free_shader_program_data(ctx, shProg);
-
- ralloc_free(shProg);
-}
-
-
-/**
- * Lookup a GLSL program object.
- */
-struct gl_shader_program *
-_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
-{
- struct gl_shader_program *shProg;
- if (name) {
- shProg = (struct gl_shader_program *)
- _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
- /* Note that both gl_shader and gl_shader_program objects are kept
- * in the same hash table. Check the object's type to be sure it's
- * what we're expecting.
- */
- if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
- return NULL;
- }
- return shProg;
- }
- return NULL;
-}
-
-
-/**
- * As above, but record an error if program is not found.
- */
-struct gl_shader_program *
-_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
- const char *caller)
-{
- if (!name) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
- return NULL;
- }
- else {
- struct gl_shader_program *shProg = (struct gl_shader_program *)
- _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
- if (!shProg) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
- return NULL;
- }
- if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
- return NULL;
- }
- return shProg;
- }
-}
-
-
-void
-_mesa_init_shader_object_functions(struct dd_function_table *driver)
-{
- driver->NewShader = _mesa_new_shader;
- driver->DeleteShader = _mesa_delete_shader;
- driver->NewShaderProgram = _mesa_new_shader_program;
- driver->DeleteShaderProgram = _mesa_delete_shader_program;
- driver->CompileShader = _mesa_ir_compile_shader;
- driver->LinkShader = _mesa_ir_link_shader;
-}
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009-2010 VMware, Inc. 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 shaderobj.c
+ * \author Brian Paul
+ *
+ */
+
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/hash.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "main/shaderobj.h"
+#include "program/program.h"
+#include "program/prog_parameter.h"
+#include "program/prog_uniform.h"
+#include "ralloc.h"
+
+/**********************************************************************/
+/*** Shader object functions ***/
+/**********************************************************************/
+
+
+/**
+ * Set ptr to point to sh.
+ * If ptr is pointing to another shader, decrement its refcount (and delete
+ * if refcount hits zero).
+ * Then set ptr to point to sh, incrementing its refcount.
+ */
+void
+_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
+ struct gl_shader *sh)
+{
+ assert(ptr);
+ if (*ptr == sh) {
+ /* no-op */
+ return;
+ }
+ if (*ptr) {
+ /* Unreference the old shader */
+ GLboolean deleteFlag = GL_FALSE;
+ struct gl_shader *old = *ptr;
+
+ ASSERT(old->RefCount > 0);
+ old->RefCount--;
+ /*printf("SHADER DECR %p (%d) to %d\n",
+ (void*) old, old->Name, old->RefCount);*/
+ deleteFlag = (old->RefCount == 0);
+
+ if (deleteFlag) {
+ if (old->Name != 0)
+ _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
+ ctx->Driver.DeleteShader(ctx, old);
+ }
+
+ *ptr = NULL;
+ }
+ assert(!*ptr);
+
+ if (sh) {
+ /* reference new */
+ sh->RefCount++;
+ /*printf("SHADER INCR %p (%d) to %d\n",
+ (void*) sh, sh->Name, sh->RefCount);*/
+ *ptr = sh;
+ }
+}
+
+void
+_mesa_init_shader(struct gl_context *ctx, struct gl_shader *shader)
+{
+ shader->RefCount = 1;
+}
+
+/**
+ * Allocate a new gl_shader object, initialize it.
+ * Called via ctx->Driver.NewShader()
+ */
+struct gl_shader *
+_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
+{
+ struct gl_shader *shader;
+ assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER ||
+ type == GL_GEOMETRY_SHADER_ARB);
+ shader = rzalloc(NULL, struct gl_shader);
+ if (shader) {
+ shader->Type = type;
+ shader->Name = name;
+ _mesa_init_shader(ctx, shader);
+ }
+ return shader;
+}
+
+
+/**
+ * Delete a shader object.
+ * Called via ctx->Driver.DeleteShader().
+ */
+static void
+_mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
+{
+ if (sh->Source)
+ free((void *) sh->Source);
+ _mesa_reference_program(ctx, &sh->Program, NULL);
+ ralloc_free(sh);
+}
+
+
+/**
+ * Lookup a GLSL shader object.
+ */
+struct gl_shader *
+_mesa_lookup_shader(struct gl_context *ctx, GLuint name)
+{
+ if (name) {
+ struct gl_shader *sh = (struct gl_shader *)
+ _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
+ /* Note that both gl_shader and gl_shader_program objects are kept
+ * in the same hash table. Check the object's type to be sure it's
+ * what we're expecting.
+ */
+ if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
+ return NULL;
+ }
+ return sh;
+ }
+ return NULL;
+}
+
+
+/**
+ * As above, but record an error if shader is not found.
+ */
+struct gl_shader *
+_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
+{
+ if (!name) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
+ return NULL;
+ }
+ else {
+ struct gl_shader *sh = (struct gl_shader *)
+ _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
+ if (!sh) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
+ return NULL;
+ }
+ if (sh->Type == GL_SHADER_PROGRAM_MESA) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
+ return NULL;
+ }
+ return sh;
+ }
+}
+
+
+
+/**********************************************************************/
+/*** Shader Program object functions ***/
+/**********************************************************************/
+
+
+/**
+ * Set ptr to point to shProg.
+ * If ptr is pointing to another object, decrement its refcount (and delete
+ * if refcount hits zero).
+ * Then set ptr to point to shProg, incrementing its refcount.
+ */
+void
+_mesa_reference_shader_program(struct gl_context *ctx,
+ struct gl_shader_program **ptr,
+ struct gl_shader_program *shProg)
+{
+ assert(ptr);
+ if (*ptr == shProg) {
+ /* no-op */
+ return;
+ }
+ if (*ptr) {
+ /* Unreference the old shader program */
+ GLboolean deleteFlag = GL_FALSE;
+ struct gl_shader_program *old = *ptr;
+
+ ASSERT(old->RefCount > 0);
+ old->RefCount--;
+#if 0
+ printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
+ (void *) old, old->Name, old->RefCount);
+#endif
+ deleteFlag = (old->RefCount == 0);
+
+ if (deleteFlag) {
+ if (old->Name != 0)
+ _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
+ ctx->Driver.DeleteShaderProgram(ctx, old);
+ }
+
+ *ptr = NULL;
+ }
+ assert(!*ptr);
+
+ if (shProg) {
+ shProg->RefCount++;
+#if 0
+ printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
+ (void *) shProg, shProg->Name, shProg->RefCount);
+#endif
+ *ptr = shProg;
+ }
+}
+
+void
+_mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+ prog->Type = GL_SHADER_PROGRAM_MESA;
+ prog->RefCount = 1;
+ prog->Attributes = _mesa_new_parameter_list();
+#if FEATURE_ARB_geometry_shader4
+ prog->Geom.VerticesOut = 0;
+ prog->Geom.InputType = GL_TRIANGLES;
+ prog->Geom.OutputType = GL_TRIANGLE_STRIP;
+#endif
+}
+
+/**
+ * Allocate a new gl_shader_program object, initialize it.
+ * Called via ctx->Driver.NewShaderProgram()
+ */
+static struct gl_shader_program *
+_mesa_new_shader_program(struct gl_context *ctx, GLuint name)
+{
+ struct gl_shader_program *shProg;
+ shProg = rzalloc(NULL, struct gl_shader_program);
+ if (shProg) {
+ shProg->Name = name;
+ _mesa_init_shader_program(ctx, shProg);
+ }
+ return shProg;
+}
+
+
+/**
+ * Clear (free) the shader program state that gets produced by linking.
+ */
+void
+_mesa_clear_shader_program_data(struct gl_context *ctx,
+ struct gl_shader_program *shProg)
+{
+ _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
+ _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
+ _mesa_reference_geomprog(ctx, &shProg->GeometryProgram, NULL);
+
+ if (shProg->Uniforms) {
+ _mesa_free_uniform_list(shProg->Uniforms);
+ shProg->Uniforms = NULL;
+ }
+
+ if (shProg->Varying) {
+ _mesa_free_parameter_list(shProg->Varying);
+ shProg->Varying = NULL;
+ }
+}
+
+
+/**
+ * Free all the data that hangs off a shader program object, but not the
+ * object itself.
+ */
+void
+_mesa_free_shader_program_data(struct gl_context *ctx,
+ struct gl_shader_program *shProg)
+{
+ GLuint i;
+ gl_shader_type sh;
+
+ assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
+
+ _mesa_clear_shader_program_data(ctx, shProg);
+
+ if (shProg->Attributes) {
+ _mesa_free_parameter_list(shProg->Attributes);
+ shProg->Attributes = NULL;
+ }
+
+ /* detach shaders */
+ for (i = 0; i < shProg->NumShaders; i++) {
+ _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
+ }
+ shProg->NumShaders = 0;
+
+ if (shProg->Shaders) {
+ free(shProg->Shaders);
+ shProg->Shaders = NULL;
+ }
+
+ if (shProg->InfoLog) {
+ ralloc_free(shProg->InfoLog);
+ shProg->InfoLog = NULL;
+ }
+
+ /* Transform feedback varying vars */
+ for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
+ free(shProg->TransformFeedback.VaryingNames[i]);
+ }
+ free(shProg->TransformFeedback.VaryingNames);
+ shProg->TransformFeedback.VaryingNames = NULL;
+ shProg->TransformFeedback.NumVarying = 0;
+
+
+ for (sh = 0; sh < MESA_SHADER_TYPES; sh++) {
+ if (shProg->_LinkedShaders[sh] != NULL) {
+ ctx->Driver.DeleteShader(ctx, shProg->_LinkedShaders[sh]);
+ shProg->_LinkedShaders[sh] = NULL;
+ }
+ }
+}
+
+
+/**
+ * Free/delete a shader program object.
+ * Called via ctx->Driver.DeleteShaderProgram().
+ */
+static void
+_mesa_delete_shader_program(struct gl_context *ctx, struct gl_shader_program *shProg)
+{
+ _mesa_free_shader_program_data(ctx, shProg);
+
+ ralloc_free(shProg);
+}
+
+
+/**
+ * Lookup a GLSL program object.
+ */
+struct gl_shader_program *
+_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
+{
+ struct gl_shader_program *shProg;
+ if (name) {
+ shProg = (struct gl_shader_program *)
+ _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
+ /* Note that both gl_shader and gl_shader_program objects are kept
+ * in the same hash table. Check the object's type to be sure it's
+ * what we're expecting.
+ */
+ if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
+ return NULL;
+ }
+ return shProg;
+ }
+ return NULL;
+}
+
+
+/**
+ * As above, but record an error if program is not found.
+ */
+struct gl_shader_program *
+_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
+ const char *caller)
+{
+ if (!name) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
+ return NULL;
+ }
+ else {
+ struct gl_shader_program *shProg = (struct gl_shader_program *)
+ _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
+ if (!shProg) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
+ return NULL;
+ }
+ if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
+ return NULL;
+ }
+ return shProg;
+ }
+}
+
+
+void
+_mesa_init_shader_object_functions(struct dd_function_table *driver)
+{
+ driver->NewShader = _mesa_new_shader;
+ driver->DeleteShader = _mesa_delete_shader;
+ driver->NewShaderProgram = _mesa_new_shader_program;
+ driver->DeleteShaderProgram = _mesa_delete_shader_program;
+ driver->CompileShader = _mesa_ir_compile_shader;
+ driver->LinkShader = _mesa_ir_link_shader;
+}
diff --git a/mesalib/src/mesa/main/state.c b/mesalib/src/mesa/main/state.c
index f11578faf..5651e3263 100644
--- a/mesalib/src/mesa/main/state.c
+++ b/mesalib/src/mesa/main/state.c
@@ -43,6 +43,7 @@
#include "pixel.h"
#include "program/program.h"
#include "program/prog_parameter.h"
+#include "shaderobj.h"
#include "state.h"
#include "stencil.h"
#include "texenvprogram.h"
@@ -53,7 +54,7 @@
static void
update_separate_specular(struct gl_context *ctx)
{
- if (NEED_SECONDARY_COLOR(ctx))
+ if (_mesa_need_secondary_color(ctx))
ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
else
ctx->_TriangleCaps &= ~DD_SEPARATE_SPECULAR;
@@ -249,7 +250,7 @@ update_program(struct gl_context *ctx)
{
const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram;
const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram;
- const struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
+ struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram;
const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current;
const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current;
const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current;
@@ -275,23 +276,31 @@ update_program(struct gl_context *ctx)
/* Use shader programs */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
fsProg->FragmentProgram);
+ _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
+ fsProg);
}
else if (ctx->FragmentProgram._Enabled) {
- /* use user-defined vertex program */
+ /* use user-defined fragment program */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
ctx->FragmentProgram.Current);
+ _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
+ NULL);
}
else if (ctx->FragmentProgram._MaintainTexEnvProgram) {
/* Use fragment program generated from fixed-function state.
*/
+ struct gl_shader_program *f = _mesa_get_fixed_func_fragment_program(ctx);
+ _mesa_reference_shader_program(ctx,
+ &ctx->Shader._CurrentFragmentProgram, f);
+
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current,
- _mesa_get_fixed_func_fragment_program(ctx));
- _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram,
- ctx->FragmentProgram._Current);
+ f->FragmentProgram);
}
else {
/* no fragment program */
_mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL);
+ _mesa_reference_shader_program(ctx, &ctx->Shader._CurrentFragmentProgram,
+ NULL);
}
if (gsProg && gsProg->LinkStatus && gsProg->GeometryProgram) {
@@ -442,7 +451,7 @@ update_color(struct gl_context *ctx)
/* This is needed to support 1.1's RGB logic ops AND
* 1.0's blending logicops.
*/
- ctx->Color._LogicOpEnabled = RGBA_LOGICOP_ENABLED(ctx);
+ ctx->Color._LogicOpEnabled = _mesa_rgba_logicop_enabled(ctx);
}
@@ -524,7 +533,7 @@ update_tricaps(struct gl_context *ctx, GLbitfield new_state)
ctx->_TriangleCaps |= DD_TRI_LIGHT_TWOSIDE;
if (ctx->Light.ShadeModel == GL_FLAT)
ctx->_TriangleCaps |= DD_FLATSHADE;
- if (NEED_SECONDARY_COLOR(ctx))
+ if (_mesa_need_secondary_color(ctx))
ctx->_TriangleCaps |= DD_SEPARATE_SPECULAR;
/*
diff --git a/mesalib/src/mesa/main/state.h b/mesalib/src/mesa/main/state.h
index 6714196dc..31573fe5b 100644
--- a/mesalib/src/mesa/main/state.h
+++ b/mesalib/src/mesa/main/state.h
@@ -46,4 +46,43 @@ extern void
_mesa_set_vp_override(struct gl_context *ctx, GLboolean flag);
+/**
+ * Is the secondary color needed?
+ */
+static INLINE GLboolean
+_mesa_need_secondary_color(const struct gl_context *ctx)
+{
+ if (ctx->Light.Enabled &&
+ ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
+ return GL_TRUE;
+
+ if (ctx->Fog.ColorSumEnabled)
+ return GL_TRUE;
+
+ if (ctx->VertexProgram._Current &&
+ (ctx->VertexProgram._Current != ctx->VertexProgram._TnlProgram) &&
+ (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_COLOR1))
+ return GL_TRUE;
+
+ if (ctx->FragmentProgram._Current &&
+ (ctx->FragmentProgram._Current != ctx->FragmentProgram._TexEnvProgram) &&
+ (ctx->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL1))
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Is RGBA LogicOp enabled?
+ */
+static INLINE GLboolean
+_mesa_rgba_logicop_enabled(const struct gl_context *ctx)
+{
+ return ctx->Color.ColorLogicOpEnabled ||
+ (ctx->Color.BlendEnabled && ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP);
+}
+
+
+
#endif
diff --git a/mesalib/src/mesa/main/texenvprogram.c b/mesalib/src/mesa/main/texenvprogram.c
deleted file mode 100644
index c30fe9616..000000000
--- a/mesalib/src/mesa/main/texenvprogram.c
+++ /dev/null
@@ -1,1618 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- * Copyright 2009 VMware, Inc. 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, sub license, 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 (including the
- * next paragraph) 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
- *
- **************************************************************************/
-
-#include "glheader.h"
-#include "imports.h"
-#include "mtypes.h"
-#include "program/program.h"
-#include "program/prog_parameter.h"
-#include "program/prog_cache.h"
-#include "program/prog_instruction.h"
-#include "program/prog_print.h"
-#include "program/prog_statevars.h"
-#include "program/programopt.h"
-#include "texenvprogram.h"
-
-
-/*
- * Note on texture units:
- *
- * The number of texture units supported by fixed-function fragment
- * processing is MAX_TEXTURE_COORD_UNITS, not MAX_TEXTURE_IMAGE_UNITS.
- * That's because there's a one-to-one correspondence between texture
- * coordinates and samplers in fixed-function processing.
- *
- * Since fixed-function vertex processing is limited to MAX_TEXTURE_COORD_UNITS
- * sets of texcoords, so is fixed-function fragment processing.
- *
- * We can safely use ctx->Const.MaxTextureUnits for loop bounds.
- */
-
-
-struct texenvprog_cache_item
-{
- GLuint hash;
- void *key;
- struct gl_fragment_program *data;
- struct texenvprog_cache_item *next;
-};
-
-static GLboolean
-texenv_doing_secondary_color(struct gl_context *ctx)
-{
- if (ctx->Light.Enabled &&
- (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR))
- return GL_TRUE;
-
- if (ctx->Fog.ColorSumEnabled)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-/**
- * Up to nine instructions per tex unit, plus fog, specular color.
- */
-#define MAX_INSTRUCTIONS ((MAX_TEXTURE_COORD_UNITS * 9) + 12)
-
-#define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM)
-
-struct mode_opt {
-#ifdef __GNUC__
- __extension__ GLubyte Source:4; /**< SRC_x */
- __extension__ GLubyte Operand:3; /**< OPR_x */
-#else
- GLubyte Source; /**< SRC_x */
- GLubyte Operand; /**< OPR_x */
-#endif
-};
-
-struct state_key {
- GLuint nr_enabled_units:8;
- GLuint enabled_units:8;
- GLuint separate_specular:1;
- GLuint fog_enabled:1;
- GLuint fog_mode:2; /**< FOG_x */
- GLuint inputs_available:12;
- GLuint num_draw_buffers:4;
-
- /* NOTE: This array of structs must be last! (see "keySize" below) */
- struct {
- GLuint enabled:1;
- GLuint source_index:3; /**< TEXTURE_x_INDEX */
- GLuint shadow:1;
- GLuint ScaleShiftRGB:2;
- GLuint ScaleShiftA:2;
-
- GLuint NumArgsRGB:3; /**< up to MAX_COMBINER_TERMS */
- GLuint ModeRGB:5; /**< MODE_x */
-
- GLuint NumArgsA:3; /**< up to MAX_COMBINER_TERMS */
- GLuint ModeA:5; /**< MODE_x */
-
- GLuint texture_cyl_wrap:1; /**< For gallium test/debug only */
-
- struct mode_opt OptRGB[MAX_COMBINER_TERMS];
- struct mode_opt OptA[MAX_COMBINER_TERMS];
- } unit[MAX_TEXTURE_UNITS];
-};
-
-#define FOG_LINEAR 0
-#define FOG_EXP 1
-#define FOG_EXP2 2
-#define FOG_UNKNOWN 3
-
-static GLuint translate_fog_mode( GLenum mode )
-{
- switch (mode) {
- case GL_LINEAR: return FOG_LINEAR;
- case GL_EXP: return FOG_EXP;
- case GL_EXP2: return FOG_EXP2;
- default: return FOG_UNKNOWN;
- }
-}
-
-#define OPR_SRC_COLOR 0
-#define OPR_ONE_MINUS_SRC_COLOR 1
-#define OPR_SRC_ALPHA 2
-#define OPR_ONE_MINUS_SRC_ALPHA 3
-#define OPR_ZERO 4
-#define OPR_ONE 5
-#define OPR_UNKNOWN 7
-
-static GLuint translate_operand( GLenum operand )
-{
- switch (operand) {
- case GL_SRC_COLOR: return OPR_SRC_COLOR;
- case GL_ONE_MINUS_SRC_COLOR: return OPR_ONE_MINUS_SRC_COLOR;
- case GL_SRC_ALPHA: return OPR_SRC_ALPHA;
- case GL_ONE_MINUS_SRC_ALPHA: return OPR_ONE_MINUS_SRC_ALPHA;
- case GL_ZERO: return OPR_ZERO;
- case GL_ONE: return OPR_ONE;
- default:
- assert(0);
- return OPR_UNKNOWN;
- }
-}
-
-#define SRC_TEXTURE 0
-#define SRC_TEXTURE0 1
-#define SRC_TEXTURE1 2
-#define SRC_TEXTURE2 3
-#define SRC_TEXTURE3 4
-#define SRC_TEXTURE4 5
-#define SRC_TEXTURE5 6
-#define SRC_TEXTURE6 7
-#define SRC_TEXTURE7 8
-#define SRC_CONSTANT 9
-#define SRC_PRIMARY_COLOR 10
-#define SRC_PREVIOUS 11
-#define SRC_ZERO 12
-#define SRC_UNKNOWN 15
-
-static GLuint translate_source( GLenum src )
-{
- switch (src) {
- case GL_TEXTURE: return SRC_TEXTURE;
- case GL_TEXTURE0:
- case GL_TEXTURE1:
- case GL_TEXTURE2:
- case GL_TEXTURE3:
- case GL_TEXTURE4:
- case GL_TEXTURE5:
- case GL_TEXTURE6:
- case GL_TEXTURE7: return SRC_TEXTURE0 + (src - GL_TEXTURE0);
- case GL_CONSTANT: return SRC_CONSTANT;
- case GL_PRIMARY_COLOR: return SRC_PRIMARY_COLOR;
- case GL_PREVIOUS: return SRC_PREVIOUS;
- case GL_ZERO:
- return SRC_ZERO;
- default:
- assert(0);
- return SRC_UNKNOWN;
- }
-}
-
-#define MODE_REPLACE 0 /* r = a0 */
-#define MODE_MODULATE 1 /* r = a0 * a1 */
-#define MODE_ADD 2 /* r = a0 + a1 */
-#define MODE_ADD_SIGNED 3 /* r = a0 + a1 - 0.5 */
-#define MODE_INTERPOLATE 4 /* r = a0 * a2 + a1 * (1 - a2) */
-#define MODE_SUBTRACT 5 /* r = a0 - a1 */
-#define MODE_DOT3_RGB 6 /* r = a0 . a1 */
-#define MODE_DOT3_RGB_EXT 7 /* r = a0 . a1 */
-#define MODE_DOT3_RGBA 8 /* r = a0 . a1 */
-#define MODE_DOT3_RGBA_EXT 9 /* r = a0 . a1 */
-#define MODE_MODULATE_ADD_ATI 10 /* r = a0 * a2 + a1 */
-#define MODE_MODULATE_SIGNED_ADD_ATI 11 /* r = a0 * a2 + a1 - 0.5 */
-#define MODE_MODULATE_SUBTRACT_ATI 12 /* r = a0 * a2 - a1 */
-#define MODE_ADD_PRODUCTS 13 /* r = a0 * a1 + a2 * a3 */
-#define MODE_ADD_PRODUCTS_SIGNED 14 /* r = a0 * a1 + a2 * a3 - 0.5 */
-#define MODE_BUMP_ENVMAP_ATI 15 /* special */
-#define MODE_UNKNOWN 16
-
-/**
- * Translate GL combiner state into a MODE_x value
- */
-static GLuint translate_mode( GLenum envMode, GLenum mode )
-{
- switch (mode) {
- case GL_REPLACE: return MODE_REPLACE;
- case GL_MODULATE: return MODE_MODULATE;
- case GL_ADD:
- if (envMode == GL_COMBINE4_NV)
- return MODE_ADD_PRODUCTS;
- else
- return MODE_ADD;
- case GL_ADD_SIGNED:
- if (envMode == GL_COMBINE4_NV)
- return MODE_ADD_PRODUCTS_SIGNED;
- else
- return MODE_ADD_SIGNED;
- case GL_INTERPOLATE: return MODE_INTERPOLATE;
- case GL_SUBTRACT: return MODE_SUBTRACT;
- case GL_DOT3_RGB: return MODE_DOT3_RGB;
- case GL_DOT3_RGB_EXT: return MODE_DOT3_RGB_EXT;
- case GL_DOT3_RGBA: return MODE_DOT3_RGBA;
- case GL_DOT3_RGBA_EXT: return MODE_DOT3_RGBA_EXT;
- case GL_MODULATE_ADD_ATI: return MODE_MODULATE_ADD_ATI;
- case GL_MODULATE_SIGNED_ADD_ATI: return MODE_MODULATE_SIGNED_ADD_ATI;
- case GL_MODULATE_SUBTRACT_ATI: return MODE_MODULATE_SUBTRACT_ATI;
- case GL_BUMP_ENVMAP_ATI: return MODE_BUMP_ENVMAP_ATI;
- default:
- assert(0);
- return MODE_UNKNOWN;
- }
-}
-
-
-/**
- * Do we need to clamp the results of the given texture env/combine mode?
- * If the inputs to the mode are in [0,1] we don't always have to clamp
- * the results.
- */
-static GLboolean
-need_saturate( GLuint mode )
-{
- switch (mode) {
- case MODE_REPLACE:
- case MODE_MODULATE:
- case MODE_INTERPOLATE:
- return GL_FALSE;
- case MODE_ADD:
- case MODE_ADD_SIGNED:
- case MODE_SUBTRACT:
- case MODE_DOT3_RGB:
- case MODE_DOT3_RGB_EXT:
- case MODE_DOT3_RGBA:
- case MODE_DOT3_RGBA_EXT:
- case MODE_MODULATE_ADD_ATI:
- case MODE_MODULATE_SIGNED_ADD_ATI:
- case MODE_MODULATE_SUBTRACT_ATI:
- case MODE_ADD_PRODUCTS:
- case MODE_ADD_PRODUCTS_SIGNED:
- case MODE_BUMP_ENVMAP_ATI:
- return GL_TRUE;
- default:
- assert(0);
- return GL_FALSE;
- }
-}
-
-
-
-/**
- * Translate TEXTURE_x_BIT to TEXTURE_x_INDEX.
- */
-static GLuint translate_tex_src_bit( GLbitfield bit )
-{
- ASSERT(bit);
- return _mesa_ffs(bit) - 1;
-}
-
-
-#define VERT_BIT_TEX_ANY (0xff << VERT_ATTRIB_TEX0)
-#define VERT_RESULT_TEX_ANY (0xff << VERT_RESULT_TEX0)
-
-/**
- * Identify all possible varying inputs. The fragment program will
- * never reference non-varying inputs, but will track them via state
- * constants instead.
- *
- * This function figures out all the inputs that the fragment program
- * has access to. The bitmask is later reduced to just those which
- * are actually referenced.
- */
-static GLbitfield get_fp_input_mask( struct gl_context *ctx )
-{
- /* _NEW_PROGRAM */
- const GLboolean vertexShader =
- (ctx->Shader.CurrentVertexProgram &&
- ctx->Shader.CurrentVertexProgram->LinkStatus &&
- ctx->Shader.CurrentVertexProgram->VertexProgram);
- const GLboolean vertexProgram = ctx->VertexProgram._Enabled;
- GLbitfield fp_inputs = 0x0;
-
- if (ctx->VertexProgram._Overriden) {
- /* Somebody's messing with the vertex program and we don't have
- * a clue what's happening. Assume that it could be producing
- * all possible outputs.
- */
- fp_inputs = ~0;
- }
- else if (ctx->RenderMode == GL_FEEDBACK) {
- /* _NEW_RENDERMODE */
- fp_inputs = (FRAG_BIT_COL0 | FRAG_BIT_TEX0);
- }
- else if (!(vertexProgram || vertexShader) ||
- !ctx->VertexProgram._Current) {
- /* Fixed function vertex logic */
- /* _NEW_ARRAY */
- GLbitfield varying_inputs = ctx->varying_vp_inputs;
-
- /* These get generated in the setup routine regardless of the
- * vertex program:
- */
- /* _NEW_POINT */
- if (ctx->Point.PointSprite)
- varying_inputs |= FRAG_BITS_TEX_ANY;
-
- /* First look at what values may be computed by the generated
- * vertex program:
- */
- /* _NEW_LIGHT */
- if (ctx->Light.Enabled) {
- fp_inputs |= FRAG_BIT_COL0;
-
- if (texenv_doing_secondary_color(ctx))
- fp_inputs |= FRAG_BIT_COL1;
- }
-
- /* _NEW_TEXTURE */
- fp_inputs |= (ctx->Texture._TexGenEnabled |
- ctx->Texture._TexMatEnabled) << FRAG_ATTRIB_TEX0;
-
- /* Then look at what might be varying as a result of enabled
- * arrays, etc:
- */
- if (varying_inputs & VERT_BIT_COLOR0)
- fp_inputs |= FRAG_BIT_COL0;
- if (varying_inputs & VERT_BIT_COLOR1)
- fp_inputs |= FRAG_BIT_COL1;
-
- fp_inputs |= (((varying_inputs & VERT_BIT_TEX_ANY) >> VERT_ATTRIB_TEX0)
- << FRAG_ATTRIB_TEX0);
-
- }
- else {
- /* calculate from vp->outputs */
- struct gl_vertex_program *vprog;
- GLbitfield64 vp_outputs;
-
- /* Choose GLSL vertex shader over ARB vertex program. Need this
- * since vertex shader state validation comes after fragment state
- * validation (see additional comments in state.c).
- */
- if (vertexShader)
- vprog = ctx->Shader.CurrentVertexProgram->VertexProgram;
- else
- vprog = ctx->VertexProgram.Current;
-
- vp_outputs = vprog->Base.OutputsWritten;
-
- /* These get generated in the setup routine regardless of the
- * vertex program:
- */
- /* _NEW_POINT */
- if (ctx->Point.PointSprite)
- vp_outputs |= FRAG_BITS_TEX_ANY;
-
- if (vp_outputs & (1 << VERT_RESULT_COL0))
- fp_inputs |= FRAG_BIT_COL0;
- if (vp_outputs & (1 << VERT_RESULT_COL1))
- fp_inputs |= FRAG_BIT_COL1;
-
- fp_inputs |= (((vp_outputs & VERT_RESULT_TEX_ANY) >> VERT_RESULT_TEX0)
- << FRAG_ATTRIB_TEX0);
- }
-
- return fp_inputs;
-}
-
-
-/**
- * Examine current texture environment state and generate a unique
- * key to identify it.
- */
-static GLuint make_state_key( struct gl_context *ctx, struct state_key *key )
-{
- GLuint i, j;
- GLbitfield inputs_referenced = FRAG_BIT_COL0;
- const GLbitfield inputs_available = get_fp_input_mask( ctx );
- GLuint keySize;
-
- memset(key, 0, sizeof(*key));
-
- /* _NEW_TEXTURE */
- for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
- const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
- const struct gl_texture_object *texObj = texUnit->_Current;
- const struct gl_tex_env_combine_state *comb = texUnit->_CurrentCombine;
- GLenum format;
-
- if (!texUnit->_ReallyEnabled || !texUnit->Enabled)
- continue;
-
- format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat;
-
- key->unit[i].enabled = 1;
- key->enabled_units |= (1<<i);
- key->nr_enabled_units = i + 1;
- inputs_referenced |= FRAG_BIT_TEX(i);
-
- key->unit[i].source_index =
- translate_tex_src_bit(texUnit->_ReallyEnabled);
-
- key->unit[i].shadow = ((texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE) &&
- ((format == GL_DEPTH_COMPONENT) ||
- (format == GL_DEPTH_STENCIL_EXT)));
-
- key->unit[i].NumArgsRGB = comb->_NumArgsRGB;
- key->unit[i].NumArgsA = comb->_NumArgsA;
-
- key->unit[i].ModeRGB =
- translate_mode(texUnit->EnvMode, comb->ModeRGB);
- key->unit[i].ModeA =
- translate_mode(texUnit->EnvMode, comb->ModeA);
-
- key->unit[i].ScaleShiftRGB = comb->ScaleShiftRGB;
- key->unit[i].ScaleShiftA = comb->ScaleShiftA;
-
- for (j = 0; j < MAX_COMBINER_TERMS; j++) {
- key->unit[i].OptRGB[j].Operand = translate_operand(comb->OperandRGB[j]);
- key->unit[i].OptA[j].Operand = translate_operand(comb->OperandA[j]);
- key->unit[i].OptRGB[j].Source = translate_source(comb->SourceRGB[j]);
- key->unit[i].OptA[j].Source = translate_source(comb->SourceA[j]);
- }
-
- if (key->unit[i].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
- /* requires some special translation */
- key->unit[i].NumArgsRGB = 2;
- key->unit[i].ScaleShiftRGB = 0;
- key->unit[i].OptRGB[0].Operand = OPR_SRC_COLOR;
- key->unit[i].OptRGB[0].Source = SRC_TEXTURE;
- key->unit[i].OptRGB[1].Operand = OPR_SRC_COLOR;
- key->unit[i].OptRGB[1].Source = texUnit->BumpTarget - GL_TEXTURE0 + SRC_TEXTURE0;
- }
-
- /* this is a back-door for enabling cylindrical texture wrap mode */
- if (texObj->Priority == 0.125)
- key->unit[i].texture_cyl_wrap = 1;
- }
-
- /* _NEW_LIGHT | _NEW_FOG */
- if (texenv_doing_secondary_color(ctx)) {
- key->separate_specular = 1;
- inputs_referenced |= FRAG_BIT_COL1;
- }
-
- /* _NEW_FOG */
- if (ctx->Fog.Enabled) {
- key->fog_enabled = 1;
- key->fog_mode = translate_fog_mode(ctx->Fog.Mode);
- inputs_referenced |= FRAG_BIT_FOGC; /* maybe */
- }
-
- /* _NEW_BUFFERS */
- key->num_draw_buffers = ctx->DrawBuffer->_NumColorDrawBuffers;
-
- key->inputs_available = (inputs_available & inputs_referenced);
-
- /* compute size of state key, ignoring unused texture units */
- keySize = sizeof(*key) - sizeof(key->unit)
- + key->nr_enabled_units * sizeof(key->unit[0]);
-
- return keySize;
-}
-
-
-/**
- * Use uregs to represent registers internally, translate to Mesa's
- * expected formats on emit.
- *
- * NOTE: These are passed by value extensively in this file rather
- * than as usual by pointer reference. If this disturbs you, try
- * remembering they are just 32bits in size.
- *
- * GCC is smart enough to deal with these dword-sized structures in
- * much the same way as if I had defined them as dwords and was using
- * macros to access and set the fields. This is much nicer and easier
- * to evolve.
- */
-struct ureg {
- GLuint file:4;
- GLuint idx:8;
- GLuint negatebase:1;
- GLuint swz:12;
- GLuint pad:7;
-};
-
-static const struct ureg undef = {
- PROGRAM_UNDEFINED,
- ~0,
- 0,
- 0,
- 0
-};
-
-
-/** State used to build the fragment program:
- */
-struct texenv_fragment_program {
- struct gl_fragment_program *program;
- struct state_key *state;
-
- GLbitfield alu_temps; /**< Track texture indirections, see spec. */
- GLbitfield temps_output; /**< Track texture indirections, see spec. */
- GLbitfield temp_in_use; /**< Tracks temporary regs which are in use. */
- GLboolean error;
-
- struct ureg src_texture[MAX_TEXTURE_COORD_UNITS];
- /* Reg containing each texture unit's sampled texture color,
- * else undef.
- */
-
- struct ureg texcoord_tex[MAX_TEXTURE_COORD_UNITS];
- /* Reg containing texcoord for a texture unit,
- * needed for bump mapping, else undef.
- */
-
- struct ureg src_previous; /**< Reg containing color from previous
- * stage. May need to be decl'd.
- */
-
- GLuint last_tex_stage; /**< Number of last enabled texture unit */
-
- struct ureg half;
- struct ureg one;
- struct ureg zero;
-};
-
-
-
-static struct ureg make_ureg(GLuint file, GLuint idx)
-{
- struct ureg reg;
- reg.file = file;
- reg.idx = idx;
- reg.negatebase = 0;
- reg.swz = SWIZZLE_NOOP;
- reg.pad = 0;
- return reg;
-}
-
-static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w )
-{
- reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x),
- GET_SWZ(reg.swz, y),
- GET_SWZ(reg.swz, z),
- GET_SWZ(reg.swz, w));
-
- return reg;
-}
-
-static struct ureg swizzle1( struct ureg reg, int x )
-{
- return swizzle(reg, x, x, x, x);
-}
-
-static struct ureg negate( struct ureg reg )
-{
- reg.negatebase ^= 1;
- return reg;
-}
-
-static GLboolean is_undef( struct ureg reg )
-{
- return reg.file == PROGRAM_UNDEFINED;
-}
-
-
-static struct ureg get_temp( struct texenv_fragment_program *p )
-{
- GLint bit;
-
- /* First try and reuse temps which have been used already:
- */
- bit = _mesa_ffs( ~p->temp_in_use & p->alu_temps );
-
- /* Then any unused temporary:
- */
- if (!bit)
- bit = _mesa_ffs( ~p->temp_in_use );
-
- if (!bit) {
- _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__);
- exit(1);
- }
-
- if ((GLuint) bit > p->program->Base.NumTemporaries)
- p->program->Base.NumTemporaries = bit;
-
- p->temp_in_use |= 1<<(bit-1);
- return make_ureg(PROGRAM_TEMPORARY, (bit-1));
-}
-
-static struct ureg get_tex_temp( struct texenv_fragment_program *p )
-{
- int bit;
-
- /* First try to find available temp not previously used (to avoid
- * starting a new texture indirection). According to the spec, the
- * ~p->temps_output isn't necessary, but will keep it there for
- * now:
- */
- bit = _mesa_ffs( ~p->temp_in_use & ~p->alu_temps & ~p->temps_output );
-
- /* Then any unused temporary:
- */
- if (!bit)
- bit = _mesa_ffs( ~p->temp_in_use );
-
- if (!bit) {
- _mesa_problem(NULL, "%s: out of temporaries\n", __FILE__);
- exit(1);
- }
-
- if ((GLuint) bit > p->program->Base.NumTemporaries)
- p->program->Base.NumTemporaries = bit;
-
- p->temp_in_use |= 1<<(bit-1);
- return make_ureg(PROGRAM_TEMPORARY, (bit-1));
-}
-
-
-/** Mark a temp reg as being no longer allocatable. */
-static void reserve_temp( struct texenv_fragment_program *p, struct ureg r )
-{
- if (r.file == PROGRAM_TEMPORARY)
- p->temps_output |= (1 << r.idx);
-}
-
-
-static void release_temps(struct gl_context *ctx, struct texenv_fragment_program *p )
-{
- GLuint max_temp = ctx->Const.FragmentProgram.MaxTemps;
-
- /* KW: To support tex_env_crossbar, don't release the registers in
- * temps_output.
- */
- if (max_temp >= sizeof(int) * 8)
- p->temp_in_use = p->temps_output;
- else
- p->temp_in_use = ~((1<<max_temp)-1) | p->temps_output;
-}
-
-
-static struct ureg register_param5( struct texenv_fragment_program *p,
- GLint s0,
- GLint s1,
- GLint s2,
- GLint s3,
- GLint s4)
-{
- gl_state_index tokens[STATE_LENGTH];
- GLuint idx;
- tokens[0] = s0;
- tokens[1] = s1;
- tokens[2] = s2;
- tokens[3] = s3;
- tokens[4] = s4;
- idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens );
- return make_ureg(PROGRAM_STATE_VAR, idx);
-}
-
-
-#define register_param1(p,s0) register_param5(p,s0,0,0,0,0)
-#define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0)
-#define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0)
-#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0)
-
-static GLuint frag_to_vert_attrib( GLuint attrib )
-{
- switch (attrib) {
- case FRAG_ATTRIB_COL0: return VERT_ATTRIB_COLOR0;
- case FRAG_ATTRIB_COL1: return VERT_ATTRIB_COLOR1;
- default:
- assert(attrib >= FRAG_ATTRIB_TEX0);
- assert(attrib <= FRAG_ATTRIB_TEX7);
- return attrib - FRAG_ATTRIB_TEX0 + VERT_ATTRIB_TEX0;
- }
-}
-
-
-static struct ureg register_input( struct texenv_fragment_program *p, GLuint input )
-{
- if (p->state->inputs_available & (1<<input)) {
- p->program->Base.InputsRead |= (1 << input);
- return make_ureg(PROGRAM_INPUT, input);
- }
- else {
- GLuint idx = frag_to_vert_attrib( input );
- return register_param3( p, STATE_INTERNAL, STATE_CURRENT_ATTRIB, idx );
- }
-}
-
-
-static void emit_arg( struct prog_src_register *reg,
- struct ureg ureg )
-{
- reg->File = ureg.file;
- reg->Index = ureg.idx;
- reg->Swizzle = ureg.swz;
- reg->Negate = ureg.negatebase ? NEGATE_XYZW : NEGATE_NONE;
- reg->Abs = GL_FALSE;
-}
-
-static void emit_dst( struct prog_dst_register *dst,
- struct ureg ureg, GLuint mask )
-{
- dst->File = ureg.file;
- dst->Index = ureg.idx;
- dst->WriteMask = mask;
- dst->CondMask = COND_TR; /* always pass cond test */
- dst->CondSwizzle = SWIZZLE_NOOP;
-}
-
-static struct prog_instruction *
-emit_op(struct texenv_fragment_program *p,
- enum prog_opcode op,
- struct ureg dest,
- GLuint mask,
- GLboolean saturate,
- struct ureg src0,
- struct ureg src1,
- struct ureg src2 )
-{
- const GLuint nr = p->program->Base.NumInstructions++;
- struct prog_instruction *inst = &p->program->Base.Instructions[nr];
-
- assert(nr < MAX_INSTRUCTIONS);
-
- _mesa_init_instructions(inst, 1);
- inst->Opcode = op;
-
- emit_arg( &inst->SrcReg[0], src0 );
- emit_arg( &inst->SrcReg[1], src1 );
- emit_arg( &inst->SrcReg[2], src2 );
-
- inst->SaturateMode = saturate ? SATURATE_ZERO_ONE : SATURATE_OFF;
-
- emit_dst( &inst->DstReg, dest, mask );
-
-#if 0
- /* Accounting for indirection tracking:
- */
- if (dest.file == PROGRAM_TEMPORARY)
- p->temps_output |= 1 << dest.idx;
-#endif
-
- return inst;
-}
-
-
-static struct ureg emit_arith( struct texenv_fragment_program *p,
- enum prog_opcode op,
- struct ureg dest,
- GLuint mask,
- GLboolean saturate,
- struct ureg src0,
- struct ureg src1,
- struct ureg src2 )
-{
- emit_op(p, op, dest, mask, saturate, src0, src1, src2);
-
- /* Accounting for indirection tracking:
- */
- if (src0.file == PROGRAM_TEMPORARY)
- p->alu_temps |= 1 << src0.idx;
-
- if (!is_undef(src1) && src1.file == PROGRAM_TEMPORARY)
- p->alu_temps |= 1 << src1.idx;
-
- if (!is_undef(src2) && src2.file == PROGRAM_TEMPORARY)
- p->alu_temps |= 1 << src2.idx;
-
- if (dest.file == PROGRAM_TEMPORARY)
- p->alu_temps |= 1 << dest.idx;
-
- p->program->Base.NumAluInstructions++;
- return dest;
-}
-
-static struct ureg emit_texld( struct texenv_fragment_program *p,
- enum prog_opcode op,
- struct ureg dest,
- GLuint destmask,
- GLuint tex_unit,
- GLuint tex_idx,
- GLuint tex_shadow,
- struct ureg coord )
-{
- struct prog_instruction *inst = emit_op( p, op,
- dest, destmask,
- GL_FALSE, /* don't saturate? */
- coord, /* arg 0? */
- undef,
- undef);
-
- inst->TexSrcTarget = tex_idx;
- inst->TexSrcUnit = tex_unit;
- inst->TexShadow = tex_shadow;
-
- p->program->Base.NumTexInstructions++;
-
- /* Accounting for indirection tracking:
- */
- reserve_temp(p, dest);
-
-#if 0
- /* Is this a texture indirection?
- */
- if ((coord.file == PROGRAM_TEMPORARY &&
- (p->temps_output & (1<<coord.idx))) ||
- (dest.file == PROGRAM_TEMPORARY &&
- (p->alu_temps & (1<<dest.idx)))) {
- p->program->Base.NumTexIndirections++;
- p->temps_output = 1<<coord.idx;
- p->alu_temps = 0;
- assert(0); /* KW: texture env crossbar */
- }
-#endif
-
- return dest;
-}
-
-
-static struct ureg register_const4f( struct texenv_fragment_program *p,
- GLfloat s0,
- GLfloat s1,
- GLfloat s2,
- GLfloat s3)
-{
- GLfloat values[4];
- GLuint idx, swizzle;
- struct ureg r;
- values[0] = s0;
- values[1] = s1;
- values[2] = s2;
- values[3] = s3;
- idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4,
- &swizzle );
- r = make_ureg(PROGRAM_CONSTANT, idx);
- r.swz = swizzle;
- return r;
-}
-
-#define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0)
-#define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1)
-#define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1)
-#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1)
-
-
-static struct ureg get_one( struct texenv_fragment_program *p )
-{
- if (is_undef(p->one))
- p->one = register_scalar_const(p, 1.0);
- return p->one;
-}
-
-static struct ureg get_half( struct texenv_fragment_program *p )
-{
- if (is_undef(p->half))
- p->half = register_scalar_const(p, 0.5);
- return p->half;
-}
-
-static struct ureg get_zero( struct texenv_fragment_program *p )
-{
- if (is_undef(p->zero))
- p->zero = register_scalar_const(p, 0.0);
- return p->zero;
-}
-
-
-static void program_error( struct texenv_fragment_program *p, const char *msg )
-{
- _mesa_problem(NULL, "%s", msg);
- p->error = 1;
-}
-
-static struct ureg get_source( struct texenv_fragment_program *p,
- GLuint src, GLuint unit )
-{
- switch (src) {
- case SRC_TEXTURE:
- assert(!is_undef(p->src_texture[unit]));
- return p->src_texture[unit];
-
- case SRC_TEXTURE0:
- case SRC_TEXTURE1:
- case SRC_TEXTURE2:
- case SRC_TEXTURE3:
- case SRC_TEXTURE4:
- case SRC_TEXTURE5:
- case SRC_TEXTURE6:
- case SRC_TEXTURE7:
- assert(!is_undef(p->src_texture[src - SRC_TEXTURE0]));
- return p->src_texture[src - SRC_TEXTURE0];
-
- case SRC_CONSTANT:
- return register_param2(p, STATE_TEXENV_COLOR, unit);
-
- case SRC_PRIMARY_COLOR:
- return register_input(p, FRAG_ATTRIB_COL0);
-
- case SRC_ZERO:
- return get_zero(p);
-
- case SRC_PREVIOUS:
- if (is_undef(p->src_previous))
- return register_input(p, FRAG_ATTRIB_COL0);
- else
- return p->src_previous;
-
- default:
- assert(0);
- return undef;
- }
-}
-
-static struct ureg emit_combine_source( struct texenv_fragment_program *p,
- GLuint mask,
- GLuint unit,
- GLuint source,
- GLuint operand )
-{
- struct ureg arg, src, one;
-
- src = get_source(p, source, unit);
-
- switch (operand) {
- case OPR_ONE_MINUS_SRC_COLOR:
- /* Get unused tmp,
- * Emit tmp = 1.0 - arg.xyzw
- */
- arg = get_temp( p );
- one = get_one( p );
- return emit_arith( p, OPCODE_SUB, arg, mask, 0, one, src, undef);
-
- case OPR_SRC_ALPHA:
- if (mask == WRITEMASK_W)
- return src;
- else
- return swizzle1( src, SWIZZLE_W );
- case OPR_ONE_MINUS_SRC_ALPHA:
- /* Get unused tmp,
- * Emit tmp = 1.0 - arg.wwww
- */
- arg = get_temp(p);
- one = get_one(p);
- return emit_arith(p, OPCODE_SUB, arg, mask, 0,
- one, swizzle1(src, SWIZZLE_W), undef);
- case OPR_ZERO:
- return get_zero(p);
- case OPR_ONE:
- return get_one(p);
- case OPR_SRC_COLOR:
- return src;
- default:
- assert(0);
- return src;
- }
-}
-
-/**
- * Check if the RGB and Alpha sources and operands match for the given
- * texture unit's combinder state. When the RGB and A sources and
- * operands match, we can emit fewer instructions.
- */
-static GLboolean args_match( const struct state_key *key, GLuint unit )
-{
- GLuint i, numArgs = key->unit[unit].NumArgsRGB;
-
- for (i = 0; i < numArgs; i++) {
- if (key->unit[unit].OptA[i].Source != key->unit[unit].OptRGB[i].Source)
- return GL_FALSE;
-
- switch (key->unit[unit].OptA[i].Operand) {
- case OPR_SRC_ALPHA:
- switch (key->unit[unit].OptRGB[i].Operand) {
- case OPR_SRC_COLOR:
- case OPR_SRC_ALPHA:
- break;
- default:
- return GL_FALSE;
- }
- break;
- case OPR_ONE_MINUS_SRC_ALPHA:
- switch (key->unit[unit].OptRGB[i].Operand) {
- case OPR_ONE_MINUS_SRC_COLOR:
- case OPR_ONE_MINUS_SRC_ALPHA:
- break;
- default:
- return GL_FALSE;
- }
- break;
- default:
- return GL_FALSE; /* impossible */
- }
- }
-
- return GL_TRUE;
-}
-
-static struct ureg emit_combine( struct texenv_fragment_program *p,
- struct ureg dest,
- GLuint mask,
- GLboolean saturate,
- GLuint unit,
- GLuint nr,
- GLuint mode,
- const struct mode_opt *opt)
-{
- struct ureg src[MAX_COMBINER_TERMS];
- struct ureg tmp, half;
- GLuint i;
-
- assert(nr <= MAX_COMBINER_TERMS);
-
- for (i = 0; i < nr; i++)
- src[i] = emit_combine_source( p, mask, unit, opt[i].Source, opt[i].Operand );
-
- switch (mode) {
- case MODE_REPLACE:
- if (mask == WRITEMASK_XYZW && !saturate)
- return src[0];
- else
- return emit_arith( p, OPCODE_MOV, dest, mask, saturate, src[0], undef, undef );
- case MODE_MODULATE:
- return emit_arith( p, OPCODE_MUL, dest, mask, saturate,
- src[0], src[1], undef );
- case MODE_ADD:
- return emit_arith( p, OPCODE_ADD, dest, mask, saturate,
- src[0], src[1], undef );
- case MODE_ADD_SIGNED:
- /* tmp = arg0 + arg1
- * result = tmp - .5
- */
- half = get_half(p);
- tmp = get_temp( p );
- emit_arith( p, OPCODE_ADD, tmp, mask, 0, src[0], src[1], undef );
- emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp, half, undef );
- return dest;
- case MODE_INTERPOLATE:
- /* Arg0 * (Arg2) + Arg1 * (1-Arg2) -- note arguments are reordered:
- */
- return emit_arith( p, OPCODE_LRP, dest, mask, saturate, src[2], src[0], src[1] );
-
- case MODE_SUBTRACT:
- return emit_arith( p, OPCODE_SUB, dest, mask, saturate, src[0], src[1], undef );
-
- case MODE_DOT3_RGBA:
- case MODE_DOT3_RGBA_EXT:
- case MODE_DOT3_RGB_EXT:
- case MODE_DOT3_RGB: {
- struct ureg tmp0 = get_temp( p );
- struct ureg tmp1 = get_temp( p );
- struct ureg neg1 = register_scalar_const(p, -1);
- struct ureg two = register_scalar_const(p, 2);
-
- /* tmp0 = 2*src0 - 1
- * tmp1 = 2*src1 - 1
- *
- * dst = tmp0 dot3 tmp1
- */
- emit_arith( p, OPCODE_MAD, tmp0, WRITEMASK_XYZW, 0,
- two, src[0], neg1);
-
- if (memcmp(&src[0], &src[1], sizeof(struct ureg)) == 0)
- tmp1 = tmp0;
- else
- emit_arith( p, OPCODE_MAD, tmp1, WRITEMASK_XYZW, 0,
- two, src[1], neg1);
- emit_arith( p, OPCODE_DP3, dest, mask, saturate, tmp0, tmp1, undef);
- return dest;
- }
- case MODE_MODULATE_ADD_ATI:
- /* Arg0 * Arg2 + Arg1 */
- return emit_arith( p, OPCODE_MAD, dest, mask, saturate,
- src[0], src[2], src[1] );
- case MODE_MODULATE_SIGNED_ADD_ATI: {
- /* Arg0 * Arg2 + Arg1 - 0.5 */
- struct ureg tmp0 = get_temp(p);
- half = get_half(p);
- emit_arith( p, OPCODE_MAD, tmp0, mask, 0, src[0], src[2], src[1] );
- emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef );
- return dest;
- }
- case MODE_MODULATE_SUBTRACT_ATI:
- /* Arg0 * Arg2 - Arg1 */
- emit_arith( p, OPCODE_MAD, dest, mask, 0, src[0], src[2], negate(src[1]) );
- return dest;
- case MODE_ADD_PRODUCTS:
- /* Arg0 * Arg1 + Arg2 * Arg3 */
- {
- struct ureg tmp0 = get_temp(p);
- emit_arith( p, OPCODE_MUL, tmp0, mask, 0, src[0], src[1], undef );
- emit_arith( p, OPCODE_MAD, dest, mask, saturate, src[2], src[3], tmp0 );
- }
- return dest;
- case MODE_ADD_PRODUCTS_SIGNED:
- /* Arg0 * Arg1 + Arg2 * Arg3 - 0.5 */
- {
- struct ureg tmp0 = get_temp(p);
- half = get_half(p);
- emit_arith( p, OPCODE_MUL, tmp0, mask, 0, src[0], src[1], undef );
- emit_arith( p, OPCODE_MAD, tmp0, mask, 0, src[2], src[3], tmp0 );
- emit_arith( p, OPCODE_SUB, dest, mask, saturate, tmp0, half, undef );
- }
- return dest;
- case MODE_BUMP_ENVMAP_ATI:
- /* special - not handled here */
- assert(0);
- return src[0];
- default:
- assert(0);
- return src[0];
- }
-}
-
-
-/**
- * Generate instructions for one texture unit's env/combiner mode.
- */
-static struct ureg
-emit_texenv(struct texenv_fragment_program *p, GLuint unit)
-{
- const struct state_key *key = p->state;
- GLboolean rgb_saturate, alpha_saturate;
- GLuint rgb_shift, alpha_shift;
- struct ureg out, dest;
-
- if (!key->unit[unit].enabled) {
- return get_source(p, SRC_PREVIOUS, 0);
- }
- if (key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
- /* this isn't really a env stage delivering a color and handled elsewhere */
- return get_source(p, SRC_PREVIOUS, 0);
- }
-
- switch (key->unit[unit].ModeRGB) {
- case MODE_DOT3_RGB_EXT:
- alpha_shift = key->unit[unit].ScaleShiftA;
- rgb_shift = 0;
- break;
- case MODE_DOT3_RGBA_EXT:
- alpha_shift = 0;
- rgb_shift = 0;
- break;
- default:
- rgb_shift = key->unit[unit].ScaleShiftRGB;
- alpha_shift = key->unit[unit].ScaleShiftA;
- break;
- }
-
- /* If we'll do rgb/alpha shifting don't saturate in emit_combine().
- * We don't want to clamp twice.
- */
- if (rgb_shift)
- rgb_saturate = GL_FALSE; /* saturate after rgb shift */
- else if (need_saturate(key->unit[unit].ModeRGB))
- rgb_saturate = GL_TRUE;
- else
- rgb_saturate = GL_FALSE;
-
- if (alpha_shift)
- alpha_saturate = GL_FALSE; /* saturate after alpha shift */
- else if (need_saturate(key->unit[unit].ModeA))
- alpha_saturate = GL_TRUE;
- else
- alpha_saturate = GL_FALSE;
-
- /* If this is the very last calculation (and various other conditions
- * are met), emit directly to the color output register. Otherwise,
- * emit to a temporary register.
- */
- if (key->separate_specular ||
- unit != p->last_tex_stage ||
- alpha_shift ||
- key->num_draw_buffers != 1 ||
- rgb_shift)
- dest = get_temp( p );
- else
- dest = make_ureg(PROGRAM_OUTPUT, FRAG_RESULT_COLOR);
-
- /* Emit the RGB and A combine ops
- */
- if (key->unit[unit].ModeRGB == key->unit[unit].ModeA &&
- args_match(key, unit)) {
- out = emit_combine( p, dest, WRITEMASK_XYZW, rgb_saturate,
- unit,
- key->unit[unit].NumArgsRGB,
- key->unit[unit].ModeRGB,
- key->unit[unit].OptRGB);
- }
- else if (key->unit[unit].ModeRGB == MODE_DOT3_RGBA_EXT ||
- key->unit[unit].ModeRGB == MODE_DOT3_RGBA) {
- out = emit_combine( p, dest, WRITEMASK_XYZW, rgb_saturate,
- unit,
- key->unit[unit].NumArgsRGB,
- key->unit[unit].ModeRGB,
- key->unit[unit].OptRGB);
- }
- else {
- /* Need to do something to stop from re-emitting identical
- * argument calculations here:
- */
- out = emit_combine( p, dest, WRITEMASK_XYZ, rgb_saturate,
- unit,
- key->unit[unit].NumArgsRGB,
- key->unit[unit].ModeRGB,
- key->unit[unit].OptRGB);
- out = emit_combine( p, dest, WRITEMASK_W, alpha_saturate,
- unit,
- key->unit[unit].NumArgsA,
- key->unit[unit].ModeA,
- key->unit[unit].OptA);
- }
-
- /* Deal with the final shift:
- */
- if (alpha_shift || rgb_shift) {
- struct ureg shift;
- GLboolean saturate = GL_TRUE; /* always saturate at this point */
-
- if (rgb_shift == alpha_shift) {
- shift = register_scalar_const(p, (GLfloat)(1<<rgb_shift));
- }
- else {
- shift = register_const4f(p,
- (GLfloat)(1<<rgb_shift),
- (GLfloat)(1<<rgb_shift),
- (GLfloat)(1<<rgb_shift),
- (GLfloat)(1<<alpha_shift));
- }
- return emit_arith( p, OPCODE_MUL, dest, WRITEMASK_XYZW,
- saturate, out, shift, undef );
- }
- else
- return out;
-}
-
-
-/**
- * Generate instruction for getting a texture source term.
- */
-static void load_texture( struct texenv_fragment_program *p, GLuint unit )
-{
- if (is_undef(p->src_texture[unit])) {
- const GLuint texTarget = p->state->unit[unit].source_index;
- struct ureg texcoord;
- struct ureg tmp = get_tex_temp( p );
-
- if (is_undef(p->texcoord_tex[unit])) {
- texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit);
- }
- else {
- /* might want to reuse this reg for tex output actually */
- texcoord = p->texcoord_tex[unit];
- }
-
- /* TODO: Use D0_MASK_XY where possible.
- */
- if (p->state->unit[unit].enabled) {
- GLboolean shadow = GL_FALSE;
-
- if (p->state->unit[unit].shadow) {
- p->program->Base.ShadowSamplers |= 1 << unit;
- shadow = GL_TRUE;
- }
-
- p->src_texture[unit] = emit_texld( p, OPCODE_TXP,
- tmp, WRITEMASK_XYZW,
- unit, texTarget, shadow,
- texcoord );
-
- p->program->Base.SamplersUsed |= (1 << unit);
- /* This identity mapping should already be in place
- * (see _mesa_init_program_struct()) but let's be safe.
- */
- p->program->Base.SamplerUnits[unit] = unit;
- }
- else
- p->src_texture[unit] = get_zero(p);
-
- if (p->state->unit[unit].texture_cyl_wrap) {
- /* set flag which is checked by Mesa->Gallium program translation */
- p->program->Base.InputFlags[0] |= PROG_PARAM_BIT_CYL_WRAP;
- }
-
- }
-}
-
-static GLboolean load_texenv_source( struct texenv_fragment_program *p,
- GLuint src, GLuint unit )
-{
- switch (src) {
- case SRC_TEXTURE:
- load_texture(p, unit);
- break;
-
- case SRC_TEXTURE0:
- case SRC_TEXTURE1:
- case SRC_TEXTURE2:
- case SRC_TEXTURE3:
- case SRC_TEXTURE4:
- case SRC_TEXTURE5:
- case SRC_TEXTURE6:
- case SRC_TEXTURE7:
- load_texture(p, src - SRC_TEXTURE0);
- break;
-
- default:
- /* not a texture src - do nothing */
- break;
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Generate instructions for loading all texture source terms.
- */
-static GLboolean
-load_texunit_sources( struct texenv_fragment_program *p, GLuint unit )
-{
- const struct state_key *key = p->state;
- GLuint i;
-
- for (i = 0; i < key->unit[unit].NumArgsRGB; i++) {
- load_texenv_source( p, key->unit[unit].OptRGB[i].Source, unit );
- }
-
- for (i = 0; i < key->unit[unit].NumArgsA; i++) {
- load_texenv_source( p, key->unit[unit].OptA[i].Source, unit );
- }
-
- return GL_TRUE;
-}
-
-/**
- * Generate instructions for loading bump map textures.
- */
-static GLboolean
-load_texunit_bumpmap( struct texenv_fragment_program *p, GLuint unit )
-{
- const struct state_key *key = p->state;
- GLuint bumpedUnitNr = key->unit[unit].OptRGB[1].Source - SRC_TEXTURE0;
- struct ureg texcDst, bumpMapRes;
- struct ureg constdudvcolor = register_const4f(p, 0.0, 0.0, 0.0, 1.0);
- struct ureg texcSrc = register_input(p, FRAG_ATTRIB_TEX0 + bumpedUnitNr);
- struct ureg rotMat0 = register_param3( p, STATE_INTERNAL, STATE_ROT_MATRIX_0, unit );
- struct ureg rotMat1 = register_param3( p, STATE_INTERNAL, STATE_ROT_MATRIX_1, unit );
-
- load_texenv_source( p, unit + SRC_TEXTURE0, unit );
-
- bumpMapRes = get_source(p, key->unit[unit].OptRGB[0].Source, unit);
- texcDst = get_tex_temp( p );
- p->texcoord_tex[bumpedUnitNr] = texcDst;
-
- /* Apply rot matrix and add coords to be available in next phase.
- * dest = (Arg0.xxxx * rotMat0 + Arg1) + (Arg0.yyyy * rotMat1)
- * note only 2 coords are affected the rest are left unchanged (mul by 0)
- */
- emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0,
- swizzle1(bumpMapRes, SWIZZLE_X), rotMat0, texcSrc );
- emit_arith( p, OPCODE_MAD, texcDst, WRITEMASK_XYZW, 0,
- swizzle1(bumpMapRes, SWIZZLE_Y), rotMat1, texcDst );
-
- /* Move 0,0,0,1 into bumpmap src if someone (crossbar) is foolish
- * enough to access this later, should optimize away.
- */
- emit_arith( p, OPCODE_MOV, bumpMapRes, WRITEMASK_XYZW, 0,
- constdudvcolor, undef, undef );
-
- return GL_TRUE;
-}
-
-/**
- * Generate a new fragment program which implements the context's
- * current texture env/combine mode.
- */
-static void
-create_new_program(struct gl_context *ctx, struct state_key *key,
- struct gl_fragment_program *program)
-{
- struct prog_instruction instBuffer[MAX_INSTRUCTIONS];
- struct texenv_fragment_program p;
- GLuint unit;
- struct ureg cf, out;
- int i;
-
- memset(&p, 0, sizeof(p));
- p.state = key;
- p.program = program;
-
- /* During code generation, use locally-allocated instruction buffer,
- * then alloc dynamic storage below.
- */
- p.program->Base.Instructions = instBuffer;
- p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB;
- p.program->Base.String = NULL;
- p.program->Base.NumTexIndirections = 1; /* is this right? */
- p.program->Base.NumTexInstructions = 0;
- p.program->Base.NumAluInstructions = 0;
- p.program->Base.NumInstructions = 0;
- p.program->Base.NumTemporaries = 0;
- p.program->Base.NumParameters = 0;
- p.program->Base.NumAttributes = 0;
- p.program->Base.NumAddressRegs = 0;
- p.program->Base.Parameters = _mesa_new_parameter_list();
- p.program->Base.InputsRead = 0x0;
-
- if (key->num_draw_buffers == 1)
- p.program->Base.OutputsWritten = 1 << FRAG_RESULT_COLOR;
- else {
- for (i = 0; i < key->num_draw_buffers; i++)
- p.program->Base.OutputsWritten |= (1 << (FRAG_RESULT_DATA0 + i));
- }
-
- for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
- p.src_texture[unit] = undef;
- p.texcoord_tex[unit] = undef;
- }
-
- p.src_previous = undef;
- p.half = undef;
- p.zero = undef;
- p.one = undef;
-
- p.last_tex_stage = 0;
- release_temps(ctx, &p);
-
- if (key->enabled_units && key->num_draw_buffers) {
- GLboolean needbumpstage = GL_FALSE;
-
- /* Zeroth pass - bump map textures first */
- for (unit = 0; unit < key->nr_enabled_units; unit++)
- if (key->unit[unit].enabled &&
- key->unit[unit].ModeRGB == MODE_BUMP_ENVMAP_ATI) {
- needbumpstage = GL_TRUE;
- load_texunit_bumpmap( &p, unit );
- }
- if (needbumpstage)
- p.program->Base.NumTexIndirections++;
-
- /* First pass - to support texture_env_crossbar, first identify
- * all referenced texture sources and emit texld instructions
- * for each:
- */
- for (unit = 0; unit < key->nr_enabled_units; unit++)
- if (key->unit[unit].enabled) {
- load_texunit_sources( &p, unit );
- p.last_tex_stage = unit;
- }
-
- /* Second pass - emit combine instructions to build final color:
- */
- for (unit = 0; unit < key->nr_enabled_units; unit++)
- if (key->unit[unit].enabled) {
- p.src_previous = emit_texenv( &p, unit );
- reserve_temp(&p, p.src_previous); /* don't re-use this temp reg */
- release_temps(ctx, &p); /* release all temps */
- }
- }
-
- cf = get_source( &p, SRC_PREVIOUS, 0 );
-
- for (i = 0; i < key->num_draw_buffers; i++) {
- if (key->num_draw_buffers == 1)
- out = make_ureg( PROGRAM_OUTPUT, FRAG_RESULT_COLOR );
- else {
- out = make_ureg( PROGRAM_OUTPUT, FRAG_RESULT_DATA0 + i );
- }
-
- if (key->separate_specular) {
- /* Emit specular add.
- */
- struct ureg s = register_input(&p, FRAG_ATTRIB_COL1);
- emit_arith( &p, OPCODE_ADD, out, WRITEMASK_XYZ, 0, cf, s, undef );
- emit_arith( &p, OPCODE_MOV, out, WRITEMASK_W, 0, cf, undef, undef );
- }
- else if (memcmp(&cf, &out, sizeof(cf)) != 0) {
- /* Will wind up in here if no texture enabled or a couple of
- * other scenarios (GL_REPLACE for instance).
- */
- emit_arith( &p, OPCODE_MOV, out, WRITEMASK_XYZW, 0, cf, undef, undef );
- }
- }
- /* Finish up:
- */
- emit_arith( &p, OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef);
-
- if (key->fog_enabled) {
- /* Pull fog mode from struct gl_context, the value in the state key is
- * a reduced value and not what is expected in FogOption
- */
- p.program->FogOption = ctx->Fog.Mode;
- p.program->Base.InputsRead |= FRAG_BIT_FOGC;
- }
- else {
- p.program->FogOption = GL_NONE;
- }
-
- if (p.program->Base.NumTexIndirections > ctx->Const.FragmentProgram.MaxTexIndirections)
- program_error(&p, "Exceeded max nr indirect texture lookups");
-
- if (p.program->Base.NumTexInstructions > ctx->Const.FragmentProgram.MaxTexInstructions)
- program_error(&p, "Exceeded max TEX instructions");
-
- if (p.program->Base.NumAluInstructions > ctx->Const.FragmentProgram.MaxAluInstructions)
- program_error(&p, "Exceeded max ALU instructions");
-
- ASSERT(p.program->Base.NumInstructions <= MAX_INSTRUCTIONS);
-
- /* Allocate final instruction array */
- p.program->Base.Instructions
- = _mesa_alloc_instructions(p.program->Base.NumInstructions);
- if (!p.program->Base.Instructions) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY,
- "generating tex env program");
- return;
- }
- _mesa_copy_instructions(p.program->Base.Instructions, instBuffer,
- p.program->Base.NumInstructions);
-
- if (key->num_draw_buffers && p.program->FogOption) {
- _mesa_append_fog_code(ctx, p.program);
- p.program->FogOption = GL_NONE;
- }
-
-
- /* Notify driver the fragment program has (actually) changed.
- */
- if (ctx->Driver.ProgramStringNotify) {
- GLboolean ok = ctx->Driver.ProgramStringNotify(ctx,
- GL_FRAGMENT_PROGRAM_ARB,
- &p.program->Base);
- /* Driver should be able to handle any texenv programs as long as
- * the driver correctly reported max number of texture units correctly,
- * etc.
- */
- ASSERT(ok);
- (void) ok; /* silence unused var warning */
- }
-
- if (DISASSEM) {
- _mesa_print_program(&p.program->Base);
- printf("\n");
- }
-}
-
-
-/**
- * Return a fragment program which implements the current
- * fixed-function texture, fog and color-sum operations.
- */
-struct gl_fragment_program *
-_mesa_get_fixed_func_fragment_program(struct gl_context *ctx)
-{
- struct gl_fragment_program *prog;
- struct state_key key;
- GLuint keySize;
-
- keySize = make_state_key(ctx, &key);
-
- prog = (struct gl_fragment_program *)
- _mesa_search_program_cache(ctx->FragmentProgram.Cache,
- &key, keySize);
-
- if (!prog) {
- prog = (struct gl_fragment_program *)
- ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
-
- create_new_program(ctx, &key, prog);
-
- _mesa_program_cache_insert(ctx, ctx->FragmentProgram.Cache,
- &key, keySize, &prog->Base);
- }
-
- return prog;
-}
diff --git a/mesalib/src/mesa/main/texenvprogram.h b/mesalib/src/mesa/main/texenvprogram.h
index 0895ebacb..dba775feb 100644
--- a/mesalib/src/mesa/main/texenvprogram.h
+++ b/mesalib/src/mesa/main/texenvprogram.h
@@ -29,7 +29,7 @@
struct gl_context;
-extern struct gl_fragment_program *
+extern struct gl_shader_program *
_mesa_get_fixed_func_fragment_program(struct gl_context *ctx);
#endif
diff --git a/mesalib/src/mesa/main/uniforms.c b/mesalib/src/mesa/main/uniforms.c
index eb289722d..523b8e1a9 100644
--- a/mesalib/src/mesa/main/uniforms.c
+++ b/mesalib/src/mesa/main/uniforms.c
@@ -1,1691 +1,1707 @@
-/*
- * Mesa 3-D graphics library
- *
- * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved.
- * Copyright © 2010 Intel Corporation
- *
- * 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 uniforms.c
- * Functions related to GLSL uniform variables.
- * \author Brian Paul
- */
-
-/**
- * XXX things to do:
- * 1. Check that the right error code is generated for all _mesa_error() calls.
- * 2. Insert FLUSH_VERTICES calls in various places
- */
-
-
-#include "main/glheader.h"
-#include "main/context.h"
-#include "main/dispatch.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "main/shaderapi.h"
-#include "main/shaderobj.h"
-#include "main/uniforms.h"
-#include "program/prog_parameter.h"
-#include "program/prog_statevars.h"
-#include "program/prog_uniform.h"
-#include "program/prog_instruction.h"
-
-
-static GLenum
-base_uniform_type(GLenum type)
-{
- switch (type) {
-#if 0 /* not needed, for now */
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
- return GL_BOOL;
-#endif
- case GL_FLOAT:
- case GL_FLOAT_VEC2:
- case GL_FLOAT_VEC3:
- case GL_FLOAT_VEC4:
- return GL_FLOAT;
- case GL_UNSIGNED_INT:
- case GL_UNSIGNED_INT_VEC2:
- case GL_UNSIGNED_INT_VEC3:
- case GL_UNSIGNED_INT_VEC4:
- return GL_UNSIGNED_INT;
- case GL_INT:
- case GL_INT_VEC2:
- case GL_INT_VEC3:
- case GL_INT_VEC4:
- return GL_INT;
- default:
- _mesa_problem(NULL, "Invalid type in base_uniform_type()");
- return GL_FLOAT;
- }
-}
-
-static struct gl_builtin_uniform_element gl_DepthRange_elements[] = {
- {"near", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_XXXX},
- {"far", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_YYYY},
- {"diff", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_ZZZZ},
-};
-
-static struct gl_builtin_uniform_element gl_ClipPlane_elements[] = {
- {NULL, {STATE_CLIPPLANE, 0, 0}, SWIZZLE_XYZW}
-};
-
-static struct gl_builtin_uniform_element gl_Point_elements[] = {
- {"size", {STATE_POINT_SIZE}, SWIZZLE_XXXX},
- {"sizeMin", {STATE_POINT_SIZE}, SWIZZLE_YYYY},
- {"sizeMax", {STATE_POINT_SIZE}, SWIZZLE_ZZZZ},
- {"fadeThresholdSize", {STATE_POINT_SIZE}, SWIZZLE_WWWW},
- {"distanceConstantAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_XXXX},
- {"distanceLinearAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_YYYY},
- {"distanceQuadraticAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_ZZZZ},
-};
-
-static struct gl_builtin_uniform_element gl_FrontMaterial_elements[] = {
- {"emission", {STATE_MATERIAL, 0, STATE_EMISSION}, SWIZZLE_XYZW},
- {"ambient", {STATE_MATERIAL, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_MATERIAL, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_MATERIAL, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
- {"shininess", {STATE_MATERIAL, 0, STATE_SHININESS}, SWIZZLE_XXXX},
-};
-
-static struct gl_builtin_uniform_element gl_BackMaterial_elements[] = {
- {"emission", {STATE_MATERIAL, 1, STATE_EMISSION}, SWIZZLE_XYZW},
- {"ambient", {STATE_MATERIAL, 1, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_MATERIAL, 1, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_MATERIAL, 1, STATE_SPECULAR}, SWIZZLE_XYZW},
- {"shininess", {STATE_MATERIAL, 1, STATE_SHININESS}, SWIZZLE_XXXX},
-};
-
-static struct gl_builtin_uniform_element gl_LightSource_elements[] = {
- {"ambient", {STATE_LIGHT, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_LIGHT, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_LIGHT, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
- {"position", {STATE_LIGHT, 0, STATE_POSITION}, SWIZZLE_XYZW},
- {"halfVector", {STATE_LIGHT, 0, STATE_HALF_VECTOR}, SWIZZLE_XYZW},
- {"spotDirection", {STATE_LIGHT, 0, STATE_SPOT_DIRECTION},
- MAKE_SWIZZLE4(SWIZZLE_X,
- SWIZZLE_Y,
- SWIZZLE_Z,
- SWIZZLE_Z)},
- {"spotCosCutoff", {STATE_LIGHT, 0, STATE_SPOT_DIRECTION}, SWIZZLE_WWWW},
- {"spotCutoff", {STATE_LIGHT, 0, STATE_SPOT_CUTOFF}, SWIZZLE_XXXX},
- {"spotExponent", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_WWWW},
- {"constantAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_XXXX},
- {"linearAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_YYYY},
- {"quadraticAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_ZZZZ},
-};
-
-static struct gl_builtin_uniform_element gl_LightModel_elements[] = {
- {"ambient", {STATE_LIGHTMODEL_AMBIENT, 0}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_FrontLightModelProduct_elements[] = {
- {"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 0}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_BackLightModelProduct_elements[] = {
- {"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 1}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_FrontLightProduct_elements[] = {
- {"ambient", {STATE_LIGHTPROD, 0, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_LIGHTPROD, 0, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_LIGHTPROD, 0, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_BackLightProduct_elements[] = {
- {"ambient", {STATE_LIGHTPROD, 0, 1, STATE_AMBIENT}, SWIZZLE_XYZW},
- {"diffuse", {STATE_LIGHTPROD, 0, 1, STATE_DIFFUSE}, SWIZZLE_XYZW},
- {"specular", {STATE_LIGHTPROD, 0, 1, STATE_SPECULAR}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_TextureEnvColor_elements[] = {
- {NULL, {STATE_TEXENV_COLOR, 0}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_EyePlaneS_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_S}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_EyePlaneT_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_T}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_EyePlaneR_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_R}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_EyePlaneQ_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_Q}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_ObjectPlaneS_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_S}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_ObjectPlaneT_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_T}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_ObjectPlaneR_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_R}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_ObjectPlaneQ_elements[] = {
- {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_Q}, SWIZZLE_XYZW},
-};
-
-static struct gl_builtin_uniform_element gl_Fog_elements[] = {
- {"color", {STATE_FOG_COLOR}, SWIZZLE_XYZW},
- {"density", {STATE_FOG_PARAMS}, SWIZZLE_XXXX},
- {"start", {STATE_FOG_PARAMS}, SWIZZLE_YYYY},
- {"end", {STATE_FOG_PARAMS}, SWIZZLE_ZZZZ},
- {"scale", {STATE_FOG_PARAMS}, SWIZZLE_WWWW},
-};
-
-static struct gl_builtin_uniform_element gl_NormalScale_elements[] = {
- {NULL, {STATE_NORMAL_SCALE}, SWIZZLE_XXXX},
-};
-
-#define MATRIX(name, statevar, modifier) \
- static struct gl_builtin_uniform_element name ## _elements[] = { \
- { NULL, { statevar, 0, 0, 0, modifier}, SWIZZLE_XYZW }, \
- { NULL, { statevar, 0, 1, 1, modifier}, SWIZZLE_XYZW }, \
- { NULL, { statevar, 0, 2, 2, modifier}, SWIZZLE_XYZW }, \
- { NULL, { statevar, 0, 3, 3, modifier}, SWIZZLE_XYZW }, \
- }
-
-MATRIX(gl_ModelViewMatrix,
- STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE);
-MATRIX(gl_ModelViewMatrixInverse,
- STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS);
-MATRIX(gl_ModelViewMatrixTranspose,
- STATE_MODELVIEW_MATRIX, 0);
-MATRIX(gl_ModelViewMatrixInverseTranspose,
- STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE);
-
-MATRIX(gl_ProjectionMatrix,
- STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE);
-MATRIX(gl_ProjectionMatrixInverse,
- STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS);
-MATRIX(gl_ProjectionMatrixTranspose,
- STATE_PROJECTION_MATRIX, 0);
-MATRIX(gl_ProjectionMatrixInverseTranspose,
- STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE);
-
-MATRIX(gl_ModelViewProjectionMatrix,
- STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE);
-MATRIX(gl_ModelViewProjectionMatrixInverse,
- STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS);
-MATRIX(gl_ModelViewProjectionMatrixTranspose,
- STATE_MVP_MATRIX, 0);
-MATRIX(gl_ModelViewProjectionMatrixInverseTranspose,
- STATE_MVP_MATRIX, STATE_MATRIX_INVERSE);
-
-MATRIX(gl_TextureMatrix,
- STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE);
-MATRIX(gl_TextureMatrixInverse,
- STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS);
-MATRIX(gl_TextureMatrixTranspose,
- STATE_TEXTURE_MATRIX, 0);
-MATRIX(gl_TextureMatrixInverseTranspose,
- STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE);
-
-static struct gl_builtin_uniform_element gl_NormalMatrix_elements[] = {
- { NULL, { STATE_MODELVIEW_MATRIX, 0, 0, 0, STATE_MATRIX_INVERSE},
- SWIZZLE_XYZW },
- { NULL, { STATE_MODELVIEW_MATRIX, 0, 1, 1, STATE_MATRIX_INVERSE},
- SWIZZLE_XYZW },
- { NULL, { STATE_MODELVIEW_MATRIX, 0, 2, 2, STATE_MATRIX_INVERSE},
- SWIZZLE_XYZW },
-};
-
-#undef MATRIX
-
-#define STATEVAR(name) {#name, name ## _elements, Elements(name ## _elements)}
-
-const struct gl_builtin_uniform_desc _mesa_builtin_uniform_desc[] = {
- STATEVAR(gl_DepthRange),
- STATEVAR(gl_ClipPlane),
- STATEVAR(gl_Point),
- STATEVAR(gl_FrontMaterial),
- STATEVAR(gl_BackMaterial),
- STATEVAR(gl_LightSource),
- STATEVAR(gl_LightModel),
- STATEVAR(gl_FrontLightModelProduct),
- STATEVAR(gl_BackLightModelProduct),
- STATEVAR(gl_FrontLightProduct),
- STATEVAR(gl_BackLightProduct),
- STATEVAR(gl_TextureEnvColor),
- STATEVAR(gl_EyePlaneS),
- STATEVAR(gl_EyePlaneT),
- STATEVAR(gl_EyePlaneR),
- STATEVAR(gl_EyePlaneQ),
- STATEVAR(gl_ObjectPlaneS),
- STATEVAR(gl_ObjectPlaneT),
- STATEVAR(gl_ObjectPlaneR),
- STATEVAR(gl_ObjectPlaneQ),
- STATEVAR(gl_Fog),
-
- STATEVAR(gl_ModelViewMatrix),
- STATEVAR(gl_ModelViewMatrixInverse),
- STATEVAR(gl_ModelViewMatrixTranspose),
- STATEVAR(gl_ModelViewMatrixInverseTranspose),
-
- STATEVAR(gl_ProjectionMatrix),
- STATEVAR(gl_ProjectionMatrixInverse),
- STATEVAR(gl_ProjectionMatrixTranspose),
- STATEVAR(gl_ProjectionMatrixInverseTranspose),
-
- STATEVAR(gl_ModelViewProjectionMatrix),
- STATEVAR(gl_ModelViewProjectionMatrixInverse),
- STATEVAR(gl_ModelViewProjectionMatrixTranspose),
- STATEVAR(gl_ModelViewProjectionMatrixInverseTranspose),
-
- STATEVAR(gl_TextureMatrix),
- STATEVAR(gl_TextureMatrixInverse),
- STATEVAR(gl_TextureMatrixTranspose),
- STATEVAR(gl_TextureMatrixInverseTranspose),
-
- STATEVAR(gl_NormalMatrix),
- STATEVAR(gl_NormalScale),
-
- {NULL, NULL, 0}
-};
-
-static GLboolean
-is_boolean_type(GLenum type)
-{
- switch (type) {
- case GL_BOOL:
- case GL_BOOL_VEC2:
- case GL_BOOL_VEC3:
- case GL_BOOL_VEC4:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-static GLboolean
-is_sampler_type(GLenum type)
-{
- switch (type) {
- case GL_SAMPLER_1D:
- case GL_SAMPLER_2D:
- case GL_SAMPLER_3D:
- case GL_SAMPLER_CUBE:
- case GL_SAMPLER_1D_SHADOW:
- case GL_SAMPLER_2D_SHADOW:
- case GL_SAMPLER_2D_RECT_ARB:
- case GL_SAMPLER_2D_RECT_SHADOW_ARB:
- case GL_SAMPLER_1D_ARRAY_EXT:
- case GL_SAMPLER_2D_ARRAY_EXT:
- case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
- case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
- return GL_TRUE;
- default:
- return GL_FALSE;
- }
-}
-
-
-static struct gl_program_parameter *
-get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
-{
- const struct gl_program *prog = NULL;
- GLint progPos;
-
- 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;
- } else {
- progPos = shProg->Uniforms->Uniforms[index].GeomPos;
- if (progPos >= 0) {
- prog = &shProg->GeometryProgram->Base;
- }
- }
- }
-
- if (!prog || progPos < 0)
- return NULL; /* should never happen */
-
- return &prog->Parameters->Parameters[progPos];
-}
-
-
-/**
- * Called by glGetActiveUniform().
- */
-static void
-_mesa_get_active_uniform(struct gl_context *ctx, GLuint program, GLuint index,
- GLsizei maxLength, GLsizei *length, GLint *size,
- GLenum *type, GLchar *nameOut)
-{
- const struct gl_shader_program *shProg;
- const struct gl_program *prog = NULL;
- const struct gl_program_parameter *param;
- GLint progPos;
-
- shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
- if (!shProg)
- return;
-
- if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
- return;
- }
-
- 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;
- } else {
- progPos = shProg->Uniforms->Uniforms[index].GeomPos;
- if (progPos >= 0) {
- prog = &shProg->GeometryProgram->Base;
- }
- }
- }
-
- if (!prog || progPos < 0)
- return; /* should never happen */
-
- ASSERT(progPos < prog->Parameters->NumParameters);
- param = &prog->Parameters->Parameters[progPos];
-
- if (nameOut) {
- _mesa_copy_string(nameOut, maxLength, length, param->Name);
- }
-
- if (size) {
- GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
- if ((GLint) param->Size > typeSize) {
- /* This is an array.
- * Array elements are placed on vector[4] boundaries so they're
- * a multiple of four floats. We round typeSize up to next multiple
- * of four to get the right size below.
- */
- typeSize = (typeSize + 3) & ~3;
- }
- /* Note that the returned size is in units of the <type>, not bytes */
- *size = param->Size / typeSize;
- }
-
- if (type) {
- *type = param->DataType;
- }
-}
-
-
-static unsigned
-get_vector_elements(GLenum type)
-{
- switch (type) {
- case GL_FLOAT:
- case GL_INT:
- case GL_BOOL:
- case GL_UNSIGNED_INT:
- default: /* Catch all the various sampler types. */
- return 1;
-
- case GL_FLOAT_VEC2:
- case GL_INT_VEC2:
- case GL_BOOL_VEC2:
- case GL_UNSIGNED_INT_VEC2:
- return 2;
-
- case GL_FLOAT_VEC3:
- case GL_INT_VEC3:
- case GL_BOOL_VEC3:
- case GL_UNSIGNED_INT_VEC3:
- return 3;
-
- case GL_FLOAT_VEC4:
- case GL_INT_VEC4:
- case GL_BOOL_VEC4:
- case GL_UNSIGNED_INT_VEC4:
- return 4;
- }
-}
-
-static void
-get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
-{
- switch (type) {
- case GL_FLOAT_MAT2:
- *rows = *cols = 2;
- break;
- case GL_FLOAT_MAT2x3:
- *rows = 3;
- *cols = 2;
- break;
- case GL_FLOAT_MAT2x4:
- *rows = 4;
- *cols = 2;
- break;
- case GL_FLOAT_MAT3:
- *rows = 3;
- *cols = 3;
- break;
- case GL_FLOAT_MAT3x2:
- *rows = 2;
- *cols = 3;
- break;
- case GL_FLOAT_MAT3x4:
- *rows = 4;
- *cols = 3;
- break;
- case GL_FLOAT_MAT4:
- *rows = 4;
- *cols = 4;
- break;
- case GL_FLOAT_MAT4x2:
- *rows = 2;
- *cols = 4;
- break;
- case GL_FLOAT_MAT4x3:
- *rows = 3;
- *cols = 4;
- break;
- default:
- *rows = *cols = 0;
- }
-}
-
-
-/**
- * Determine the number of rows and columns occupied by a uniform
- * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
- * the number of rows = 1 and cols = number of elements in the vector.
- */
-static void
-get_uniform_rows_cols(const struct gl_program_parameter *p,
- GLint *rows, GLint *cols)
-{
- get_matrix_dims(p->DataType, rows, cols);
- if (*rows == 0 && *cols == 0) {
- /* not a matrix type, probably a float or vector */
- *rows = 1;
- *cols = get_vector_elements(p->DataType);
- }
-}
-
-
-/**
- * Helper for get_uniform[fi]v() functions.
- * Given a shader program name and uniform location, return a pointer
- * to the shader program and return the program parameter position.
- */
-static void
-lookup_uniform_parameter(struct gl_context *ctx, GLuint program, GLint location,
- struct gl_program **progOut, GLint *paramPosOut)
-{
- struct gl_shader_program *shProg
- = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
- struct gl_program *prog = NULL;
- GLint progPos = -1;
-
- /* if shProg is NULL, we'll have already recorded an error */
-
- if (shProg) {
- if (!shProg->Uniforms ||
- location < 0 ||
- location >= (GLint) shProg->Uniforms->NumUniforms) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
- }
- else {
- /* OK, find the gl_program and program parameter location */
- 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;
- } else {
- progPos = shProg->Uniforms->Uniforms[location].GeomPos;
- if (progPos >= 0) {
- prog = &shProg->GeometryProgram->Base;
- }
- }
- }
- }
- }
-
- *progOut = prog;
- *paramPosOut = progPos;
-}
-
-
-/**
- * GLGL uniform arrays and structs require special handling.
- *
- * The GL_ARB_shader_objects spec says that if you use
- * glGetUniformLocation to get the location of an array, you CANNOT
- * access other elements of the array by adding an offset to the
- * returned location. For example, you must call
- * glGetUniformLocation("foo[16]") if you want to set the 16th element
- * of the array with glUniform().
- *
- * HOWEVER, some other OpenGL drivers allow accessing array elements
- * by adding an offset to the returned array location. And some apps
- * seem to depend on that behaviour.
- *
- * Mesa's gl_uniform_list doesn't directly support this since each
- * entry in the list describes one uniform variable, not one uniform
- * element. We could insert dummy entries in the list for each array
- * element after [0] but that causes complications elsewhere.
- *
- * We solve this problem by encoding two values in the location that's
- * returned by glGetUniformLocation():
- * a) index into gl_uniform_list::Uniforms[] for the uniform
- * b) an array/field offset (0 for simple types)
- *
- * These two values are encoded in the high and low halves of a GLint.
- * By putting the uniform number in the high part and the offset in the
- * low part, we can support the unofficial ability to index into arrays
- * by adding offsets to the location value.
- */
-static void
-merge_location_offset(GLint *location, GLint offset)
-{
- *location = (*location << 16) | offset;
-}
-
-
-/**
- * Separate the uniform location and parameter offset. See above.
- */
-static void
-split_location_offset(GLint *location, GLint *offset)
-{
- *offset = *location & 0xffff;
- *location = *location >> 16;
-}
-
-
-
-/**
- * Called via glGetUniformfv().
- */
-static void
-_mesa_get_uniformfv(struct gl_context *ctx, GLuint program, GLint location,
- GLfloat *params)
-{
- struct gl_program *prog;
- GLint paramPos;
- GLint offset;
-
- split_location_offset(&location, &offset);
-
- lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
-
- if (prog) {
- const struct gl_program_parameter *p =
- &prog->Parameters->Parameters[paramPos];
- GLint rows, cols, i, j, k;
-
- get_uniform_rows_cols(p, &rows, &cols);
-
- k = 0;
- for (i = 0; i < rows; i++) {
- const int base = paramPos + offset + i;
-
- for (j = 0; j < cols; j++ ) {
- params[k++] = prog->Parameters->ParameterValues[base][j];
- }
- }
- }
-}
-
-
-/**
- * Called via glGetUniformiv().
- * \sa _mesa_get_uniformfv, only difference is a cast.
- */
-static void
-_mesa_get_uniformiv(struct gl_context *ctx, GLuint program, GLint location,
- GLint *params)
-{
- struct gl_program *prog;
- GLint paramPos;
- GLint offset;
-
- split_location_offset(&location, &offset);
-
- lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
-
- if (prog) {
- const struct gl_program_parameter *p =
- &prog->Parameters->Parameters[paramPos];
- GLint rows, cols, i, j, k;
-
- get_uniform_rows_cols(p, &rows, &cols);
-
- k = 0;
- for (i = 0; i < rows; i++) {
- const int base = paramPos + offset + i;
-
- for (j = 0; j < cols; j++ ) {
- params[k++] = (GLint) prog->Parameters->ParameterValues[base][j];
- }
- }
- }
-}
-
-
-/**
- * Called via glGetUniformuiv().
- * New in GL_EXT_gpu_shader4, OpenGL 3.0
- * \sa _mesa_get_uniformfv, only difference is a cast.
- */
-static void
-_mesa_get_uniformuiv(struct gl_context *ctx, GLuint program, GLint location,
- GLuint *params)
-{
- struct gl_program *prog;
- GLint paramPos;
- GLint offset;
-
- split_location_offset(&location, &offset);
-
- lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
-
- if (prog) {
- const struct gl_program_parameter *p =
- &prog->Parameters->Parameters[paramPos];
- GLint rows, cols, i, j, k;
-
- get_uniform_rows_cols(p, &rows, &cols);
-
- k = 0;
- for (i = 0; i < rows; i++) {
- const int base = paramPos + offset + i;
-
- for (j = 0; j < cols; j++ ) {
- params[k++] = (GLuint) prog->Parameters->ParameterValues[base][j];
- }
- }
- }
-}
-
-
-/**
- * Called via glGetUniformLocation().
- *
- * The return value will encode two values, the uniform location and an
- * offset (used for arrays, structs).
- */
-GLint
-_mesa_get_uniform_location(struct gl_context *ctx, struct gl_shader_program *shProg,
- const GLchar *name)
-{
- GLint offset = 0, location = -1;
-
- if (shProg->LinkStatus == GL_FALSE) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
- return -1;
- }
-
- /* XXX we should return -1 if the uniform was declared, but not
- * actually used.
- */
-
- /* XXX we need to be able to parse uniform names for structs and arrays
- * such as:
- * mymatrix[1]
- * mystruct.field1
- */
-
- {
- /* handle 1-dimension arrays here... */
- char *c = strchr(name, '[');
- if (c) {
- /* truncate name at [ */
- const GLint len = c - name;
- GLchar *newName = malloc(len + 1);
- if (!newName)
- return -1; /* out of mem */
- memcpy(newName, name, len);
- newName[len] = 0;
-
- location = _mesa_lookup_uniform(shProg->Uniforms, newName);
- if (location >= 0) {
- const GLint element = atoi(c + 1);
- if (element > 0) {
- /* get type of the uniform array element */
- struct gl_program_parameter *p;
- p = get_uniform_parameter(shProg, location);
- if (p) {
- GLint rows, cols;
- get_matrix_dims(p->DataType, &rows, &cols);
- if (rows < 1)
- rows = 1;
- offset = element * rows;
- }
- }
- }
-
- free(newName);
- }
- }
-
- if (location < 0) {
- location = _mesa_lookup_uniform(shProg->Uniforms, name);
- }
-
- if (location >= 0) {
- merge_location_offset(&location, offset);
- }
-
- return location;
-}
-
-
-
-/**
- * Update the vertex/fragment program's TexturesUsed array.
- *
- * This needs to be called after glUniform(set sampler var) is called.
- * A call to glUniform(samplerVar, value) causes a sampler to point to a
- * particular texture unit. We know the sampler's texture target
- * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
- * set by glUniform() calls.
- *
- * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
- * information to update the prog->TexturesUsed[] values.
- * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
- * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
- * We'll use that info for state validation before rendering.
- */
-void
-_mesa_update_shader_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 unit = prog->SamplerUnits[s];
- GLuint tgt = prog->SamplerTargets[s];
- assert(unit < MAX_TEXTURE_IMAGE_UNITS);
- assert(tgt < NUM_TEXTURE_TARGETS);
- prog->TexturesUsed[unit] |= (1 << tgt);
- }
- }
-}
-
-
-/**
- * Check if the type given by userType is allowed to set a uniform of the
- * target type. Generally, equivalence is required, but setting Boolean
- * uniforms can be done with glUniformiv or glUniformfv.
- */
-static GLboolean
-compatible_types(GLenum userType, GLenum targetType)
-{
- if (userType == targetType)
- return GL_TRUE;
-
- if (targetType == GL_BOOL && (userType == GL_FLOAT ||
- userType == GL_UNSIGNED_INT ||
- userType == GL_INT))
- return GL_TRUE;
-
- if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
- userType == GL_UNSIGNED_INT_VEC2 ||
- userType == GL_INT_VEC2))
- return GL_TRUE;
-
- if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
- userType == GL_UNSIGNED_INT_VEC3 ||
- userType == GL_INT_VEC3))
- return GL_TRUE;
-
- if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
- userType == GL_UNSIGNED_INT_VEC4 ||
- userType == GL_INT_VEC4))
- return GL_TRUE;
-
- if (is_sampler_type(targetType) && userType == GL_INT)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Set the value of a program's uniform variable.
- * \param program the program whose uniform to update
- * \param index the index of the program parameter for the uniform
- * \param offset additional parameter slot offset (for arrays)
- * \param type the incoming datatype of 'values'
- * \param count the number of uniforms to set
- * \param elems number of elements per uniform (1, 2, 3 or 4)
- * \param values the new values, of datatype 'type'
- */
-static void
-set_program_uniform(struct gl_context *ctx, struct gl_program *program,
- GLint index, GLint offset,
- GLenum type, GLsizei count, GLint elems,
- const void *values)
-{
- const struct gl_program_parameter *param =
- &program->Parameters->Parameters[index];
-
- assert(offset >= 0);
- assert(elems >= 1);
- assert(elems <= 4);
-
- if (!compatible_types(type, param->DataType)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
- return;
- }
-
- if (index + offset > (GLint) program->Parameters->Size) {
- /* out of bounds! */
- return;
- }
-
- if (param->Type == PROGRAM_SAMPLER) {
- /* This controls which texture unit which is used by a sampler */
- GLboolean changed = GL_FALSE;
- GLint i;
-
- /* this should have been caught by the compatible_types() check */
- ASSERT(type == GL_INT);
-
- /* loop over number of samplers to change */
- for (i = 0; i < count; i++) {
- GLuint sampler =
- (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
- GLuint texUnit = ((GLuint *) values)[i];
-
- /* 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 for '%s')",
- param->Name);
- return;
- }
-
- /* This maps a sampler to a texture unit: */
- if (sampler < MAX_SAMPLERS) {
-#if 0
- printf("Set program %p sampler %d '%s' to unit %u\n",
- program, sampler, param->Name, texUnit);
-#endif
- if (program->SamplerUnits[sampler] != texUnit) {
- program->SamplerUnits[sampler] = texUnit;
- changed = GL_TRUE;
- }
- }
- }
-
- if (changed) {
- /* When a sampler's value changes it usually requires rewriting
- * a GPU program's TEX instructions since there may not be a
- * sampler->texture lookup table. We signal this with the
- * ProgramStringNotify() callback.
- */
- FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
- _mesa_update_shader_textures_used(program);
- /* Do we need to care about the return value here?
- * This should not be the first time the driver was notified of
- * this program.
- */
- (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
- }
- }
- else {
- /* ordinary uniform variable */
- const GLboolean isUniformBool = is_boolean_type(param->DataType);
- const GLenum basicType = base_uniform_type(type);
- const GLint slots = (param->Size + 3) / 4;
- const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
- GLsizei k, i;
-
- if ((GLint) param->Size > typeSize) {
- /* an array */
- /* we'll ignore extra data below */
- }
- else {
- /* non-array: count must be at most one; count == 0 is handled by the loop below */
- if (count > 1) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniform(uniform '%s' is not an array)",
- param->Name);
- return;
- }
- }
-
- /* loop over number of array elements */
- for (k = 0; k < count; k++) {
- GLfloat *uniformVal;
-
- if (offset + k >= slots) {
- /* Extra array data is ignored */
- break;
- }
-
- /* uniformVal (the destination) is always float[4] */
- uniformVal = program->Parameters->ParameterValues[index + offset + k];
-
- if (basicType == GL_INT) {
- /* convert user's ints to floats */
- const GLint *iValues = ((const GLint *) values) + k * elems;
- for (i = 0; i < elems; i++) {
- uniformVal[i] = (GLfloat) iValues[i];
- }
- }
- else if (basicType == GL_UNSIGNED_INT) {
- /* convert user's uints to floats */
- const GLuint *iValues = ((const GLuint *) values) + k * elems;
- for (i = 0; i < elems; i++) {
- uniformVal[i] = (GLfloat) iValues[i];
- }
- }
- else {
- const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
- assert(basicType == GL_FLOAT);
- for (i = 0; i < elems; i++) {
- uniformVal[i] = fValues[i];
- }
- }
-
- /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
- if (isUniformBool) {
- for (i = 0; i < elems; i++) {
- uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
- }
- }
- }
- }
-}
-
-
-/**
- * Called via glUniform*() functions.
- */
-void
-_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
- GLint location, GLsizei count,
- const GLvoid *values, GLenum type)
-{
- struct gl_uniform *uniform;
- GLint elems, offset;
-
- 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 < -1) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location=%d)",
- location);
- return;
- }
-
- split_location_offset(&location, &offset);
-
- if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location=%d)", location);
- return;
- }
-
- if (count < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
- return;
- }
-
- elems = _mesa_sizeof_glsl_type(type);
-
- FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
-
- uniform = &shProg->Uniforms->Uniforms[location];
-
- if (ctx->Shader.Flags & GLSL_UNIFORMS) {
- const GLenum basicType = base_uniform_type(type);
- GLint i;
- printf("Mesa: set program %u uniform %s (loc %d) to: ",
- shProg->Name, uniform->Name, location);
- if (basicType == GL_INT) {
- const GLint *v = (const GLint *) values;
- for (i = 0; i < count * elems; i++) {
- printf("%d ", v[i]);
- }
- }
- else if (basicType == GL_UNSIGNED_INT) {
- const GLuint *v = (const GLuint *) values;
- for (i = 0; i < count * elems; i++) {
- printf("%u ", v[i]);
- }
- }
- else {
- const GLfloat *v = (const GLfloat *) values;
- assert(basicType == GL_FLOAT);
- for (i = 0; i < count * elems; i++) {
- printf("%g ", v[i]);
- }
- }
- printf("\n");
- }
-
- /* 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) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->VertPos;
- if (index >= 0) {
- set_program_uniform(ctx, &shProg->VertexProgram->Base,
- index, offset, type, count, elems, values);
- }
- }
-
- if (shProg->FragmentProgram) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->FragPos;
- if (index >= 0) {
- set_program_uniform(ctx, &shProg->FragmentProgram->Base,
- index, offset, type, count, elems, values);
- }
- }
-
- if (shProg->GeometryProgram) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->GeomPos;
- if (index >= 0) {
- set_program_uniform(ctx, &shProg->GeometryProgram->Base,
- index, offset, type, count, elems, values);
- }
- }
-
- uniform->Initialized = GL_TRUE;
-}
-
-
-/**
- * Set a matrix-valued program parameter.
- */
-static void
-set_program_uniform_matrix(struct gl_context *ctx, struct gl_program *program,
- GLuint index, GLuint offset,
- GLuint count, GLuint rows, GLuint cols,
- GLboolean transpose, const GLfloat *values)
-{
- GLuint mat, row, col;
- GLuint src = 0;
- const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
- const GLuint slots = (param->Size + 3) / 4;
- const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
- GLint nr, nc;
-
- /* check that the number of rows, columns is correct */
- get_matrix_dims(param->DataType, &nr, &nc);
- if (rows != nr || cols != nc) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniformMatrix(matrix size mismatch)");
- return;
- }
-
- if ((GLint) param->Size <= typeSize) {
- /* non-array: count must be at most one; count == 0 is handled by the loop below */
- if (count > 1) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUniformMatrix(uniform is not an array)");
- return;
- }
- }
-
- /*
- * Note: the _columns_ of a matrix are stored in program registers, not
- * the rows. So, the loops below look a little funny.
- * XXX could optimize this a bit...
- */
-
- /* loop over matrices */
- for (mat = 0; mat < count; mat++) {
-
- /* each matrix: */
- for (col = 0; col < cols; col++) {
- GLfloat *v;
- if (offset >= slots) {
- /* Ignore writes beyond the end of (the used part of) an array */
- return;
- }
- v = program->Parameters->ParameterValues[index + offset];
- for (row = 0; row < rows; row++) {
- if (transpose) {
- v[row] = values[src + row * cols + col];
- }
- else {
- v[row] = values[src + col * rows + row];
- }
- }
-
- offset++;
- }
-
- src += rows * cols; /* next matrix */
- }
-}
-
-
-/**
- * Called by glUniformMatrix*() functions.
- * Note: cols=2, rows=4 ==> array[2] of vec4
- */
-void
-_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
- GLint cols, GLint rows,
- GLint location, GLsizei count,
- GLboolean transpose, const GLfloat *values)
-{
- struct gl_uniform *uniform;
- GLint offset;
-
- 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 */
-
- if (location < -1) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
- return;
- }
-
- split_location_offset(&location, &offset);
-
- if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
- return;
- }
- if (values == NULL) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
- return;
- }
-
- FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
-
- uniform = &shProg->Uniforms->Uniforms[location];
-
- if (shProg->VertexProgram) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->VertPos;
- if (index >= 0) {
- set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
- index, offset,
- count, rows, cols, transpose, values);
- }
- }
-
- if (shProg->FragmentProgram) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->FragPos;
- if (index >= 0) {
- set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
- index, offset,
- count, rows, cols, transpose, values);
- }
- }
-
- if (shProg->GeometryProgram) {
- /* convert uniform location to program parameter index */
- GLint index = uniform->GeomPos;
- if (index >= 0) {
- set_program_uniform_matrix(ctx, &shProg->GeometryProgram->Base,
- index, offset,
- count, rows, cols, transpose, values);
- }
- }
-
- uniform->Initialized = GL_TRUE;
-}
-
-
-void GLAPIENTRY
-_mesa_Uniform1fARB(GLint location, GLfloat v0)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_FLOAT);
-}
-
-void GLAPIENTRY
-_mesa_Uniform2fARB(GLint location, GLfloat v0, GLfloat v1)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLfloat v[2];
- v[0] = v0;
- v[1] = v1;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC2);
-}
-
-void GLAPIENTRY
-_mesa_Uniform3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLfloat v[3];
- v[0] = v0;
- v[1] = v1;
- v[2] = v2;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC3);
-}
-
-void GLAPIENTRY
-_mesa_Uniform4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2,
- GLfloat v3)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLfloat v[4];
- v[0] = v0;
- v[1] = v1;
- v[2] = v2;
- v[3] = v3;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC4);
-}
-
-void GLAPIENTRY
-_mesa_Uniform1iARB(GLint location, GLint v0)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_INT);
-}
-
-void GLAPIENTRY
-_mesa_Uniform2iARB(GLint location, GLint v0, GLint v1)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint v[2];
- v[0] = v0;
- v[1] = v1;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC2);
-}
-
-void GLAPIENTRY
-_mesa_Uniform3iARB(GLint location, GLint v0, GLint v1, GLint v2)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint v[3];
- v[0] = v0;
- v[1] = v1;
- v[2] = v2;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC3);
-}
-
-void GLAPIENTRY
-_mesa_Uniform4iARB(GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLint v[4];
- v[0] = v0;
- v[1] = v1;
- v[2] = v2;
- v[3] = v3;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC4);
-}
-
-void GLAPIENTRY
-_mesa_Uniform1fvARB(GLint location, GLsizei count, const GLfloat * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT);
-}
-
-void GLAPIENTRY
-_mesa_Uniform2fvARB(GLint location, GLsizei count, const GLfloat * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC2);
-}
-
-void GLAPIENTRY
-_mesa_Uniform3fvARB(GLint location, GLsizei count, const GLfloat * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC3);
-}
-
-void GLAPIENTRY
-_mesa_Uniform4fvARB(GLint location, GLsizei count, const GLfloat * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC4);
-}
-
-void GLAPIENTRY
-_mesa_Uniform1ivARB(GLint location, GLsizei count, const GLint * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT);
-}
-
-void GLAPIENTRY
-_mesa_Uniform2ivARB(GLint location, GLsizei count, const GLint * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC2);
-}
-
-void GLAPIENTRY
-_mesa_Uniform3ivARB(GLint location, GLsizei count, const GLint * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC3);
-}
-
-void GLAPIENTRY
-_mesa_Uniform4ivARB(GLint location, GLsizei count, const GLint * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC4);
-}
-
-
-/** OpenGL 3.0 GLuint-valued functions **/
-void GLAPIENTRY
-_mesa_Uniform1ui(GLint location, GLuint v0)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_UNSIGNED_INT);
-}
-
-void GLAPIENTRY
-_mesa_Uniform2ui(GLint location, GLuint v0, GLuint v1)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint v[2];
- v[0] = v0;
- v[1] = v1;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC2);
-}
-
-void GLAPIENTRY
-_mesa_Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint v[3];
- v[0] = v0;
- v[1] = v1;
- v[2] = v2;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC3);
-}
-
-void GLAPIENTRY
-_mesa_Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
-{
- GET_CURRENT_CONTEXT(ctx);
- GLuint v[4];
- v[0] = v0;
- v[1] = v1;
- v[2] = v2;
- v[3] = v3;
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC4);
-}
-
-void GLAPIENTRY
-_mesa_Uniform1uiv(GLint location, GLsizei count, const GLuint *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT);
-}
-
-void GLAPIENTRY
-_mesa_Uniform2uiv(GLint location, GLsizei count, const GLuint *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC2);
-}
-
-void GLAPIENTRY
-_mesa_Uniform3uiv(GLint location, GLsizei count, const GLuint *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC3);
-}
-
-void GLAPIENTRY
-_mesa_Uniform4uiv(GLint location, GLsizei count, const GLuint *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC4);
-}
-
-
-
-void GLAPIENTRY
-_mesa_UniformMatrix2fvARB(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 2, 2, location, count, transpose, value);
-}
-
-void GLAPIENTRY
-_mesa_UniformMatrix3fvARB(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 3, 3, location, count, transpose, value);
-}
-
-void GLAPIENTRY
-_mesa_UniformMatrix4fvARB(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat * value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 4, 4, location, count, transpose, value);
-}
-
-
-/**
- * Non-square UniformMatrix are OpenGL 2.1
- */
-void GLAPIENTRY
-_mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 2, 3, location, count, transpose, value);
-}
-
-void GLAPIENTRY
-_mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 3, 2, location, count, transpose, value);
-}
-
-void GLAPIENTRY
-_mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 2, 4, location, count, transpose, value);
-}
-
-void GLAPIENTRY
-_mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 4, 2, location, count, transpose, value);
-}
-
-void GLAPIENTRY
-_mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 3, 4, location, count, transpose, value);
-}
-
-void GLAPIENTRY
-_mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose,
- const GLfloat *value)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
- 4, 3, location, count, transpose, value);
-}
-
-
-void GLAPIENTRY
-_mesa_GetUniformfvARB(GLhandleARB program, GLint location, GLfloat *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_get_uniformfv(ctx, program, location, params);
-}
-
-
-void GLAPIENTRY
-_mesa_GetUniformivARB(GLhandleARB program, GLint location, GLint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_get_uniformiv(ctx, program, location, params);
-}
-
-
-/* GL3 */
-void GLAPIENTRY
-_mesa_GetUniformuiv(GLhandleARB program, GLint location, GLuint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_get_uniformuiv(ctx, program, location, params);
-}
-
-
-
-GLint GLAPIENTRY
-_mesa_GetUniformLocationARB(GLhandleARB programObj, const GLcharARB *name)
-{
- struct gl_shader_program *shProg;
-
- GET_CURRENT_CONTEXT(ctx);
-
- shProg = _mesa_lookup_shader_program_err(ctx, programObj,
- "glGetUniformLocation");
- if (!shProg)
- return -1;
-
- return _mesa_get_uniform_location(ctx, shProg, name);
-}
-
-
-void GLAPIENTRY
-_mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
- GLsizei maxLength, GLsizei * length, GLint * size,
- GLenum * type, GLcharARB * name)
-{
- GET_CURRENT_CONTEXT(ctx);
- _mesa_get_active_uniform(ctx, program, index, maxLength, length, size,
- type, name);
-}
-
-
-/**
- * Plug in shader uniform-related functions into API dispatch table.
- */
-void
-_mesa_init_shader_uniform_dispatch(struct _glapi_table *exec)
-{
-#if FEATURE_GL
- SET_Uniform1fARB(exec, _mesa_Uniform1fARB);
- SET_Uniform2fARB(exec, _mesa_Uniform2fARB);
- SET_Uniform3fARB(exec, _mesa_Uniform3fARB);
- SET_Uniform4fARB(exec, _mesa_Uniform4fARB);
- SET_Uniform1iARB(exec, _mesa_Uniform1iARB);
- SET_Uniform2iARB(exec, _mesa_Uniform2iARB);
- SET_Uniform3iARB(exec, _mesa_Uniform3iARB);
- SET_Uniform4iARB(exec, _mesa_Uniform4iARB);
- SET_Uniform1fvARB(exec, _mesa_Uniform1fvARB);
- SET_Uniform2fvARB(exec, _mesa_Uniform2fvARB);
- SET_Uniform3fvARB(exec, _mesa_Uniform3fvARB);
- SET_Uniform4fvARB(exec, _mesa_Uniform4fvARB);
- SET_Uniform1ivARB(exec, _mesa_Uniform1ivARB);
- SET_Uniform2ivARB(exec, _mesa_Uniform2ivARB);
- SET_Uniform3ivARB(exec, _mesa_Uniform3ivARB);
- SET_Uniform4ivARB(exec, _mesa_Uniform4ivARB);
- SET_UniformMatrix2fvARB(exec, _mesa_UniformMatrix2fvARB);
- SET_UniformMatrix3fvARB(exec, _mesa_UniformMatrix3fvARB);
- SET_UniformMatrix4fvARB(exec, _mesa_UniformMatrix4fvARB);
-
- SET_GetActiveUniformARB(exec, _mesa_GetActiveUniformARB);
- SET_GetUniformLocationARB(exec, _mesa_GetUniformLocationARB);
- SET_GetUniformfvARB(exec, _mesa_GetUniformfvARB);
- SET_GetUniformivARB(exec, _mesa_GetUniformivARB);
-
- /* OpenGL 2.1 */
- SET_UniformMatrix2x3fv(exec, _mesa_UniformMatrix2x3fv);
- SET_UniformMatrix3x2fv(exec, _mesa_UniformMatrix3x2fv);
- SET_UniformMatrix2x4fv(exec, _mesa_UniformMatrix2x4fv);
- SET_UniformMatrix4x2fv(exec, _mesa_UniformMatrix4x2fv);
- SET_UniformMatrix3x4fv(exec, _mesa_UniformMatrix3x4fv);
- SET_UniformMatrix4x3fv(exec, _mesa_UniformMatrix4x3fv);
-
- /* OpenGL 3.0 */
- /* XXX finish dispatch */
- SET_Uniform1uiEXT(exec, _mesa_Uniform1ui);
- SET_Uniform2uiEXT(exec, _mesa_Uniform2ui);
- SET_Uniform3uiEXT(exec, _mesa_Uniform3ui);
- SET_Uniform4uiEXT(exec, _mesa_Uniform4ui);
- SET_Uniform1uivEXT(exec, _mesa_Uniform1uiv);
- SET_Uniform2uivEXT(exec, _mesa_Uniform2uiv);
- SET_Uniform3uivEXT(exec, _mesa_Uniform3uiv);
- SET_Uniform4uivEXT(exec, _mesa_Uniform4uiv);
- SET_GetUniformuivEXT(exec, _mesa_GetUniformuiv);
-
-
-#endif /* FEATURE_GL */
-}
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved.
+ * Copyright © 2010 Intel Corporation
+ *
+ * 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 uniforms.c
+ * Functions related to GLSL uniform variables.
+ * \author Brian Paul
+ */
+
+/**
+ * XXX things to do:
+ * 1. Check that the right error code is generated for all _mesa_error() calls.
+ * 2. Insert FLUSH_VERTICES calls in various places
+ */
+
+
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/dispatch.h"
+#include "main/mfeatures.h"
+#include "main/mtypes.h"
+#include "main/shaderapi.h"
+#include "main/shaderobj.h"
+#include "main/uniforms.h"
+#include "program/prog_parameter.h"
+#include "program/prog_statevars.h"
+#include "program/prog_uniform.h"
+#include "program/prog_instruction.h"
+
+
+static GLenum
+base_uniform_type(GLenum type)
+{
+ switch (type) {
+#if 0 /* not needed, for now */
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ return GL_BOOL;
+#endif
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ return GL_FLOAT;
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ return GL_UNSIGNED_INT;
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ return GL_INT;
+ default:
+ _mesa_problem(NULL, "Invalid type in base_uniform_type()");
+ return GL_FLOAT;
+ }
+}
+
+static struct gl_builtin_uniform_element gl_DepthRange_elements[] = {
+ {"near", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_XXXX},
+ {"far", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_YYYY},
+ {"diff", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_ZZZZ},
+};
+
+static struct gl_builtin_uniform_element gl_ClipPlane_elements[] = {
+ {NULL, {STATE_CLIPPLANE, 0, 0}, SWIZZLE_XYZW}
+};
+
+static struct gl_builtin_uniform_element gl_Point_elements[] = {
+ {"size", {STATE_POINT_SIZE}, SWIZZLE_XXXX},
+ {"sizeMin", {STATE_POINT_SIZE}, SWIZZLE_YYYY},
+ {"sizeMax", {STATE_POINT_SIZE}, SWIZZLE_ZZZZ},
+ {"fadeThresholdSize", {STATE_POINT_SIZE}, SWIZZLE_WWWW},
+ {"distanceConstantAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_XXXX},
+ {"distanceLinearAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_YYYY},
+ {"distanceQuadraticAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_ZZZZ},
+};
+
+static struct gl_builtin_uniform_element gl_FrontMaterial_elements[] = {
+ {"emission", {STATE_MATERIAL, 0, STATE_EMISSION}, SWIZZLE_XYZW},
+ {"ambient", {STATE_MATERIAL, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
+ {"diffuse", {STATE_MATERIAL, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
+ {"specular", {STATE_MATERIAL, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
+ {"shininess", {STATE_MATERIAL, 0, STATE_SHININESS}, SWIZZLE_XXXX},
+};
+
+static struct gl_builtin_uniform_element gl_BackMaterial_elements[] = {
+ {"emission", {STATE_MATERIAL, 1, STATE_EMISSION}, SWIZZLE_XYZW},
+ {"ambient", {STATE_MATERIAL, 1, STATE_AMBIENT}, SWIZZLE_XYZW},
+ {"diffuse", {STATE_MATERIAL, 1, STATE_DIFFUSE}, SWIZZLE_XYZW},
+ {"specular", {STATE_MATERIAL, 1, STATE_SPECULAR}, SWIZZLE_XYZW},
+ {"shininess", {STATE_MATERIAL, 1, STATE_SHININESS}, SWIZZLE_XXXX},
+};
+
+static struct gl_builtin_uniform_element gl_LightSource_elements[] = {
+ {"ambient", {STATE_LIGHT, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
+ {"diffuse", {STATE_LIGHT, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
+ {"specular", {STATE_LIGHT, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
+ {"position", {STATE_LIGHT, 0, STATE_POSITION}, SWIZZLE_XYZW},
+ {"halfVector", {STATE_LIGHT, 0, STATE_HALF_VECTOR}, SWIZZLE_XYZW},
+ {"spotDirection", {STATE_LIGHT, 0, STATE_SPOT_DIRECTION},
+ MAKE_SWIZZLE4(SWIZZLE_X,
+ SWIZZLE_Y,
+ SWIZZLE_Z,
+ SWIZZLE_Z)},
+ {"spotCosCutoff", {STATE_LIGHT, 0, STATE_SPOT_DIRECTION}, SWIZZLE_WWWW},
+ {"spotCutoff", {STATE_LIGHT, 0, STATE_SPOT_CUTOFF}, SWIZZLE_XXXX},
+ {"spotExponent", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_WWWW},
+ {"constantAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_XXXX},
+ {"linearAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_YYYY},
+ {"quadraticAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_ZZZZ},
+};
+
+static struct gl_builtin_uniform_element gl_LightModel_elements[] = {
+ {"ambient", {STATE_LIGHTMODEL_AMBIENT, 0}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_FrontLightModelProduct_elements[] = {
+ {"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 0}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_BackLightModelProduct_elements[] = {
+ {"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 1}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_FrontLightProduct_elements[] = {
+ {"ambient", {STATE_LIGHTPROD, 0, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
+ {"diffuse", {STATE_LIGHTPROD, 0, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
+ {"specular", {STATE_LIGHTPROD, 0, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_BackLightProduct_elements[] = {
+ {"ambient", {STATE_LIGHTPROD, 0, 1, STATE_AMBIENT}, SWIZZLE_XYZW},
+ {"diffuse", {STATE_LIGHTPROD, 0, 1, STATE_DIFFUSE}, SWIZZLE_XYZW},
+ {"specular", {STATE_LIGHTPROD, 0, 1, STATE_SPECULAR}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_TextureEnvColor_elements[] = {
+ {NULL, {STATE_TEXENV_COLOR, 0}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_EyePlaneS_elements[] = {
+ {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_S}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_EyePlaneT_elements[] = {
+ {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_T}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_EyePlaneR_elements[] = {
+ {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_R}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_EyePlaneQ_elements[] = {
+ {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_Q}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_ObjectPlaneS_elements[] = {
+ {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_S}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_ObjectPlaneT_elements[] = {
+ {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_T}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_ObjectPlaneR_elements[] = {
+ {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_R}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_ObjectPlaneQ_elements[] = {
+ {NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_Q}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_Fog_elements[] = {
+ {"color", {STATE_FOG_COLOR}, SWIZZLE_XYZW},
+ {"density", {STATE_FOG_PARAMS}, SWIZZLE_XXXX},
+ {"start", {STATE_FOG_PARAMS}, SWIZZLE_YYYY},
+ {"end", {STATE_FOG_PARAMS}, SWIZZLE_ZZZZ},
+ {"scale", {STATE_FOG_PARAMS}, SWIZZLE_WWWW},
+};
+
+static struct gl_builtin_uniform_element gl_NormalScale_elements[] = {
+ {NULL, {STATE_NORMAL_SCALE}, SWIZZLE_XXXX},
+};
+
+static struct gl_builtin_uniform_element gl_MESABumpRotMatrix0_elements[] = {
+ {NULL, {STATE_INTERNAL, STATE_ROT_MATRIX_0}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_MESABumpRotMatrix1_elements[] = {
+ {NULL, {STATE_INTERNAL, STATE_ROT_MATRIX_1}, SWIZZLE_XYZW},
+};
+
+static struct gl_builtin_uniform_element gl_MESAFogParamsOptimized_elements[] = {
+ {NULL, {STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED}, SWIZZLE_XYZW},
+};
+
+#define MATRIX(name, statevar, modifier) \
+ static struct gl_builtin_uniform_element name ## _elements[] = { \
+ { NULL, { statevar, 0, 0, 0, modifier}, SWIZZLE_XYZW }, \
+ { NULL, { statevar, 0, 1, 1, modifier}, SWIZZLE_XYZW }, \
+ { NULL, { statevar, 0, 2, 2, modifier}, SWIZZLE_XYZW }, \
+ { NULL, { statevar, 0, 3, 3, modifier}, SWIZZLE_XYZW }, \
+ }
+
+MATRIX(gl_ModelViewMatrix,
+ STATE_MODELVIEW_MATRIX, STATE_MATRIX_TRANSPOSE);
+MATRIX(gl_ModelViewMatrixInverse,
+ STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVTRANS);
+MATRIX(gl_ModelViewMatrixTranspose,
+ STATE_MODELVIEW_MATRIX, 0);
+MATRIX(gl_ModelViewMatrixInverseTranspose,
+ STATE_MODELVIEW_MATRIX, STATE_MATRIX_INVERSE);
+
+MATRIX(gl_ProjectionMatrix,
+ STATE_PROJECTION_MATRIX, STATE_MATRIX_TRANSPOSE);
+MATRIX(gl_ProjectionMatrixInverse,
+ STATE_PROJECTION_MATRIX, STATE_MATRIX_INVTRANS);
+MATRIX(gl_ProjectionMatrixTranspose,
+ STATE_PROJECTION_MATRIX, 0);
+MATRIX(gl_ProjectionMatrixInverseTranspose,
+ STATE_PROJECTION_MATRIX, STATE_MATRIX_INVERSE);
+
+MATRIX(gl_ModelViewProjectionMatrix,
+ STATE_MVP_MATRIX, STATE_MATRIX_TRANSPOSE);
+MATRIX(gl_ModelViewProjectionMatrixInverse,
+ STATE_MVP_MATRIX, STATE_MATRIX_INVTRANS);
+MATRIX(gl_ModelViewProjectionMatrixTranspose,
+ STATE_MVP_MATRIX, 0);
+MATRIX(gl_ModelViewProjectionMatrixInverseTranspose,
+ STATE_MVP_MATRIX, STATE_MATRIX_INVERSE);
+
+MATRIX(gl_TextureMatrix,
+ STATE_TEXTURE_MATRIX, STATE_MATRIX_TRANSPOSE);
+MATRIX(gl_TextureMatrixInverse,
+ STATE_TEXTURE_MATRIX, STATE_MATRIX_INVTRANS);
+MATRIX(gl_TextureMatrixTranspose,
+ STATE_TEXTURE_MATRIX, 0);
+MATRIX(gl_TextureMatrixInverseTranspose,
+ STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE);
+
+static struct gl_builtin_uniform_element gl_NormalMatrix_elements[] = {
+ { NULL, { STATE_MODELVIEW_MATRIX, 0, 0, 0, STATE_MATRIX_INVERSE},
+ SWIZZLE_XYZW },
+ { NULL, { STATE_MODELVIEW_MATRIX, 0, 1, 1, STATE_MATRIX_INVERSE},
+ SWIZZLE_XYZW },
+ { NULL, { STATE_MODELVIEW_MATRIX, 0, 2, 2, STATE_MATRIX_INVERSE},
+ SWIZZLE_XYZW },
+};
+
+#undef MATRIX
+
+#define STATEVAR(name) {#name, name ## _elements, Elements(name ## _elements)}
+
+const struct gl_builtin_uniform_desc _mesa_builtin_uniform_desc[] = {
+ STATEVAR(gl_DepthRange),
+ STATEVAR(gl_ClipPlane),
+ STATEVAR(gl_Point),
+ STATEVAR(gl_FrontMaterial),
+ STATEVAR(gl_BackMaterial),
+ STATEVAR(gl_LightSource),
+ STATEVAR(gl_LightModel),
+ STATEVAR(gl_FrontLightModelProduct),
+ STATEVAR(gl_BackLightModelProduct),
+ STATEVAR(gl_FrontLightProduct),
+ STATEVAR(gl_BackLightProduct),
+ STATEVAR(gl_TextureEnvColor),
+ STATEVAR(gl_EyePlaneS),
+ STATEVAR(gl_EyePlaneT),
+ STATEVAR(gl_EyePlaneR),
+ STATEVAR(gl_EyePlaneQ),
+ STATEVAR(gl_ObjectPlaneS),
+ STATEVAR(gl_ObjectPlaneT),
+ STATEVAR(gl_ObjectPlaneR),
+ STATEVAR(gl_ObjectPlaneQ),
+ STATEVAR(gl_Fog),
+
+ STATEVAR(gl_ModelViewMatrix),
+ STATEVAR(gl_ModelViewMatrixInverse),
+ STATEVAR(gl_ModelViewMatrixTranspose),
+ STATEVAR(gl_ModelViewMatrixInverseTranspose),
+
+ STATEVAR(gl_ProjectionMatrix),
+ STATEVAR(gl_ProjectionMatrixInverse),
+ STATEVAR(gl_ProjectionMatrixTranspose),
+ STATEVAR(gl_ProjectionMatrixInverseTranspose),
+
+ STATEVAR(gl_ModelViewProjectionMatrix),
+ STATEVAR(gl_ModelViewProjectionMatrixInverse),
+ STATEVAR(gl_ModelViewProjectionMatrixTranspose),
+ STATEVAR(gl_ModelViewProjectionMatrixInverseTranspose),
+
+ STATEVAR(gl_TextureMatrix),
+ STATEVAR(gl_TextureMatrixInverse),
+ STATEVAR(gl_TextureMatrixTranspose),
+ STATEVAR(gl_TextureMatrixInverseTranspose),
+
+ STATEVAR(gl_NormalMatrix),
+ STATEVAR(gl_NormalScale),
+
+ STATEVAR(gl_MESABumpRotMatrix0),
+ STATEVAR(gl_MESABumpRotMatrix1),
+ STATEVAR(gl_MESAFogParamsOptimized),
+
+ {NULL, NULL, 0}
+};
+
+static GLboolean
+is_boolean_type(GLenum type)
+{
+ switch (type) {
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+static GLboolean
+is_sampler_type(GLenum type)
+{
+ switch (type) {
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_2D_RECT_ARB:
+ case GL_SAMPLER_2D_RECT_SHADOW_ARB:
+ case GL_SAMPLER_1D_ARRAY_EXT:
+ case GL_SAMPLER_2D_ARRAY_EXT:
+ case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
+ case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
+ return GL_TRUE;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+static struct gl_program_parameter *
+get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
+{
+ const struct gl_program *prog = NULL;
+ GLint progPos;
+
+ 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;
+ } else {
+ progPos = shProg->Uniforms->Uniforms[index].GeomPos;
+ if (progPos >= 0) {
+ prog = &shProg->GeometryProgram->Base;
+ }
+ }
+ }
+
+ if (!prog || progPos < 0)
+ return NULL; /* should never happen */
+
+ return &prog->Parameters->Parameters[progPos];
+}
+
+
+/**
+ * Called by glGetActiveUniform().
+ */
+static void
+_mesa_get_active_uniform(struct gl_context *ctx, GLuint program, GLuint index,
+ GLsizei maxLength, GLsizei *length, GLint *size,
+ GLenum *type, GLchar *nameOut)
+{
+ const struct gl_shader_program *shProg;
+ const struct gl_program *prog = NULL;
+ const struct gl_program_parameter *param;
+ GLint progPos;
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
+ if (!shProg)
+ return;
+
+ if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
+ return;
+ }
+
+ 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;
+ } else {
+ progPos = shProg->Uniforms->Uniforms[index].GeomPos;
+ if (progPos >= 0) {
+ prog = &shProg->GeometryProgram->Base;
+ }
+ }
+ }
+
+ if (!prog || progPos < 0)
+ return; /* should never happen */
+
+ ASSERT(progPos < prog->Parameters->NumParameters);
+ param = &prog->Parameters->Parameters[progPos];
+
+ if (nameOut) {
+ _mesa_copy_string(nameOut, maxLength, length, param->Name);
+ }
+
+ if (size) {
+ GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
+ if ((GLint) param->Size > typeSize) {
+ /* This is an array.
+ * Array elements are placed on vector[4] boundaries so they're
+ * a multiple of four floats. We round typeSize up to next multiple
+ * of four to get the right size below.
+ */
+ typeSize = (typeSize + 3) & ~3;
+ }
+ /* Note that the returned size is in units of the <type>, not bytes */
+ *size = param->Size / typeSize;
+ }
+
+ if (type) {
+ *type = param->DataType;
+ }
+}
+
+
+static unsigned
+get_vector_elements(GLenum type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_BOOL:
+ case GL_UNSIGNED_INT:
+ default: /* Catch all the various sampler types. */
+ return 1;
+
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_BOOL_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ return 2;
+
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_BOOL_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ return 3;
+
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_BOOL_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ return 4;
+ }
+}
+
+static void
+get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
+{
+ switch (type) {
+ case GL_FLOAT_MAT2:
+ *rows = *cols = 2;
+ break;
+ case GL_FLOAT_MAT2x3:
+ *rows = 3;
+ *cols = 2;
+ break;
+ case GL_FLOAT_MAT2x4:
+ *rows = 4;
+ *cols = 2;
+ break;
+ case GL_FLOAT_MAT3:
+ *rows = 3;
+ *cols = 3;
+ break;
+ case GL_FLOAT_MAT3x2:
+ *rows = 2;
+ *cols = 3;
+ break;
+ case GL_FLOAT_MAT3x4:
+ *rows = 4;
+ *cols = 3;
+ break;
+ case GL_FLOAT_MAT4:
+ *rows = 4;
+ *cols = 4;
+ break;
+ case GL_FLOAT_MAT4x2:
+ *rows = 2;
+ *cols = 4;
+ break;
+ case GL_FLOAT_MAT4x3:
+ *rows = 3;
+ *cols = 4;
+ break;
+ default:
+ *rows = *cols = 0;
+ }
+}
+
+
+/**
+ * Determine the number of rows and columns occupied by a uniform
+ * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
+ * the number of rows = 1 and cols = number of elements in the vector.
+ */
+static void
+get_uniform_rows_cols(const struct gl_program_parameter *p,
+ GLint *rows, GLint *cols)
+{
+ get_matrix_dims(p->DataType, rows, cols);
+ if (*rows == 0 && *cols == 0) {
+ /* not a matrix type, probably a float or vector */
+ *rows = 1;
+ *cols = get_vector_elements(p->DataType);
+ }
+}
+
+
+/**
+ * Helper for get_uniform[fi]v() functions.
+ * Given a shader program name and uniform location, return a pointer
+ * to the shader program and return the program parameter position.
+ */
+static void
+lookup_uniform_parameter(struct gl_context *ctx, GLuint program, GLint location,
+ struct gl_program **progOut, GLint *paramPosOut)
+{
+ struct gl_shader_program *shProg
+ = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
+ struct gl_program *prog = NULL;
+ GLint progPos = -1;
+
+ /* if shProg is NULL, we'll have already recorded an error */
+
+ if (shProg) {
+ if (!shProg->Uniforms ||
+ location < 0 ||
+ location >= (GLint) shProg->Uniforms->NumUniforms) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
+ }
+ else {
+ /* OK, find the gl_program and program parameter location */
+ 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;
+ } else {
+ progPos = shProg->Uniforms->Uniforms[location].GeomPos;
+ if (progPos >= 0) {
+ prog = &shProg->GeometryProgram->Base;
+ }
+ }
+ }
+ }
+ }
+
+ *progOut = prog;
+ *paramPosOut = progPos;
+}
+
+
+/**
+ * GLGL uniform arrays and structs require special handling.
+ *
+ * The GL_ARB_shader_objects spec says that if you use
+ * glGetUniformLocation to get the location of an array, you CANNOT
+ * access other elements of the array by adding an offset to the
+ * returned location. For example, you must call
+ * glGetUniformLocation("foo[16]") if you want to set the 16th element
+ * of the array with glUniform().
+ *
+ * HOWEVER, some other OpenGL drivers allow accessing array elements
+ * by adding an offset to the returned array location. And some apps
+ * seem to depend on that behaviour.
+ *
+ * Mesa's gl_uniform_list doesn't directly support this since each
+ * entry in the list describes one uniform variable, not one uniform
+ * element. We could insert dummy entries in the list for each array
+ * element after [0] but that causes complications elsewhere.
+ *
+ * We solve this problem by encoding two values in the location that's
+ * returned by glGetUniformLocation():
+ * a) index into gl_uniform_list::Uniforms[] for the uniform
+ * b) an array/field offset (0 for simple types)
+ *
+ * These two values are encoded in the high and low halves of a GLint.
+ * By putting the uniform number in the high part and the offset in the
+ * low part, we can support the unofficial ability to index into arrays
+ * by adding offsets to the location value.
+ */
+static void
+merge_location_offset(GLint *location, GLint offset)
+{
+ *location = (*location << 16) | offset;
+}
+
+
+/**
+ * Separate the uniform location and parameter offset. See above.
+ */
+static void
+split_location_offset(GLint *location, GLint *offset)
+{
+ *offset = *location & 0xffff;
+ *location = *location >> 16;
+}
+
+
+
+/**
+ * Called via glGetUniformfv().
+ */
+static void
+_mesa_get_uniformfv(struct gl_context *ctx, GLuint program, GLint location,
+ GLfloat *params)
+{
+ struct gl_program *prog;
+ GLint paramPos;
+ GLint offset;
+
+ split_location_offset(&location, &offset);
+
+ lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
+
+ if (prog) {
+ const struct gl_program_parameter *p =
+ &prog->Parameters->Parameters[paramPos];
+ GLint rows, cols, i, j, k;
+
+ get_uniform_rows_cols(p, &rows, &cols);
+
+ k = 0;
+ for (i = 0; i < rows; i++) {
+ const int base = paramPos + offset + i;
+
+ for (j = 0; j < cols; j++ ) {
+ params[k++] = prog->Parameters->ParameterValues[base][j];
+ }
+ }
+ }
+}
+
+
+/**
+ * Called via glGetUniformiv().
+ * \sa _mesa_get_uniformfv, only difference is a cast.
+ */
+static void
+_mesa_get_uniformiv(struct gl_context *ctx, GLuint program, GLint location,
+ GLint *params)
+{
+ struct gl_program *prog;
+ GLint paramPos;
+ GLint offset;
+
+ split_location_offset(&location, &offset);
+
+ lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
+
+ if (prog) {
+ const struct gl_program_parameter *p =
+ &prog->Parameters->Parameters[paramPos];
+ GLint rows, cols, i, j, k;
+
+ get_uniform_rows_cols(p, &rows, &cols);
+
+ k = 0;
+ for (i = 0; i < rows; i++) {
+ const int base = paramPos + offset + i;
+
+ for (j = 0; j < cols; j++ ) {
+ params[k++] = (GLint) prog->Parameters->ParameterValues[base][j];
+ }
+ }
+ }
+}
+
+
+/**
+ * Called via glGetUniformuiv().
+ * New in GL_EXT_gpu_shader4, OpenGL 3.0
+ * \sa _mesa_get_uniformfv, only difference is a cast.
+ */
+static void
+_mesa_get_uniformuiv(struct gl_context *ctx, GLuint program, GLint location,
+ GLuint *params)
+{
+ struct gl_program *prog;
+ GLint paramPos;
+ GLint offset;
+
+ split_location_offset(&location, &offset);
+
+ lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
+
+ if (prog) {
+ const struct gl_program_parameter *p =
+ &prog->Parameters->Parameters[paramPos];
+ GLint rows, cols, i, j, k;
+
+ get_uniform_rows_cols(p, &rows, &cols);
+
+ k = 0;
+ for (i = 0; i < rows; i++) {
+ const int base = paramPos + offset + i;
+
+ for (j = 0; j < cols; j++ ) {
+ params[k++] = (GLuint) prog->Parameters->ParameterValues[base][j];
+ }
+ }
+ }
+}
+
+
+/**
+ * Called via glGetUniformLocation().
+ *
+ * The return value will encode two values, the uniform location and an
+ * offset (used for arrays, structs).
+ */
+GLint
+_mesa_get_uniform_location(struct gl_context *ctx, struct gl_shader_program *shProg,
+ const GLchar *name)
+{
+ GLint offset = 0, location = -1;
+
+ if (shProg->LinkStatus == GL_FALSE) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
+ return -1;
+ }
+
+ /* XXX we should return -1 if the uniform was declared, but not
+ * actually used.
+ */
+
+ /* XXX we need to be able to parse uniform names for structs and arrays
+ * such as:
+ * mymatrix[1]
+ * mystruct.field1
+ */
+
+ {
+ /* handle 1-dimension arrays here... */
+ char *c = strchr(name, '[');
+ if (c) {
+ /* truncate name at [ */
+ const GLint len = c - name;
+ GLchar *newName = malloc(len + 1);
+ if (!newName)
+ return -1; /* out of mem */
+ memcpy(newName, name, len);
+ newName[len] = 0;
+
+ location = _mesa_lookup_uniform(shProg->Uniforms, newName);
+ if (location >= 0) {
+ const GLint element = atoi(c + 1);
+ if (element > 0) {
+ /* get type of the uniform array element */
+ struct gl_program_parameter *p;
+ p = get_uniform_parameter(shProg, location);
+ if (p) {
+ GLint rows, cols;
+ get_matrix_dims(p->DataType, &rows, &cols);
+ if (rows < 1)
+ rows = 1;
+ offset = element * rows;
+ }
+ }
+ }
+
+ free(newName);
+ }
+ }
+
+ if (location < 0) {
+ location = _mesa_lookup_uniform(shProg->Uniforms, name);
+ }
+
+ if (location >= 0) {
+ merge_location_offset(&location, offset);
+ }
+
+ return location;
+}
+
+
+
+/**
+ * Update the vertex/fragment program's TexturesUsed array.
+ *
+ * This needs to be called after glUniform(set sampler var) is called.
+ * A call to glUniform(samplerVar, value) causes a sampler to point to a
+ * particular texture unit. We know the sampler's texture target
+ * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
+ * set by glUniform() calls.
+ *
+ * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
+ * information to update the prog->TexturesUsed[] values.
+ * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
+ * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
+ * We'll use that info for state validation before rendering.
+ */
+void
+_mesa_update_shader_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 unit = prog->SamplerUnits[s];
+ GLuint tgt = prog->SamplerTargets[s];
+ assert(unit < MAX_TEXTURE_IMAGE_UNITS);
+ assert(tgt < NUM_TEXTURE_TARGETS);
+ prog->TexturesUsed[unit] |= (1 << tgt);
+ }
+ }
+}
+
+
+/**
+ * Check if the type given by userType is allowed to set a uniform of the
+ * target type. Generally, equivalence is required, but setting Boolean
+ * uniforms can be done with glUniformiv or glUniformfv.
+ */
+static GLboolean
+compatible_types(GLenum userType, GLenum targetType)
+{
+ if (userType == targetType)
+ return GL_TRUE;
+
+ if (targetType == GL_BOOL && (userType == GL_FLOAT ||
+ userType == GL_UNSIGNED_INT ||
+ userType == GL_INT))
+ return GL_TRUE;
+
+ if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
+ userType == GL_UNSIGNED_INT_VEC2 ||
+ userType == GL_INT_VEC2))
+ return GL_TRUE;
+
+ if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
+ userType == GL_UNSIGNED_INT_VEC3 ||
+ userType == GL_INT_VEC3))
+ return GL_TRUE;
+
+ if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
+ userType == GL_UNSIGNED_INT_VEC4 ||
+ userType == GL_INT_VEC4))
+ return GL_TRUE;
+
+ if (is_sampler_type(targetType) && userType == GL_INT)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Set the value of a program's uniform variable.
+ * \param program the program whose uniform to update
+ * \param index the index of the program parameter for the uniform
+ * \param offset additional parameter slot offset (for arrays)
+ * \param type the incoming datatype of 'values'
+ * \param count the number of uniforms to set
+ * \param elems number of elements per uniform (1, 2, 3 or 4)
+ * \param values the new values, of datatype 'type'
+ */
+static void
+set_program_uniform(struct gl_context *ctx, struct gl_program *program,
+ GLint index, GLint offset,
+ GLenum type, GLsizei count, GLint elems,
+ const void *values)
+{
+ const struct gl_program_parameter *param =
+ &program->Parameters->Parameters[index];
+
+ assert(offset >= 0);
+ assert(elems >= 1);
+ assert(elems <= 4);
+
+ if (!compatible_types(type, param->DataType)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
+ return;
+ }
+
+ if (index + offset > (GLint) program->Parameters->Size) {
+ /* out of bounds! */
+ return;
+ }
+
+ if (param->Type == PROGRAM_SAMPLER) {
+ /* This controls which texture unit which is used by a sampler */
+ GLboolean changed = GL_FALSE;
+ GLint i;
+
+ /* this should have been caught by the compatible_types() check */
+ ASSERT(type == GL_INT);
+
+ /* loop over number of samplers to change */
+ for (i = 0; i < count; i++) {
+ GLuint sampler =
+ (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
+ GLuint texUnit = ((GLuint *) values)[i];
+
+ /* 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 for '%s')",
+ param->Name);
+ return;
+ }
+
+ /* This maps a sampler to a texture unit: */
+ if (sampler < MAX_SAMPLERS) {
+#if 0
+ printf("Set program %p sampler %d '%s' to unit %u\n",
+ program, sampler, param->Name, texUnit);
+#endif
+ if (program->SamplerUnits[sampler] != texUnit) {
+ program->SamplerUnits[sampler] = texUnit;
+ changed = GL_TRUE;
+ }
+ }
+ }
+
+ if (changed) {
+ /* When a sampler's value changes it usually requires rewriting
+ * a GPU program's TEX instructions since there may not be a
+ * sampler->texture lookup table. We signal this with the
+ * ProgramStringNotify() callback.
+ */
+ FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
+ _mesa_update_shader_textures_used(program);
+ /* Do we need to care about the return value here?
+ * This should not be the first time the driver was notified of
+ * this program.
+ */
+ (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
+ }
+ }
+ else {
+ /* ordinary uniform variable */
+ const GLboolean isUniformBool = is_boolean_type(param->DataType);
+ const GLenum basicType = base_uniform_type(type);
+ const GLint slots = (param->Size + 3) / 4;
+ const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
+ GLsizei k, i;
+
+ if ((GLint) param->Size > typeSize) {
+ /* an array */
+ /* we'll ignore extra data below */
+ }
+ else {
+ /* non-array: count must be at most one; count == 0 is handled by the loop below */
+ if (count > 1) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUniform(uniform '%s' is not an array)",
+ param->Name);
+ return;
+ }
+ }
+
+ /* loop over number of array elements */
+ for (k = 0; k < count; k++) {
+ GLfloat *uniformVal;
+
+ if (offset + k >= slots) {
+ /* Extra array data is ignored */
+ break;
+ }
+
+ /* uniformVal (the destination) is always float[4] */
+ uniformVal = program->Parameters->ParameterValues[index + offset + k];
+
+ if (basicType == GL_INT) {
+ /* convert user's ints to floats */
+ const GLint *iValues = ((const GLint *) values) + k * elems;
+ for (i = 0; i < elems; i++) {
+ uniformVal[i] = (GLfloat) iValues[i];
+ }
+ }
+ else if (basicType == GL_UNSIGNED_INT) {
+ /* convert user's uints to floats */
+ const GLuint *iValues = ((const GLuint *) values) + k * elems;
+ for (i = 0; i < elems; i++) {
+ uniformVal[i] = (GLfloat) iValues[i];
+ }
+ }
+ else {
+ const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
+ assert(basicType == GL_FLOAT);
+ for (i = 0; i < elems; i++) {
+ uniformVal[i] = fValues[i];
+ }
+ }
+
+ /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
+ if (isUniformBool) {
+ for (i = 0; i < elems; i++) {
+ uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * Called via glUniform*() functions.
+ */
+void
+_mesa_uniform(struct gl_context *ctx, struct gl_shader_program *shProg,
+ GLint location, GLsizei count,
+ const GLvoid *values, GLenum type)
+{
+ struct gl_uniform *uniform;
+ GLint elems, offset;
+
+ 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 < -1) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location=%d)",
+ location);
+ return;
+ }
+
+ split_location_offset(&location, &offset);
+
+ if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location=%d)", location);
+ return;
+ }
+
+ if (count < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
+ return;
+ }
+
+ elems = _mesa_sizeof_glsl_type(type);
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+
+ uniform = &shProg->Uniforms->Uniforms[location];
+
+ if (ctx->Shader.Flags & GLSL_UNIFORMS) {
+ const GLenum basicType = base_uniform_type(type);
+ GLint i;
+ printf("Mesa: set program %u uniform %s (loc %d) to: ",
+ shProg->Name, uniform->Name, location);
+ if (basicType == GL_INT) {
+ const GLint *v = (const GLint *) values;
+ for (i = 0; i < count * elems; i++) {
+ printf("%d ", v[i]);
+ }
+ }
+ else if (basicType == GL_UNSIGNED_INT) {
+ const GLuint *v = (const GLuint *) values;
+ for (i = 0; i < count * elems; i++) {
+ printf("%u ", v[i]);
+ }
+ }
+ else {
+ const GLfloat *v = (const GLfloat *) values;
+ assert(basicType == GL_FLOAT);
+ for (i = 0; i < count * elems; i++) {
+ printf("%g ", v[i]);
+ }
+ }
+ printf("\n");
+ }
+
+ /* 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) {
+ /* convert uniform location to program parameter index */
+ GLint index = uniform->VertPos;
+ if (index >= 0) {
+ set_program_uniform(ctx, &shProg->VertexProgram->Base,
+ index, offset, type, count, elems, values);
+ }
+ }
+
+ if (shProg->FragmentProgram) {
+ /* convert uniform location to program parameter index */
+ GLint index = uniform->FragPos;
+ if (index >= 0) {
+ set_program_uniform(ctx, &shProg->FragmentProgram->Base,
+ index, offset, type, count, elems, values);
+ }
+ }
+
+ if (shProg->GeometryProgram) {
+ /* convert uniform location to program parameter index */
+ GLint index = uniform->GeomPos;
+ if (index >= 0) {
+ set_program_uniform(ctx, &shProg->GeometryProgram->Base,
+ index, offset, type, count, elems, values);
+ }
+ }
+
+ uniform->Initialized = GL_TRUE;
+}
+
+
+/**
+ * Set a matrix-valued program parameter.
+ */
+static void
+set_program_uniform_matrix(struct gl_context *ctx, struct gl_program *program,
+ GLuint index, GLuint offset,
+ GLuint count, GLuint rows, GLuint cols,
+ GLboolean transpose, const GLfloat *values)
+{
+ GLuint mat, row, col;
+ GLuint src = 0;
+ const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
+ const GLuint slots = (param->Size + 3) / 4;
+ const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
+ GLint nr, nc;
+
+ /* check that the number of rows, columns is correct */
+ get_matrix_dims(param->DataType, &nr, &nc);
+ if (rows != nr || cols != nc) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUniformMatrix(matrix size mismatch)");
+ return;
+ }
+
+ if ((GLint) param->Size <= typeSize) {
+ /* non-array: count must be at most one; count == 0 is handled by the loop below */
+ if (count > 1) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glUniformMatrix(uniform is not an array)");
+ return;
+ }
+ }
+
+ /*
+ * Note: the _columns_ of a matrix are stored in program registers, not
+ * the rows. So, the loops below look a little funny.
+ * XXX could optimize this a bit...
+ */
+
+ /* loop over matrices */
+ for (mat = 0; mat < count; mat++) {
+
+ /* each matrix: */
+ for (col = 0; col < cols; col++) {
+ GLfloat *v;
+ if (offset >= slots) {
+ /* Ignore writes beyond the end of (the used part of) an array */
+ return;
+ }
+ v = program->Parameters->ParameterValues[index + offset];
+ for (row = 0; row < rows; row++) {
+ if (transpose) {
+ v[row] = values[src + row * cols + col];
+ }
+ else {
+ v[row] = values[src + col * rows + row];
+ }
+ }
+
+ offset++;
+ }
+
+ src += rows * cols; /* next matrix */
+ }
+}
+
+
+/**
+ * Called by glUniformMatrix*() functions.
+ * Note: cols=2, rows=4 ==> array[2] of vec4
+ */
+void
+_mesa_uniform_matrix(struct gl_context *ctx, struct gl_shader_program *shProg,
+ GLint cols, GLint rows,
+ GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *values)
+{
+ struct gl_uniform *uniform;
+ GLint offset;
+
+ 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 */
+
+ if (location < -1) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
+ return;
+ }
+
+ split_location_offset(&location, &offset);
+
+ if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
+ return;
+ }
+ if (values == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
+
+ uniform = &shProg->Uniforms->Uniforms[location];
+
+ if (shProg->VertexProgram) {
+ /* convert uniform location to program parameter index */
+ GLint index = uniform->VertPos;
+ if (index >= 0) {
+ set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
+ index, offset,
+ count, rows, cols, transpose, values);
+ }
+ }
+
+ if (shProg->FragmentProgram) {
+ /* convert uniform location to program parameter index */
+ GLint index = uniform->FragPos;
+ if (index >= 0) {
+ set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
+ index, offset,
+ count, rows, cols, transpose, values);
+ }
+ }
+
+ if (shProg->GeometryProgram) {
+ /* convert uniform location to program parameter index */
+ GLint index = uniform->GeomPos;
+ if (index >= 0) {
+ set_program_uniform_matrix(ctx, &shProg->GeometryProgram->Base,
+ index, offset,
+ count, rows, cols, transpose, values);
+ }
+ }
+
+ uniform->Initialized = GL_TRUE;
+}
+
+
+void GLAPIENTRY
+_mesa_Uniform1fARB(GLint location, GLfloat v0)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_FLOAT);
+}
+
+void GLAPIENTRY
+_mesa_Uniform2fARB(GLint location, GLfloat v0, GLfloat v1)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat v[2];
+ v[0] = v0;
+ v[1] = v1;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC2);
+}
+
+void GLAPIENTRY
+_mesa_Uniform3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat v[3];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC3);
+}
+
+void GLAPIENTRY
+_mesa_Uniform4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2,
+ GLfloat v3)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat v[4];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_FLOAT_VEC4);
+}
+
+void GLAPIENTRY
+_mesa_Uniform1iARB(GLint location, GLint v0)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_INT);
+}
+
+void GLAPIENTRY
+_mesa_Uniform2iARB(GLint location, GLint v0, GLint v1)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint v[2];
+ v[0] = v0;
+ v[1] = v1;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC2);
+}
+
+void GLAPIENTRY
+_mesa_Uniform3iARB(GLint location, GLint v0, GLint v1, GLint v2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint v[3];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC3);
+}
+
+void GLAPIENTRY
+_mesa_Uniform4iARB(GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint v[4];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_INT_VEC4);
+}
+
+void GLAPIENTRY
+_mesa_Uniform1fvARB(GLint location, GLsizei count, const GLfloat * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT);
+}
+
+void GLAPIENTRY
+_mesa_Uniform2fvARB(GLint location, GLsizei count, const GLfloat * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC2);
+}
+
+void GLAPIENTRY
+_mesa_Uniform3fvARB(GLint location, GLsizei count, const GLfloat * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC3);
+}
+
+void GLAPIENTRY
+_mesa_Uniform4fvARB(GLint location, GLsizei count, const GLfloat * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_FLOAT_VEC4);
+}
+
+void GLAPIENTRY
+_mesa_Uniform1ivARB(GLint location, GLsizei count, const GLint * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT);
+}
+
+void GLAPIENTRY
+_mesa_Uniform2ivARB(GLint location, GLsizei count, const GLint * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC2);
+}
+
+void GLAPIENTRY
+_mesa_Uniform3ivARB(GLint location, GLsizei count, const GLint * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC3);
+}
+
+void GLAPIENTRY
+_mesa_Uniform4ivARB(GLint location, GLsizei count, const GLint * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_INT_VEC4);
+}
+
+
+/** OpenGL 3.0 GLuint-valued functions **/
+void GLAPIENTRY
+_mesa_Uniform1ui(GLint location, GLuint v0)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, &v0, GL_UNSIGNED_INT);
+}
+
+void GLAPIENTRY
+_mesa_Uniform2ui(GLint location, GLuint v0, GLuint v1)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint v[2];
+ v[0] = v0;
+ v[1] = v1;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC2);
+}
+
+void GLAPIENTRY
+_mesa_Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint v[3];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC3);
+}
+
+void GLAPIENTRY
+_mesa_Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint v[4];
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, 1, v, GL_UNSIGNED_INT_VEC4);
+}
+
+void GLAPIENTRY
+_mesa_Uniform1uiv(GLint location, GLsizei count, const GLuint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT);
+}
+
+void GLAPIENTRY
+_mesa_Uniform2uiv(GLint location, GLsizei count, const GLuint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC2);
+}
+
+void GLAPIENTRY
+_mesa_Uniform3uiv(GLint location, GLsizei count, const GLuint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC3);
+}
+
+void GLAPIENTRY
+_mesa_Uniform4uiv(GLint location, GLsizei count, const GLuint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform(ctx, ctx->Shader.ActiveProgram, location, count, value, GL_UNSIGNED_INT_VEC4);
+}
+
+
+
+void GLAPIENTRY
+_mesa_UniformMatrix2fvARB(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 2, 2, location, count, transpose, value);
+}
+
+void GLAPIENTRY
+_mesa_UniformMatrix3fvARB(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 3, 3, location, count, transpose, value);
+}
+
+void GLAPIENTRY
+_mesa_UniformMatrix4fvARB(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat * value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 4, 4, location, count, transpose, value);
+}
+
+
+/**
+ * Non-square UniformMatrix are OpenGL 2.1
+ */
+void GLAPIENTRY
+_mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 2, 3, location, count, transpose, value);
+}
+
+void GLAPIENTRY
+_mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 3, 2, location, count, transpose, value);
+}
+
+void GLAPIENTRY
+_mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 2, 4, location, count, transpose, value);
+}
+
+void GLAPIENTRY
+_mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 4, 2, location, count, transpose, value);
+}
+
+void GLAPIENTRY
+_mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 3, 4, location, count, transpose, value);
+}
+
+void GLAPIENTRY
+_mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_uniform_matrix(ctx, ctx->Shader.ActiveProgram,
+ 4, 3, location, count, transpose, value);
+}
+
+
+void GLAPIENTRY
+_mesa_GetUniformfvARB(GLhandleARB program, GLint location, GLfloat *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_get_uniformfv(ctx, program, location, params);
+}
+
+
+void GLAPIENTRY
+_mesa_GetUniformivARB(GLhandleARB program, GLint location, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_get_uniformiv(ctx, program, location, params);
+}
+
+
+/* GL3 */
+void GLAPIENTRY
+_mesa_GetUniformuiv(GLhandleARB program, GLint location, GLuint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_get_uniformuiv(ctx, program, location, params);
+}
+
+
+
+GLint GLAPIENTRY
+_mesa_GetUniformLocationARB(GLhandleARB programObj, const GLcharARB *name)
+{
+ struct gl_shader_program *shProg;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ shProg = _mesa_lookup_shader_program_err(ctx, programObj,
+ "glGetUniformLocation");
+ if (!shProg)
+ return -1;
+
+ return _mesa_get_uniform_location(ctx, shProg, name);
+}
+
+
+void GLAPIENTRY
+_mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
+ GLsizei maxLength, GLsizei * length, GLint * size,
+ GLenum * type, GLcharARB * name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_get_active_uniform(ctx, program, index, maxLength, length, size,
+ type, name);
+}
+
+
+/**
+ * Plug in shader uniform-related functions into API dispatch table.
+ */
+void
+_mesa_init_shader_uniform_dispatch(struct _glapi_table *exec)
+{
+#if FEATURE_GL
+ SET_Uniform1fARB(exec, _mesa_Uniform1fARB);
+ SET_Uniform2fARB(exec, _mesa_Uniform2fARB);
+ SET_Uniform3fARB(exec, _mesa_Uniform3fARB);
+ SET_Uniform4fARB(exec, _mesa_Uniform4fARB);
+ SET_Uniform1iARB(exec, _mesa_Uniform1iARB);
+ SET_Uniform2iARB(exec, _mesa_Uniform2iARB);
+ SET_Uniform3iARB(exec, _mesa_Uniform3iARB);
+ SET_Uniform4iARB(exec, _mesa_Uniform4iARB);
+ SET_Uniform1fvARB(exec, _mesa_Uniform1fvARB);
+ SET_Uniform2fvARB(exec, _mesa_Uniform2fvARB);
+ SET_Uniform3fvARB(exec, _mesa_Uniform3fvARB);
+ SET_Uniform4fvARB(exec, _mesa_Uniform4fvARB);
+ SET_Uniform1ivARB(exec, _mesa_Uniform1ivARB);
+ SET_Uniform2ivARB(exec, _mesa_Uniform2ivARB);
+ SET_Uniform3ivARB(exec, _mesa_Uniform3ivARB);
+ SET_Uniform4ivARB(exec, _mesa_Uniform4ivARB);
+ SET_UniformMatrix2fvARB(exec, _mesa_UniformMatrix2fvARB);
+ SET_UniformMatrix3fvARB(exec, _mesa_UniformMatrix3fvARB);
+ SET_UniformMatrix4fvARB(exec, _mesa_UniformMatrix4fvARB);
+
+ SET_GetActiveUniformARB(exec, _mesa_GetActiveUniformARB);
+ SET_GetUniformLocationARB(exec, _mesa_GetUniformLocationARB);
+ SET_GetUniformfvARB(exec, _mesa_GetUniformfvARB);
+ SET_GetUniformivARB(exec, _mesa_GetUniformivARB);
+
+ /* OpenGL 2.1 */
+ SET_UniformMatrix2x3fv(exec, _mesa_UniformMatrix2x3fv);
+ SET_UniformMatrix3x2fv(exec, _mesa_UniformMatrix3x2fv);
+ SET_UniformMatrix2x4fv(exec, _mesa_UniformMatrix2x4fv);
+ SET_UniformMatrix4x2fv(exec, _mesa_UniformMatrix4x2fv);
+ SET_UniformMatrix3x4fv(exec, _mesa_UniformMatrix3x4fv);
+ SET_UniformMatrix4x3fv(exec, _mesa_UniformMatrix4x3fv);
+
+ /* OpenGL 3.0 */
+ /* XXX finish dispatch */
+ SET_Uniform1uiEXT(exec, _mesa_Uniform1ui);
+ SET_Uniform2uiEXT(exec, _mesa_Uniform2ui);
+ SET_Uniform3uiEXT(exec, _mesa_Uniform3ui);
+ SET_Uniform4uiEXT(exec, _mesa_Uniform4ui);
+ SET_Uniform1uivEXT(exec, _mesa_Uniform1uiv);
+ SET_Uniform2uivEXT(exec, _mesa_Uniform2uiv);
+ SET_Uniform3uivEXT(exec, _mesa_Uniform3uiv);
+ SET_Uniform4uivEXT(exec, _mesa_Uniform4uiv);
+ SET_GetUniformuivEXT(exec, _mesa_GetUniformuiv);
+
+
+#endif /* FEATURE_GL */
+}