diff options
Diffstat (limited to 'src/mesa/tnl/t_vb_arbprogram_sse.c')
-rw-r--r-- | src/mesa/tnl/t_vb_arbprogram_sse.c | 1330 |
1 files changed, 0 insertions, 1330 deletions
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 d0f66fd6196..00000000000 --- 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 |