#include "s_texture.h"
+#ifdef USE_TCC
+
/* UREG - a way of representing an FP source register including
* swizzling and negation in a single GLuint. Major flaw is the
* limitiation to source->Index < 32. Secondary flaw is the fact that
}
}
+static void emit( struct fragment_program *p,
+ const char *fmt,
+ ... )
+{
+ va_list ap;
+ va_start( ap, fmt );
+
+ if (p->c_strlen < sizeof(p->c_str))
+ p->c_strlen += vsnprintf( p->c_str + p->c_strlen,
+ sizeof(p->c_str) - p->c_strlen,
+ fmt, ap );
+
+ va_end( ap );
+}
+
+static INLINE void emit_char( struct fragment_program *p, char c )
+{
+ if (p->c_strlen < sizeof(p->c_str)) {
+ p->c_str[p->c_strlen] = c;
+ p->c_strlen++;
+ }
+}
+
/**
* Retrieve a ureg for the given source register. Will emit
{
GLuint src;
-/* fprintf(stderr, "%s File %d, Index %d\n", */
-/* __FUNCTION__, source->File, source->Index); */
-
assert(source->Index < 32); /* limitiation of UREG representation */
src = UREG( src_reg_file( source->File ), source->Index );
return src;
}
-static void print_header( void )
+
+static void print_header( struct fragment_program *p )
{
- printf("static void run_program( const GLfloat (*local_param)[4], \n"
- " const GLfloat (*env_param)[4], \n"
- " const GLfloat (*state_param)[4], \n"
- " const GLfloat (*interp)[4], \n"
- " GLfloat *outputs)\n"
+ emit(p, "\n\n\n");
+
+ /* Mesa's program_parameter struct:
+ */
+ emit(p,
+ "struct program_parameter\n"
+ "{\n"
+ " const char *Name;\n"
+ " int Type;\n"
+ " int StateIndexes[6];\n"
+ " float Values[4];\n"
+ "};\n");
+
+
+ /* Texture samplers, not written yet:
+ */
+ emit(p, "extern void TEX( void *ctx, const float *txc, int unit, float *rslt );\n"
+ "extern void TXB( void *ctx, const float *txc, int unit, float *rslt );\n"
+ "extern void TXP( void *ctx, const float *txc, int unit, float *rslt );\n");
+
+ /* Resort to the standard math library (float versions):
+ */
+ emit(p, "extern float fabsf( float );\n"
+ "extern float cosf( float );\n"
+ "extern float sinf( float );\n"
+ "extern float expf( float );\n"
+ "extern float powf( float, float );\n"
+ "extern float floorf( float );\n");
+
+ /* These ones we have fast code in Mesa for:
+ */
+ emit(p, "extern float LOG2( float );\n"
+ "extern float _mesa_inv_sqrtf( float );\n");
+
+ /* The usual macros, not really needed, but handy:
+ */
+ emit(p, "#define MIN2(x,y) ((x)<(y)?(x):(y))\n"
+ "#define MAX2(x,y) ((x)<(y)?(x):(y))\n"
+ "#define SATURATE(x) ((x)>1.0?1.0:((x)<0.0?0.0:(x)))\n");
+
+ /* Our function!
+ */
+ emit(p, "int run_program( void *ctx, \n"
+ " const float (*local_param)[4], \n"
+ " const float (*env_param)[4], \n"
+ " const struct program_parameter *state_param, \n"
+ " const float (*interp)[4], \n"
+ " float (*outputs)[4])\n"
"{\n"
- " GLfloat temp[32][4];\n"
+ " float temp[32][4];\n"
);
}
-static void print_footer( void )
+static void print_footer( struct fragment_program *p )
{
- printf("}\n");
+ emit(p, " return 1;");
+ emit(p, "}\n");
}
-static void print_dest_reg( const struct fp_instruction *inst )
+static void print_dest_reg( struct fragment_program *p,
+ const struct fp_instruction *inst )
{
switch (inst->DstReg.File) {
case PROGRAM_OUTPUT:
- printf("outputs[%d]", inst->DstReg.Index);
+ emit(p, "outputs[%d]", inst->DstReg.Index);
break;
case PROGRAM_TEMPORARY:
- printf("temp[%d]", inst->DstReg.Index);
+ emit(p, "temp[%d]", inst->DstReg.Index);
break;
default:
break;
}
}
-static void print_dest( const struct fp_instruction *inst,
+static void print_dest( struct fragment_program *p,
+ const struct fp_instruction *inst,
GLuint idx )
{
- print_dest_reg(inst);
- printf("[%d]", idx);
+ print_dest_reg(p, inst);
+ emit(p, "[%d]", idx);
}
#define UREG_SRC0(reg) (((reg)>>UREG_CHANNEL_X_SHIFT) & 0x7)
-static void print_reg( GLuint arg )
+static void print_reg( struct fragment_program *p,
+ GLuint arg )
{
switch (GET_UREG_TYPE(arg)) {
- case UREG_TYPE_TEMP: printf("temp"); break;
- case UREG_TYPE_INTERP: printf("interp"); break;
- case UREG_TYPE_LOCAL_CONST: printf("local_const"); break;
- case UREG_TYPE_ENV_CONST: printf("env_const"); break;
- case UREG_TYPE_STATE_CONST: printf("state_const"); break;
- case UREG_TYPE_PARAM: printf("param"); break;
+ case UREG_TYPE_TEMP: emit(p, "temp"); break;
+ case UREG_TYPE_INTERP: emit(p, "interp"); break;
+ case UREG_TYPE_LOCAL_CONST: emit(p, "local_const"); break;
+ case UREG_TYPE_ENV_CONST: emit(p, "env_const"); break;
+ case UREG_TYPE_STATE_CONST: emit(p, "state_param"); break;
+ case UREG_TYPE_PARAM: emit(p, "param"); break;
};
- printf("[%d]", GET_UREG_NR(arg));
+ emit(p, "[%d]", GET_UREG_NR(arg));
+
+ if (GET_UREG_TYPE(arg) == UREG_TYPE_STATE_CONST) {
+ emit(p, ".Values");
+ }
}
-static void print_arg( const struct fragment_program *p,
+static void print_arg( struct fragment_program *p,
GLuint arg )
{
GLuint src = UREG_SRC0(arg);
if (src == _ZERO) {
- printf("0");
+ emit(p, "0");
return;
}
if (arg & (1<<UREG_CHANNEL_X_NEGATE_SHIFT))
- printf("-");
+ emit(p, "-");
if (src == _ONE) {
- printf("1");
+ emit(p, "1");
return;
}
- if (GET_UREG_TYPE(arg) == UREG_TYPE_STATE_CONST) {
- printf("%g", p->Parameters->Parameters[GET_UREG_NR(arg)].Values[src]);
+ if (GET_UREG_TYPE(arg) == UREG_TYPE_STATE_CONST &&
+ p->Parameters->Parameters[GET_UREG_NR(arg)].Type == CONSTANT) {
+ emit(p, "%g", p->Parameters->Parameters[GET_UREG_NR(arg)].Values[src]);
return;
}
- print_reg( arg );
+ print_reg( p, arg );
switch (src){
- case _X: printf("[0]"); break;
- case _Y: printf("[1]"); break;
- case _Z: printf("[2]"); break;
- case _W: printf("[3]"); break;
+ case _X: emit(p, "[0]"); break;
+ case _Y: emit(p, "[1]"); break;
+ case _Z: emit(p, "[2]"); break;
+ case _W: emit(p, "[3]"); break;
}
}
/* This is where the handling of expressions breaks down into string
* processing:
*/
-static void print_expression( const struct fragment_program *p,
+static void print_expression( struct fragment_program *p,
GLuint i,
const char *fmt,
va_list ap )
fmt += 2;
}
else {
- putchar(*fmt);
+ emit_char(p, *fmt);
fmt++;
}
}
- printf(";\n");
+ emit(p, ";\n");
+}
+
+static void do_tex_kill( struct fragment_program *p,
+ const struct fp_instruction *inst,
+ GLuint arg )
+{
+ GLuint i;
+
+ emit(p, "if (");
+
+ for (i = 0; i < 4; i++) {
+ print_arg( p, deref(arg, i) );
+ emit(p, " < 0 ");
+ if (i + 1 < 4)
+ emit(p, "|| ");
+ }
+
+ emit(p, ")\n");
+ emit(p, " return 0;\n");
+
}
-static void do_tex_simple( const struct fragment_program *p,
+static void do_tex_simple( struct fragment_program *p,
const struct fp_instruction *inst,
const char *fn, GLuint texunit, GLuint arg )
{
- printf(" %s( ctx, ", fn);
- print_reg(arg);
- printf(", %d, ", texunit );
- print_dest_reg(inst);
- printf(");\n");
+ emit(p, " %s( ctx, ", fn);
+ print_reg( p, arg );
+ emit(p, ", %d, ", texunit );
+ print_dest_reg(p, inst);
+ emit(p, ");\n");
}
-static void do_tex( const struct fragment_program *p,
+static void do_tex( struct fragment_program *p,
const struct fp_instruction *inst,
const char *fn, GLuint texunit, GLuint arg )
{
return;
}
- printf(" {\n");
- printf(" GLfloat texcoord[4];\n");
- printf(" GLfloat result[4];\n");
+ emit(p, " {\n");
+ emit(p, " float texcoord[4];\n");
+ emit(p, " float result[4];\n");
for (i = 0; i < 4; i++) {
- printf(" texcoord[%d] = ", i);
+ emit(p, " texcoord[%d] = ", i);
print_arg( p, deref(arg, i) );
- printf(";\n");
+ emit(p, ";\n");
}
- printf(" %s( ctx, texcoord, %d, result);\n", fn, texunit );
+ emit(p, " %s( ctx, texcoord, %d, result);\n", fn, texunit );
for (i = 0; i < 4; i++) {
if (inst->DstReg.WriteMask[i]) {
- printf(" ");
- print_dest(inst, i);
- printf(" = result[%d];\n", i);
+ emit(p, " ");
+ print_dest(p, inst, i);
+ emit(p, " = result[%d];\n", i);
}
}
- printf(" }\n");
+ emit(p, " }\n");
+}
+
+
+static void saturate( struct fragment_program *p,
+ const struct fp_instruction *inst,
+ GLuint i )
+{
+ emit(p, " ");
+ print_dest(p, inst, i);
+ emit(p, " = SATURATE( ");
+ print_dest(p, inst, i);
+ emit(p, ");\n");
}
static void assign_single( GLuint i,
- const struct fragment_program *p,
+ struct fragment_program *p,
const struct fp_instruction *inst,
const char *fmt,
... )
va_start( ap, fmt );
if (inst->DstReg.WriteMask[i]) {
- printf(" ");
- print_dest(inst, i);
- printf(" = ");
+ emit(p, " ");
+ print_dest(p, inst, i);
+ emit(p, " = ");
print_expression( p, i, fmt, ap);
+ if (inst->Saturate)
+ saturate(p, inst, i);
}
va_end( ap );
}
-static void assign4( const struct fragment_program *p,
+static void assign4( struct fragment_program *p,
const struct fp_instruction *inst,
const char *fmt,
... )
for (i = 0; i < 4; i++)
if (inst->DstReg.WriteMask[i]) {
- printf(" ");
- print_dest(inst, i);
- printf(" = ");
+ emit(p, " ");
+ print_dest(p, inst, i);
+ emit(p, " = ");
print_expression( p, i, fmt, ap);
+ if (inst->Saturate)
+ saturate(p, inst, i);
}
va_end( ap );
}
-static void assign4_replicate( const struct fragment_program *p,
+static void assign4_replicate( struct fragment_program *p,
const struct fp_instruction *inst,
const char *fmt,
... )
{
- GLuint i;
+ GLuint i, first = 0;
GLboolean ok = 0;
va_list ap;
for (i = 0; i < 4; i++)
- if (inst->DstReg.WriteMask[i])
+ if (inst->DstReg.WriteMask[i]) {
ok = 1;
+ first = i;
+ break;
+ }
if (!ok) return;
va_start( ap, fmt );
- printf(" ");
-
- for (i = 0; i < 4; i++)
- if (inst->DstReg.WriteMask[i]) {
- print_dest(inst, i);
- printf(" = ");
- }
+ emit(p, " ");
+ print_dest(p, inst, first);
+ emit(p, " = ");
print_expression( p, 0, fmt, ap);
-
+ if (inst->Saturate)
+ saturate(p, inst, first);
va_end( ap );
-}
-
-
+ for (i = first+1; i < 4; i++)
+ if (inst->DstReg.WriteMask[i]) {
+ emit(p, " ");
+ print_dest(p, inst, i);
+ emit(p, " = ");
+ print_dest(p, inst, first);
+ emit(p, ";\n");
+ }
+}
+
-static void upload_program( const struct fragment_program *p )
+static void translate_program( struct fragment_program *p )
{
const struct fp_instruction *inst = p->Instructions;
src[i] = src_vector( &inst->SrcReg[i] );
/* Print the original program instruction string */
+ if (p->Base.String)
{
const char *s = (const char *) p->Base.String + inst->StringPos;
- printf(" /* ");
+ emit(p, " /* ");
while (*s != ';') {
- putchar(*s);
+ emit_char(p, *s);
s++;
}
- printf("; */\n");
+ emit(p, "; */\n");
}
switch (inst->Opcode) {
case FP_OPCODE_ABS:
- assign4(p, inst, "FABSF(%s)", src[0]);
+ assign4(p, inst, "fabsf(%s)", src[0]);
break;
case FP_OPCODE_ADD:
* result[1] = a[1] * b[1];
* result[2] = a[2] * 1;
* result[3] = 1 * b[3];
- *
- * Here we hope that the compiler can optimize away "x*1" to "x".
*/
- assign4(p, inst,
- "%s*%s",
- swizzle(src[0], _ONE, _Y, _Z, _ONE),
- swizzle(src[1], _ONE, _Y, _ONE, _W ));
+ assign_single(0, p, inst, "1.0");
+
+ assign_single(1, p, inst, "%s * %s",
+ deref(src[0], _Y), deref(src[1], _Y));
+
+ assign_single(2, p, inst, "%s", deref(src[0], _Z));
+ assign_single(3, p, inst, "%s", deref(src[1], _W));
break;
case FP_OPCODE_EX2:
- assign4_replicate(p, inst, "EX2(%s)", src[0]);
+ assign4_replicate(p, inst, "powf(2.0, %s)", src[0]);
break;
case FP_OPCODE_FLR:
- assign4_replicate(p, inst, "FLR(%s)", src[0]);
+ assign4_replicate(p, inst, "floorf(%s)", src[0]);
break;
case FP_OPCODE_FRC:
- assign4_replicate(p, inst, "FRC(%s)", src[0]);
+ assign4_replicate(p, inst, "%s - floorf(%s)", src[0], src[0]);
break;
case FP_OPCODE_KIL:
- /* TODO */
+ do_tex_kill(p, inst, src[0]);
break;
case FP_OPCODE_LG2:
- assign4_replicate(p, inst, "LOG(%s)", deref(src[0], _X));
+ assign4_replicate(p, inst, "LOG2(%s)", src[0]);
break;
case FP_OPCODE_LIT:
assign_single(0, p, inst, "1.0");
assign_single(1, p, inst, "MIN2(%s, 0)", deref(src[0], _X));
- assign_single(2, p, inst, "(%s > 0.0) ? EXP(%s * MIN2(%s, 0)) : 0.0",
+ assign_single(2, p, inst, "(%s > 0.0) ? expf(%s * MIN2(%s, 0)) : 0.0",
deref(src[0], _X),
deref(src[0], _Z),
deref(src[0], _Y));
break;
case FP_OPCODE_POW:
- assign4_replicate(p, inst, "POW(%s, %s)",
- deref(src[0], _X),
- deref(src[1], _X));
+ assign4_replicate(p, inst, "powf(%s, %s)", src[0], src[1]);
break;
case FP_OPCODE_RCP:
- assign4_replicate(p, inst, "1.0/%s", deref(src[0], _X));
+ assign4_replicate(p, inst, "1.0/%s", src[0]);
break;
case FP_OPCODE_RSQ:
- assign4_replicate(p, inst, "INV_SQRTF(%s)", deref(src[0], _X));
+ assign4_replicate(p, inst, "_mesa_inv_sqrtf(%s)", src[0]);
break;
case FP_OPCODE_SCS:
if (inst->DstReg.WriteMask[0]) {
- assign_single(0, p, inst, "COS(%s)", deref(src[0], _X));
+ assign_single(0, p, inst, "cosf(%s)", deref(src[0], _X));
}
if (inst->DstReg.WriteMask[1]) {
- assign_single(1, p, inst, "SIN(%s)", deref(src[0], _X));
+ assign_single(1, p, inst, "sinf(%s)", deref(src[0], _X));
}
break;
break;
case FP_OPCODE_SIN:
- assign4_replicate(p, inst, "SIN(%s)", deref(src[0], _X));
+ assign4_replicate(p, inst, "sinf(%s)", src[0]);
break;
case FP_OPCODE_SLT:
do_tex(p, inst, "TXP", inst->TexSrcUnit, src[0]);
break;
- case FP_OPCODE_X2D:
+ case FP_OPCODE_XPD:
/* Cross product:
* result.x = src[0].y * src[1].z - src[0].z * src[1].y;
* result.y = src[0].z * src[1].x - src[0].x * src[1].z;
break;
default:
+ emit(p, "BOGUS OPCODE\n");
return;
}
}
void _swrast_translate_program( GLcontext *ctx )
{
- if (ctx->FragmentProgram.Current) {
- print_header();
- upload_program( ctx->FragmentProgram.Current );
- print_footer();
+ struct fragment_program *p = ctx->FragmentProgram.Current;
+
+ if (p) {
+ p->c_strlen = 0;
+
+ print_header( p );
+ translate_program( p );
+ print_footer( p );
}
}
+#endif /*USE_TCC*/