Use tcc and the emitted C code from s_fragprog_to_c.c to dynamically compile
authorKeith Whitwell <keith@tungstengraphics.com>
Wed, 14 Apr 2004 21:19:34 +0000 (21:19 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Wed, 14 Apr 2004 21:19:34 +0000 (21:19 +0000)
and execute fragment programs.  Very limited and experimental, but works
well enough to run arbfplight.c.

http://fabrice.bellard.free.fr/tcc/

Compile with 'make linux-tcc', being sure to make clean first.

Make-config
Makefile
progs/Makefile
progs/tests/Makefile
src/mesa/main/mtypes.h
src/mesa/sources
src/mesa/swrast/s_context.h
src/mesa/swrast/s_fragprog_to_c.c
src/mesa/swrast/s_nvfragprog.c
src/mesa/swrast/s_tcc.c [new file with mode: 0644]

index 2b2362fa00743df1b815119ed21f8dbd0a6ad645..7e37afaa20f0df23e5f466f5de1eb535fb46e7ee 100644 (file)
@@ -685,7 +685,7 @@ linux-x86:
        "CC = gcc" \
        "CXX = g++" \
        "CFLAGS = -Wall -O3 -ansi -pedantic -fPIC -D_POSIX_SOURCE -D_POSIX_C_SOURCE=199309L -D_SVID_SOURCE -D_BSD_SOURCE -DUSE_XSHM -DUSE_X86_ASM -DUSE_MMX_ASM -DUSE_3DNOW_ASM -DUSE_SSE_ASM -DPTHREADS -I/usr/X11R6/include" \
-       "CXXFLAGS = -Wall -O3 -ansi -pedantic -fPIC -D_POSIX_SOURCE -D_POSIX_C_SOURCE=199309L -D_SVID_SOURCE -D_BSD_SOURCE" \
+       "CXXFLAGS = -Wall -g -ansi -pedantic -fPIC -D_POSIX_SOURCE -D_POSIX_C_SOURCE=199309L -D_SVID_SOURCE -D_BSD_SOURCE" \
        "GLUT_CFLAGS = -fexceptions" \
        "GL_LIB_DEPS = -L/usr/X11R6/lib -lX11 -lXext -lm -lpthread" \
        "OSMESA_LIB_DEPS = -L$(TOP)/lib -lGL" \
index ad59e5b85bc3fbf465db0c42f1d690d4a9f6510b..10bf76d25d6b5115ca6961febe79e51ea7d6c3f8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ SUBDIRS = src progs
 
 default: $(TOP)/configs/current
        @for dir in $(SUBDIRS) ; do \
-               (cd $$dir ; make) ; \
+               (cd $$dir ; make) || exit 1 ; \
        done
 
 
@@ -78,6 +78,7 @@ linux-sparc \
 linux-sparc5 \
 linux-static \
 linux-ultrasparc \
+linux-tcc \
 linux-x86 \
 linux-x86-debug \
 linux-x86-64 \
index 7f4ee09961951f3a658d6f27e4b38836bc13a649..c44c9d73e4a294f31e65adbaca5c3d1f30ef3a59 100644 (file)
@@ -10,7 +10,7 @@ SUBDIRS = $(PROGRAM_DIRS)
 default: $(TOP)/configs/current
        @for dir in $(SUBDIRS) ; do \
                if [ -d $$dir ] ; then \
-                       (cd $$dir ; make) ; \
+                       (cd $$dir ; make) || exit 1 ; \
                fi \
        done
 
index ee75e71c7d7ca7660e6164950ef1b7d9368b8ef7..ac354aeeb69a88f287166bfa207a4fafe66f3539 100644 (file)
@@ -15,6 +15,7 @@ SOURCES = antialias.c \
        arbfptest1.c \
        arbfptexture.c \
        arbfptrig.c \
+       arbfpwpos.c \
        arbvptest1.c \
        arbvptest3.c \
        arbvptorus.c \
index b74eeacccab7e8297e83669dea08399e946756f2..aeeab8273327bfa0f03f4159567b14ff86c06c11 100644 (file)
@@ -1579,6 +1579,11 @@ struct fragment_program
    GLuint NumTexIndirections;
    GLenum FogOption;
    struct program_parameter_list *Parameters; /**< array [NumParameters] */
+
+#ifdef USE_TCC
+   char c_str[4096];           /* experimental... */
+   int c_strlen;
+#endif
 };
 
 
index 249734f7837d125f249f327739c9fca1af988e51..14c4205bbd9596d52e7bc96db8c899dd07bc0714 100644 (file)
@@ -70,6 +70,7 @@ ARRAY_CACHE_SOURCES = \
        array_cache/ac_import.c
 
 SWRAST_SOURCES = \
+       swrast/s_fragprog_to_c.c \
        swrast/s_aaline.c \
        swrast/s_aatriangle.c \
        swrast/s_accum.c \
@@ -95,6 +96,7 @@ SWRAST_SOURCES = \
        swrast/s_readpix.c \
        swrast/s_span.c \
        swrast/s_stencil.c \
+       swrast/s_tcc.c \
        swrast/s_texture.c \
        swrast/s_texstore.c \
        swrast/s_triangle.c \
index d6a14e6b4a050de386320d2853f730c28872e5fb..9d14c89bd601fcd270a94f3a768e0748d35c9bb5 100644 (file)
@@ -384,4 +384,18 @@ _swrast_validate_derived( GLcontext *ctx );
 #define FixedToChan(X)  FixedToInt(X)
 #endif
 
+
+
+extern void 
+_swrast_translate_program( GLcontext *ctx );
+
+extern GLboolean 
+_swrast_execute_codegen_program(GLcontext *ctx,
+                               const struct fragment_program *program, 
+                               GLuint maxInst,
+                               struct fp_machine *machine, 
+                               const struct sw_span *span,
+                               GLuint column );
+
+
 #endif
index f4bae2a82d000d4c0fccb5517ab163d1694829f6..647510a4c97319fdefa652a827d8ed35fab06455 100644 (file)
@@ -157,19 +157,20 @@ static void emit( struct fragment_program *p,
    va_list ap;
    va_start( ap, fmt );  
 
-   p->c_strlen += vsnprintf( p->c_str + p->c_strlen, 
-                            sizeof(p->c_str) - p->c_strlen,
-                            fmt, ap );
+   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))
+   if (p->c_strlen < sizeof(p->c_str)) {
        p->c_str[p->c_strlen] = c;
-   
-   p->c_strlen++;
+       p->c_strlen++;
+   }
 }
 
 
@@ -202,6 +203,18 @@ static void print_header( struct fragment_program *p )
 {
    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"
@@ -229,10 +242,10 @@ static void print_header( struct fragment_program *p )
 
    /* Our function!
     */
-   emit(p, "void run_program( void *ctx, \n"
+   emit(p, "int run_program( void *ctx, \n"
          "                  const float (*local_param)[4], \n"
          "                  const float (*env_param)[4], \n"
-         "                  const float (*state_param)[4], \n"
+         "                  const struct program_parameter *state_param, \n"
          "                  const float (*interp)[4], \n"
          "                  float (*outputs)[4])\n"
          "{\n"
@@ -242,6 +255,7 @@ static void print_header( struct fragment_program *p )
 
 static void print_footer( struct fragment_program *p )
 {
+   emit(p, "   return 1;");
    emit(p, "}\n");
 }
 
@@ -279,11 +293,15 @@ static void print_reg( struct fragment_program *p,
    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_const"); break;
+   case UREG_TYPE_STATE_CONST: emit(p, "state_param"); break;
    case UREG_TYPE_PARAM: emit(p, "param"); break;
    };
    
    emit(p, "[%d]", GET_UREG_NR(arg));
+
+   if (GET_UREG_TYPE(arg) == UREG_TYPE_STATE_CONST) {
+      emit(p, ".Values");
+   }
 }
 
 
@@ -305,7 +323,8 @@ static void print_arg( struct fragment_program *p,
       return;
    }
 
-   if (GET_UREG_TYPE(arg) == UREG_TYPE_STATE_CONST) {
+   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;
    }
@@ -347,6 +366,26 @@ static void print_expression( struct fragment_program *p,
    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( struct fragment_program *p,
                           const struct fp_instruction *inst,
                           const char *fn, GLuint texunit, GLuint arg )
@@ -641,7 +680,7 @@ static void translate_program( struct fragment_program *p )
         break;
 
       case FP_OPCODE_KIL:
-        /* TODO */
+        do_tex_kill(p, inst, src[0]);
         break;
 
       case FP_OPCODE_LG2: 
@@ -774,10 +813,6 @@ void _swrast_translate_program( GLcontext *ctx )
       print_header( p );
       translate_program( p );
       print_footer( p );
-      emit_char(p, 0);
-      
-      printf("C program length: %d/%d chars\n", p->c_strlen, strlen(p->c_str));
-      printf(p->c_str);
    }
 }
 
index 036c1870d1f806191d46867443868527cf84413c..f7510bf3ddfe7ed4c2624787ebaaf65715f77d0d 100644 (file)
@@ -1357,10 +1357,18 @@ _swrast_exec_fragment_program( GLcontext *ctx, struct sw_span *span )
          init_machine(ctx, &ctx->FragmentProgram.Machine,
                       ctx->FragmentProgram.Current, span, i);
 
+#ifdef USE_TCC
+         if (!_swrast_execute_codegen_program(ctx, program, ~0,
+                                             &ctx->FragmentProgram.Machine,
+                                             span, i)) {
+            span->array->mask[i] = GL_FALSE;  /* killed fragment */
+         }
+#else
          if (!execute_program(ctx, program, ~0,
                               &ctx->FragmentProgram.Machine, span, i)) {
             span->array->mask[i] = GL_FALSE;  /* killed fragment */
          }
+#endif
 
          /* Store output registers */
          {
diff --git a/src/mesa/swrast/s_tcc.c b/src/mesa/swrast/s_tcc.c
new file mode 100644 (file)
index 0000000..3d8f550
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.1
+ *
+ * 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.
+ */
+
+/* An attempt to hook s_fragprog_to_c.c up to libtcc.a to try &
+ * generate some real code.
+ *
+ * TCC isn't threadsafe, so it will need additional locking help if we
+ * end up using it as a backend in mesa.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "nvfragprog.h"
+#include "macros.h"
+#include "program.h"
+
+#include "s_nvfragprog.h"
+#include "s_texture.h"
+
+#ifdef USE_TCC
+
+#include <libtcc.h>
+
+typedef int (*cfunc)( void *ctx, 
+                     const GLfloat (*local_param)[4], 
+                     const GLfloat (*env_param)[4], 
+                     const struct program_parameter *state_param, 
+                     const GLfloat (*interp)[4], 
+                     GLfloat (*outputs)[4]);
+
+
+static cfunc current_func;
+static struct fragment_program *current_program;
+static TCCState *current_tcc_state;
+
+
+static void TEX( void *cc, const float *texcoord, int unit, float *result )
+{
+   GLcontext *ctx = (GLcontext *)cc;
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
+   GLfloat lambda = 1.0;       /* hack */
+   GLchan rgba[4];
+
+   swrast->TextureSample[unit](ctx, unit, ctx->Texture.Unit[unit]._Current,
+                               1, (const GLfloat (*)[4]) texcoord,
+                               &lambda, &rgba);
+
+   result[0] = CHAN_TO_FLOAT(rgba[0]);
+   result[1] = CHAN_TO_FLOAT(rgba[1]);
+   result[2] = CHAN_TO_FLOAT(rgba[2]);
+   result[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
+
+static void TXB( void *cc, const float *texcoord, int unit, float *result )
+{
+   GLcontext *ctx = (GLcontext *)cc;
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
+   GLfloat lambda = 1.0;       /* hack */
+   GLchan rgba[4];
+
+   /* texcoord[3] is the bias to add to lambda */
+   lambda += texcoord[3];
+
+
+   /* Is it necessary to reset texcoord[3] to 1 at this point?
+    */
+   swrast->TextureSample[unit](ctx, unit, ctx->Texture.Unit[unit]._Current,
+                               1, (const GLfloat (*)[4]) texcoord,
+                               &lambda, &rgba);
+
+   result[0] = CHAN_TO_FLOAT(rgba[0]);
+   result[1] = CHAN_TO_FLOAT(rgba[1]);
+   result[2] = CHAN_TO_FLOAT(rgba[2]);
+   result[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
+
+static void TXP( void *cc, const float *texcoord, int unit, float *result )
+{
+   /* I think that TEX needs to undo the perspective divide which has
+    * already occurred.  In the meantime, TXP is correct to do this:
+    */
+   TEX( cc, texcoord, unit, result );
+}
+
+
+static cfunc codegen( TCCState *s, const char *prog, const char *fname )
+{
+    unsigned long val;
+
+    if (s) 
+       tcc_delete(s);
+    
+    s = tcc_new();
+    if (!s) 
+       return 0;
+
+    tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
+    tcc_compile_string(s, prog);
+
+/*     tcc_add_dll("/usr/lib/libm.so"); */
+
+    tcc_add_symbol(s, "TEX", (unsigned long)&TEX);
+    tcc_add_symbol(s, "TXB", (unsigned long)&TXB);
+    tcc_add_symbol(s, "TXP", (unsigned long)&TXP);
+
+
+    tcc_relocate(s);
+    tcc_get_symbol(s, &val, fname);
+    return (cfunc) val;
+}
+
+/* TCC isn't threadsafe and even seems not to like having more than
+ * one TCCState created or used at any one time in a single threaded
+ * environment.  So, this code is all for investigation only and can't
+ * currently be used in Mesa proper.
+ *
+ * I've taken some liberties with globals myself, now.
+ */
+GLboolean
+_swrast_execute_codegen_program( GLcontext *ctx,
+                        const struct fragment_program *program, GLuint maxInst,
+                        struct fp_machine *machine, const struct sw_span *span,
+                        GLuint column )
+{
+   if (program != current_program) {
+      
+      _swrast_translate_program( ctx );
+
+      fprintf(stderr, "%s: compiling:\n%s\n", __FUNCTION__, program->c_str);
+
+      current_program = program;
+      current_func = codegen( current_tcc_state, program->c_str, 
+                             "run_program" );
+   }
+
+   assert(current_func);
+
+   return current_func( ctx,
+                       program->Base.LocalParams,
+                       (const GLfloat (*)[4])ctx->FragmentProgram.Parameters, 
+                       program->Parameters->Parameters,
+                       (const GLfloat (*)[4])machine->Inputs,
+                       machine->Outputs );
+}
+
+#else  /* USE_TCC */
+
+GLboolean
+_swrast_execute_codegen_program( GLcontext *ctx,
+                        const struct fragment_program *program, GLuint maxInst,
+                        struct fp_machine *machine, const struct sw_span *span,
+                        GLuint column )
+{
+   return 0;
+}
+
+#endif