* \author Karl Rasche
*/
+/**
+Notes on program parameters, etc.
+
+The instructions we emit will use six kinds of source registers:
+
+ PROGRAM_INPUT - input registers
+ PROGRAM_TEMPORARY - temp registers
+ PROGRAM_ADDRESS - address/indirect register
+ PROGRAM_SAMPLER - texture sampler
+ PROGRAM_CONSTANT - indexes into program->Parameters, a known constant/literal
+ PROGRAM_STATE_VAR - indexes into program->Parameters, and may actually be:
+ + a state variable, like "state.fog.color", or
+ + a pointer to a "program.local[k]" parameter, or
+ + a pointer to a "program.env[k]" parameter
+
+Basically, all the program.local[] and program.env[] values will get mapped
+into the unified gl_program->Parameters array. This solves the problem of
+having three separate program parameter arrays.
+*/
+
+
#include "main/glheader.h"
#include "main/imports.h"
#include "main/context.h"
#include "shader/grammar/grammar_mesa.h"
#include "arbprogparse.h"
#include "program.h"
+#include "programopt.h"
#include "prog_parameter.h"
#include "prog_statevars.h"
#include "prog_instruction.h"
-
-/* For ARB programs, use the NV instruction limits */
-#define MAX_INSTRUCTIONS MAX2(MAX_NV_FRAGMENT_PROGRAM_INSTRUCTIONS, \
- MAX_NV_VERTEX_PROGRAM_INSTRUCTIONS)
-
-
/**
* This is basically a union of the vertex_program and fragment_program
* structs that we can use to parse the program into
GLint i = parse_integer (inst, Program);
if ((i < 0) || (i >= (int)ctx->Const.MaxDrawBuffers)) {
+ *color = 0;
program_error(ctx, Program->Position, "Invalid draw buffer index");
return 1;
}
/**
+ * Validate the index of a texture coordinate
+ *
* \param coord The texture unit index
* \return 0 on sucess, 1 on error
*/
{
GLint i = parse_integer (inst, Program);
- if ((i < 0) || (i >= (int)ctx->Const.MaxTextureUnits)) {
- program_error(ctx, Program->Position, "Invalid texture unit index");
+ if ((i < 0) || (i >= (int)ctx->Const.MaxTextureCoordUnits)) {
+ program_error(ctx, Program->Position, "Invalid texture coordinate index");
+ return 1;
+ }
+
+ *coord = (GLuint) i;
+ return 0;
+}
+
+
+/**
+ * Validate the index of a texture image unit
+ *
+ * \param coord The texture unit index
+ * \return 0 on sucess, 1 on error
+ */
+static GLuint
+parse_teximage_num (GLcontext * ctx, const GLubyte ** inst,
+ struct arb_program *Program, GLuint * coord)
+{
+ GLint i = parse_integer (inst, Program);
+
+ if ((i < 0) || (i >= (int)ctx->Const.MaxTextureImageUnits)) {
+ program_error(ctx, Program->Position, "Invalid texture image index");
return 1;
}
return 0;
}
+
/**
* \param coord The weight index
* \return 0 on sucess, 1 on error
*/
parse_output_color_num(ctx, inst, Program, &out_color);
ASSERT(out_color < MAX_DRAW_BUFFERS);
- *outputReg = FRAG_RESULT_COLR;
+ *outputReg = FRAG_RESULT_COLOR;
}
else {
/* for vtx programs, this is VERTEX_RESULT_POSITION */
case FRAGMENT_RESULT_DEPTH:
if (Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
/* for frag programs, this is FRAGMENT_RESULT_DEPTH */
- *outputReg = FRAG_RESULT_DEPR;
+ *outputReg = FRAG_RESULT_DEPTH;
}
else {
/* for vtx programs, this is VERTEX_RESULT_COLOR */
if (param_var->param_binding_begin == ~0U)
param_var->param_binding_begin = idx;
param_var->param_binding_length++;
- Program->Base.NumParameters++;
}
}
else {
if (param_var->param_binding_begin == ~0U)
param_var->param_binding_begin = idx;
param_var->param_binding_length++;
- Program->Base.NumParameters++;
}
break;
if (param_var->param_binding_begin == ~0U)
param_var->param_binding_begin = idx;
param_var->param_binding_length++;
- Program->Base.NumParameters++;
/* Check if there is more: 0 -> we're done, else its an integer */
if (**inst) {
idx = _mesa_add_state_reference(Program->Base.Parameters,
state_tokens);
param_var->param_binding_length++;
- Program->Base.NumParameters++;
}
}
else {
const_values, 4);
if (param_var->param_binding_begin == ~0U)
param_var->param_binding_begin = idx;
- param_var->param_binding_type = PROGRAM_CONSTANT;
+ param_var->param_binding_type = PROGRAM_STATE_VAR;
+ /* Note: when we reference this parameter in an instruction later,
+ * we'll check if it's really a constant/immediate and set the
+ * instruction register type appropriately.
+ */
param_var->param_binding_length++;
- Program->Base.NumParameters++;
break;
default:
return 1;
}
+ Program->Base.NumParameters = Program->Base.Parameters->NumParameters;
+
/* Make sure we haven't blown past our parameter limits */
if (((Program->Base.Target == GL_VERTEX_PROGRAM_ARB) &&
- (Program->Base.NumParameters >=
+ (Program->Base.NumParameters >
ctx->Const.VertexProgram.MaxLocalParams))
|| ((Program->Base.Target == GL_FRAGMENT_PROGRAM_ARB)
- && (Program->Base.NumParameters >=
+ && (Program->Base.NumParameters >
ctx->Const.FragmentProgram.MaxLocalParams))) {
program_error(ctx, Program->Position, "Too many parameter variables");
return 1;
static GLuint
parse_masked_dst_reg (GLcontext * ctx, const GLubyte ** inst,
struct var_cache **vc_head, struct arb_program *Program,
- enum register_file *File, GLuint *Index, GLint *WriteMask)
+ gl_register_file *File, GLuint *Index, GLint *WriteMask)
{
GLuint tmp, result;
struct var_cache *dst;
parse_src_reg (GLcontext * ctx, const GLubyte ** inst,
struct var_cache **vc_head,
struct arb_program *Program,
- enum register_file * File, GLint * Index,
+ gl_register_file * File, GLint * Index,
GLboolean *IsRelOffset )
{
struct var_cache *src;
return 1;
}
- *File = (enum register_file) src->param_binding_type;
+ *File = (gl_register_file) src->param_binding_type;
switch (*(*inst)++) {
case ARRAY_INDEX_ABSOLUTE:
if (parse_param_use (ctx, inst, vc_head, Program, &src))
return 1;
- *File = (enum register_file) src->param_binding_type;
+ *File = (gl_register_file) src->param_binding_type;
*Index = src->param_binding_begin;
break;
}
/* XXX: We have to handle offsets someplace in here! -- or are those above? */
case vt_param:
- *File = (enum register_file) src->param_binding_type;
+ *File = (gl_register_file) src->param_binding_type;
*Index = src->param_binding_begin;
break;
return 1;
}
+ if (*File == PROGRAM_STATE_VAR) {
+ gl_register_file file;
+
+ /* If we're referencing the Program->Parameters[] array, check if the
+ * parameter is really a constant/literal. If so, set File to CONSTANT.
+ */
+ assert(*Index < (GLint) Program->Base.Parameters->NumParameters);
+ file = Program->Base.Parameters->Parameters[*Index].Type;
+ if (file == PROGRAM_CONSTANT)
+ *File = PROGRAM_CONSTANT;
+ }
+
/* Add attributes to InputsRead only if they are used the program.
* This avoids the handling of unused ATTRIB declarations in the drivers. */
if (*File == PROGRAM_INPUT)
struct arb_program *program,
struct prog_src_register *reg)
{
- enum register_file file;
+ gl_register_file file;
GLint index;
GLubyte negateMask;
GLubyte swizzle[4];
reg->File = file;
reg->Index = index;
reg->Swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
- reg->NegateBase = negateMask;
+ reg->Negate = negateMask;
reg->RelAddr = isRelOffset;
return 0;
}
struct arb_program *program,
struct prog_src_register *reg)
{
- enum register_file file;
+ gl_register_file file;
GLint index;
GLubyte negateMask;
GLubyte swizzle[4];
reg->File = file;
reg->Index = index;
reg->Swizzle = (swizzle[0] << 0);
- reg->NegateBase = negateMask;
+ reg->Negate = negateMask;
reg->RelAddr = isRelOffset;
return 0;
}
{
GLint mask;
GLuint idx;
- enum register_file file;
+ gl_register_file file;
if (parse_masked_dst_reg (ctx, inst, vc_head, program, &file, &idx, &mask))
return 1;
_mesa_init_instructions(fp, 1);
- /* Record the position in the program string for debugging */
- fp->StringPos = Program->Position;
-
/* OP_ALU_INST or OP_TEX_INST */
instClass = *(*inst)++;
{
GLubyte swizzle[4];
GLubyte negateMask;
- enum register_file file;
+ gl_register_file file;
GLint index;
if (parse_src_reg(ctx, inst, vc_head, Program, &file, &index, &rel))
parse_extended_swizzle_mask(inst, swizzle, &negateMask);
fp->SrcReg[0].File = file;
fp->SrcReg[0].Index = index;
- fp->SrcReg[0].NegateBase = negateMask;
+ fp->SrcReg[0].Negate = negateMask;
fp->SrcReg[0].Swizzle = MAKE_SWIZZLE4(swizzle[0],
swizzle[1],
swizzle[2],
return 1;
/* texImageUnit */
- if (parse_texcoord_num (ctx, inst, Program, &texcoord))
+ if (parse_teximage_num (ctx, inst, Program, &texcoord))
return 1;
fp->TexSrcUnit = texcoord;
break;
}
+ if (shadow_tex)
+ fp->TexShadow = 1;
+
/* Don't test the first time a particular sampler is seen. Each time
* after that, make sure the shadow state is the same.
*/
code = *(*inst)++;
_mesa_init_instructions(vp, 1);
- /* Record the position in the program string for debugging */
- vp->StringPos = Program->Position;
switch (type) {
/* XXX: */
GLubyte swizzle[4];
GLubyte negateMask;
GLboolean relAddr;
- enum register_file file;
+ gl_register_file file;
GLint index;
if (parse_dst_reg(ctx, inst, vc_head, Program, &vp->DstReg))
parse_extended_swizzle_mask (inst, swizzle, &negateMask);
vp->SrcReg[0].File = file;
vp->SrcReg[0].Index = index;
- vp->SrcReg[0].NegateBase = negateMask;
+ vp->SrcReg[0].Negate = negateMask;
vp->SrcReg[0].Swizzle = MAKE_SWIZZLE4(swizzle[0],
swizzle[1],
swizzle[2],
fprintf (stderr, "%s\n",
Program->Base.Parameters->Parameters[a + b].Name);
if (Program->Base.Parameters->Parameters[a + b].Type == PROGRAM_STATE_VAR) {
- const char *s;
+ char *s;
s = _mesa_program_state_string(Program->Base.Parameters->Parameters
[a + b].StateIndexes);
fprintf(stderr, "%s\n", s);
- _mesa_free((char *) s);
+ _mesa_free(s);
}
else
fprintf (stderr, "%f %f %f %f\n",
: ctx->Const.VertexProgram.MaxInstructions;
GLint err = 0;
- ASSERT(MAX_INSTRUCTIONS >= maxInst);
+ ASSERT(MAX_PROGRAM_INSTRUCTIONS >= maxInst);
Program->MajorVersion = (GLuint) * inst++;
Program->MinorVersion = (GLuint) * inst++;
const GLuint numInst = Program->Base.NumInstructions;
_mesa_init_instructions(Program->Base.Instructions + numInst, 1);
Program->Base.Instructions[numInst].Opcode = OPCODE_END;
- /* YYY Wrong Position in program, whatever, at least not random -> crash
- Program->Position = parse_position (&inst);
- */
- Program->Base.Instructions[numInst].StringPos = Program->Position;
}
Program->Base.NumInstructions++;
if (ctx->Extensions.NV_texture_rectangle
&& !enable_ext(ctx, id, "texture_rectangle"))
return GL_FALSE;
- if (ctx->Extensions.ARB_draw_buffers
- && !enable_ext(ctx, id, "draw_buffers"))
+ if (!enable_ext(ctx, id, "draw_buffers"))
return GL_FALSE;
if (ctx->Extensions.MESA_texture_array
&& !enable_ext(ctx, id, "texture_array"))
/* Initialize the arb_program struct */
program->Base.String = strz;
- program->Base.Instructions = _mesa_alloc_instructions(MAX_INSTRUCTIONS);
+ program->Base.Instructions = _mesa_alloc_instructions(MAX_PROGRAM_INSTRUCTIONS);
program->Base.NumInstructions =
program->Base.NumTemporaries =
program->Base.NumParameters =
_mesa_free (parsed);
- /* Reallocate the instruction array from size [MAX_INSTRUCTIONS]
+ /* Reallocate the instruction array from size [MAX_PROGRAM_INSTRUCTIONS]
* to size [ap.Base.NumInstructions].
*/
program->Base.Instructions
= _mesa_realloc_instructions(program->Base.Instructions,
- MAX_INSTRUCTIONS,
+ MAX_PROGRAM_INSTRUCTIONS,
program->Base.NumInstructions);
return !err;
_mesa_free_parameter_list(program->Base.Parameters);
program->Base.Parameters = ap.Base.Parameters;
+ /* Append fog instructions now if the program has "OPTION ARB_fog_exp"
+ * or similar. We used to leave this up to drivers, but it appears
+ * there's no hardware that wants to do fog in a discrete stage separate
+ * from the fragment shader.
+ */
+ if (program->FogOption != GL_NONE) {
+ _mesa_append_fog_code(ctx, program);
+ program->FogOption = GL_NONE;
+ }
+
#if DEBUG_FP
_mesa_printf("____________Fragment program %u ________\n", program->Base.Id);
_mesa_print_program(&program->Base);