#include "glheader.h"
#include "context.h"
#include "prog_parameter.h"
#include "prog_statevars.h"
#include "programopt.h"
#include "prog_instruction.h"
void
_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog)
{
struct prog_instruction *newInst;
const GLuint origLen = vprog->Base.NumInstructions;
const GLuint newLen = origLen + 4;
GLuint i;
static const gl_state_index mvpState[4][STATE_LENGTH] = {
{ STATE_MVP_MATRIX, 0, 0, 0, 0 },
{ STATE_MVP_MATRIX, 0, 1, 1, 0 },
{ STATE_MVP_MATRIX, 0, 2, 2, 0 },
{ STATE_MVP_MATRIX, 0, 3, 3, 0 },
};
GLint mvpRef[4];
for (i = 0; i < 4; i++) {
mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
mvpState[i]);
}
newInst = _mesa_alloc_instructions(newLen);
if (!newInst) {
_mesa_error(ctx, GL_OUT_OF_MEMORY,
"glProgramString(inserting position_invariant code)");
return;
}
_mesa_init_instructions(newInst, 4);
for (i = 0; i < 4; i++) {
newInst[i].Opcode = OPCODE_DP4;
newInst[i].DstReg.File = PROGRAM_OUTPUT;
newInst[i].DstReg.Index = VERT_RESULT_HPOS;
newInst[i].DstReg.WriteMask = (WRITEMASK_X << i);
newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR;
newInst[i].SrcReg[0].Index = mvpRef[i];
newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
newInst[i].SrcReg[1].File = PROGRAM_INPUT;
newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS;
newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
}
_mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
_mesa_free(vprog->Base.Instructions);
vprog->Base.Instructions = newInst;
vprog->Base.NumInstructions = newLen;
vprog->Base.InputsRead |= VERT_BIT_POS;
vprog->Base.OutputsWritten |= (1 << VERT_RESULT_HPOS);
}
void
_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog)
{
static const gl_state_index fogPStateOpt[STATE_LENGTH]
= { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 };
static const gl_state_index fogColorState[STATE_LENGTH]
= { STATE_FOG_COLOR, 0, 0, 0, 0};
struct prog_instruction *newInst, *inst;
const GLuint origLen = fprog->Base.NumInstructions;
const GLuint newLen = origLen + 5;
GLuint i;
GLint fogPRefOpt, fogColorRef;
GLuint colorTemp, fogFactorTemp;
if (fprog->FogOption == GL_NONE) {
_mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
" with FogOption == GL_NONE");
return;
}
newInst = _mesa_alloc_instructions(newLen);
if (!newInst) {
_mesa_error(ctx, GL_OUT_OF_MEMORY,
"glProgramString(inserting fog_option code)");
return;
}
_mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen);
fogPRefOpt
= _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt);
fogColorRef
= _mesa_add_state_reference(fprog->Base.Parameters, fogColorState);
colorTemp = fprog->Base.NumTemporaries++;
fogFactorTemp = fprog->Base.NumTemporaries++;
inst = newInst;
for (i = 0; i < fprog->Base.NumInstructions; i++) {
if (inst->Opcode == OPCODE_END)
break;
if (inst->DstReg.File == PROGRAM_OUTPUT &&
inst->DstReg.Index == FRAG_RESULT_COLR) {
inst->DstReg.File = PROGRAM_TEMPORARY;
inst->DstReg.Index = colorTemp;
inst->SaturateMode = SATURATE_ZERO_ONE;
}
inst++;
}
assert(inst->Opcode == OPCODE_END);
_mesa_init_instructions(inst, 5);
if (fprog->FogOption == GL_LINEAR) {
inst->Opcode = OPCODE_MAD;
inst->DstReg.File = PROGRAM_TEMPORARY;
inst->DstReg.Index = fogFactorTemp;
inst->DstReg.WriteMask = WRITEMASK_X;
inst->SrcReg[0].File = PROGRAM_INPUT;
inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC;
inst->SrcReg[0].Swizzle = SWIZZLE_X;
inst->SrcReg[1].File = PROGRAM_STATE_VAR;
inst->SrcReg[1].Index = fogPRefOpt;
inst->SrcReg[1].Swizzle = SWIZZLE_X;
inst->SrcReg[2].File = PROGRAM_STATE_VAR;
inst->SrcReg[2].Index = fogPRefOpt;
inst->SrcReg[2].Swizzle = SWIZZLE_Y;
inst->SaturateMode = SATURATE_ZERO_ONE;
inst++;
}
else {
ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2);
inst->Opcode = OPCODE_MUL;
inst->DstReg.File = PROGRAM_TEMPORARY;
inst->DstReg.Index = fogFactorTemp;
inst->DstReg.WriteMask = WRITEMASK_X;
inst->SrcReg[0].File = PROGRAM_STATE_VAR;
inst->SrcReg[0].Index = fogPRefOpt;
inst->SrcReg[0].Swizzle
= (fprog->FogOption == GL_EXP) ? SWIZZLE_Z : SWIZZLE_W;
inst->SrcReg[1].File = PROGRAM_INPUT;
inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC;
inst->SrcReg[1].Swizzle = SWIZZLE_X;
inst++;
if (fprog->FogOption == GL_EXP2) {
inst->Opcode = OPCODE_MUL;
inst->DstReg.File = PROGRAM_TEMPORARY;
inst->DstReg.Index = fogFactorTemp;
inst->DstReg.WriteMask = WRITEMASK_X;
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
inst->SrcReg[0].Index = fogFactorTemp;
inst->SrcReg[0].Swizzle = SWIZZLE_X;
inst->SrcReg[1].File = PROGRAM_TEMPORARY;
inst->SrcReg[1].Index = fogFactorTemp;
inst->SrcReg[1].Swizzle = SWIZZLE_X;
inst++;
}
inst->Opcode = OPCODE_EX2;
inst->DstReg.File = PROGRAM_TEMPORARY;
inst->DstReg.Index = fogFactorTemp;
inst->DstReg.WriteMask = WRITEMASK_X;
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
inst->SrcReg[0].Index = fogFactorTemp;
inst->SrcReg[0].NegateBase = GL_TRUE;
inst->SrcReg[0].Swizzle = SWIZZLE_X;
inst->SaturateMode = SATURATE_ZERO_ONE;
inst++;
}
inst->Opcode = OPCODE_LRP;
inst->DstReg.File = PROGRAM_OUTPUT;
inst->DstReg.Index = FRAG_RESULT_COLR;
inst->DstReg.WriteMask = WRITEMASK_XYZ;
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
inst->SrcReg[0].Index = fogFactorTemp;
inst->SrcReg[0].Swizzle
= MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X);
inst->SrcReg[1].File = PROGRAM_TEMPORARY;
inst->SrcReg[1].Index = colorTemp;
inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
inst->SrcReg[2].File = PROGRAM_STATE_VAR;
inst->SrcReg[2].Index = fogColorRef;
inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
inst++;
inst->Opcode = OPCODE_MOV;
inst->DstReg.File = PROGRAM_OUTPUT;
inst->DstReg.Index = FRAG_RESULT_COLR;
inst->DstReg.WriteMask = WRITEMASK_W;
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
inst->SrcReg[0].Index = colorTemp;
inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
inst++;
inst->Opcode = OPCODE_END;
inst++;
_mesa_free(fprog->Base.Instructions);
fprog->Base.Instructions = newInst;
fprog->Base.NumInstructions = inst - newInst;
fprog->Base.InputsRead |= FRAG_BIT_FOGC;
}
static GLboolean
is_texture_instruction(const struct prog_instruction *inst)
{
switch (inst->Opcode) {
case OPCODE_TEX:
case OPCODE_TXB:
case OPCODE_TXD:
case OPCODE_TXL:
case OPCODE_TXP:
case OPCODE_TXP_NV:
return GL_TRUE;
default:
return GL_FALSE;
}
}
void
_mesa_count_texture_indirections(struct gl_program *prog)
{
GLuint indirections = 1;
GLbitfield tempsOutput = 0x0;
GLbitfield aluTemps = 0x0;
GLuint i;
for (i = 0; i < prog->NumInstructions; i++) {
const struct prog_instruction *inst = prog->Instructions + i;
if (is_texture_instruction(inst)) {
if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) &&
(tempsOutput & (1 << inst->SrcReg[0].Index))) ||
((inst->Opcode != OPCODE_KIL) &&
(inst->DstReg.File == PROGRAM_TEMPORARY) &&
(aluTemps & (1 << inst->DstReg.Index))))
{
indirections++;
tempsOutput = 0x0;
aluTemps = 0x0;
}
}
else {
GLuint j;
for (j = 0; j < 3; j++) {
if (inst->SrcReg[j].File == PROGRAM_TEMPORARY)
aluTemps |= (1 << inst->SrcReg[j].Index);
}
if (inst->DstReg.File == PROGRAM_TEMPORARY)
aluTemps |= (1 << inst->DstReg.Index);
}
if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY))
tempsOutput |= (1 << inst->DstReg.Index);
}
prog->NumTexIndirections = indirections;
}
void
_mesa_count_texture_instructions(struct gl_program *prog)
{
GLuint i;
prog->NumTexInstructions = 0;
for (i = 0; i < prog->NumInstructions; i++) {
prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i);
}
}