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