Index: src/mesa/drivers/dri/i915/i915_context.h =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/drivers/dri/i915/i915_context.h,v retrieving revision 1.7 diff -u -r1.7 i915_context.h --- src/mesa/drivers/dri/i915/i915_context.h 18 Aug 2006 09:04:48 -0000 1.7 +++ src/mesa/drivers/dri/i915/i915_context.h 15 Sep 2006 18:51:00 -0000 @@ -29,6 +29,7 @@ #define I915CONTEXT_INC #include "intel_context.h" +#include "i915_reg.h" #define I915_FALLBACK_TEXTURE 0x1000 #define I915_FALLBACK_COLORMASK 0x2000 @@ -103,6 +104,8 @@ #define I915_PROGRAM_SIZE 192 +#define I915_MAX_INSN (I915_MAX_TEX_INSN+I915_MAX_ALU_INSN) + /* Hardware version of a parsed fragment program. "Derived" from the * mesa fragment_program struct. @@ -152,7 +155,10 @@ * use. */ - + /* Track which R registers are "live" for each instruction. + * A register is live between the time it's written to and the last time + * it's read. */ + GLuint usedRegs[I915_MAX_INSN]; /* Helpers for i915_fragprog.c: */ Index: src/mesa/drivers/dri/i915/i915_fragprog.c =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/drivers/dri/i915/i915_fragprog.c,v retrieving revision 1.18 diff -u -r1.18 i915_fragprog.c --- src/mesa/drivers/dri/i915/i915_fragprog.c 20 Jul 2006 16:49:57 -0000 1.18 +++ src/mesa/drivers/dri/i915/i915_fragprog.c 15 Sep 2006 18:51:00 -0000 @@ -207,7 +207,7 @@ GLuint coord = src_vector( p, &inst->SrcReg[0], program); \ /* Texel lookup */ \ \ - i915_emit_texld( p, \ + i915_emit_texld( p, inst, \ get_result_vector( p, inst ), \ get_result_flags( inst ), \ sampler, \ @@ -230,7 +230,6 @@ #define EMIT_2ARG_ARITH( OP ) EMIT_ARITH( OP, 2 ) #define EMIT_3ARG_ARITH( OP ) EMIT_ARITH( OP, 3 ) - /* Possible concerns: * * SIN, COS -- could use another taylor step? @@ -246,6 +245,9 @@ { const struct gl_fragment_program *program = p->ctx->FragmentProgram._Current; const struct prog_instruction *inst = program->Base.Instructions; + const struct prog_instruction *instStart = inst; + int nInstr = program->Base.NumInstructions; + GLuint regsUsed = 0xffff0000; /* _mesa_debug_fp_inst(program->Base.NumInstructions, inst); */ @@ -262,6 +264,76 @@ swizzle(tmp,ONE,ZERO,ONE,ONE), 0, 0); return; } + + if (nInstr > I915_MAX_INSN) + { + i915_program_error( p, "Exceeded max instructions" ); + return; + } + inst += nInstr; + /* TODO: consider moving this into core */ + do + { + int opArgs = 0; + + inst--; + nInstr--; + switch (inst->Opcode) + { + case OPCODE_ABS: + case OPCODE_COS: + case OPCODE_EX2: + case OPCODE_FLR: + case OPCODE_FRC: + case OPCODE_KIL: + case OPCODE_LG2: + case OPCODE_LIT: + case OPCODE_MOV: + case OPCODE_RCP: + case OPCODE_RSQ: + case OPCODE_SCS: + case OPCODE_SIN: + case OPCODE_SWZ: + case OPCODE_TEX: + case OPCODE_TXB: + case OPCODE_TXP: + opArgs = 1; + break; + case OPCODE_ADD: + case OPCODE_DP3: + case OPCODE_DP4: + case OPCODE_DPH: + case OPCODE_DST: + case OPCODE_MAX: + case OPCODE_MIN: + case OPCODE_MUL: + case OPCODE_POW: + case OPCODE_SGE: + case OPCODE_SLT: + case OPCODE_SUB: + case OPCODE_XPD: + opArgs = 2; + break; + case OPCODE_CMP: + case OPCODE_LRP: + case OPCODE_MAD: + opArgs = 3; + break; + default: + break; + } + /* Register is written to: unmark as live for this and preceeding ops */ + if (inst->DstReg.File == PROGRAM_TEMPORARY) + regsUsed &= ~(1 << inst->DstReg.Index); + for (int a = 0; a < opArgs; a++) + { + /* Register is read from: mark as live for this and preceeding ops */ + if (inst->SrcReg[a].File == PROGRAM_TEMPORARY) + regsUsed |= 1 << inst->SrcReg[a].Index; + } + p->usedRegs[nInstr] = regsUsed; + } + while (inst > instStart); while (1) { GLuint src0, src1, src2, flags; @@ -410,7 +482,7 @@ src0 = src_vector( p, &inst->SrcReg[0], program); tmp = i915_get_utemp( p ); - i915_emit_texld( p, + i915_emit_texld( p, inst, tmp, A0_DEST_CHANNEL_ALL, /* use a dummy dest reg */ 0, src0, Index: src/mesa/drivers/dri/i915/i915_program.c =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/drivers/dri/i915/i915_program.c,v retrieving revision 1.6 diff -u -r1.6 i915_program.c --- src/mesa/drivers/dri/i915/i915_program.c 18 Aug 2006 09:04:48 -0000 1.6 +++ src/mesa/drivers/dri/i915/i915_program.c 15 Sep 2006 18:51:00 -0000 @@ -38,6 +38,7 @@ #include "i915_context.h" #include "i915_program.h" +#include "program_instruction.h" #define A0_DEST( reg ) (((reg)&UREG_TYPE_NR_MASK)>>UREG_A0_DEST_SHIFT_LEFT) #define D0_DEST( reg ) (((reg)&UREG_TYPE_NR_MASK)>>UREG_A0_DEST_SHIFT_LEFT) @@ -194,7 +195,22 @@ return dest; } +static GLuint get_free_rreg (struct i915_fragment_program *p, + const struct prog_instruction *inst) +{ + const struct gl_fragment_program *program = p->ctx->FragmentProgram._Current; + const struct prog_instruction *instStart = program->Base.Instructions; + int instn = inst - instStart; + int bit = ffs (~p->usedRegs[instn]); + if (!bit) { + i915_program_error(p, "Can't find free R reg"); + return UREG_BAD; + } + return UREG(REG_TYPE_R, bit - 1); +} + GLuint i915_emit_texld( struct i915_fragment_program *p, + const struct prog_instruction *inst, GLuint dest, GLuint destmask, GLuint sampler, @@ -202,19 +218,20 @@ GLuint op ) { if (coord != UREG(GET_UREG_TYPE(coord), GET_UREG_NR(coord))) { - /* No real way to work around this in the general case - need to - * allocate and declare a new temporary register (a utemp won't - * do). Will fallback for now. - */ - i915_program_error(p, "Can't (yet) swizzle TEX arguments"); - return 0; + /* With the help of the "needed registers" table created earlier, pick + * a register we can MOV the swizzled TC to (since TEX doesn't support + * swizzled sources) */ + GLuint swizCoord = get_free_rreg (p, inst); + if (swizCoord == UREG_BAD) return 0; + i915_emit_arith( p, A0_MOV, swizCoord, A0_DEST_CHANNEL_ALL, 0, coord, 0, 0 ); + coord = swizCoord; } /* Don't worry about saturate as we only support */ if (destmask != A0_DEST_CHANNEL_ALL) { GLuint tmp = i915_get_utemp(p); - i915_emit_texld( p, tmp, A0_DEST_CHANNEL_ALL, sampler, coord, op ); + i915_emit_texld( p, inst, tmp, A0_DEST_CHANNEL_ALL, sampler, coord, op ); i915_emit_arith( p, A0_MOV, dest, destmask, 0, tmp, 0, 0 ); return dest; } Index: src/mesa/drivers/dri/i915/i915_program.h =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/drivers/dri/i915/i915_program.h,v retrieving revision 1.3 diff -u -r1.3 i915_program.h --- src/mesa/drivers/dri/i915/i915_program.h 1 Sep 2005 03:32:48 -0000 1.3 +++ src/mesa/drivers/dri/i915/i915_program.h 15 Sep 2006 18:51:00 -0000 @@ -110,6 +110,7 @@ extern GLuint i915_emit_texld( struct i915_fragment_program *p, + const struct prog_instruction *inst, GLuint dest, GLuint destmask, GLuint sampler, Index: src/mesa/drivers/dri/i915/i915_texprog.c =================================================================== RCS file: /cvs/mesa/Mesa/src/mesa/drivers/dri/i915/i915_texprog.c,v retrieving revision 1.6 diff -u -r1.6 i915_texprog.c --- src/mesa/drivers/dri/i915/i915_texprog.c 11 Apr 2006 11:41:11 -0000 1.6 +++ src/mesa/drivers/dri/i915/i915_texprog.c 15 Sep 2006 18:51:01 -0000 @@ -69,7 +69,7 @@ if (p->VB->TexCoordPtr[unit]->size == 4) op = T0_TEXLDP; - p->src_texture = i915_emit_texld( p, tmp, A0_DEST_CHANNEL_ALL, + p->src_texture = i915_emit_texld( p, 0, tmp, A0_DEST_CHANNEL_ALL, sampler, texcoord, op ); }