fix minor typo in comment
[mesa.git] / src / mesa / swrast / s_fragprog_to_c.c
index b649da2a3ed57e4349bdf5f1d7336d54108f4b15..d5d27d0bcf713cddb35a3ea8f69983b8a8cf035d 100644 (file)
@@ -39,6 +39,8 @@
 #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
@@ -150,6 +152,29 @@ static GLuint src_reg_file( GLuint file )
    }
 }
 
+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
@@ -159,9 +184,6 @@ static GLuint src_vector( const struct fp_src_register *source )
 {
    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 );
@@ -178,92 +200,145 @@ static GLuint src_vector( const struct fp_src_register *source )
    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;
    }   
 }
 
@@ -271,7 +346,7 @@ static void print_arg( const struct fragment_program *p,
 /* 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 )
@@ -286,27 +361,47 @@ static void print_expression( const struct fragment_program *p,
         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 )
 {
@@ -325,31 +420,43 @@ static void do_tex( const struct fragment_program *p,
       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,
                           ... )
@@ -358,16 +465,18 @@ static void assign_single( GLuint i,
    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,
                     ... )
@@ -378,47 +487,56 @@ static void assign4( const struct fragment_program *p,
 
    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");
+      }
+}
+        
 
 
 
@@ -464,7 +582,7 @@ static GLuint nr_args( GLuint opcode )
 
 
 
-static void upload_program( const struct fragment_program *p )
+static void translate_program( struct fragment_program *p )
 {
    const struct fp_instruction *inst = p->Instructions;
 
@@ -477,19 +595,20 @@ static void upload_program( const struct fragment_program *p )
         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: 
@@ -541,39 +660,40 @@ static void upload_program( const struct fragment_program *p )
          * 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));
@@ -607,26 +727,24 @@ static void upload_program( const struct fragment_program *p )
         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;
 
@@ -635,7 +753,7 @@ static void upload_program( const struct fragment_program *p )
         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: 
@@ -662,7 +780,7 @@ static void upload_program( const struct fragment_program *p )
         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;
@@ -678,6 +796,7 @@ static void upload_program( const struct fragment_program *p )
         break;
 
       default:
+        emit(p, "BOGUS OPCODE\n");
         return;
       }
    }
@@ -689,10 +808,15 @@ static void upload_program( const struct fragment_program *p )
 
 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*/