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.
This commit is contained in:
@@ -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" \
|
||||
|
3
Makefile
3
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 \
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -15,6 +15,7 @@ SOURCES = antialias.c \
|
||||
arbfptest1.c \
|
||||
arbfptexture.c \
|
||||
arbfptrig.c \
|
||||
arbfpwpos.c \
|
||||
arbvptest1.c \
|
||||
arbvptest3.c \
|
||||
arbvptorus.c \
|
||||
|
@@ -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
|
||||
};
|
||||
|
||||
|
||||
|
@@ -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 \
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 */
|
||||
{
|
||||
|
185
src/mesa/swrast/s_tcc.c
Normal file
185
src/mesa/swrast/s_tcc.c
Normal file
@@ -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
|
Reference in New Issue
Block a user