diff options
author | Brian <brian@yutani.localnet.net> | 2007-04-16 11:03:14 -0600 |
---|---|---|
committer | Brian <brian@yutani.localnet.net> | 2007-04-16 11:03:14 -0600 |
commit | 921b0084198168effa08f688f078249ae29ee6c3 (patch) | |
tree | 7f79b54ab7b11af939a9559b29a680d2d3979888 | |
parent | aa6992a296a51d8a336b88baf9c2a93e0ba5a812 (diff) |
removed unused t_vb_arbprogram stage
-rw-r--r-- | src/mesa/tnl/t_vb_arbprogram.c | 1617 | ||||
-rw-r--r-- | src/mesa/tnl/t_vb_arbprogram.h | 206 | ||||
-rw-r--r-- | src/mesa/tnl/t_vb_arbprogram_sse.c | 1330 |
3 files changed, 0 insertions, 3153 deletions
diff --git a/src/mesa/tnl/t_vb_arbprogram.c b/src/mesa/tnl/t_vb_arbprogram.c deleted file mode 100644 index 58c82cf715..0000000000 --- a/src/mesa/tnl/t_vb_arbprogram.c +++ /dev/null @@ -1,1617 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5.3 - * - * Copyright (C) 1999-2007 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_arb_program.c - * Compile vertex programs to an intermediate representation. - * Execute vertex programs over a buffer of vertices. - * \author Keith Whitwell, Brian Paul - */ - -#include "glheader.h" -#include "context.h" -#include "imports.h" -#include "macros.h" -#include "mtypes.h" -#include "arbprogparse.h" -#include "light.h" -#include "program.h" -#include "prog_instruction.h" -#include "prog_parameter.h" -#include "prog_statevars.h" -#include "programopt.h" -#include "math/m_matrix.h" -#include "t_context.h" -#include "t_pipeline.h" -#include "t_vb_arbprogram.h" -#include "tnl.h" - - -#define DISASSEM 0 - - -struct compilation { - GLuint reg_active; - union instruction *csr; -}; - - -#define ARB_VP_MACHINE(stage) ((struct arb_vp_machine *)(stage->privatePtr)) - -#define PUFF(x) ((x)[1] = (x)[2] = (x)[3] = (x)[0]) - - - -/* Lower precision functions for the EXP, LOG and LIT opcodes. The - * LOG2() implementation is probably not accurate enough, and the - * attempted optimization for Exp2 is definitely not accurate - * enough - it discards all of t's fractional bits! - */ -static GLfloat RoughApproxLog2(GLfloat t) -{ - return LOG2(t); -} - -static GLfloat RoughApproxExp2(GLfloat t) -{ -#if 0 - fi_type fi; - fi.i = (GLint) t; - fi.i = (fi.i << 23) + 0x3f800000; - return fi.f; -#else - return (GLfloat) _mesa_pow(2.0, t); -#endif -} - -static GLfloat RoughApproxPower(GLfloat x, GLfloat y) -{ - if (x == 0.0 && y == 0.0) - return 1.0; /* spec requires this */ - else - return RoughApproxExp2(y * RoughApproxLog2(x)); -} - - -/* Higher precision functions for the EX2, LG2 and POW opcodes: - */ -static GLfloat ApproxLog2(GLfloat t) -{ - return (GLfloat) (LOGF(t) * 1.442695F); -} - -static GLfloat ApproxExp2(GLfloat t) -{ - return (GLfloat) _mesa_pow(2.0, t); -} - -static GLfloat ApproxPower(GLfloat x, GLfloat y) -{ - return (GLfloat) _mesa_pow(x, y); -} - - -/** - * Perform a reduced swizzle: - */ -static void do_RSW( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.rsw.dst]; - const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0]; - const GLuint swz = op.rsw.swz; - const GLuint neg = op.rsw.neg; - GLfloat tmp[4]; - - /* Need a temporary to be correct in the case where result == arg0. - */ - COPY_4V(tmp, arg0); - - result[0] = tmp[GET_SWZ(swz, 0)]; - result[1] = tmp[GET_SWZ(swz, 1)]; - result[2] = tmp[GET_SWZ(swz, 2)]; - result[3] = tmp[GET_SWZ(swz, 3)]; - - if (neg) { - if (neg & 0x1) result[0] = -result[0]; - if (neg & 0x2) result[1] = -result[1]; - if (neg & 0x4) result[2] = -result[2]; - if (neg & 0x8) result[3] = -result[3]; - } -} - -/** - * Perform a full swizzle - */ -static void do_SWZ( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.rsw.dst]; - const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0]; - const GLuint swz = op.rsw.swz; - const GLuint neg = op.rsw.neg; - GLfloat tmp[6]; - tmp[4] = 0.0; - tmp[5] = 1.0; - - /* Need a temporary to be correct in the case where result == arg0. - */ - COPY_4V(tmp, arg0); - - result[0] = tmp[GET_SWZ(swz, 0)]; - result[1] = tmp[GET_SWZ(swz, 1)]; - result[2] = tmp[GET_SWZ(swz, 2)]; - result[3] = tmp[GET_SWZ(swz, 3)]; - - if (neg) { - if (neg & 0x1) result[0] = -result[0]; - if (neg & 0x2) result[1] = -result[1]; - if (neg & 0x4) result[2] = -result[2]; - if (neg & 0x8) result[3] = -result[3]; - } -} - -/* Used to implement write masking. To make things easier for the sse - * generator I've gone back to a 1 argument version of this function - * (dst.msk = arg), rather than the semantically cleaner (dst = SEL - * arg0, arg1, msk) - * - * That means this is the only instruction which doesn't write a full - * 4 dwords out. This would make such a program harder to analyse, - * but it looks like analysis is going to take place on a higher level - * anyway. - */ -static void do_MSK( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *dst = m->File[0][op.msk.dst]; - const GLfloat *arg = m->File[op.msk.file][op.msk.idx]; - - if (op.msk.mask & WRITEMASK_X) dst[0] = arg[0]; - if (op.msk.mask & WRITEMASK_Y) dst[1] = arg[1]; - if (op.msk.mask & WRITEMASK_Z) dst[2] = arg[2]; - if (op.msk.mask & WRITEMASK_W) dst[3] = arg[3]; -} - - -static void do_PRT( struct arb_vp_machine *m, union instruction op ) -{ - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - _mesa_printf("%d: %f %f %f %f\n", m->vtx_nr, - arg0[0], arg0[1], arg0[2], arg0[3]); -} - - -/** - * The traditional ALU and texturing instructions. All operate on - * internal registers and ignore write masks and swizzling issues. - */ - -static void do_ABS( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = (arg0[0] < 0.0) ? -arg0[0] : arg0[0]; - result[1] = (arg0[1] < 0.0) ? -arg0[1] : arg0[1]; - result[2] = (arg0[2] < 0.0) ? -arg0[2] : arg0[2]; - result[3] = (arg0[3] < 0.0) ? -arg0[3] : arg0[3]; -} - -static void do_ADD( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = arg0[0] + arg1[0]; - result[1] = arg0[1] + arg1[1]; - result[2] = arg0[2] + arg1[2]; - result[3] = arg0[3] + arg1[3]; -} - - -static void do_DP3( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = (arg0[0] * arg1[0] + - arg0[1] * arg1[1] + - arg0[2] * arg1[2]); - - PUFF(result); -} - - - -static void do_DP4( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = (arg0[0] * arg1[0] + - arg0[1] * arg1[1] + - arg0[2] * arg1[2] + - arg0[3] * arg1[3]); - - PUFF(result); -} - -static void do_DPH( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = (arg0[0] * arg1[0] + - arg0[1] * arg1[1] + - arg0[2] * arg1[2] + - 1.0 * arg1[3]); - - PUFF(result); -} - -static void do_DST( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - /* This should be ok even if result == arg0 or result == arg1. - */ - result[0] = 1.0F; - result[1] = arg0[1] * arg1[1]; - result[2] = arg0[2]; - result[3] = arg1[3]; -} - - -/* Intended to be high precision: - */ -static void do_EX2( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = ApproxExp2(arg0[0]); - PUFF(result); -} - - -/* Allowed to be lower precision: - */ -static void do_EXP( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat tmp = arg0[0]; - const GLfloat flr_tmp = FLOORF(tmp); - const GLfloat frac_tmp = tmp - flr_tmp; - - result[0] = LDEXPF(1.0, (int)flr_tmp); - result[1] = frac_tmp; - result[2] = RoughApproxExp2(tmp); - result[3] = 1.0F; -} - -static void do_FLR( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = FLOORF(arg0[0]); - result[1] = FLOORF(arg0[1]); - result[2] = FLOORF(arg0[2]); - result[3] = FLOORF(arg0[3]); -} - -static void do_FRC( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = arg0[0] - FLOORF(arg0[0]); - result[1] = arg0[1] - FLOORF(arg0[1]); - result[2] = arg0[2] - FLOORF(arg0[2]); - result[3] = arg0[3] - FLOORF(arg0[3]); -} - -static void do_INT( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = (GLfloat) (GLint) arg0[0]; - result[1] = (GLfloat) (GLint) arg0[1]; - result[2] = (GLfloat) (GLint) arg0[2]; - result[3] = (GLfloat) (GLint) arg0[3]; -} - -/* High precision log base 2: - */ -static void do_LG2( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = ApproxLog2(arg0[0]); - PUFF(result); -} - - - -static void do_LIT( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - GLfloat tmp[4]; /* use temp in case arg0 == result register */ - - tmp[0] = 1.0; - tmp[1] = arg0[0]; - if (arg0[0] > 0.0) { - tmp[2] = RoughApproxPower(arg0[1], arg0[3]); - } - else { - tmp[2] = 0.0; - } - tmp[3] = 1.0; - - COPY_4V(result, tmp); -} - - -/* Intended to allow a lower precision than required for LG2 above. - */ -static void do_LOG( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat tmp = FABSF(arg0[0]); - int exponent; - const GLfloat mantissa = FREXPF(tmp, &exponent); - - result[0] = (GLfloat) (exponent - 1); - result[1] = 2.0 * mantissa; /* map [.5, 1) -> [1, 2) */ - result[2] = exponent + LOG2(mantissa); - result[3] = 1.0; -} - -static void do_MAX( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = (arg0[0] > arg1[0]) ? arg0[0] : arg1[0]; - result[1] = (arg0[1] > arg1[1]) ? arg0[1] : arg1[1]; - result[2] = (arg0[2] > arg1[2]) ? arg0[2] : arg1[2]; - result[3] = (arg0[3] > arg1[3]) ? arg0[3] : arg1[3]; -} - - -static void do_MIN( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = (arg0[0] < arg1[0]) ? arg0[0] : arg1[0]; - result[1] = (arg0[1] < arg1[1]) ? arg0[1] : arg1[1]; - result[2] = (arg0[2] < arg1[2]) ? arg0[2] : arg1[2]; - result[3] = (arg0[3] < arg1[3]) ? arg0[3] : arg1[3]; -} - -static void do_MOV( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = arg0[0]; - result[1] = arg0[1]; - result[2] = arg0[2]; - result[3] = arg0[3]; -} - -static void do_MUL( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = arg0[0] * arg1[0]; - result[1] = arg0[1] * arg1[1]; - result[2] = arg0[2] * arg1[2]; - result[3] = arg0[3] * arg1[3]; -} - - -/* Intended to be "high" precision - */ -static void do_POW( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = (GLfloat)ApproxPower(arg0[0], arg1[0]); - PUFF(result); -} - -static void do_REL( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const 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]; - - result[0] = arg0[0]; - result[1] = arg0[1]; - result[2] = arg0[2]; - result[3] = arg0[3]; -} - -static void do_RCP( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = 1.0F / arg0[0]; - PUFF(result); -} - -static void do_RSQ( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - - result[0] = INV_SQRTF(FABSF(arg0[0])); - PUFF(result); -} - - -static void do_SGE( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = (arg0[0] >= arg1[0]) ? 1.0F : 0.0F; - result[1] = (arg0[1] >= arg1[1]) ? 1.0F : 0.0F; - result[2] = (arg0[2] >= arg1[2]) ? 1.0F : 0.0F; - result[3] = (arg0[3] >= arg1[3]) ? 1.0F : 0.0F; -} - - -static void do_SLT( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = (arg0[0] < arg1[0]) ? 1.0F : 0.0F; - result[1] = (arg0[1] < arg1[1]) ? 1.0F : 0.0F; - result[2] = (arg0[2] < arg1[2]) ? 1.0F : 0.0F; - result[3] = (arg0[3] < arg1[3]) ? 1.0F : 0.0F; -} - -static void do_SUB( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - - result[0] = arg0[0] - arg1[0]; - result[1] = arg0[1] - arg1[1]; - result[2] = arg0[2] - arg1[2]; - result[3] = arg0[3] - arg1[3]; -} - - -static void do_XPD( struct arb_vp_machine *m, union instruction op ) -{ - GLfloat *result = m->File[0][op.alu.dst]; - const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0]; - const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1]; - GLfloat tmp[3]; - - tmp[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1]; - tmp[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2]; - tmp[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0]; - - /* Need a temporary to be correct in the case where result == arg0 - * or result == arg1. - */ - result[0] = tmp[0]; - result[1] = tmp[1]; - result[2] = tmp[2]; -} - -static void do_NOP( struct arb_vp_machine *m, union instruction op ) -{ -} - -/* Some useful debugging functions: - */ -static void print_mask( GLuint mask ) -{ - _mesa_printf("."); - if (mask & WRITEMASK_X) _mesa_printf("x"); - if (mask & WRITEMASK_Y) _mesa_printf("y"); - if (mask & WRITEMASK_Z) _mesa_printf("z"); - if (mask & WRITEMASK_W) _mesa_printf("w"); -} - -static void print_reg( GLuint file, GLuint reg ) -{ - static const char *reg_file[] = { - "REG", - "LOCAL_PARAM", - "ENV_PARAM", - "STATE_VAR", - }; - - if (file == 0) { - if (reg == REG_RES) - _mesa_printf("RES"); - else if (reg >= REG_ARG0 && reg <= REG_ARG1) - _mesa_printf("ARG%d", reg - REG_ARG0); - else if (reg >= REG_TMP0 && reg <= REG_TMP11) - _mesa_printf("TMP%d", reg - REG_TMP0); - else if (reg >= REG_IN0 && reg <= REG_IN31) - _mesa_printf("IN%d", reg - REG_IN0); - else if (reg >= REG_OUT0 && reg <= REG_OUT23) - _mesa_printf("OUT%d", reg - REG_OUT0); - else if (reg == REG_ADDR) - _mesa_printf("ADDR"); - else if (reg == REG_ID) - _mesa_printf("ID"); - else - _mesa_printf("REG%d", reg); - } - else - _mesa_printf("%s:%d", reg_file[file], reg); -} - - -static void print_RSW( union instruction op ) -{ - GLuint swz = op.rsw.swz; - GLuint neg = op.rsw.neg; - GLuint i; - - _mesa_printf("RSW "); - print_reg(0, op.rsw.dst); - _mesa_printf(", "); - print_reg(op.rsw.file0, op.rsw.idx0); - _mesa_printf("."); - for (i = 0; i < 4; i++, swz >>= 3) { - const char *cswz = "xyzw01"; - if (neg & (1<<i)) - _mesa_printf("-"); - _mesa_printf("%c", cswz[swz&0x7]); - } - _mesa_printf("\n"); -} - -static void print_SWZ( union instruction op ) -{ - GLuint swz = op.rsw.swz; - GLuint neg = op.rsw.neg; - GLuint i; - - _mesa_printf("SWZ "); - print_reg(0, op.rsw.dst); - _mesa_printf(", "); - print_reg(op.rsw.file0, op.rsw.idx0); - _mesa_printf("."); - for (i = 0; i < 4; i++, swz >>= 3) { - const char *cswz = "xyzw01"; - if (neg & (1<<i)) - _mesa_printf("-"); - _mesa_printf("%c", cswz[swz&0x7]); - } - _mesa_printf("\n"); -} - - -static void print_ALU( union instruction op ) -{ - _mesa_printf("%s ", _mesa_opcode_string((enum prog_opcode) op.alu.opcode)); - print_reg(0, op.alu.dst); - _mesa_printf(", "); - print_reg(op.alu.file0, op.alu.idx0); - if (_mesa_num_inst_src_regs((enum prog_opcode) op.alu.opcode) > 1) { - _mesa_printf(", "); - print_reg(op.alu.file1, op.alu.idx1); - } - _mesa_printf("\n"); -} - -static void print_MSK( union instruction op ) -{ - _mesa_printf("MSK "); - print_reg(0, op.msk.dst); - print_mask(op.msk.mask); - _mesa_printf(", "); - print_reg(op.msk.file, op.msk.idx); - _mesa_printf("\n"); -} - -static void print_NOP( union instruction op ) -{ -} - -void -_tnl_disassem_vba_insn( union instruction op ) -{ - switch (op.alu.opcode) { - case OPCODE_ABS: - case OPCODE_ADD: - case OPCODE_DP3: - case OPCODE_DP4: - case OPCODE_DPH: - case OPCODE_DST: - case OPCODE_EX2: - case OPCODE_EXP: - case OPCODE_FLR: - case OPCODE_FRC: - case OPCODE_INT: - case OPCODE_LG2: - case OPCODE_LIT: - case OPCODE_LOG: - case OPCODE_MAX: - case OPCODE_MIN: - case OPCODE_MOV: - case OPCODE_MUL: - case OPCODE_POW: - case OPCODE_PRINT: - case OPCODE_RCP: - case OPCODE_RSQ: - case OPCODE_SGE: - case OPCODE_SLT: - case OPCODE_SUB: - case OPCODE_XPD: - print_ALU(op); - break; - case OPCODE_ARA: - case OPCODE_ARL: - case OPCODE_ARL_NV: - case OPCODE_ARR: - case OPCODE_BRA: - case OPCODE_CAL: - case OPCODE_END: - case OPCODE_MAD: - case OPCODE_POPA: - case OPCODE_PUSHA: - case OPCODE_RCC: - case OPCODE_RET: - case OPCODE_SSG: - print_NOP(op); - break; - case OPCODE_SWZ: - print_SWZ(op); - break; - case RSW: - print_RSW(op); - break; - case MSK: - print_MSK(op); - break; - case REL: - print_ALU(op); - break; - default: - _mesa_problem(NULL, "Bad opcode in _tnl_disassem_vba_insn()"); - } -} - -typedef void (*gpu_function)(struct arb_vp_machine *m, union instruction op); - -static gpu_function opcode_func[MAX_OPCODE+3] = -{ - do_NOP, - do_ABS, - do_ADD, - do_NOP,/*ARA*/ - do_NOP,/*ARL*/ - do_NOP,/*ARL_NV*/ - do_NOP,/*ARR*/ - do_NOP,/*BGNLOOP*/ - do_NOP,/*BGNSUB*/ - do_NOP,/*BRA*/ - do_NOP,/*BRK*/ - do_NOP,/*CAL*/ - do_NOP,/*CMP*/ - do_NOP,/*CONT*/ - do_NOP,/*COS*/ - do_NOP,/*DDX*/ - do_NOP,/*DDY*/ - do_DP3, - do_DP4, - do_DPH, - do_DST, - do_NOP,/*ELSE*/ - do_NOP,/*END*/ - do_NOP,/*ENDIF*/ - do_NOP,/*ENDLOOP*/ - do_NOP,/*ENDSUB*/ - do_EX2, - do_EXP, - do_FLR, - do_FRC, - do_NOP,/*IF*/ - do_INT, - do_NOP,/*KIL*/ - do_NOP,/*KIL_NV*/ - do_LG2, - do_LIT, - do_LOG, - do_NOP,/*LRP*/ - do_NOP,/*MAD*/ - do_MAX, - do_MIN, - do_MOV, - do_MUL, - do_NOP,/*NOISE1*/ - do_NOP,/*NOISE2*/ - do_NOP,/*NOISE3*/ - do_NOP,/*NOISE4*/ - do_NOP,/*PK2H*/ - do_NOP,/*PK2US*/ - do_NOP,/*PK4B*/ - do_NOP,/*PK4UB*/ - do_POW, - do_NOP,/*POPA*/ - do_PRT, - do_NOP,/*PUSHA*/ - do_NOP,/*RCC*/ - do_RCP,/*RCP*/ - do_NOP,/*RET*/ - do_NOP,/*RFL*/ - do_RSQ, - do_NOP,/*SCS*/ - do_NOP,/*SEQ*/ - do_NOP,/*SFL*/ - do_SGE, - do_NOP,/*SGT*/ - do_NOP,/*SIN*/ - do_NOP,/*SLE*/ - do_SLT, - do_NOP,/*SNE*/ - do_NOP,/*SSG*/ - do_NOP,/*STR*/ - do_SUB, - do_SWZ,/*SWZ*/ - do_NOP,/*TEX*/ - do_NOP,/*TXB*/ - do_NOP,/*TXD*/ - do_NOP,/*TXL*/ - do_NOP,/*TXP*/ - do_NOP,/*TXP_NV*/ - do_NOP,/*UP2H*/ - do_NOP,/*UP2US*/ - do_NOP,/*UP4B*/ - do_NOP,/*UP4UB*/ - do_NOP,/*X2D*/ - do_XPD, - do_RSW, - do_MSK, - do_REL, -}; - -static union instruction *cvp_next_instruction( struct compilation *cp ) -{ - union instruction *op = cp->csr++; - _mesa_bzero(op, sizeof(*op)); - return op; -} - -static struct reg cvp_make_reg( GLuint file, GLuint idx ) -{ - struct reg reg; - reg.file = file; - reg.idx = idx; - return reg; -} - -static struct reg cvp_emit_rel( struct compilation *cp, - struct reg reg, - struct reg tmpreg ) -{ - union instruction *op = cvp_next_instruction(cp); - op->alu.opcode = REL; - op->alu.file0 = reg.file; - op->alu.idx0 = reg.idx; - op->alu.dst = tmpreg.idx; - return tmpreg; -} - - -static struct reg cvp_load_reg( struct compilation *cp, - GLuint file, - GLuint index, - GLuint rel, - GLuint tmpidx ) -{ - struct reg tmpreg = cvp_make_reg(FILE_REG, tmpidx); - struct reg reg; - - switch (file) { - case PROGRAM_TEMPORARY: - assert(REG_TMP0 + index <= REG_TMP11); - return cvp_make_reg(FILE_REG, REG_TMP0 + index); - - case PROGRAM_INPUT: - return cvp_make_reg(FILE_REG, REG_IN0 + index); - - case PROGRAM_OUTPUT: - return cvp_make_reg(FILE_REG, REG_OUT0 + index); - - /* These two aren't populated by the parser? - */ - case PROGRAM_LOCAL_PARAM: - reg = cvp_make_reg(FILE_LOCAL_PARAM, index); - if (rel) - return cvp_emit_rel(cp, reg, tmpreg); - else - return reg; - - case PROGRAM_ENV_PARAM: - reg = cvp_make_reg(FILE_ENV_PARAM, index); - if (rel) - return cvp_emit_rel(cp, reg, tmpreg); - else - return reg; - - case PROGRAM_STATE_VAR: - case PROGRAM_CONSTANT: - case PROGRAM_UNIFORM: - reg = cvp_make_reg(FILE_STATE_PARAM, index); - if (rel) - return cvp_emit_rel(cp, reg, tmpreg); - else - return reg; - - /* Invalid values: - */ - case PROGRAM_WRITE_ONLY: - case PROGRAM_ADDRESS: - default: - _mesa_problem(NULL, "Invalid register file %d in cvp_load_reg()", file); - assert(0); - return tmpreg; /* can't happen */ - } -} - -static struct reg cvp_emit_arg( struct compilation *cp, - const struct prog_src_register *src, - GLuint arg ) -{ - struct reg reg = cvp_load_reg( cp, src->File, src->Index, src->RelAddr, arg ); - union instruction rsw, noop; - - /* Emit any necessary swizzling. - */ - _mesa_bzero(&rsw, sizeof(rsw)); - rsw.rsw.neg = src->NegateBase ? WRITEMASK_XYZW : 0; - - /* we're expecting 2-bit swizzles below... */ -#if 1 /* XXX THESE ASSERTIONS CURRENTLY FAIL DURING GLEAN TESTS! */ -/* hopefully no longer happens? */ - ASSERT(GET_SWZ(src->Swizzle, 0) < 4); - ASSERT(GET_SWZ(src->Swizzle, 1) < 4); - ASSERT(GET_SWZ(src->Swizzle, 2) < 4); - ASSERT(GET_SWZ(src->Swizzle, 3) < 4); -#endif - rsw.rsw.swz = src->Swizzle; - - _mesa_bzero(&noop, sizeof(noop)); - noop.rsw.neg = 0; - noop.rsw.swz = SWIZZLE_NOOP; - - if (_mesa_memcmp(&rsw, &noop, sizeof(rsw)) !=0) { - union instruction *op = cvp_next_instruction(cp); - struct reg rsw_reg = cvp_make_reg(FILE_REG, REG_ARG0 + arg); - *op = rsw; - op->rsw.opcode = RSW; - op->rsw.file0 = reg.file; - op->rsw.idx0 = reg.idx; - op->rsw.dst = rsw_reg.idx; - return rsw_reg; - } - else - return reg; -} - -static GLuint cvp_choose_result( struct compilation *cp, - const struct prog_dst_register *dst, - union instruction *fixup ) -{ - GLuint mask = dst->WriteMask; - GLuint idx; - - switch (dst->File) { - case PROGRAM_TEMPORARY: - idx = REG_TMP0 + dst->Index; - break; - case PROGRAM_OUTPUT: - idx = REG_OUT0 + dst->Index; - break; - default: -#if 0 - /* IF/ELSE/ENDIF instructions will hit this */ - assert(0); -#endif - return REG_RES; /* can't happen */ - } - - /* Optimization: When writing (with a writemask) to an undefined - * value for the first time, the writemask may be ignored. - */ - if (mask != WRITEMASK_XYZW && (cp->reg_active & (1 << idx))) { - fixup->msk.opcode = MSK; - fixup->msk.dst = idx; - fixup->msk.file = FILE_REG; - fixup->msk.idx = REG_RES; - fixup->msk.mask = mask; - cp->reg_active |= 1 << idx; - return REG_RES; - } - else { - _mesa_bzero(fixup, sizeof(*fixup)); - cp->reg_active |= 1 << idx; - return idx; - } -} - - -static void cvp_emit_inst( struct compilation *cp, - const struct prog_instruction *inst ) -{ - union instruction *op; - union instruction fixup; - struct reg reg[3]; - GLuint result, nr_args, i; - - /* Need to handle SWZ, ARL specially. - */ - switch (inst->Opcode) { - /* Split into mul and add: - */ - case OPCODE_MAD: - result = cvp_choose_result( cp, &inst->DstReg, &fixup ); - for (i = 0; i < 3; i++) - reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0+i ); - - op = cvp_next_instruction(cp); - op->alu.opcode = OPCODE_MUL; - op->alu.file0 = reg[0].file; - op->alu.idx0 = reg[0].idx; - op->alu.file1 = reg[1].file; - op->alu.idx1 = reg[1].idx; - op->alu.dst = REG_ARG0; - - op = cvp_next_instruction(cp); - op->alu.opcode = OPCODE_ADD; - op->alu.file0 = FILE_REG; - op->alu.idx0 = REG_ARG0; - op->alu.file1 = reg[2].file; - op->alu.idx1 = reg[2].idx; - op->alu.dst = result; - - if (result == REG_RES) { - op = cvp_next_instruction(cp); - *op = fixup; - } - break; - - case OPCODE_ARL: - reg[0] = cvp_emit_arg( cp, &inst->SrcReg[0], REG_ARG0 ); - - op = cvp_next_instruction(cp); - op->alu.opcode = OPCODE_FLR; - op->alu.dst = REG_ADDR; - op->alu.file0 = reg[0].file; - op->alu.idx0 = reg[0].idx; - break; - - case OPCODE_END: - break; - - case OPCODE_SWZ: - result = cvp_choose_result( cp, &inst->DstReg, &fixup ); - reg[0] = cvp_load_reg( cp, inst->SrcReg[0].File, - inst->SrcReg[0].Index, inst->SrcReg[0].RelAddr, REG_ARG0 ); - op = cvp_next_instruction(cp); - op->rsw.opcode = inst->Opcode; - op->rsw.file0 = reg[0].file; - op->rsw.idx0 = reg[0].idx; - op->rsw.dst = result; - op->rsw.swz = inst->SrcReg[0].Swizzle; - op->rsw.neg = inst->SrcReg[0].NegateBase; - - if (result == REG_RES) { - op = cvp_next_instruction(cp); - *op = fixup; - } - break; - - case OPCODE_NOP: - break; - - case OPCODE_BRA: - /* XXX implement */ - break; - - default: - result = cvp_choose_result( cp, &inst->DstReg, &fixup ); - nr_args = _mesa_num_inst_src_regs(inst->Opcode); - for (i = 0; i < nr_args; i++) - reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0 + i ); - - op = cvp_next_instruction(cp); - op->alu.opcode = inst->Opcode; - op->alu.file0 = reg[0].file; - op->alu.idx0 = reg[0].idx; - op->alu.file1 = reg[1].file; - op->alu.idx1 = reg[1].idx; - op->alu.dst = result; - - if (result == REG_RES) { - op = cvp_next_instruction(cp); - *op = fixup; - } - break; - } -} - -static void free_tnl_data( struct gl_vertex_program *program ) -{ - struct tnl_compiled_program *p = (struct tnl_compiled_program *) program->TnlData; - if (p->compiled_func) - _mesa_free((void *)p->compiled_func); - _mesa_free(p); - program->TnlData = NULL; -} - -static void compile_vertex_program( struct gl_vertex_program *program, - GLboolean try_codegen ) -{ - struct compilation cp; - struct tnl_compiled_program *p = CALLOC_STRUCT(tnl_compiled_program); - GLint i; - -#if 1 - if (!program->IsNVProgram && program->IsPositionInvariant) { - printf("Adding MVP code\n"); - if (!program->Base.Parameters) - program->Base.Parameters = _mesa_new_parameter_list(); - _mesa_insert_mvp_code(NULL, program); - program->IsPositionInvariant = 0; - } -#endif - - if (program->TnlData) - free_tnl_data( program ); - - program->TnlData = p; - - /* Initialize cp. Note that ctx and VB aren't used in compilation - * so we don't have to worry about statechanges: - */ - _mesa_memset(&cp, 0, sizeof(cp)); - cp.csr = p->instructions; - - /* Compile instructions: - */ - for (i = 0; i < program->Base.NumInstructions; i++) { - cvp_emit_inst(&cp, &program->Base.Instructions[i]); - } - - /* Finish up: - */ - p->nr_instructions = cp.csr - p->instructions; - - /* Print/disassemble: - */ - if (DISASSEM) { - for (i = 0; i < p->nr_instructions; i++) { - _tnl_disassem_vba_insn(p->instructions[i]); - } - _mesa_printf("\n\n"); - } - -#ifdef USE_SSE_ASM - if (try_codegen) - _tnl_sse_codegen_vertex_program(p); -#endif - -} - - - -/* ---------------------------------------------------------------------- - * Execution - */ -static void userclip( GLcontext *ctx, - GLvector4f *clip, - GLubyte *clipmask, - GLubyte *clipormask, - GLubyte *clipandmask ) -{ - GLuint p; - - for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { - if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { - GLuint nr, i; - const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; - const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; - const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; - const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; - GLfloat *coord = (GLfloat *)clip->data; - GLuint stride = clip->stride; - GLuint count = clip->count; - - for (nr = 0, i = 0 ; i < count ; i++) { - GLfloat dp = (coord[0] * a + - coord[1] * b + - coord[2] * c + - coord[3] * d); - - if (dp < 0) { - nr++; - clipmask[i] |= CLIP_USER_BIT; - } - - STRIDE_F(coord, stride); - } - - if (nr > 0) { - *clipormask |= CLIP_USER_BIT; - if (nr == count) { - *clipandmask |= CLIP_USER_BIT; - return; - } - } - } - } -} - - -static GLboolean -do_ndc_cliptest(GLcontext *ctx, struct arb_vp_machine *m) -{ - TNLcontext *tnl = TNL_CONTEXT(ctx); - struct vertex_buffer *VB = m->VB; - - /* Cliptest and perspective divide. Clip functions must clear - * the clipmask. - */ - m->ormask = 0; - m->andmask = CLIP_FRUSTUM_BITS; - - if (tnl->NeedNdcCoords) { - VB->NdcPtr = - _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr, - &m->ndcCoords, - m->clipmask, - &m->ormask, - &m->andmask ); - } - else { - VB->NdcPtr = NULL; - _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr, - NULL, - m->clipmask, - &m->ormask, - &m->andmask ); - } - - if (m->andmask) { - /* All vertices are outside the frustum */ - return GL_FALSE; - } - - /* Test userclip planes. This contributes to VB->ClipMask. - */ - /** XXX NEW_SLANG _Enabled ??? */ - if (ctx->Transform.ClipPlanesEnabled && (!ctx->VertexProgram._Enabled || - ctx->VertexProgram.Current->IsPositionInvariant)) { - userclip( ctx, - VB->ClipPtr, - m->clipmask, - &m->ormask, - &m->andmask ); - - if (m->andmask) { - return GL_FALSE; - } - } - - VB->ClipAndMask = m->andmask; - VB->ClipOrMask = m->ormask; - VB->ClipMask = m->clipmask; - - return GL_TRUE; -} - - -static INLINE void call_func( struct tnl_compiled_program *p, - struct arb_vp_machine *m ) -{ - p->compiled_func(m); -} - - -/** - * 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. - */ -static GLboolean -run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage) -{ - const struct gl_vertex_program *program = ctx->VertexProgram._Current; - struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; - struct arb_vp_machine *m = ARB_VP_MACHINE(stage); - struct tnl_compiled_program *p; - GLuint i, j; - GLbitfield outputs; - -#define FORCE_PROG_EXECUTE_C 1 -#if FORCE_PROG_EXECUTE_C - return GL_TRUE; -#else - if (!program) - return GL_TRUE; -#endif - - if (program->Base.Parameters) { - _mesa_load_state_parameters(ctx, program->Base.Parameters); - } - - p = (struct tnl_compiled_program *)program->TnlData; - assert(p); - - - m->nr_inputs = m->nr_outputs = 0; - - for (i = 0; i < VERT_ATTRIB_MAX; i++) { - if (program->Base.InputsRead & (1<<i)) { - GLuint j = m->nr_inputs++; - m->input[j].idx = i; - m->input[j].data = (GLfloat *)m->VB->AttribPtr[i]->data; - m->input[j].stride = m->VB->AttribPtr[i]->stride; - m->input[j].size = m->VB->AttribPtr[i]->size; - ASSIGN_4V(m->File[0][REG_IN0 + i], 0, 0, 0, 1); - } - } - - for (i = 0; i < VERT_RESULT_MAX; i++) { - if (program->Base.OutputsWritten & (1 << i)) { - GLuint j = m->nr_outputs++; - m->output[j].idx = i; - m->output[j].data = (GLfloat *)m->attribs[i].data; - } - } - - - /* Run the actual program: - */ - for (m->vtx_nr = 0; m->vtx_nr < VB->Count; m->vtx_nr++) { - for (j = 0; j < m->nr_inputs; j++) { - GLuint idx = REG_IN0 + m->input[j].idx; - switch (m->input[j].size) { - case 4: m->File[0][idx][3] = m->input[j].data[3]; - case 3: m->File[0][idx][2] = m->input[j].data[2]; - case 2: m->File[0][idx][1] = m->input[j].data[1]; - case 1: m->File[0][idx][0] = m->input[j].data[0]; - } -#if 0 - printf(" attr %d/%d: %g %g %g %g\n", j, idx-REG_IN0, - m->input[j].data[0], - m->input[j].data[1], - m->input[j].data[2], - m->input[j].data[3]); -#endif - STRIDE_F(m->input[j].data, m->input[j].stride); - } - - - if (p->compiled_func) { - call_func( p, m ); - } - else { - GLint pc; - for (pc = 0; pc < p->nr_instructions; pc++) { - union instruction inst = p->instructions[pc]; - opcode_func[inst.alu.opcode]( m, inst ); - } - } - - for (j = 0; j < m->nr_outputs; j++) { - GLuint idx = REG_OUT0 + m->output[j].idx; - m->output[j].data[0] = m->File[0][idx][0]; - m->output[j].data[1] = m->File[0][idx][1]; - m->output[j].data[2] = m->File[0][idx][2]; - m->output[j].data[3] = m->File[0][idx][3]; - m->output[j].data += 4; - } - - } - - /* Setup the VB pointers so that the next pipeline stages get - * their data from the right place (the program output arrays). - * - * TODO: 1) Have tnl use these RESULT values for outputs rather - * than trying to shoe-horn inputs and outputs into one set of - * values. - * - * TODO: 2) Integrate t_vertex.c so that we just go straight ahead - * and build machine vertices here. - */ - - /* XXX There seems to be confusion between using the VERT_ATTRIB_* - * values vs _TNL_ATTRIB_* tokens here: - */ - outputs = program->Base.OutputsWritten; - - if (program->IsPositionInvariant) { - /* We need the exact same transform as in the fixed function path here - to guarantee invariance, depending on compiler optimization flags results - could be different otherwise */ - VB->ClipPtr = TransformRaw( &m->attribs[0], - &ctx->_ModelProjectMatrix, - m->VB->AttribPtr[0] ); - - /* Drivers expect this to be clean to element 4... - */ - switch (VB->ClipPtr->size) { - case 1: - /* impossible */ - case 2: - _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 ); - /* fall-through */ - case 3: - _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 ); - /* fall-through */ - case 4: - break; - } - } - else { - VB->ClipPtr = &m->attribs[VERT_RESULT_HPOS]; - VB->ClipPtr->count = VB->Count; - } - - if (outputs & (1<<VERT_RESULT_COL0)) { - VB->ColorPtr[0] = - VB->AttribPtr[VERT_ATTRIB_COLOR0] = &m->attribs[VERT_RESULT_COL0]; - } - - if (outputs & (1<<VERT_RESULT_BFC0)) { - VB->ColorPtr[1] = &m->attribs[VERT_RESULT_BFC0]; - } - - if (outputs & (1<<VERT_RESULT_COL1)) { - VB->SecondaryColorPtr[0] = - VB->AttribPtr[VERT_ATTRIB_COLOR1] = &m->attribs[VERT_RESULT_COL1]; - } - - if (outputs & (1<<VERT_RESULT_BFC1)) { - VB->SecondaryColorPtr[1] = &m->attribs[VERT_RESULT_BFC1]; - } - - if (outputs & (1<<VERT_RESULT_FOGC)) { - VB->FogCoordPtr = - VB->AttribPtr[VERT_ATTRIB_FOG] = &m->attribs[VERT_RESULT_FOGC]; - } - - if (outputs & (1<<VERT_RESULT_PSIZ)) { - VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &m->attribs[VERT_RESULT_PSIZ]; - } - - for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { - if (outputs & (1<<(VERT_RESULT_TEX0+i))) { - VB->TexCoordPtr[i] = - VB->AttribPtr[VERT_ATTRIB_TEX0+i] = &m->attribs[VERT_RESULT_TEX0 + i]; - } - } - - for (i = 0; i < ctx->Const.MaxVarying; i++) { - if (outputs & (1 << (VERT_RESULT_VAR0 + i))) { - /* Note: varying results get put into the generic attributes */ - VB->AttribPtr[VERT_ATTRIB_GENERIC0+i] - = &m->attribs[VERT_RESULT_VAR0 + i]; - } - } - -#if 0 - for (i = 0; i < VB->Count; 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)[1], - VEC_ELT(VB->ClipPtr, GLfloat, i)[2], - VEC_ELT(VB->ClipPtr, GLfloat, i)[3], - VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[0], - VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[1], - VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[2], - VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[3]); - } -#endif - - /* Perform NDC and cliptest operations: - */ - return do_ndc_cliptest(ctx, m); -} - - -static void -validate_vertex_program( GLcontext *ctx, struct tnl_pipeline_stage *stage ) -{ - struct arb_vp_machine *m = ARB_VP_MACHINE(stage); - struct gl_vertex_program *program = ctx->VertexProgram._Current; - - /* don't use this module since it only handles 12 temp regs */ - /* Need to allocate more bits for register indexes, etc. */ -#define FORCE_OLD 1 -#if FORCE_OLD - if (0) { -#else - if (program) { -#endif - if (!program->TnlData) - compile_vertex_program( program, m->try_codegen ); - - /* Grab the state GL state and put into registers: - */ - m->File[FILE_LOCAL_PARAM] = program->Base.LocalParams; - m->File[FILE_ENV_PARAM] = ctx->VertexProgram.Parameters; - /* GL_NV_vertex_programs can't reference GL state */ - if (program->Base.Parameters) - m->File[FILE_STATE_PARAM] = program->Base.Parameters->ParameterValues; - else - m->File[FILE_STATE_PARAM] = NULL; - } -} - - -/** - * Called the first time stage->run is called. In effect, don't - * allocate data until the first time the stage is run. - */ -static GLboolean init_vertex_program( GLcontext *ctx, - struct tnl_pipeline_stage *stage ) -{ - TNLcontext *tnl = TNL_CONTEXT(ctx); - struct vertex_buffer *VB = &(tnl->vb); - struct arb_vp_machine *m; - const GLuint size = VB->Size; - GLuint i; - - /* spot checks to be sure the opcode table is correct */ - assert(opcode_func[OPCODE_SGE] == do_SGE); - assert(opcode_func[OPCODE_XPD] == do_XPD); - - stage->privatePtr = _mesa_calloc(sizeof(*m)); - m = ARB_VP_MACHINE(stage); - if (!m) - return GL_FALSE; - - /* arb_vertex_machine struct should subsume the VB: - */ - m->VB = VB; - - m->File[0] = (GLfloat(*)[4])ALIGN_MALLOC(REG_MAX * sizeof(GLfloat) * 4, 16); - - /* Initialize regs where necessary: - */ - ASSIGN_4V(m->File[0][REG_ID], 0, 0, 0, 1); - ASSIGN_4V(m->File[0][REG_ONES], 1, 1, 1, 1); - ASSIGN_4V(m->File[0][REG_SWZ], 1, -1, 0, 0); - ASSIGN_4V(m->File[0][REG_NEG], -1, -1, -1, -1); - ASSIGN_4V(m->File[0][REG_LIT], 1, 0, 0, 1); - ASSIGN_4V(m->File[0][REG_LIT2], 1, .5, .2, 1); /* debug value */ - - if (_mesa_getenv("MESA_EXPERIMENTAL")) - m->try_codegen = GL_TRUE; - - /* Allocate arrays of vertex output values */ - for (i = 0; i < VERT_RESULT_MAX; i++) { - _mesa_vector4f_alloc( &m->attribs[i], 0, size, 32 ); - m->attribs[i].size = 4; - } - - /* a few other misc allocations */ - _mesa_vector4f_alloc( &m->ndcCoords, 0, size, 32 ); - m->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 ); - - if (ctx->VertexProgram._MaintainTnlProgram) - _mesa_allow_light_in_model( ctx, GL_FALSE ); - - m->fpucntl_rnd_neg = RND_NEG_FPU; /* const value */ - m->fpucntl_restore = RESTORE_FPU; /* const value */ - - return GL_TRUE; -} - - -/** - * Destructor for this pipeline stage. - */ -static void dtr( struct tnl_pipeline_stage *stage ) -{ - struct arb_vp_machine *m = ARB_VP_MACHINE(stage); - - if (m) { - GLuint i; - - /* free the vertex program result arrays */ - for (i = 0; i < VERT_RESULT_MAX; i++) - _mesa_vector4f_free( &m->attribs[i] ); - - /* free misc arrays */ - _mesa_vector4f_free( &m->ndcCoords ); - ALIGN_FREE( m->clipmask ); - ALIGN_FREE( m->File[0] ); - - _mesa_free( m ); - stage->privatePtr = NULL; - } -} - - -/** - * Public description of this pipeline stage. - */ -const struct tnl_pipeline_stage _tnl_arb_vertex_program_stage = -{ - "arb-vertex-program", - NULL, /* private_data */ - init_vertex_program, /* create */ - dtr, /* destroy */ - validate_vertex_program, /* validate */ - run_arb_vertex_program /* run */ -}; - - -/** - * Called via ctx->Driver.ProgramStringNotify() after a new vertex program - * string has been parsed. - */ -void -_tnl_program_string(GLcontext *ctx, GLenum target, struct gl_program *program) -{ - if (target == GL_VERTEX_PROGRAM_ARB) { - /* free any existing tnl data hanging off the program */ - struct gl_vertex_program *vprog = (struct gl_vertex_program *) program; - if (vprog->TnlData) { - free_tnl_data(vprog); - } - } -} diff --git a/src/mesa/tnl/t_vb_arbprogram.h b/src/mesa/tnl/t_vb_arbprogram.h deleted file mode 100644 index 1bec2a411e..0000000000 --- a/src/mesa/tnl/t_vb_arbprogram.h +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Mesa 3-D graphics library - * Version: 6.5 - * - * Copyright (C) 1999-2005 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_arb_program.c - * Compile vertex programs to an intermediate representation. - * Execute vertex programs over a buffer of vertices. - * \author Keith Whitwell, Brian Paul - */ - - -#ifndef _T_VB_ARBPROGRAM_H_ -#define _T_VB_ARBPROGRAM_H_ - - -/* New, internal instructions: - */ -#define RSW (MAX_OPCODE) -#define MSK (MAX_OPCODE+1) -#define REL (MAX_OPCODE+2) - -/** - * Register files for vertex programs - */ -#define FILE_REG 0 /* temporaries */ -#define FILE_LOCAL_PARAM 1 /* local parameters */ -#define FILE_ENV_PARAM 2 /* global parameters */ -#define FILE_STATE_PARAM 3 /* GL state references */ - -#define REG_ARG0 0 -#define REG_ARG1 1 -#define REG_ARG2 2 -#define REG_RES 3 -#define REG_ADDR 4 -#define REG_TMP0 5 -#define REG_TMP11 16 -#define REG_OUT0 17 -#define REG_OUT23 40 -#define REG_IN0 41 -#define REG_IN31 72 -#define REG_ID 73 /* 0,0,0,1 */ -#define REG_ONES 74 /* 1,1,1,1 */ -#define REG_SWZ 75 /* 1,-1,0,0 */ -#define REG_NEG 76 /* -1,-1,-1,-1 */ -#define REG_LIT 77 /* 1,0,0,1 */ -#define REG_LIT2 78 /* 1,0,0,1 */ -#define REG_SCRATCH 79 /* internal temporary. XXX we can't actually use this because 70 doesn't fit in the 5-bit 'dst' instruction field! */ -#define REG_UNDEF 127 /* special case - never used */ -#define REG_MAX 128 -#define REG_INVALID ~0 - - -#if 0 -#define REG_OUT14 31 -#define REG_IN0 32 -#define REG_IN31 63 -#define REG_ID 64 /* 0,0,0,1 */ -#define REG_ONES 65 /* 1,1,1,1 */ -#define REG_SWZ 66 /* 1,-1,0,0 */ -#define REG_NEG 67 /* -1,-1,-1,-1 */ -#define REG_LIT 68 /* 1,0,0,1 */ -#define REG_LIT2 69 /* 1,0,0,1 */ -#define REG_SCRATCH 70 /* internal temporary. XXX we can't actually use this because 70 doesn't fit in the 5-bit 'dst' instruction field! */ -#define REG_UNDEF 127 /* special case - never used */ -#define REG_MAX 128 -#define REG_INVALID ~0 -#endif - -/* ARB_vp instructions are broken down into one or more of the - * following micro-instructions, each representable in a 64 bit packed - * structure. - */ -struct reg { - GLuint file:2; - GLuint idx:8; -}; - - -union instruction { - struct { - GLuint opcode:7; - GLuint dst:6; - GLuint file0:2; - GLuint idx0:8; - GLuint file1:2; - GLuint idx1:7; - GLuint pad:2; - GLuint pad2; - } alu; - - struct { - GLuint opcode:7; - GLuint dst:6; - GLuint file0:2; - GLuint idx0:8; - GLuint neg:4; - GLuint swz:12; /* xyzw01 */ - } rsw; - - struct { - GLuint opcode:7; - GLuint dst:6; - GLuint file:2; - GLuint idx:8; - GLuint mask:4; - GLuint pad:7; - GLuint pad2; - } msk; -}; - - -/** - * Reduced swizzle is a 3-bit field, for simplicity same as normal swizzle, X/Y/Z/W/0/1 allowed. - */ - -struct input { - GLuint idx; - GLfloat *data; - GLuint stride; - GLuint size; -}; - -struct output { - GLuint idx; - GLfloat *data; -}; - - - -/*--------------------------------------------------------------------------- */ -#if defined(USE_SSE_ASM) -#ifdef NO_FAST_MATH -#define RESTORE_FPU (DEFAULT_X86_FPU) -#define RND_NEG_FPU (DEFAULT_X86_FPU | 0x400) -#else -#define RESTORE_FPU (FAST_X86_FPU) -#define RND_NEG_FPU (FAST_X86_FPU | 0x400) -#endif -#else -#define RESTORE_FPU 0 -#define RND_NEG_FPU 0 -#endif - - -/** - * Private storage for the vertex program pipeline stage. - */ -struct arb_vp_machine { - GLfloat (*File[4])[4]; /* All values referencable from the program. */ - - struct input input[VERT_ATTRIB_MAX]; - GLuint nr_inputs; - - struct output output[VERT_RESULT_MAX]; - GLuint nr_outputs; - - GLvector4f attribs[VERT_RESULT_MAX]; /**< result vectors. */ - GLvector4f ndcCoords; /**< normalized device coords */ - GLubyte *clipmask; /**< clip flags */ - GLubyte ormask, andmask; /**< for clipping */ - - GLuint vtx_nr; /**< loop counter */ - - struct vertex_buffer *VB; - - GLshort fpucntl_rnd_neg; /* constant value */ - GLshort fpucntl_restore; /* constant value */ - - GLboolean try_codegen; -}; - -struct tnl_compiled_program { - union instruction instructions[1024]; - GLint nr_instructions; - void (*compiled_func)( struct arb_vp_machine * ); /**< codegen'd program */ -}; - -void _tnl_program_string_change( struct gl_vertex_program * ); -void _tnl_program_destroy( struct gl_vertex_program * ); - -void _tnl_disassem_vba_insn( union instruction op ); - -GLboolean _tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p); - -#endif diff --git a/src/mesa/tnl/t_vb_arbprogram_sse.c b/src/mesa/tnl/t_vb_arbprogram_sse.c deleted file mode 100644 index d0f66fd619..0000000000 --- a/src/mesa/tnl/t_vb_arbprogram_sse.c +++ /dev/null @@ -1,1330 +0,0 @@ -/* - * 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/x87/SSE/SSE2 machine code using mesa's rtasm runtime assembler. - * - * This is very much a first attempt - build something that works. - * There are probably better approaches for applying SSE to vertex - * programs, and the whole thing is crying out for static analysis of - * the programs to avoid redundant operations. - * - * \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 "prog_instruction.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 - temp - * EBX - point to 'm->File[0]' - * ECX - point to 'm->File[3]' - * EDX - holds 'm' - * EBP, - * ESI, - * EDI - */ - -#define DISASSEM 0 - -#define FAIL \ -do { \ - _mesa_printf("x86 translation failed in %s\n", __FUNCTION__); \ - return GL_FALSE; \ -} while (0) - -struct compilation { - struct x86_function func; - struct tnl_compiled_program *p; - 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; - GLshort fpucntl; -}; - -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 GLint get_offset( const void *a, const void *b ) -{ - return (const char *)b - (const char *)a; -} - - -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_BX); - 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 void invalidate_xmm( struct compilation *cp, - GLuint file, GLuint idx ) -{ - GLuint i; - - /* Invalidate any old copy of this register in XMM0-7. - */ - 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; - } - } -} - - -/* Return an XMM reg to receive the results of an operation. - */ -static struct x86_reg get_dst_xmm_reg( struct compilation *cp, - GLuint file, GLuint idx ) -{ - struct x86_reg reg; - - /* Invalidate any old copy of this register in XMM0-7. Don't reuse - * as this may be one of the arguments. - */ - invalidate_xmm( cp, file, idx ); - - 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; -} - -/* As above, but return a pointer. Note - this pointer may alias - * those returned by get_arg_ptr(). - */ -static struct x86_reg get_dst_ptr( struct compilation *cp, - GLuint file, GLuint idx ) -{ - /* Invalidate any old copy of this register in XMM0-7. Don't reuse - * as this may be one of the arguments. - */ - invalidate_xmm( cp, file, idx ); - - return get_reg_ptr(file, idx); -} - - - -/* 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); -} - -/* As above, but always return a pointer: - */ -static struct x86_reg get_arg_ptr( struct compilation *cp, GLuint file, GLuint idx ) -{ - GLuint i; - - /* If there is a modified version of this register in one of the - * XMM regs, write it out to memory. - */ - for (i = 0; i < 8; i++) { - if (cp->xmm[i].file == file && - cp->xmm[i].idx == idx && - cp->xmm[i].dirty) - spill(cp, i); - } - - return get_reg_ptr(file, idx); -} - -/* Emulate pshufd insn in regular SSE, if necessary: - */ -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); - } -} - -static void set_fpu_round_neg_inf( struct compilation *cp ) -{ - if (cp->fpucntl != RND_NEG_FPU) { - struct x86_reg regEDX = x86_make_reg(file_REG32, reg_DX); - struct arb_vp_machine *m = NULL; - - cp->fpucntl = RND_NEG_FPU; - x87_fnclex(&cp->func); - x87_fldcw(&cp->func, x86_make_disp(regEDX, get_offset(m, &m->fpucntl_rnd_neg))); - } -} - - -/* 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_xmm_reg(cp, FILE_REG, op.rsw.dst); - GLuint swz = GET_SWZ(op.rsw.swz, 0) | (GET_SWZ(op.rsw.swz, 1) << 2) | - (GET_SWZ(op.rsw.swz, 2) << 4| (GET_SWZ(op.rsw.swz, 3) << 6)); - 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 - */ - /* is the emit_pshufd necessary? only SWZ can negate individual components */ - 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; -} - -/* Perform a full swizzle - */ -static GLboolean emit_SWZ( 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_xmm_reg(cp, FILE_REG, op.rsw.dst); - struct x86_reg negs = get_arg(cp, FILE_REG, REG_SWZ); - struct x86_reg tmp = get_xmm_reg(cp); - GLubyte neg = op.rsw.neg; - GLubyte shuf2, swz, savepos, savemask, swizzle[4]; - - swizzle[0] = GET_SWZ(op.rsw.swz, 0); - swizzle[1] = GET_SWZ(op.rsw.swz, 1); - swizzle[2] = GET_SWZ(op.rsw.swz, 2); - swizzle[3] = GET_SWZ(op.rsw.swz, 3); - - swz = SHUF((swizzle[0] & 3), (swizzle[1] & 3), - (swizzle[2] & 3), (swizzle[3] & 3)); - - emit_pshufd(cp, dst, arg0, swz); - - /* can handle negation and replace with zero with the same shuffle/mul */ - shuf2 = SHUF(swizzle[0] == 4 ? 2 : (neg & 1), - swizzle[1] == 4 ? 2 : ((neg & 2) >> 1), - swizzle[2] == 4 ? 2 : ((neg & 4) >> 2), - swizzle[3] == 4 ? 2 : ((neg & 8) >> 3)); - - /* now the hard part is getting those 1's in there... */ - savepos = 0; - savemask = 0; - if (swizzle[0] == 5) savepos = 1; - if (swizzle[1] == 5) savepos = 2; - else savemask |= 1 << 2; - if (swizzle[2] == 5) savepos = 3; - else savemask |= 2 << 4; - if (swizzle[3] == 5) savepos = 4; - else savemask |= 3 << 6; - if (savepos) { - /* need a mov first as movss from memory will overwrite high bits of xmm reg */ - sse_movups(&cp->func, tmp, negs); - /* can only replace lowest 32bits, thus move away that part first */ - emit_pshufd(cp, dst, dst, savemask); - sse_movss(&cp->func, dst, tmp); - emit_pshufd(cp, dst, dst, (savepos - 1) | (savemask & 0xfc)); - } - - if (shuf2) { - /* Load 1,-1,0,0 - * Use neg as arg to pshufd - * Multiply - */ - emit_pshufd(cp, tmp, negs, shuf2); - sse_mulps(&cp->func, dst, tmp); - } - - return GL_TRUE; -} - -/* Helper for writemask: - */ -static GLboolean emit_shuf_copy1( struct compilation *cp, - struct x86_reg dst, - struct x86_reg arg0, - struct x86_reg arg1, - GLubyte shuf ) -{ - struct x86_reg tmp = get_xmm_reg(cp); - sse_movups(&cp->func, dst, arg1); - emit_pshufd(cp, dst, dst, shuf); - emit_pshufd(cp, tmp, arg0, shuf); - - sse_movss(&cp->func, dst, tmp); - - emit_pshufd(cp, dst, dst, shuf); - return GL_TRUE; -} - - -/* Helper for writemask: - */ -static GLboolean emit_shuf_copy2( struct compilation *cp, - struct x86_reg dst, - struct x86_reg arg0, - struct x86_reg arg1, - GLubyte shuf ) -{ - struct x86_reg tmp = get_xmm_reg(cp); - emit_pshufd(cp, dst, arg1, shuf); - emit_pshufd(cp, tmp, arg0, shuf); - - sse_shufps(&cp->func, dst, tmp, SHUF(X, Y, Z, W)); - - emit_pshufd(cp, dst, dst, shuf); - return GL_TRUE; -} - - -static void emit_x87_ex2( struct compilation *cp ) -{ - struct x86_reg st0 = x86_make_reg(file_x87, 0); - struct x86_reg st1 = x86_make_reg(file_x87, 1); - struct x86_reg st3 = x86_make_reg(file_x87, 3); - - set_fpu_round_neg_inf( cp ); - - x87_fld(&cp->func, st0); /* a a */ - x87_fprndint( &cp->func ); /* int(a) a */ - x87_fld(&cp->func, st0); /* int(a) int(a) a */ - x87_fstp(&cp->func, st3); /* int(a) a int(a)*/ - x87_fsubp(&cp->func, st1); /* frac(a) int(a) */ - x87_f2xm1(&cp->func); /* (2^frac(a))-1 int(a)*/ - x87_fld1(&cp->func); /* 1 (2^frac(a))-1 int(a)*/ - x87_faddp(&cp->func, st1); /* 2^frac(a) int(a) */ - x87_fscale(&cp->func); /* 2^a */ -} - -#if 0 -static GLboolean emit_MSK2( struct compilation *cp, union instruction op ) -{ - struct x86_reg arg0 = get_arg(cp, op.msk.file, op.msk.arg); - struct x86_reg arg1 = get_arg(cp, FILE_REG, op.msk.dst); /* NOTE! */ - struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.msk.dst); - - /* make full width bitmask in tmp - * dst = ~tmp - * tmp &= arg0 - * dst &= arg1 - * dst |= tmp - */ - emit_pshufd(cp, tmp, get_arg(cp, FILE_REG, REG_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)); - sse2_pnot(&cp->func, dst, tmp); - sse2_pand(&cp->func, arg0, tmp); - sse2_pand(&cp->func, arg1, dst); - sse2_por(&cp->func, tmp, dst); - return GL_TRUE; -} -#endif - - -/* 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. - */ -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); /* NOTE! */ - struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.msk.dst); - - /* Note that dst and dst0 refer to the same program variable, but - * will definitely be different XMM registers. We're effectively - * treating this as a 2 argument SEL now, just one of which happens - * always to be the same register as the destination. - */ - - switch (op.msk.mask) { - case 0: - sse_movups(&cp->func, dst, dst0); - return GL_TRUE; - - case WRITEMASK_X: - if (arg.file == file_XMM) { - sse_movups(&cp->func, dst, dst0); - sse_movss(&cp->func, dst, arg); - } - else { - struct x86_reg tmp = get_xmm_reg(cp); - sse_movups(&cp->func, dst, dst0); - sse_movss(&cp->func, tmp, arg); - sse_movss(&cp->func, dst, tmp); - } - return GL_TRUE; - - case WRITEMASK_XY: - sse_movups(&cp->func, dst, dst0); - sse_shufps(&cp->func, dst, arg, SHUF(X, Y, Z, W)); - return GL_TRUE; - - case WRITEMASK_ZW: - sse_movups(&cp->func, dst, arg); - sse_shufps(&cp->func, dst, dst0, SHUF(X, Y, Z, W)); - return GL_TRUE; - - case WRITEMASK_YZW: - if (dst0.file == file_XMM) { - sse_movups(&cp->func, dst, arg); - sse_movss(&cp->func, dst, dst0); - } - else { - struct x86_reg tmp = get_xmm_reg(cp); - sse_movups(&cp->func, dst, arg); - sse_movss(&cp->func, tmp, dst0); - sse_movss(&cp->func, dst, tmp); - } - return GL_TRUE; - - case WRITEMASK_Y: - emit_shuf_copy1(cp, dst, arg, dst0, SHUF(Y,X,Z,W)); - return GL_TRUE; - - case WRITEMASK_Z: - emit_shuf_copy1(cp, dst, arg, dst0, SHUF(Z,Y,X,W)); - return GL_TRUE; - - case WRITEMASK_W: - emit_shuf_copy1(cp, dst, arg, dst0, SHUF(W,Y,Z,X)); - return GL_TRUE; - - case WRITEMASK_XZ: - emit_shuf_copy2(cp, dst, arg, dst0, SHUF(X,Z,Y,W)); - return GL_TRUE; - - case WRITEMASK_XW: - emit_shuf_copy2(cp, dst, arg, dst0, SHUF(X,W,Z,Y)); - - case WRITEMASK_YZ: - emit_shuf_copy2(cp, dst, arg, dst0, SHUF(Z,Y,X,W)); - return GL_TRUE; - - case WRITEMASK_YW: - emit_shuf_copy2(cp, dst, arg, dst0, SHUF(W,Y,Z,X)); - return GL_TRUE; - - case WRITEMASK_XZW: - emit_shuf_copy1(cp, dst, dst0, arg, SHUF(Y,X,Z,W)); - return GL_TRUE; - - case WRITEMASK_XYW: - emit_shuf_copy1(cp, dst, dst0, arg, SHUF(Z,Y,X,W)); - return GL_TRUE; - - case WRITEMASK_XYZ: - emit_shuf_copy1(cp, dst, dst0, arg, SHUF(W,Y,Z,X)); - return GL_TRUE; - - case WRITEMASK_XYZW: - sse_movups(&cp->func, dst, arg); - return GL_TRUE; - - default: - assert(0); - break; - } -} - - - -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_xmm_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_xmm_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_xmm_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_xmm_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_xmm_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 (from DP3): - */ - 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); - emit_pshufd(cp, tmp, arg1, SHUF(W,W,W,W)); - sse_addss(&cp->func, dst, tmp); - sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X)); - return GL_TRUE; -} - -#if 0 -static GLboolean emit_DST( struct compilation *cp, union instruction op ) -{ - struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg arg1 = get_arg_ptr(cp, op.alu.file1, op.alu.idx1); - struct x86_reg dst = get_dst_ptr(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]; */ - - /* Would rather do some of this with integer regs, but: - * 1) No proper support for immediate values yet - * 2) I'd need to push/pop somewhere to get a free reg. - */ - x87_fld1(&cp->func); - x87_fstp(&cp->func, dst); /* would rather do an immediate store... */ - x87_fld(&cp->func, x86_make_disp(arg0, 4)); - x87_fmul(&cp->func, x86_make_disp(arg1, 4)); - x87_fstp(&cp->func, x86_make_disp(dst, 4)); - - if (!eq(arg0, dst)) { - x86_fld(&cp->func, x86_make_disp(arg0, 8)); - x86_stp(&cp->func, x86_make_disp(dst, 8)); - } - - if (!eq(arg1, dst)) { - x86_fld(&cp->func, x86_make_disp(arg0, 12)); - x86_stp(&cp->func, x86_make_disp(dst, 12)); - } - - return GL_TRUE; -} -#else -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_xmm_reg(cp, FILE_REG, op.alu.dst); - struct x86_reg tmp = get_xmm_reg(cp); - struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES); - - emit_shuf_copy2(cp, dst, arg0, ones, SHUF(X,W,Z,Y)); - emit_shuf_copy2(cp, tmp, arg1, ones, SHUF(X,Z,Y,W)); - sse_mulps(&cp->func, dst, tmp); - -/* dst[0] = 1.0 * 1.0F; */ -/* dst[1] = arg0[1] * arg1[1]; */ -/* dst[2] = arg0[2] * 1.0; */ -/* dst[3] = 1.0 * arg1[3]; */ - - return GL_TRUE; -} -#endif - -static GLboolean emit_LG2( struct compilation *cp, union instruction op ) -{ - struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst); - - x87_fld1(&cp->func); /* 1 */ - x87_fld(&cp->func, arg0); /* a0 1 */ - x87_fyl2x(&cp->func); /* log2(a0) */ - x87_fst(&cp->func, x86_make_disp(dst, 0)); - x87_fst(&cp->func, x86_make_disp(dst, 4)); - x87_fst(&cp->func, x86_make_disp(dst, 8)); - x87_fstp(&cp->func, x86_make_disp(dst, 12)); - - return GL_TRUE; -} - - -static GLboolean emit_EX2( struct compilation *cp, union instruction op ) -{ - struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst); - - /* CAUTION: dst may alias arg0! - */ - x87_fld(&cp->func, arg0); - - emit_x87_ex2(cp); - - x87_fst(&cp->func, x86_make_disp(dst, 0)); - x87_fst(&cp->func, x86_make_disp(dst, 4)); - x87_fst(&cp->func, x86_make_disp(dst, 8)); - x87_fst(&cp->func, x86_make_disp(dst, 12)); - return GL_TRUE; -} - -static GLboolean emit_EXP( struct compilation *cp, union instruction op ) -{ - struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst); - struct x86_reg st0 = x86_make_reg(file_x87, 0); - struct x86_reg st1 = x86_make_reg(file_x87, 1); - struct x86_reg st3 = x86_make_reg(file_x87, 3); - - /* CAUTION: dst may alias arg0! - */ - x87_fld(&cp->func, arg0); /* arg0.x */ - x87_fld(&cp->func, st0); /* arg arg */ - - /* by default, fpu is setup to round-to-nearest. We want to - * change this now, and track the state through to the end of the - * generated function so that it isn't repeated unnecessarily. - * Alternately, could subtract .5 to get round to -inf behaviour. - */ - set_fpu_round_neg_inf( cp ); - x87_fprndint( &cp->func ); /* flr(a) a */ - x87_fld(&cp->func, st0); /* flr(a) flr(a) a */ - x87_fld1(&cp->func); /* 1 floor(a) floor(a) a */ - x87_fst(&cp->func, x86_make_disp(dst, 12)); /* stack unchanged */ - x87_fscale(&cp->func); /* 2^floor(a) floor(a) a */ - x87_fst(&cp->func, st3); /* 2^floor(a) floor(a) a 2^floor(a)*/ - x87_fstp(&cp->func, x86_make_disp(dst, 0)); /* flr(a) a 2^flr(a) */ - x87_fsubrp(&cp->func, st1); /* frac(a) 2^flr(a) */ - x87_fst(&cp->func, x86_make_disp(dst, 4)); /* frac(a) 2^flr(a) */ - x87_f2xm1(&cp->func); /* (2^frac(a))-1 2^flr(a)*/ - x87_fld1(&cp->func); /* 1 (2^frac(a))-1 2^flr(a)*/ - x87_faddp(&cp->func, st1); /* 2^frac(a) 2^flr(a) */ - x87_fmulp(&cp->func, st1); /* 2^a */ - x87_fst(&cp->func, x86_make_disp(dst, 8)); - - - -/* dst[0] = 2^floor(tmp); */ -/* dst[1] = frac(tmp); */ -/* dst[2] = 2^floor(tmp) * 2^frac(tmp); */ -/* dst[3] = 1.0F; */ - return GL_TRUE; -} - -static GLboolean emit_LOG( struct compilation *cp, union instruction op ) -{ - struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst); - struct x86_reg st0 = x86_make_reg(file_x87, 0); - struct x86_reg st1 = x86_make_reg(file_x87, 1); - struct x86_reg st2 = x86_make_reg(file_x87, 2); - - /* CAUTION: dst may alias arg0! - */ - x87_fld(&cp->func, arg0); /* arg0.x */ - x87_fabs(&cp->func); /* |arg0.x| */ - x87_fxtract(&cp->func); /* mantissa(arg0.x), exponent(arg0.x) */ - x87_fst(&cp->func, st2); /* mantissa, exponent, mantissa */ - x87_fld1(&cp->func); /* 1, mantissa, exponent, mantissa */ - x87_fyl2x(&cp->func); /* log2(mantissa), exponent, mantissa */ - x87_fadd(&cp->func, st0, st1); /* e+l2(m), e, m */ - x87_fstp(&cp->func, x86_make_disp(dst, 8)); /* e, m */ - - x87_fld1(&cp->func); /* 1, e, m */ - x87_fsub(&cp->func, st1, st0); /* 1, e-1, m */ - x87_fstp(&cp->func, x86_make_disp(dst, 12)); /* e-1,m */ - x87_fstp(&cp->func, dst); /* m */ - - x87_fadd(&cp->func, st0, st0); /* 2m */ - x87_fstp(&cp->func, x86_make_disp(dst, 4)); - - return GL_TRUE; -} - -static GLboolean emit_FLR( struct compilation *cp, union instruction op ) -{ - struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst); - int i; - - set_fpu_round_neg_inf( cp ); - - for (i = 0; i < 4; i++) { - x87_fld(&cp->func, x86_make_disp(arg0, i*4)); - x87_fprndint( &cp->func ); - x87_fstp(&cp->func, x86_make_disp(dst, i*4)); - } - - - return GL_TRUE; -} - -static GLboolean emit_FRC( struct compilation *cp, union instruction op ) -{ - struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst); - struct x86_reg st0 = x86_make_reg(file_x87, 0); - struct x86_reg st1 = x86_make_reg(file_x87, 1); - int i; - - set_fpu_round_neg_inf( cp ); - - /* Knowing liveness info or even just writemask would be useful - * here: - */ - for (i = 0; i < 4; i++) { - x87_fld(&cp->func, x86_make_disp(arg0, i*4)); - x87_fld(&cp->func, st0); /* a a */ - x87_fprndint( &cp->func ); /* flr(a) a */ - x87_fsubrp(&cp->func, st1); /* frc(a) */ - x87_fstp(&cp->func, x86_make_disp(dst, i*4)); - } - - return GL_TRUE; -} - - - -static GLboolean emit_LIT( struct compilation *cp, union instruction op ) -{ -#if 1 - struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst); - struct x86_reg lit = get_arg(cp, FILE_REG, REG_LIT); - struct x86_reg tmp = get_xmm_reg(cp); - struct x86_reg st1 = x86_make_reg(file_x87, 1); - struct x86_reg regEAX = x86_make_reg(file_REG32, reg_AX); - GLubyte *fixup1, *fixup2; - - - /* Load the interesting parts of arg0: - */ - x87_fld(&cp->func, x86_make_disp(arg0, 12)); /* a3 */ - x87_fld(&cp->func, x86_make_disp(arg0, 4)); /* a1 a3 */ - x87_fld(&cp->func, x86_make_disp(arg0, 0)); /* a0 a1 a3 */ - - /* Intialize dst: - */ - sse_movaps(&cp->func, tmp, lit); - sse_movaps(&cp->func, dst, tmp); - - /* Check arg0[0]: - */ - x87_fldz(&cp->func); /* 0 a0 a1 a3 */ - x87_fucomp(&cp->func, st1); /* a0 a1 a3 */ - x87_fnstsw(&cp->func, regEAX); - x86_sahf(&cp->func); - fixup1 = x86_jcc_forward(&cp->func, cc_AE); - - x87_fstp(&cp->func, x86_make_disp(dst, 4)); /* a1 a3 */ - - /* Check arg0[1]: - */ - x87_fldz(&cp->func); /* 0 a1 a3 */ - x87_fucomp(&cp->func, st1); /* a1 a3 */ - x87_fnstsw(&cp->func, regEAX); - x86_sahf(&cp->func); - fixup2 = x86_jcc_forward(&cp->func, cc_AE); - - /* Compute pow(a1, a3) - */ - x87_fyl2x(&cp->func); /* a3*log2(a1) */ - - emit_x87_ex2( cp ); /* 2^(a3*log2(a1)) */ - - x87_fstp(&cp->func, x86_make_disp(dst, 8)); - - /* Land jumps: - */ - x86_fixup_fwd_jump(&cp->func, fixup1); - x86_fixup_fwd_jump(&cp->func, fixup2); -#else - struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst); - struct x86_reg ones = get_reg_ptr(FILE_REG, REG_LIT); - sse_movups(&cp->func, dst, ones); -#endif - return GL_TRUE; -} - - - -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_xmm_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_xmm_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_xmm_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_xmm_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_ptr(cp, op.alu.file0, op.alu.idx0); - struct x86_reg arg1 = get_arg_ptr(cp, op.alu.file1, op.alu.idx1); - struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst); - - x87_fld(&cp->func, arg1); /* a1 */ - x87_fld(&cp->func, arg0); /* a0 a1 */ - x87_fyl2x(&cp->func); /* a1*log2(a0) */ - - emit_x87_ex2( cp ); /* 2^(a1*log2(a0)) */ - - x87_fst(&cp->func, x86_make_disp(dst, 0)); - x87_fst(&cp->func, x86_make_disp(dst, 4)); - x87_fst(&cp->func, x86_make_disp(dst, 8)); - x87_fstp(&cp->func, x86_make_disp(dst, 12)); - - return GL_TRUE; -} - -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_xmm_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_xmm_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_xmm_reg(cp, FILE_REG, op.alu.dst); -#if 0 - struct x86_reg neg = get_reg_ptr(FILE_REG, REG_NEG); - -/* get abs value first. This STILL doesn't work. - Looks like we get bogus neg values ? -*/ - sse_movss(&cp->func, dst, arg0); - sse_mulss(&cp->func, dst, neg); - sse_maxss(&cp->func, dst, arg0); - - sse_rsqrtss(&cp->func, dst, dst); -#endif - 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_xmm_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_xmm_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_xmm_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_xmm_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, /* ARA */ - emit_NOP, /* ARL */ - emit_NOP, /* ARL_NV */ - emit_NOP, /* ARR */ - emit_NOP, /* BRA */ - emit_NOP, /* CAL */ - emit_NOP, /* CMP */ - emit_NOP, /* COS */ - emit_NOP, /* DDX */ - emit_NOP, /* DDY */ - emit_DP3, - emit_DP4, - emit_DPH, - emit_DST, - emit_NOP, /* END */ - emit_EX2, - emit_EXP, - emit_FLR, - emit_FRC, - emit_NOP, /* KIL */ - emit_NOP, /* KIL_NV */ - emit_LG2, - emit_LIT, - emit_LOG, - emit_NOP, /* LRP */ - emit_NOP, /* MAD */ - emit_MAX, - emit_MIN, - emit_MOV, - emit_MUL, - emit_NOP, /* PK2H */ - emit_NOP, /* PK2US */ - emit_NOP, /* PK4B */ - emit_NOP, /* PK4UB */ - emit_POW, - emit_NOP, /* POPA */ - emit_PRT, - emit_NOP, /* PUSHA */ - emit_NOP, /* RCC */ - emit_RCP, - emit_NOP, /* RET */ - emit_NOP, /* RFL */ - emit_RSQ, - emit_NOP, /* SCS */ - emit_NOP, /* SEQ */ - emit_NOP, /* SFL */ - emit_SGE, - emit_NOP, /* SGT */ - emit_NOP, /* SIN */ - emit_NOP, /* SLE */ - emit_SLT, - emit_NOP, /* SNE */ - emit_NOP, /* SSG */ - emit_NOP, /* STR */ - emit_SUB, - emit_SWZ, /* SWZ */ - emit_NOP, /* TEX */ - emit_NOP, /* TXB */ - emit_NOP, /* TXD */ - emit_NOP, /* TXL */ - emit_NOP, /* TXP */ - emit_NOP, /* TXP_NV */ - emit_NOP, /* UP2H */ - emit_NOP, /* UP2US */ - emit_NOP, /* UP4B */ - emit_NOP, /* UP4UB */ - emit_NOP, /* X2D */ - emit_XPD, - emit_RSW, - emit_MSK, - emit_REL, -}; - - - -static GLboolean build_vertex_program( struct compilation *cp ) -{ - struct arb_vp_machine *m = NULL; - GLuint j; - - struct x86_reg regEBX = x86_make_reg(file_REG32, reg_BX); - struct x86_reg regECX = x86_make_reg(file_REG32, reg_CX); - struct x86_reg regEDX = x86_make_reg(file_REG32, reg_DX); - - x86_push(&cp->func, regEBX); - - x86_mov(&cp->func, regEDX, x86_fn_arg(&cp->func, 1)); - x86_mov(&cp->func, regEBX, x86_make_disp(regEDX, get_offset(m, m->File + FILE_REG))); - x86_mov(&cp->func, regECX, x86_make_disp(regEDX, get_offset(m, m->File + FILE_STATE_PARAM))); - - for (j = 0; j < cp->p->nr_instructions; j++) { - union instruction inst = cp->p->instructions[j]; - cp->insn_counter = j+1; /* avoid zero */ - - if (DISASSEM) { - _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); - - /* Restore FPU control word? - */ - if (cp->fpucntl != RESTORE_FPU) { - x87_fnclex(&cp->func); - x87_fldcw(&cp->func, x86_make_disp(regEDX, get_offset(m, &m->fpucntl_restore))); - } - - x86_pop(&cp->func, regEBX); - 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 tnl_compiled_program *p) -{ - struct compilation cp; - - /* sanity checks */ - assert(emit_func[OPCODE_ABS] == emit_ABS); - assert(emit_func[OPCODE_MUL] == emit_MUL); - assert(emit_func[OPCODE_XPD] == emit_XPD); - - _mesa_memset(&cp, 0, sizeof(cp)); - cp.p = p; - cp.have_sse2 = 1; - - if (p->compiled_func) { - _mesa_free((void *)p->compiled_func); - p->compiled_func = NULL; - } - - x86_init_func(&cp.func); - - cp.fpucntl = RESTORE_FPU; - - - /* Note ctx state is not referenced in building the function, so it - * depends only on the list of instructions: - */ - if (!build_vertex_program(&cp)) { - x86_release_func( &cp.func ); - return GL_FALSE; - } - - - p->compiled_func = (void (*)(struct arb_vp_machine *))x86_get_func( &cp.func ); - return GL_TRUE; -} - - - -#else - -GLboolean -_tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p) -{ - /* Dummy version for when USE_SSE_ASM not defined */ - return GL_FALSE; -} - -#endif |