Runtime generate sse/sse2 code for some vertex programs. Experimental

and only active when _TNL_FIXED_FUNCTION_PROGRAM is defined *and*
the MESA_EXPERIMENTAL environment variable is set...
Works for the arbfplight demo at least.
This commit is contained in:
Keith Whitwell
2005-06-08 22:10:16 +00:00
parent 002d0ad3e9
commit ea93b2986b
3 changed files with 973 additions and 79 deletions

View File

@@ -26,7 +26,7 @@
* \file t_arb_program.c * \file t_arb_program.c
* Compile vertex programs to an intermediate representation. * Compile vertex programs to an intermediate representation.
* Execute vertex programs over a buffer of vertices. * Execute vertex programs over a buffer of vertices.
* \author Keith Whitwell, Brian Paul * \author Keith Whitwell
*/ */
#include "glheader.h" #include "glheader.h"
@@ -53,6 +53,12 @@ struct opcode_info {
void (*print)( union instruction , const struct opcode_info * ); void (*print)( union instruction , const struct opcode_info * );
}; };
struct compilation {
GLuint reg_active;
union instruction *csr;
struct vertex_buffer *VB; /* for input sizes! */
};
#define ARB_VP_MACHINE(stage) ((struct arb_vp_machine *)(stage->privatePtr)) #define ARB_VP_MACHINE(stage) ((struct arb_vp_machine *)(stage->privatePtr))
@@ -117,7 +123,7 @@ static GLfloat RoughApproxPower(GLfloat x, GLfloat y)
*/ */
static void do_RSW( struct arb_vp_machine *m, union instruction op ) static void do_RSW( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.rsw.dst]; GLfloat *result = m->File[0][op.rsw.dst];
const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0]; const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0];
GLuint swz = op.rsw.swz; GLuint swz = op.rsw.swz;
GLuint neg = op.rsw.neg; GLuint neg = op.rsw.neg;
@@ -147,7 +153,7 @@ static void do_RSW( struct arb_vp_machine *m, union instruction op )
*/ */
static void do_MSK( struct arb_vp_machine *m, union instruction op ) static void do_MSK( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *dst = m->reg[op.msk.dst]; GLfloat *dst = m->File[0][op.msk.dst];
const GLfloat *arg = m->File[op.msk.file][op.msk.idx]; const GLfloat *arg = m->File[op.msk.file][op.msk.idx];
if (op.msk.mask & 0x1) dst[0] = arg[0]; if (op.msk.mask & 0x1) dst[0] = arg[0];
@@ -173,7 +179,7 @@ static void do_PRT( struct arb_vp_machine *m, union instruction op )
static void do_ABS( struct arb_vp_machine *m, union instruction op ) static void do_ABS( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
result[0] = (arg0[0] < 0.0) ? -arg0[0] : arg0[0]; result[0] = (arg0[0] < 0.0) ? -arg0[0] : arg0[0];
@@ -184,7 +190,7 @@ static void do_ABS( struct arb_vp_machine *m, union instruction op )
static void do_ADD( struct arb_vp_machine *m, union instruction op ) static void do_ADD( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -197,7 +203,7 @@ static void do_ADD( struct arb_vp_machine *m, union instruction op )
static void do_DP3( struct arb_vp_machine *m, union instruction op ) static void do_DP3( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -212,7 +218,7 @@ static void do_DP3( struct arb_vp_machine *m, union instruction op )
static void do_DP4( struct arb_vp_machine *m, union instruction op ) static void do_DP4( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -226,7 +232,7 @@ static void do_DP4( struct arb_vp_machine *m, union instruction op )
static void do_DPH( struct arb_vp_machine *m, union instruction op ) static void do_DPH( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -240,7 +246,7 @@ static void do_DPH( struct arb_vp_machine *m, union instruction op )
static void do_DST( struct arb_vp_machine *m, union instruction op ) static void do_DST( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -253,7 +259,7 @@ static void do_DST( struct arb_vp_machine *m, union instruction op )
static void do_EX2( struct arb_vp_machine *m, union instruction op ) static void do_EX2( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
result[0] = (GLfloat)RoughApproxPow2(arg0[0]); result[0] = (GLfloat)RoughApproxPow2(arg0[0]);
@@ -262,7 +268,7 @@ static void do_EX2( struct arb_vp_machine *m, union instruction op )
static void do_EXP( struct arb_vp_machine *m, union instruction op ) static void do_EXP( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
GLfloat tmp = arg0[0]; GLfloat tmp = arg0[0];
GLfloat flr_tmp = FLOORF(tmp); GLfloat flr_tmp = FLOORF(tmp);
@@ -278,7 +284,7 @@ static void do_EXP( struct arb_vp_machine *m, union instruction op )
static void do_FLR( struct arb_vp_machine *m, union instruction op ) static void do_FLR( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
result[0] = FLOORF(arg0[0]); result[0] = FLOORF(arg0[0]);
@@ -289,7 +295,7 @@ static void do_FLR( struct arb_vp_machine *m, union instruction op )
static void do_FRC( struct arb_vp_machine *m, union instruction op ) static void do_FRC( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
result[0] = arg0[0] - FLOORF(arg0[0]); result[0] = arg0[0] - FLOORF(arg0[0]);
@@ -300,7 +306,7 @@ static void do_FRC( struct arb_vp_machine *m, union instruction op )
static void do_LG2( struct arb_vp_machine *m, union instruction op ) static void do_LG2( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
result[0] = RoughApproxLog2(arg0[0]); result[0] = RoughApproxLog2(arg0[0]);
@@ -311,7 +317,7 @@ static void do_LG2( struct arb_vp_machine *m, union instruction op )
static void do_LIT( struct arb_vp_machine *m, union instruction op ) static void do_LIT( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat epsilon = 1.0F / 256.0F; /* per NV spec */ const GLfloat epsilon = 1.0F / 256.0F; /* per NV spec */
@@ -330,7 +336,7 @@ static void do_LIT( struct arb_vp_machine *m, union instruction op )
static void do_LOG( struct arb_vp_machine *m, union instruction op ) static void do_LOG( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
GLfloat tmp = FABSF(arg0[0]); GLfloat tmp = FABSF(arg0[0]);
int exponent; int exponent;
@@ -344,7 +350,7 @@ static void do_LOG( struct arb_vp_machine *m, union instruction op )
static void do_MAX( struct arb_vp_machine *m, union instruction op ) static void do_MAX( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -357,7 +363,7 @@ static void do_MAX( struct arb_vp_machine *m, union instruction op )
static void do_MIN( struct arb_vp_machine *m, union instruction op ) static void do_MIN( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -369,7 +375,7 @@ static void do_MIN( struct arb_vp_machine *m, union instruction op )
static void do_MOV( struct arb_vp_machine *m, union instruction op ) static void do_MOV( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
result[0] = arg0[0]; result[0] = arg0[0];
@@ -380,7 +386,7 @@ static void do_MOV( struct arb_vp_machine *m, union instruction op )
static void do_MUL( struct arb_vp_machine *m, union instruction op ) static void do_MUL( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -393,7 +399,7 @@ static void do_MUL( struct arb_vp_machine *m, union instruction op )
static void do_POW( struct arb_vp_machine *m, union instruction op ) static void do_POW( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -403,8 +409,8 @@ static void do_POW( struct arb_vp_machine *m, union instruction op )
static void do_REL( struct arb_vp_machine *m, union instruction op ) static void do_REL( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
GLuint idx = (op.alu.idx0 + (GLint)m->reg[REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1); GLuint idx = (op.alu.idx0 + (GLint)m->File[0][REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1);
const GLfloat *arg0 = m->File[op.alu.file0][idx]; const GLfloat *arg0 = m->File[op.alu.file0][idx];
result[0] = arg0[0]; result[0] = arg0[0];
@@ -415,7 +421,7 @@ static void do_REL( struct arb_vp_machine *m, union instruction op )
static void do_RCP( struct arb_vp_machine *m, union instruction op ) static void do_RCP( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
result[0] = 1.0F / arg0[0]; result[0] = 1.0F / arg0[0];
@@ -424,7 +430,7 @@ static void do_RCP( struct arb_vp_machine *m, union instruction op )
static void do_RSQ( struct arb_vp_machine *m, union instruction op ) static void do_RSQ( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
result[0] = INV_SQRTF(FABSF(arg0[0])); result[0] = INV_SQRTF(FABSF(arg0[0]));
@@ -434,7 +440,7 @@ static void do_RSQ( struct arb_vp_machine *m, union instruction op )
static void do_SGE( struct arb_vp_machine *m, union instruction op ) static void do_SGE( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -447,7 +453,7 @@ static void do_SGE( struct arb_vp_machine *m, union instruction op )
static void do_SLT( struct arb_vp_machine *m, union instruction op ) static void do_SLT( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -459,7 +465,7 @@ static void do_SLT( struct arb_vp_machine *m, union instruction op )
static void do_SUB( struct arb_vp_machine *m, union instruction op ) static void do_SUB( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -472,7 +478,7 @@ static void do_SUB( struct arb_vp_machine *m, union instruction op )
static void do_XPD( struct arb_vp_machine *m, union instruction op ) static void do_XPD( struct arb_vp_machine *m, union instruction op )
{ {
GLfloat *result = m->reg[op.alu.dst]; GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
@@ -618,6 +624,12 @@ static const struct opcode_info opcode_info[] =
{ 1, "REL", print_ALU }, { 1, "REL", print_ALU },
}; };
void _tnl_disassem_vba_insn( union instruction op )
{
const struct opcode_info *info = &opcode_info[op.alu.opcode];
info->print( op, info );
}
static void (* const opcode_func[])(struct arb_vp_machine *, union instruction) = static void (* const opcode_func[])(struct arb_vp_machine *, union instruction) =
{ {
@@ -1006,12 +1018,18 @@ static void compile_vertex_program( struct arb_vp_machine *m,
*/ */
if (DISASSEM) { if (DISASSEM) {
for (i = 0; i < m->nr_instructions; i++) { for (i = 0; i < m->nr_instructions; i++) {
union instruction insn = m->instructions[i]; _tnl_disassem_vba_insn(m->instructions[i]);
const struct opcode_info *info = &opcode_info[insn.alu.opcode];
info->print( insn, info );
} }
_mesa_printf("\n\n"); _mesa_printf("\n\n");
} }
#ifdef USE_SSE_ASM
/* TODO: check if anything changed...
*/
if (m->try_codegen)
_tnl_sse_codegen_vertex_program(m);
#endif
} }
@@ -1120,7 +1138,10 @@ static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
} }
static void call_func( struct arb_vp_machine *m )
{
m->func(m);
}
/** /**
* Execute the given vertex program. * Execute the given vertex program.
@@ -1148,7 +1169,7 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
/* Initialize regs where necessary: /* Initialize regs where necessary:
*/ */
ASSIGN_4V(m->reg[REG_ID], 0, 0, 0, 1); ASSIGN_4V(m->File[0][REG_ID], 0, 0, 0, 1);
m->nr_inputs = m->nr_outputs = 0; m->nr_inputs = m->nr_outputs = 0;
@@ -1159,7 +1180,7 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
m->input[j].data = m->VB->AttribPtr[i]->data; m->input[j].data = m->VB->AttribPtr[i]->data;
m->input[j].stride = m->VB->AttribPtr[i]->stride; m->input[j].stride = m->VB->AttribPtr[i]->stride;
m->input[j].size = m->VB->AttribPtr[i]->size; m->input[j].size = m->VB->AttribPtr[i]->size;
ASSIGN_4V(m->reg[REG_IN0 + i], 0, 0, 0, 1); ASSIGN_4V(m->File[0][REG_IN0 + i], 0, 0, 0, 1);
} }
} }
@@ -1178,26 +1199,31 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
for (j = 0; j < m->nr_inputs; j++) { for (j = 0; j < m->nr_inputs; j++) {
GLuint idx = REG_IN0 + m->input[j].idx; GLuint idx = REG_IN0 + m->input[j].idx;
switch (m->input[j].size) { switch (m->input[j].size) {
case 4: m->reg[idx][3] = m->input[j].data[3]; case 4: m->File[0][idx][3] = m->input[j].data[3];
case 3: m->reg[idx][2] = m->input[j].data[2]; case 3: m->File[0][idx][2] = m->input[j].data[2];
case 2: m->reg[idx][1] = m->input[j].data[1]; case 2: m->File[0][idx][1] = m->input[j].data[1];
case 1: m->reg[idx][0] = m->input[j].data[0]; case 1: m->File[0][idx][0] = m->input[j].data[0];
} }
STRIDE_F(m->input[j].data, m->input[j].stride); STRIDE_F(m->input[j].data, m->input[j].stride);
} }
for (j = 0; j < m->nr_instructions; j++) { if (m->func) {
union instruction inst = m->instructions[j]; call_func( m );
opcode_func[inst.alu.opcode]( m, inst ); }
else {
for (j = 0; j < m->nr_instructions; j++) {
union instruction inst = m->instructions[j];
opcode_func[inst.alu.opcode]( m, inst );
}
} }
for (j = 0; j < m->nr_outputs; j++) { for (j = 0; j < m->nr_outputs; j++) {
GLuint idx = REG_OUT0 + m->output[j].idx; GLuint idx = REG_OUT0 + m->output[j].idx;
m->output[j].data[0] = m->reg[idx][0]; m->output[j].data[0] = m->File[0][idx][0];
m->output[j].data[1] = m->reg[idx][1]; m->output[j].data[1] = m->File[0][idx][1];
m->output[j].data[2] = m->reg[idx][2]; m->output[j].data[2] = m->File[0][idx][2];
m->output[j].data[3] = m->reg[idx][3]; m->output[j].data[3] = m->File[0][idx][3];
m->output[j].data += 4; m->output[j].data += 4;
} }
} }
@@ -1250,17 +1276,17 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
} }
} }
#if 0 #if 1
for (i = 0; i < VB->Count; i++) { for (i = 0; i < VB->Count; i++) {
printf("Out %d: %f %f %f %f %f %f %f %f\n", i, printf("Out %d: %f %f %f %f %f %f %f %f\n", i,
VEC_ELT(VB->ClipPtr, GLfloat, i)[0], VEC_ELT(VB->ClipPtr, GLfloat, i)[0],
VEC_ELT(VB->ClipPtr, GLfloat, i)[1], VEC_ELT(VB->ClipPtr, GLfloat, i)[1],
VEC_ELT(VB->ClipPtr, GLfloat, i)[2], VEC_ELT(VB->ClipPtr, GLfloat, i)[2],
VEC_ELT(VB->ClipPtr, GLfloat, i)[3], VEC_ELT(VB->ClipPtr, GLfloat, i)[3],
VEC_ELT(VB->ColorPtr[0], GLfloat, i)[0], VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[0],
VEC_ELT(VB->ColorPtr[0], GLfloat, i)[1], VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[1],
VEC_ELT(VB->ColorPtr[0], GLfloat, i)[2], VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[2],
VEC_ELT(VB->ColorPtr[0], GLfloat, i)[3]); VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[3]);
} }
#endif #endif
@@ -1288,7 +1314,6 @@ validate_vertex_program( GLcontext *ctx, struct tnl_pipeline_stage *stage )
/* Grab the state GL state and put into registers: /* Grab the state GL state and put into registers:
*/ */
m->File[FILE_REG] = m->reg;
m->File[FILE_LOCAL_PARAM] = program->Base.LocalParams; m->File[FILE_LOCAL_PARAM] = program->Base.LocalParams;
m->File[FILE_ENV_PARAM] = ctx->VertexProgram.Parameters; m->File[FILE_ENV_PARAM] = ctx->VertexProgram.Parameters;
m->File[FILE_STATE_PARAM] = program->Parameters->ParameterValues; m->File[FILE_STATE_PARAM] = program->Parameters->ParameterValues;
@@ -1324,6 +1349,13 @@ static GLboolean init_vertex_program( GLcontext *ctx,
m->VB = VB; m->VB = VB;
m->ctx = ctx; m->ctx = ctx;
m->File[0] = ALIGN_MALLOC(REG_MAX * sizeof(GLfloat) * 4, 16);
if (_mesa_getenv("MESA_EXPERIMENTAL"))
m->try_codegen = 1;
_mesa_printf("try_codegen %d\n", m->try_codegen);
/* Allocate arrays of vertex output values */ /* Allocate arrays of vertex output values */
for (i = 0; i < VERT_RESULT_MAX; i++) { for (i = 0; i < VERT_RESULT_MAX; i++) {
_mesa_vector4f_alloc( &m->attribs[i], 0, size, 32 ); _mesa_vector4f_alloc( &m->attribs[i], 0, size, 32 );
@@ -1363,6 +1395,7 @@ static void dtr( struct tnl_pipeline_stage *stage )
/* free misc arrays */ /* free misc arrays */
_mesa_vector4f_free( &m->ndcCoords ); _mesa_vector4f_free( &m->ndcCoords );
ALIGN_FREE( m->clipmask ); ALIGN_FREE( m->clipmask );
ALIGN_FREE( m->File[0] );
FREE( m ); FREE( m );
stage->privatePtr = NULL; stage->privatePtr = NULL;

View File

@@ -40,28 +40,11 @@
#define MSK (VP_MAX_OPCODE+1) #define MSK (VP_MAX_OPCODE+1)
#define REL (VP_MAX_OPCODE+2) #define REL (VP_MAX_OPCODE+2)
/* Layout of register file:
0 -- Scratch (Arg0)
1 -- Scratch (Arg1)
2 -- Scratch (Result)
4 -- Program Temporary 0
16 -- Program Temporary 12 (max for NV_VERTEX_PROGRAM)
17 -- Output 0
31 -- Output 15 (max for NV_VERTEX_PROGRAM) (Last writeable register)
32 -- Parameter 0
..
127 -- Parameter 63 (max for NV_VERTEX_PROGRAM)
*/
#define FILE_REG 0 #define FILE_REG 0
#define FILE_LOCAL_PARAM 1 #define FILE_LOCAL_PARAM 1
#define FILE_ENV_PARAM 2 #define FILE_ENV_PARAM 2
#define FILE_STATE_PARAM 3 #define FILE_STATE_PARAM 3
#define REG_ARG0 0 #define REG_ARG0 0
#define REG_ARG1 1 #define REG_ARG1 1
#define REG_ARG2 2 #define REG_ARG2 2
@@ -74,6 +57,10 @@
#define REG_IN0 32 #define REG_IN0 32
#define REG_IN15 47 #define REG_IN15 47
#define REG_ID 48 /* 0,0,0,1 */ #define REG_ID 48 /* 0,0,0,1 */
#define REG_ONES 49 /* 1,1,1,1 */
#define REG_SWZ 50 /* -1,1,0,0 */
#define REG_NEG 51 /* -1,-1,-1,-1 */
#define REG_UNDEF 127 /* special case - never used */
#define REG_MAX 128 #define REG_MAX 128
#define REG_INVALID ~0 #define REG_INVALID ~0
@@ -81,7 +68,6 @@
* following micro-instructions, each representable in a 32 bit packed * following micro-instructions, each representable in a 32 bit packed
* structure. * structure.
*/ */
struct reg { struct reg {
GLuint file:2; GLuint file:2;
GLuint idx:7; GLuint idx:7;
@@ -124,13 +110,6 @@ union instruction {
#define GET_RSW(swz, idx) (((swz) >> ((idx)*2)) & 0x3) #define GET_RSW(swz, idx) (((swz) >> ((idx)*2)) & 0x3)
struct compilation {
GLuint reg_active;
union instruction *csr;
struct vertex_buffer *VB; /* for input sizes! */
};
struct input { struct input {
GLuint idx; GLuint idx;
GLfloat *data; GLfloat *data;
@@ -149,8 +128,7 @@ struct output {
* Private storage for the vertex program pipeline stage. * Private storage for the vertex program pipeline stage.
*/ */
struct arb_vp_machine { struct arb_vp_machine {
GLfloat reg[REG_MAX][4]; /* Program temporaries, inputs and outputs */ GLfloat (*File[4])[4]; /* All values referencable from the program. */
GLfloat (*File[4])[4]; /* All values reference-able from the program. */
GLint AddressReg; GLint AddressReg;
struct input input[16]; struct input input[16];
@@ -170,9 +148,14 @@ struct arb_vp_machine {
GLuint vtx_nr; /**< loop counter */ GLuint vtx_nr; /**< loop counter */
void (*func)( struct arb_vp_machine * ); /**< codegen'd program? */
struct vertex_buffer *VB; struct vertex_buffer *VB;
GLcontext *ctx; GLcontext *ctx;
GLboolean try_codegen;
}; };
void _tnl_disassem_vba_insn( union instruction op );
#endif #endif

View File

@@ -0,0 +1,878 @@
/*
* Mesa 3-D graphics library
* Version: 6.3
*
* Copyright (C) 1999-2004 Brian Paul 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 t_vb_arb_program_sse.c
*
* Translate simplified vertex_program representation to x86/SSE/SSE2
* machine code using mesa's rtasm runtime assembler.
*
* \author Keith Whitwell
*/
#include "glheader.h"
#include "context.h"
#include "imports.h"
#include "macros.h"
#include "mtypes.h"
#include "arbprogparse.h"
#include "program.h"
#include "math/m_matrix.h"
#include "math/m_translate.h"
#include "t_context.h"
#include "t_vb_arbprogram.h"
#if defined(USE_SSE_ASM)
#include "x86/rtasm/x86sse.h"
#include "x86/common_x86_asm.h"
#define X 0
#define Y 1
#define Z 2
#define W 3
/* Reg usage:
*
* EAX - point to 'm->File[0]'
* ECX - point to 'm->File[3]'
* EDX,
* EBX,
* ESP,
* EBP,
* ESI,
* EDI
*/
#define FAIL \
do { \
_mesa_printf("x86 translation failed in %s\n", __FUNCTION__); \
return GL_FALSE; \
} while (0)
struct compilation {
struct x86_function func;
struct arb_vp_machine *m;
GLuint insn_counter;
struct {
GLuint file:2;
GLuint idx:7;
GLuint dirty:1;
GLuint last_used:10;
} xmm[8];
struct {
struct x86_reg base;
} file[4];
GLboolean have_sse2;
};
static INLINE GLboolean eq( struct x86_reg a,
struct x86_reg b )
{
return (a.file == b.file &&
a.idx == b.idx &&
a.mod == b.mod &&
a.disp == b.disp);
}
static struct x86_reg get_reg_ptr(GLuint file,
GLuint idx )
{
struct x86_reg reg;
switch (file) {
case FILE_REG:
reg = x86_make_reg(file_REG32, reg_AX);
assert(idx != REG_UNDEF);
break;
case FILE_STATE_PARAM:
reg = x86_make_reg(file_REG32, reg_CX);
break;
default:
assert(0);
}
return x86_make_disp(reg, 16 * idx);
}
static void spill( struct compilation *cp, GLuint idx )
{
struct x86_reg oldval = get_reg_ptr(cp->xmm[idx].file,
cp->xmm[idx].idx);
assert(cp->xmm[idx].dirty);
sse_movups(&cp->func, oldval, x86_make_reg(file_XMM, idx));
cp->xmm[idx].dirty = 0;
}
static struct x86_reg get_xmm_reg( struct compilation *cp )
{
GLuint i;
GLuint oldest = 0;
for (i = 0; i < 8; i++)
if (cp->xmm[i].last_used < cp->xmm[oldest].last_used)
oldest = i;
/* Need to write out the old value?
*/
if (cp->xmm[oldest].dirty)
spill(cp, oldest);
assert(cp->xmm[oldest].last_used != cp->insn_counter);
cp->xmm[oldest].file = FILE_REG;
cp->xmm[oldest].idx = REG_UNDEF;
cp->xmm[oldest].last_used = cp->insn_counter;
return x86_make_reg(file_XMM, oldest);
}
static struct x86_reg get_dst_reg( struct compilation *cp,
GLuint file, GLuint idx )
{
struct x86_reg reg;
GLuint i;
/* Invalidate any old copy of this register in XMM0-7. Don't reuse
* as this may be one of the arguments.
*/
for (i = 0; i < 8; i++) {
if (cp->xmm[i].file == file && cp->xmm[i].idx == idx) {
cp->xmm[i].file = FILE_REG;
cp->xmm[i].idx = REG_UNDEF;
cp->xmm[i].dirty = 0;
break;
}
}
reg = get_xmm_reg( cp );
cp->xmm[reg.idx].file = file;
cp->xmm[reg.idx].idx = idx;
cp->xmm[reg.idx].dirty = 1;
return reg;
}
/* Return an XMM reg if the argument is resident, otherwise return a
* base+offset pointer to the saved value.
*/
static struct x86_reg get_arg( struct compilation *cp, GLuint file, GLuint idx )
{
GLuint i;
for (i = 0; i < 8; i++) {
if (cp->xmm[i].file == file &&
cp->xmm[i].idx == idx) {
cp->xmm[i].last_used = cp->insn_counter;
return x86_make_reg(file_XMM, i);
}
}
return get_reg_ptr(file, idx);
}
static void emit_pshufd( struct compilation *cp,
struct x86_reg dst,
struct x86_reg arg0,
GLubyte shuf )
{
if (cp->have_sse2) {
sse2_pshufd(&cp->func, dst, arg0, shuf);
cp->func.fn = 0;
}
else {
if (!eq(dst, arg0))
sse_movups(&cp->func, dst, arg0);
sse_shufps(&cp->func, dst, dst, shuf);
}
}
/* Perform a reduced swizzle.
*/
static GLboolean emit_RSW( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.rsw.file0, op.rsw.idx0);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.rsw.dst);
GLuint swz = op.rsw.swz;
GLuint neg = op.rsw.neg;
emit_pshufd(cp, dst, arg0, swz);
if (neg) {
struct x86_reg negs = get_arg(cp, FILE_REG, REG_SWZ);
struct x86_reg tmp = get_xmm_reg(cp);
/* Load 1,-1,0,0
* Use neg as arg to pshufd
* Multiply
*/
emit_pshufd(cp, tmp, negs,
SHUF((neg & 1) ? 1 : 0,
(neg & 2) ? 1 : 0,
(neg & 4) ? 1 : 0,
(neg & 8) ? 1 : 0));
sse_mulps(&cp->func, dst, tmp);
}
return GL_TRUE;
}
/* Used to implement write masking. This and most of the other instructions
* here would be easier to implement if there had been a translation
* to a 2 argument format (dst/arg0, arg1) at the shader level before
* attempting to translate to x86/sse code.
*/
/* Hmm. I went back to MSK from SEL to make things easier -- was that just BS?
*/
static GLboolean emit_MSK( struct compilation *cp, union instruction op )
{
struct x86_reg arg = get_arg(cp, op.msk.file, op.msk.idx);
struct x86_reg dst0 = get_arg(cp, FILE_REG, op.msk.dst);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.msk.dst);
sse_movups(&cp->func, dst, dst0);
switch (op.msk.mask) {
case 0:
return GL_TRUE;
case WRITEMASK_X:
if (arg.file == file_XMM) {
sse_movss(&cp->func, dst, arg);
}
else {
struct x86_reg tmp = get_xmm_reg(cp);
sse_movss(&cp->func, tmp, arg);
sse_movss(&cp->func, dst, tmp);
}
return GL_TRUE;
case WRITEMASK_Y: {
struct x86_reg tmp = get_xmm_reg(cp);
emit_pshufd(cp, dst, dst, SHUF(Y, X, Z, W));
emit_pshufd(cp, tmp, arg, SHUF(Y, X, Z, W));
sse_movss(&cp->func, dst, tmp);
emit_pshufd(cp, dst, dst, SHUF(Y, X, Z, W));
return GL_TRUE;
}
case WRITEMASK_Z: {
struct x86_reg tmp = get_xmm_reg(cp);
emit_pshufd(cp, dst, dst, SHUF(Z, Y, X, W));
emit_pshufd(cp, tmp, arg, SHUF(Z, Y, X, W));
sse_movss(&cp->func, dst, tmp);
emit_pshufd(cp, dst, dst, SHUF(Z, Y, X, W));
return GL_TRUE;
}
case WRITEMASK_W: {
struct x86_reg tmp = get_xmm_reg(cp);
emit_pshufd(cp, dst, dst, SHUF(W, Y, Z, X));
emit_pshufd(cp, tmp, arg, SHUF(W, Y, Z, X));
sse_movss(&cp->func, dst, tmp);
emit_pshufd(cp, dst, dst, SHUF(W, Y, Z, X));
return GL_TRUE;
}
case WRITEMASK_XY:
sse_shufps(&cp->func, dst, arg, SHUF(X, Y, Z, W));
return GL_TRUE;
case WRITEMASK_ZW: {
struct x86_reg tmp = get_xmm_reg(cp);
sse_movups(&cp->func, tmp, dst);
sse_movups(&cp->func, dst, arg);
sse_shufps(&cp->func, dst, tmp, SHUF(X, Y, Z, W));
return GL_TRUE;
}
case WRITEMASK_YZW: {
struct x86_reg tmp = get_xmm_reg(cp);
sse_movss(&cp->func, tmp, dst);
sse_movups(&cp->func, dst, arg);
sse_movss(&cp->func, dst, tmp);
return GL_TRUE;
}
case WRITEMASK_XYZW:
sse_movups(&cp->func, dst, arg);
return GL_TRUE;
default:
FAIL;
}
#if 0
/* The catchall implementation:
*/
/* make full width bitmask in tmp
* dst = ~tmp
* tmp &= arg0
* dst &= arg1
* dst |= tmp
*/
{
struct x86_reg negs = get_arg(cp, FILE_REG, REG_NEGS);
emit_pshufd(cp, tmp, negs,
SHUF((op.msk.mask & 1) ? 2 : 0,
(op.msk.mask & 2) ? 2 : 0,
(op.msk.mask & 4) ? 2 : 0,
(op.msk.mask & 8) ? 2 : 0));
sse_mulps(&cp->func, dst, tmp);
}
return GL_TRUE;
#endif
FAIL;
}
static GLboolean emit_PRT( struct compilation *cp, union instruction op )
{
FAIL;
}
/**
* The traditional instructions. All operate on internal registers
* and ignore write masks and swizzling issues.
*/
static GLboolean emit_ABS( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
struct x86_reg neg = get_reg_ptr(FILE_REG, REG_NEG);
sse_movups(&cp->func, dst, arg0);
sse_mulps(&cp->func, dst, neg);
sse_maxps(&cp->func, dst, arg0);
return GL_TRUE;
}
static GLboolean emit_ADD( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
sse_movups(&cp->func, dst, arg0);
sse_addps(&cp->func, dst, arg1);
return GL_TRUE;
}
/* The dotproduct instructions don't really do that well in sse:
*/
static GLboolean emit_DP3( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
struct x86_reg tmp = get_xmm_reg(cp);
sse_movups(&cp->func, dst, arg0);
sse_mulps(&cp->func, dst, arg1);
/* Now the hard bit: sum the first 3 values:
*/
sse_movhlps(&cp->func, tmp, dst);
sse_addss(&cp->func, dst, tmp); /* a*x+c*z, b*y, ?, ? */
emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
sse_addss(&cp->func, dst, tmp);
sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
return GL_TRUE;
}
static GLboolean emit_DP4( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
struct x86_reg tmp = get_xmm_reg(cp);
sse_movups(&cp->func, dst, arg0);
sse_mulps(&cp->func, dst, arg1);
/* Now the hard bit: sum the values:
*/
sse_movhlps(&cp->func, tmp, dst);
sse_addps(&cp->func, dst, tmp); /* a*x+c*z, b*y+d*w, a*x+c*z, b*y+d*w */
emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
sse_addss(&cp->func, dst, tmp);
sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
return GL_TRUE;
}
static GLboolean emit_DPH( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1); */
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
/* dst[0] = (arg0[0] * arg1[0] + */
/* arg0[1] * arg1[1] + */
/* arg0[2] * arg1[2] + */
/* 1.0 * arg1[3]); */
sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
FAIL;
}
static GLboolean emit_DST( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1); */
/* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
/* dst[0] = 1.0 * 1.0F; */
/* dst[1] = arg0[1] * arg1[1]; */
/* dst[2] = arg0[2] * 1.0; */
/* dst[3] = 1.0 * arg1[3]; */
FAIL;
}
static GLboolean emit_EX2( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
/* dst[0] = (GLfloat)RoughApproxPow2(arg0[0]); */
sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
FAIL;
}
static GLboolean emit_EXP( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
/* GLfloat tmp = arg0[0]; */
/* GLfloat flr_tmp = FLOORF(tmp); */
/* dst[0] = (GLfloat) (1 << (int)flr_tmp); */
/* dst[1] = tmp - flr_tmp; */
/* dst[2] = RoughApproxPow2(tmp); */
/* dst[3] = 1.0F; */
FAIL;
}
static GLboolean emit_FLR( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
/* dst[0] = FLOORF(arg0[0]); */
/* dst[1] = FLOORF(arg0[1]); */
/* dst[2] = FLOORF(arg0[2]); */
/* dst[3] = FLOORF(arg0[3]); */
FAIL;
}
static GLboolean emit_FRC( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
/* dst[0] = arg0[0] - FLOORF(arg0[0]); */
/* dst[1] = arg0[1] - FLOORF(arg0[1]); */
/* dst[2] = arg0[2] - FLOORF(arg0[2]); */
/* dst[3] = arg0[3] - FLOORF(arg0[3]); */
FAIL;
}
static GLboolean emit_LG2( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
/* dst[0] = RoughApproxLog2(arg0[0]); */
/* sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X)); */
FAIL;
}
static GLboolean emit_LIT( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
/* const GLfloat epsilon = 1.0F / 256.0F; */
/* GLfloat tmp[4]; */
/* tmp[0] = MAX2(arg0[0], 0.0F); */
/* tmp[1] = MAX2(arg0[1], 0.0F); */
/* tmp[3] = CLAMP(arg0[3], -(128.0F - epsilon), (128.0F - epsilon)); */
/* dst[0] = 1.0; */
/* dst[1] = tmp[0]; */
/* dst[2] = (tmp[0] > 0.0) ? RoughApproxPower(tmp[1], tmp[3]) : 0.0F; */
/* dst[3] = 1.0; */
FAIL;
}
static GLboolean emit_LOG( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
/* GLfloat tmp = FABSF(arg0[0]); */
/* int exponent; */
/* GLfloat mantissa = FREXPF(tmp, &exponent); */
/* dst[0] = (GLfloat) (exponent - 1); */
/* dst[1] = 2.0 * mantissa; // map [.5, 1) -> [1, 2) */
/* dst[2] = dst[0] + LOG2(dst[1]); */
/* dst[3] = 1.0; */
FAIL;
}
static GLboolean emit_MAX( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
sse_movups(&cp->func, dst, arg0);
sse_maxps(&cp->func, dst, arg1);
return GL_TRUE;
}
static GLboolean emit_MIN( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
sse_movups(&cp->func, dst, arg0);
sse_minps(&cp->func, dst, arg1);
return GL_TRUE;
}
static GLboolean emit_MOV( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
sse_movups(&cp->func, dst, arg0);
return GL_TRUE;
}
static GLboolean emit_MUL( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
sse_movups(&cp->func, dst, arg0);
sse_mulps(&cp->func, dst, arg1);
return GL_TRUE;
}
static GLboolean emit_POW( struct compilation *cp, union instruction op )
{
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0); */
/* struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1); */
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
/* dst[0] = (GLfloat)RoughApproxPower(arg0[0], arg1[0]); */
sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
FAIL;
}
static GLboolean emit_REL( struct compilation *cp, union instruction op )
{
/* GLuint idx = (op.alu.idx0 + (GLint)cp->File[0][REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1); */
/* GLuint idx = 0; */
/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, idx); */
/* struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst); */
/* dst[0] = arg0[0]; */
/* dst[1] = arg0[1]; */
/* dst[2] = arg0[2]; */
/* dst[3] = arg0[3]; */
FAIL;
}
static GLboolean emit_RCP( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
if (cp->have_sse2) {
sse2_rcpss(&cp->func, dst, arg0);
}
else {
struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
sse_movss(&cp->func, dst, ones);
sse_divss(&cp->func, dst, arg0);
}
sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
return GL_TRUE;
}
static GLboolean emit_RSQ( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
sse_rsqrtss(&cp->func, dst, arg0);
sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
return GL_TRUE;
}
static GLboolean emit_SGE( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
sse_movups(&cp->func, dst, arg0);
sse_cmpps(&cp->func, dst, arg1, cc_NotLessThan);
sse_andps(&cp->func, dst, ones);
return GL_TRUE;
}
static GLboolean emit_SLT( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
sse_movups(&cp->func, dst, arg0);
sse_cmpps(&cp->func, dst, arg1, cc_LessThan);
sse_andps(&cp->func, dst, ones);
return GL_TRUE;
}
static GLboolean emit_SUB( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
sse_movups(&cp->func, dst, arg0);
sse_subps(&cp->func, dst, arg1);
return GL_TRUE;
}
static GLboolean emit_XPD( struct compilation *cp, union instruction op )
{
struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
struct x86_reg dst = get_dst_reg(cp, FILE_REG, op.alu.dst);
struct x86_reg tmp0 = get_xmm_reg(cp);
struct x86_reg tmp1 = get_xmm_reg(cp);
/* Could avoid tmp0, tmp1 if we overwrote arg0, arg1. Need a way
* to invalidate registers. This will come with better analysis
* (liveness analysis) of the incoming program.
*/
emit_pshufd(cp, dst, arg0, SHUF(Y, Z, X, W));
emit_pshufd(cp, tmp1, arg1, SHUF(Z, X, Y, W));
sse_mulps(&cp->func, dst, tmp1);
emit_pshufd(cp, tmp0, arg0, SHUF(Z, X, Y, W));
emit_pshufd(cp, tmp1, arg1, SHUF(Y, Z, X, W));
sse_mulps(&cp->func, tmp0, tmp1);
sse_subps(&cp->func, dst, tmp0);
/* dst[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1]; */
/* dst[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2]; */
/* dst[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0]; */
/* dst[3] is undef */
return GL_TRUE;
}
static GLboolean emit_NOP( struct compilation *cp, union instruction op )
{
return GL_TRUE;
}
static GLboolean (* const emit_func[])(struct compilation *, union instruction) =
{
emit_ABS,
emit_ADD,
emit_NOP,
emit_DP3,
emit_DP4,
emit_DPH,
emit_DST,
emit_NOP,
emit_EX2,
emit_EXP,
emit_FLR,
emit_FRC,
emit_LG2,
emit_LIT,
emit_LOG,
emit_NOP,
emit_MAX,
emit_MIN,
emit_MOV,
emit_MUL,
emit_POW,
emit_PRT,
emit_NOP,
emit_RCP,
emit_RSQ,
emit_SGE,
emit_SLT,
emit_SUB,
emit_RSW,
emit_XPD,
emit_RSW,
emit_MSK,
emit_REL,
};
static GLint get_offset( const void *a, const void *b )
{
return (const char *)b - (const char *)a;
}
static GLboolean build_vertex_program( struct compilation *cp )
{
GLuint j;
struct x86_reg regEAX = x86_make_reg(file_REG32, reg_AX);
struct x86_reg parmECX = x86_make_reg(file_REG32, reg_CX);
x86_mov(&cp->func, regEAX, x86_fn_arg(&cp->func, 1));
x86_mov(&cp->func, parmECX, regEAX);
x86_mov(&cp->func, regEAX, x86_make_disp(regEAX, get_offset(cp->m, cp->m->File + FILE_REG)));
x86_mov(&cp->func, parmECX, x86_make_disp(parmECX, get_offset(cp->m, cp->m->File + FILE_STATE_PARAM)));
for (j = 0; j < cp->m->nr_instructions; j++) {
union instruction inst = cp->m->instructions[j];
cp->insn_counter = j+1; /* avoid zero */
_mesa_printf("%p: ", cp->func.csr);
_tnl_disassem_vba_insn( inst );
cp->func.fn = NULL;
if (!emit_func[inst.alu.opcode]( cp, inst )) {
return GL_FALSE;
}
}
/* TODO: only for outputs:
*/
for (j = 0; j < 8; j++) {
if (cp->xmm[j].dirty)
spill(cp, j);
}
/* Exit mmx state?
*/
if (cp->func.need_emms)
mmx_emms(&cp->func);
x86_ret(&cp->func);
return GL_TRUE;
}
/**
* Execute the given vertex program.
*
* TODO: Integrate the t_vertex.c code here, to build machine vertices
* directly at this point.
*
* TODO: Eliminate the VB struct entirely and just use
* struct arb_vertex_machine.
*/
GLboolean
_tnl_sse_codegen_vertex_program(struct arb_vp_machine *m)
{
struct compilation cp;
memset(&cp, 0, sizeof(cp));
cp.m = m;
cp.have_sse2 = 1;
if (m->func) {
free((void *)m->func);
m->func = NULL;
}
x86_init_func(&cp.func);
if (!build_vertex_program(&cp)) {
x86_release_func( &cp.func );
return GL_FALSE;
}
m->func = (void (*)(struct arb_vp_machine *))x86_get_func( &cp.func );
return GL_TRUE;
}
#else
GLboolean
_tnl_sse_codegen_vertex_program( GLcontext *ctx )
{
/* Dummy version for when USE_SSE_ASM not defined */
return GL_FALSE;
}
#endif