summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Whitwell <keith@tungstengraphics.com>2004-04-14 21:19:34 +0000
committerKeith Whitwell <keith@tungstengraphics.com>2004-04-14 21:19:34 +0000
commit6fb235661a3a78174e7554b292332a1dbb24f171 (patch)
treea7eafade7171277a5120581c825e26df867c51b4 /src
parente3b0dde49c8f14d7e5de440e9e914612868078f5 (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/mesa/main/mtypes.h5
-rw-r--r--src/mesa/sources2
-rw-r--r--src/mesa/swrast/s_context.h14
-rw-r--r--src/mesa/swrast/s_fragprog_to_c.c65
-rw-r--r--src/mesa/swrast/s_nvfragprog.c8
-rw-r--r--src/mesa/swrast/s_tcc.c185
6 files changed, 264 insertions, 15 deletions
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 <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