note to self: don't post this late...

Rune Petersen wrote:
> Hi,
> 
> Getting proper SIN and COS wasn't as easy as it appeared. I had to make
> make some changes to the fragment program code.
> 
> general FP changes:
> - support HHH swizzle for vector instructions.
> - don't copy a source to a temp when it is not XYZW swizzled, but
>   combine the two and have the swizzle resolve any issues.
>   (saves temps/instructions with more elaborate shader code)
> - Disable refcounting of temps.
>   The temp R0 in progs/fp/tri-cos.c is freed prematurely.
>   This should be resolved properly.
> - fix overflow in cnstv[].
> 
> 
> SIN & COS:
> they are based on:
>       http://www.devmaster.net/forums/showthread.php?t=5784
> 
> There is an fast and a slow(high precision) version of SIN & COS.
> 
> For SIN:
> fast = 2 vector instructions
> slow = 5 vector instructions
> 
> For COS:
> fast = 5 vector instructions + 2 scaler instructions
> slow = 8 vector instructions + 2 scaler instructions
> 
> The fast version appears to do a fine enough job, at least with the
> simple test I have made.
> 
> 
> Rune Petersen

diff --git a/src/mesa/drivers/dri/r300/r300_context.c b/src/mesa/drivers/dri/r300/r300_context.c
diff --git a/src/mesa/drivers/dri/r300/r300_context.h b/src/mesa/drivers/dri/r300/r300_context.h
index 02f8e91..fa636d8 100644
--- a/src/mesa/drivers/dri/r300/r300_context.h
+++ b/src/mesa/drivers/dri/r300/r300_context.h
@@ -729,6 +729,9 @@ struct r300_fragment_program {
 	GLboolean params_uptodate;
 
 	int max_temp_idx;
+
+	/* the index of the sin constant is stored here */
+	GLint const_sin;
 };
 
 #define R300_MAX_AOS_ARRAYS		16
diff --git a/src/mesa/drivers/dri/r300/r300_fragprog.c b/src/mesa/drivers/dri/r300/r300_fragprog.c
index 6e85f0b..eff86e9 100644
--- a/src/mesa/drivers/dri/r300/r300_fragprog.c
+++ b/src/mesa/drivers/dri/r300/r300_fragprog.c
@@ -51,6 +51,8 @@
 #include "r300_fragprog.h"
 #include "r300_reg.h"
 
+#define FAST_SIN
+
 /*
  * Usefull macros and values
  */
@@ -187,6 +189,10 @@ static const struct {
 #define SLOT_VECTOR	(1<<0)
 #define SLOT_SCALAR	(1<<3)
 #define SLOT_BOTH	(SLOT_VECTOR | SLOT_SCALAR)
+
+/* mapping from SWIZZLE_* to r300 native values for scalar insns */
+#define SWIZZLE_HALF 6
+
 #define MAKE_SWZ3(x, y, z) (MAKE_SWIZZLE4(SWIZZLE_##x, \
 					  SWIZZLE_##y, \
 					  SWIZZLE_##z, \
@@ -208,7 +214,7 @@ static const struct r300_pfs_swizzle {
 	{ MAKE_SWZ3(W, Z, Y), R300_FPI0_ARGC_SRC0CA_WZY, 1, SLOT_BOTH },
 	{ MAKE_SWZ3(ONE, ONE, ONE), R300_FPI0_ARGC_ONE, 0, 0},
 	{ MAKE_SWZ3(ZERO, ZERO, ZERO), R300_FPI0_ARGC_ZERO, 0, 0},
-	{ PFS_INVAL, R300_FPI0_ARGC_HALF, 0, 0},
+	{ MAKE_SWZ3(HALF, HALF, HALF), R300_FPI0_ARGC_HALF, 0, 0},
 	{ PFS_INVAL, 0, 0, 0},
 };
 
@@ -232,8 +238,6 @@ static const struct {
 	{ PFS_INVAL, PFS_INVAL, PFS_INVAL}
 };
 
-/* mapping from SWIZZLE_* to r300 native values for scalar insns */
-#define SWIZZLE_HALF 6
 static const struct {
 	int base;	/* hw value of swizzle */
 	int stride;	/* difference between SRC0/1/2 */
@@ -590,6 +594,7 @@ static GLuint do_swizzle(struct r300_fragment_program *rp,
 	/* If swizzling from something without an XYZW native swizzle,
 	 * emit result to a temp, and do new swizzle from the temp.
 	 */
+#if 0
 	if (REG_GET_VSWZ(src) != SWIZZLE_XYZ ||
 	    REG_GET_SSWZ(src) != SWIZZLE_W) {
 		GLuint temp = get_temp_reg(rp);
@@ -603,10 +608,33 @@ static GLuint do_swizzle(struct r300_fragment_program *rp,
 			   0);
 		src = temp;
 	}
+#endif
 
 	/* set scalar swizzling */
 	REG_SET_SSWZ(src, GET_SWZ(arbswz, 3));
 
+	if (REG_GET_VSWZ(src) != SWIZZLE_XYZ ||
+	    REG_GET_SSWZ(src) != SWIZZLE_W) {
+	    GLuint vsrcswz = (v_swiz[REG_GET_VSWZ(src)].hash & (SWZ_X_MASK|SWZ_Y_MASK|SWZ_Z_MASK)) | REG_GET_SSWZ(src) << 9;
+	    GLint i;
+
+	    GLuint newswz = 0;
+	    GLuint offset;
+	    for(i=0; i < 4; ++i){
+		offset = GET_SWZ(arbswz, i);
+		
+		newswz |= (offset <= 3)?GET_SWZ(vsrcswz, offset) << i*3:offset << i*3;
+	    }
+
+	    arbswz = newswz & (SWZ_X_MASK|SWZ_Y_MASK|SWZ_Z_MASK);
+	    REG_SET_SSWZ(src, GET_SWZ(newswz, 3));
+	}
+	else
+	{
+	    /* set scalar swizzling */
+	    REG_SET_SSWZ(src, GET_SWZ(arbswz, 3));
+
+	}
 	do {
 		vswz = REG_GET_VSWZ(src);
 		do {
@@ -746,9 +774,11 @@ static int t_hw_src(struct r300_fragment_program *rp,
 
 		idx = cs->temps[index].reg;
 
+/*
 		if (!REG_GET_NO_USE(src) &&
 		    (--cs->temps[index].refcount == 0))
 			free_temp(rp, src);
+*/
 		break;
 	case REG_TYPE_INPUT:
 		idx = cs->inputs[index].reg;
@@ -790,9 +820,11 @@ static int t_hw_dst(struct r300_fragment_program *rp,
 		}
 		idx = cs->temps[index].reg;
 
+/*
 		if (!REG_GET_NO_USE(dest) &&
 		    (--cs->temps[index].refcount == 0))
 			free_temp(rp, dest);
+*/
 
 		cs->dest_in_node |= (1 << idx);
 		cs->used_in_node |= (1 << idx);
@@ -1201,7 +1233,6 @@ static GLboolean parse_program(struct r300_fragment_program *rp)
 			flags = PFS_FLAG_SAT;
 		else
 			flags = 0;
-
 		if (fpi->Opcode != OPCODE_KIL) {
 			dest = t_dst(rp, fpi->DstReg);
 			mask = fpi->DstReg.WriteMask;
@@ -1234,62 +1265,88 @@ static GLboolean parse_program(struct r300_fragment_program *rp)
 			break;
 		case OPCODE_COS:
 			/*
-			 * cos using taylor serie:
-			 * cos(x) = 1 - x^2/2! + x^4/4! - x^6/6!
+			 * cos using a parabola (see SIN):
+			 * cos(x):
+			 *   x += PI/2
+			 *   x = (x < PI)?x : x-2*PI
+			 *   result = sin(x)
 			 */
 			temp = get_temp_reg(rp);
-			cnstv[0] = 0.5;
-			cnstv[1] = 0.041666667;
-			cnstv[2] = 0.001388889;
-			cnstv[4] = 0.0;
-			cnst = emit_const4fv(rp, cnstv);
+			if(rp->const_sin == -1){
+			    cnstv[0] = 1.273239545;
+			    cnstv[1] =-0.405284735;
+			    cnstv[2] = 3.141592654;
+			    cnstv[3] = 0.225;
+			    rp->const_sin = emit_const4fv(rp, cnstv);
+			}
+			cnst = rp->const_sin;			
 			src[0] = t_scalar_src(rp, fpi->SrcReg[0]);
 
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_XYZ,
-				   src[0],
-				   src[0],
-				   pfs_zero,
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_Y | WRITEMASK_Z,
-				   temp, temp,
-				   pfs_zero,
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_Z,
-				   temp,
-				   swizzle(temp, X, X, X, W),
-				   pfs_zero,
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_XYZ,
-				   temp, cnst,
+			emit_arith(rp, PFS_OP_LG2, temp, WRITEMASK_W,
+				   pfs_half,
+				   undef,
+				   undef,
+				   0);
+
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_X,
+				   swizzle(cnst, Z, Z, Z, Z), //PI
+				   pfs_half,
+				   swizzle(src[0], X, X, X, X),
+				   0);
+
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_W,
+				   negate(swizzle(temp, W, W, W, W)), //-2
+				   swizzle(cnst, Z, Z, Z, Z), //PI
+				   swizzle(temp, X, X, X, X),
+				   0);
+
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_Y,
+				   swizzle(cnst, Z, Z, Z, Z), //PI
+				   negate(pfs_half),
+				   swizzle(src[0], X, X, X, X),
+				   0);
+			
+			emit_arith(rp, PFS_OP_CMP, temp, WRITEMASK_Z,
+				   swizzle(temp, W, W, W, W),
+				   swizzle(temp, X, X, X, X),
+				   swizzle(temp, Y, Y, Y, Y), 
+				   0);
+
+			/* SIN */
+
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_X | WRITEMASK_Y,
+				   swizzle(temp, Z, Z, Z, Z),
+				   cnst,
 				   pfs_zero,
+				   0);
+
+#ifdef FAST_SIN
+			emit_arith(rp, PFS_OP_MAD, dest, mask,
+				   swizzle(temp, Y, Y, Y, Y),
+				   absolute(swizzle(temp, Z, Z, Z, Z)),
+				   swizzle(temp, X, X, X, X),
 				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_X,
-				   pfs_one,
-				   pfs_one,
-				   negate(temp),
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_X,
-				   temp,
-				   pfs_one,
-				   swizzle(temp, Y, Y, Y, W),
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_X,
-				   temp,
-				   pfs_one,
-				   negate(swizzle(temp, Z, Z, Z, W)),
-				   flags);
+#else
+
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_X,
+				   swizzle(temp, Y, Y, Y, Y),
+				   absolute(swizzle(temp, Z, Z, Z, Z)),
+				   swizzle(temp, X, X, X, X),
+				   0);
+			
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_Y,
+				   swizzle(temp, X, X, X, X),
+				   absolute(swizzle(temp, X, X, X, X)),
+				   negate(swizzle(temp, X, X, X, X)),
+				   0);
+
+
 			emit_arith(rp, PFS_OP_MAD, dest, mask,
+				   swizzle(temp, Y, Y, Y, Y),
+				   swizzle(cnst, W, W, W, W),
 				   swizzle(temp, X, X, X, X),
-				   pfs_one,
-				   pfs_zero,
 				   flags);
+#endif
 			free_temp(rp, temp);
 			break;
 		case OPCODE_DP3:
@@ -1398,7 +1455,7 @@ static GLboolean parse_program(struct r300_fragment_program *rp)
 			 * change the compare to (t.x + 0.5) > 0.5 we may
 			 * save one instruction by doing CMP -t.x 
 			 */
-			cnstv[0] = cnstv[1] = cnstv[2] = cnstv[4] = 0.50001;
+			cnstv[0] = cnstv[1] = cnstv[2] = cnstv[3] = 0.50001;
 			src[0] = t_src(rp, fpi->SrcReg[0]);
 			temp = get_temp_reg(rp);
 			cnst = emit_const4fv(rp, cnstv);
@@ -1548,68 +1605,55 @@ static GLboolean parse_program(struct r300_fragment_program *rp)
 			break;
 		case OPCODE_SIN:
 			/*
-			 * sin using taylor serie:
-			 * sin(x) = x - x^3/3! + x^5/5! - x^7/7!
+			 *  using a parabola:
+			 * sin(x) = 4/pi * x + -4/(pi*pi) * x * abs(x)
+			 * extra precision is obtained by weighting against
+			 * itself squared.
 			 */
+
 			temp = get_temp_reg(rp);
-			cnstv[0] = 0.333333333;
-			cnstv[1] = 0.008333333;
-			cnstv[2] = 0.000198413;
-			cnstv[4] = 0.0;
-			cnst = emit_const4fv(rp, cnstv);
+			if(rp->const_sin == -1){
+			    cnstv[0] = 1.273239545;
+			    cnstv[1] =-0.405284735;
+			    cnstv[2] = 3.141592654;
+			    cnstv[3] = 0.225;
+			    rp->const_sin = emit_const4fv(rp, cnstv);
+			}
+			cnst = rp->const_sin;
 			src[0] = t_scalar_src(rp, fpi->SrcReg[0]);
 
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_XYZ,
-				   src[0],
-				   src[0],
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_X | WRITEMASK_Y,
+				   swizzle(src[0], X, X, X, X),
+				   cnst,
 				   pfs_zero,
+				   0);
+#ifdef FAST_SIN
+			emit_arith(rp, PFS_OP_MAD, dest, mask,
+				   swizzle(temp, Y, Y, Y, Y),
+				   absolute(swizzle(src[0], X, X, X, X)),
+				   swizzle(temp, X, X, X, X),
 				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_Y | WRITEMASK_Z,
-				   temp, temp,
-				   pfs_zero,
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_Z,
-				   temp,
-				   swizzle(temp, X, X, X, W),
-				   pfs_zero,
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_XYZ,
-				   src[0],
-				   temp,
-				   pfs_zero,
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_XYZ,
-				   temp, cnst,
-				   pfs_zero,
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_X,
-				   src[0],
-				   pfs_one,
-				   negate(temp),
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_X,
-				   temp,
-				   pfs_one,
-				   swizzle(temp, Y, Y, Y, W),
-				   flags);
-			emit_arith(rp, PFS_OP_MAD, temp,
-				   WRITEMASK_X,
-				   temp,
-				   pfs_one,
-				   negate(swizzle(temp, Z, Z, Z, W)),
-				   flags);
+#else
+
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_X,
+				   swizzle(temp, Y, Y, Y, Y),
+				   absolute(swizzle(src[0], X, X, X, X)),
+				   swizzle(temp, X, X, X, X),
+				   0);
+			
+			emit_arith(rp, PFS_OP_MAD, temp, WRITEMASK_Y,
+				   swizzle(temp, X, X, X, X),
+				   absolute(swizzle(temp, X, X, X, X)),
+				   negate(swizzle(temp, X, X, X, X)),
+				   0);
+
+
 			emit_arith(rp, PFS_OP_MAD, dest, mask,
+				   swizzle(temp, Y, Y, Y, Y),
+				   swizzle(cnst, W, W, W, W),
 				   swizzle(temp, X, X, X, X),
-				   pfs_one,
-				   pfs_zero,
 				   flags);
+#endif
 			free_temp(rp, temp);
 			break;
 		case OPCODE_SLT:
@@ -1703,6 +1747,7 @@ static void init_program(struct r300_fragment_program *rp)
 	rp->max_temp_idx = 0;
 	rp->node[0].alu_end = -1;
 	rp->node[0].tex_end = -1;
+	rp->const_sin = -1;
 	
 	_mesa_memset(cs, 0, sizeof(*rp->cs));
 	for (i=0;i<PFS_MAX_ALU_INST;i++) {
diff --git a/src/mesa/drivers/dri/r300/r300_state.c b/src/mesa/drivers/dri/r300/r300_state.c
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to