From 6fb235661a3a78174e7554b292332a1dbb24f171 Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Wed, 14 Apr 2004 21:19:34 +0000 Subject: Use tcc and the emitted C code from s_fragprog_to_c.c to dynamically compile 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 | 2 +- Makefile | 3 +- progs/Makefile | 2 +- progs/tests/Makefile | 1 + src/mesa/main/mtypes.h | 5 ++ src/mesa/sources | 2 + src/mesa/swrast/s_context.h | 14 +++ src/mesa/swrast/s_fragprog_to_c.c | 65 ++++++++++---- src/mesa/swrast/s_nvfragprog.c | 8 ++ src/mesa/swrast/s_tcc.c | 185 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 269 insertions(+), 18 deletions(-) create mode 100644 src/mesa/swrast/s_tcc.c diff --git a/Make-config b/Make-config index 2b2362fa00..7e37afaa20 100644 --- a/Make-config +++ b/Make-config @@ -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" \ diff --git a/Makefile b/Makefile index ad59e5b85b..10bf76d25d 100644 --- 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 \ diff --git a/progs/Makefile b/progs/Makefile index 7f4ee09961..c44c9d73e4 100644 --- a/progs/Makefile +++ b/progs/Makefile @@ -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 diff --git a/progs/tests/Makefile b/progs/tests/Makefile index ee75e71c7d..ac354aeeb6 100644 --- a/progs/tests/Makefile +++ b/progs/tests/Makefile @@ -15,6 +15,7 @@ SOURCES = antialias.c \ arbfptest1.c \ arbfptexture.c \ arbfptrig.c \ + arbfpwpos.c \ arbvptest1.c \ arbvptest3.c \ arbvptorus.c \ diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index b74eeaccca..aeeab82733 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -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 }; diff --git a/src/mesa/sources b/src/mesa/sources index 249734f783..14c4205bbd 100644 --- a/src/mesa/sources +++ b/src/mesa/sources @@ -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 \ diff --git a/src/mesa/swrast/s_context.h b/src/mesa/swrast/s_context.h index d6a14e6b4a..9d14c89bd6 100644 --- a/src/mesa/swrast/s_context.h +++ b/src/mesa/swrast/s_context.h @@ -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 diff --git a/src/mesa/swrast/s_fragprog_to_c.c b/src/mesa/swrast/s_fragprog_to_c.c index f4bae2a82d..647510a4c9 100644 --- a/src/mesa/swrast/s_fragprog_to_c.c +++ b/src/mesa/swrast/s_fragprog_to_c.c @@ -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); } } diff --git a/src/mesa/swrast/s_nvfragprog.c b/src/mesa/swrast/s_nvfragprog.c index 036c1870d1..f7510bf3dd 100644 --- a/src/mesa/swrast/s_nvfragprog.c +++ b/src/mesa/swrast/s_nvfragprog.c @@ -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 index 0000000000..3d8f550ece --- /dev/null +++ b/src/mesa/swrast/s_tcc.c @@ -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 +#include + + +#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 + +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 -- cgit v1.2.3