summaryrefslogtreecommitdiff
path: root/src/mesa/tnl
diff options
context:
space:
mode:
authorKeith Whitwell <keith@tungstengraphics.com>2005-06-09 14:55:34 +0000
committerKeith Whitwell <keith@tungstengraphics.com>2005-06-09 14:55:34 +0000
commit81032030ff42dd78133d85f7cabab5fb4c9aaf1e (patch)
treed91f33c2f2c3d0814b43ae0da17a4f120c4e4372 /src/mesa/tnl
parenta8534885efb13ec7f071192c1504513cd90d07de (diff)
Store compiled vertex program representations in a pointer in the
vertex_program struct. Allow switching between regular and vertex_program implementations of fixed function TNL with the MESA_TNL_PROG environment var (previously this required recompilation). Ensure program compilation only references program data, not the wider context. This means that compiled programs only need to be invalidated when the program string changes, not on other state changes.
Diffstat (limited to 'src/mesa/tnl')
-rw-r--r--src/mesa/tnl/t_context.c8
-rw-r--r--src/mesa/tnl/t_context.h11
-rw-r--r--src/mesa/tnl/t_pipeline.c18
-rw-r--r--src/mesa/tnl/t_pipeline.h1
-rw-r--r--src/mesa/tnl/t_vb_arbprogram.c90
-rw-r--r--src/mesa/tnl/t_vb_arbprogram.h32
-rw-r--r--src/mesa/tnl/t_vb_arbprogram_sse.c29
-rw-r--r--src/mesa/tnl/t_vb_program.c3
-rw-r--r--src/mesa/tnl/t_vp_build.h4
9 files changed, 118 insertions, 78 deletions
diff --git a/src/mesa/tnl/t_context.c b/src/mesa/tnl/t_context.c
index 48119d2d58..a6a7cdc738 100644
--- a/src/mesa/tnl/t_context.c
+++ b/src/mesa/tnl/t_context.c
@@ -95,7 +95,11 @@ _tnl_CreateContext( GLcontext *ctx )
_tnl_save_init( ctx );
_tnl_array_init( ctx );
_tnl_vtx_init( ctx );
- _tnl_install_pipeline( ctx, _tnl_default_pipeline );
+
+ if (ctx->_MaintainTnlProgram)
+ _tnl_install_pipeline( ctx, _tnl_vp_pipeline );
+ else
+ _tnl_install_pipeline( ctx, _tnl_default_pipeline );
/* Initialize the arrayelt helper
*/
@@ -140,6 +144,8 @@ _tnl_DestroyContext( GLcontext *ctx )
_tnl_destroy_pipeline( ctx );
_ae_destroy_context( ctx );
+ _tnl_ProgramCacheDestroy( ctx );
+
FREE(tnl);
ctx->swtnl_context = NULL;
}
diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h
index 4988920cf2..cdaa252e8f 100644
--- a/src/mesa/tnl/t_context.h
+++ b/src/mesa/tnl/t_context.h
@@ -614,6 +614,15 @@ struct tnl_clipspace
};
+
+struct tnl_cache {
+ GLuint hash;
+ void *key;
+ void *data;
+ struct tnl_cache *next;
+};
+
+
struct tnl_device_driver
{
/***
@@ -769,6 +778,8 @@ typedef struct
GLvertexformat exec_vtxfmt;
GLvertexformat save_vtxfmt;
+ struct tnl_cache *vp_cache;
+
} TNLcontext;
diff --git a/src/mesa/tnl/t_pipeline.c b/src/mesa/tnl/t_pipeline.c
index 6b0ea815e2..61bfed290e 100644
--- a/src/mesa/tnl/t_pipeline.c
+++ b/src/mesa/tnl/t_pipeline.c
@@ -131,9 +131,8 @@ void _tnl_run_pipeline( GLcontext *ctx )
* (ie const or non-const).
*/
if (check_input_changes( ctx ) || tnl->pipeline.new_state) {
-#if TNL_FIXED_FUNCTION_PROGRAM
- _tnl_UpdateFixedFunctionProgram( ctx );
-#endif
+ if (ctx->_MaintainTnlProgram)
+ _tnl_UpdateFixedFunctionProgram( ctx );
for (i = 0; i < tnl->pipeline.nr_stages ; i++) {
struct tnl_pipeline_stage *s = &tnl->pipeline.stages[i];
@@ -197,9 +196,6 @@ void _tnl_run_pipeline( GLcontext *ctx )
* case, if it becomes necessary to do so.
*/
const struct tnl_pipeline_stage *_tnl_default_pipeline[] = {
-#if TNL_FIXED_FUNCTION_PROGRAM
- &_tnl_arb_vertex_program_stage,
-#else
&_tnl_vertex_transform_stage,
&_tnl_normal_transform_stage,
&_tnl_lighting_stage,
@@ -208,9 +204,15 @@ const struct tnl_pipeline_stage *_tnl_default_pipeline[] = {
&_tnl_texture_transform_stage,
&_tnl_point_attenuation_stage,
#if defined(FEATURE_NV_vertex_program) || defined(FEATURE_ARB_vertex_program)
- &_tnl_vertex_program_stage,
-#endif
+ &_tnl_arb_vertex_program_stage,
+ &_tnl_vertex_program_stage,
#endif
&_tnl_render_stage,
NULL
};
+
+const struct tnl_pipeline_stage *_tnl_vp_pipeline[] = {
+ &_tnl_arb_vertex_program_stage,
+ &_tnl_render_stage,
+ NULL
+};
diff --git a/src/mesa/tnl/t_pipeline.h b/src/mesa/tnl/t_pipeline.h
index a9d8c7e489..6c7a0814c5 100644
--- a/src/mesa/tnl/t_pipeline.h
+++ b/src/mesa/tnl/t_pipeline.h
@@ -59,6 +59,7 @@ extern const struct tnl_pipeline_stage _tnl_render_stage;
/* Shorthand to plug in the default pipeline:
*/
extern const struct tnl_pipeline_stage *_tnl_default_pipeline[];
+extern const struct tnl_pipeline_stage *_tnl_vp_pipeline[];
/* Convenience routines provided by t_vb_render.c:
diff --git a/src/mesa/tnl/t_vb_arbprogram.c b/src/mesa/tnl/t_vb_arbprogram.c
index 07dc34d266..4789b79017 100644
--- a/src/mesa/tnl/t_vb_arbprogram.c
+++ b/src/mesa/tnl/t_vb_arbprogram.c
@@ -56,7 +56,6 @@ struct opcode_info {
struct compilation {
GLuint reg_active;
union instruction *csr;
- struct vertex_buffer *VB; /* for input sizes! */
};
@@ -518,7 +517,7 @@ static void print_reg( GLuint file, GLuint reg )
_mesa_printf("ARG%d", reg - REG_ARG0);
else if (reg >= REG_TMP0 && reg <= REG_TMP11)
_mesa_printf("TMP%d", reg - REG_TMP0);
- else if (reg >= REG_IN0 && reg <= REG_IN15)
+ else if (reg >= REG_IN0 && reg <= REG_IN31)
_mesa_printf("IN%d", reg - REG_IN0);
else if (reg >= REG_OUT0 && reg <= REG_OUT14)
_mesa_printf("OUT%d", reg - REG_OUT0);
@@ -989,18 +988,33 @@ static void cvp_emit_inst( struct compilation *cp,
}
}
+static void free_tnl_data( struct vertex_program *program )
+{
+ struct tnl_compiled_program *p = program->TnlData;
+ if (p->compiled_func) free((void *)p->compiled_func);
+ free(p);
+ program->TnlData = NULL;
+}
-static void compile_vertex_program( struct arb_vp_machine *m,
- const struct vertex_program *program )
+static void compile_vertex_program( struct vertex_program *program,
+ GLboolean try_codegen )
{
struct compilation cp;
+ struct tnl_compiled_program *p = CALLOC_STRUCT(tnl_compiled_program);
GLuint i;
- /* Initialize cp:
+ _mesa_printf("%s\n", __FUNCTION__);
+
+ if (program->TnlData)
+ free_tnl_data( program );
+
+ program->TnlData = p;
+
+ /* Initialize cp. Note that ctx and VB aren't used in compilation
+ * so we don't have to worry about statechanges:
*/
memset(&cp, 0, sizeof(cp));
- cp.VB = m->VB;
- cp.csr = m->store;
+ cp.csr = p->instructions;
/* Compile instructions:
*/
@@ -1010,24 +1024,20 @@ static void compile_vertex_program( struct arb_vp_machine *m,
/* Finish up:
*/
- m->instructions = m->store;
- m->nr_instructions = cp.csr - m->store;
-
+ p->nr_instructions = cp.csr - p->instructions;
/* Print/disassemble:
*/
if (DISASSEM) {
- for (i = 0; i < m->nr_instructions; i++) {
- _tnl_disassem_vba_insn(m->instructions[i]);
+ for (i = 0; i < p->nr_instructions; i++) {
+ _tnl_disassem_vba_insn(p->instructions[i]);
}
_mesa_printf("\n\n");
}
#ifdef USE_SSE_ASM
- /* TODO: check if anything changed...
- */
- if (m->try_codegen)
- _tnl_sse_codegen_vertex_program(m);
+ if (try_codegen)
+ _tnl_sse_codegen_vertex_program(p);
#endif
}
@@ -1046,7 +1056,7 @@ static void userclip( GLcontext *ctx,
{
GLuint p;
- for (p = 0; p < ctx->Const.MaxClipPlanes; p++)
+ for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
GLuint nr, i;
const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
@@ -1079,6 +1089,7 @@ static void userclip( GLcontext *ctx,
}
}
}
+ }
}
@@ -1138,9 +1149,10 @@ static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
}
-static void call_func( struct arb_vp_machine *m )
+static INLINE void call_func( struct tnl_compiled_program *p,
+ struct arb_vp_machine *m )
{
- m->func(m);
+ p->compiled_func(m);
}
/**
@@ -1160,12 +1172,18 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
ctx->_TnlProgram);
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
- GLuint i, j, outputs = program->OutputsWritten;
+ struct tnl_compiled_program *p;
+ GLuint i, j, outputs;
+
+ if (!program || program->IsNVProgram)
+ return GL_TRUE;
if (program->Parameters) {
_mesa_load_state_parameters(ctx, program->Parameters);
}
+ p = (struct tnl_compiled_program *)program->TnlData;
+ assert(p);
/* Initialize regs where necessary:
*/
@@ -1173,11 +1191,11 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
m->nr_inputs = m->nr_outputs = 0;
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < _TNL_ATTRIB_MAX; i++) {
if (program->InputsRead & (1<<i)) {
GLuint j = m->nr_inputs++;
m->input[j].idx = i;
- m->input[j].data = m->VB->AttribPtr[i]->data;
+ m->input[j].data = (GLfloat *)m->VB->AttribPtr[i]->data;
m->input[j].stride = m->VB->AttribPtr[i]->stride;
m->input[j].size = m->VB->AttribPtr[i]->size;
ASSIGN_4V(m->File[0][REG_IN0 + i], 0, 0, 0, 1);
@@ -1188,7 +1206,7 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
if (program->OutputsWritten & (1<<i)) {
GLuint j = m->nr_outputs++;
m->output[j].idx = i;
- m->output[j].data = m->attribs[i].data;
+ m->output[j].data = (GLfloat *)m->attribs[i].data;
}
}
@@ -1208,12 +1226,12 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
STRIDE_F(m->input[j].data, m->input[j].stride);
}
- if (m->func) {
- call_func( m );
+ if (p->compiled_func) {
+ call_func( p, m );
}
else {
- for (j = 0; j < m->nr_instructions; j++) {
- union instruction inst = m->instructions[j];
+ for (j = 0; j < p->nr_instructions; j++) {
+ union instruction inst = p->instructions[j];
opcode_func[inst.alu.opcode]( m, inst );
}
}
@@ -1241,6 +1259,8 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
VB->ClipPtr = &m->attribs[VERT_RESULT_HPOS];
VB->ClipPtr->count = VB->Count;
+ outputs = program->OutputsWritten;
+
if (outputs & (1<<VERT_RESULT_COL0)) {
VB->ColorPtr[0] = &m->attribs[VERT_RESULT_COL0];
VB->AttribPtr[VERT_ATTRIB_COLOR0] = VB->ColorPtr[0];
@@ -1303,14 +1323,13 @@ validate_vertex_program( GLcontext *ctx, struct tnl_pipeline_stage *stage )
struct vertex_program *program =
(ctx->VertexProgram._Enabled ? ctx->VertexProgram.Current : 0);
-#if TNL_FIXED_FUNCTION_PROGRAM
- if (!program) {
+ if (!program && ctx->_MaintainTnlProgram) {
program = ctx->_TnlProgram;
}
-#endif
if (program) {
- compile_vertex_program( m, program );
+ if (!program->TnlData)
+ compile_vertex_program( program, m->try_codegen );
/* Grab the state GL state and put into registers:
*/
@@ -1354,8 +1373,6 @@ static GLboolean init_vertex_program( GLcontext *ctx,
if (_mesa_getenv("MESA_EXPERIMENTAL"))
m->try_codegen = 1;
- _mesa_printf("try_codegen %d\n", m->try_codegen);
-
/* Allocate arrays of vertex output values */
for (i = 0; i < VERT_RESULT_MAX; i++) {
_mesa_vector4f_alloc( &m->attribs[i], 0, size, 32 );
@@ -1366,11 +1383,8 @@ static GLboolean init_vertex_program( GLcontext *ctx,
_mesa_vector4f_alloc( &m->ndcCoords, 0, size, 32 );
m->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
-
-#if TNL_FIXED_FUNCTION_PROGRAM
- _mesa_allow_light_in_model( ctx, GL_FALSE );
-#endif
-
+ if (ctx->_MaintainTnlProgram)
+ _mesa_allow_light_in_model( ctx, GL_FALSE );
return GL_TRUE;
}
diff --git a/src/mesa/tnl/t_vb_arbprogram.h b/src/mesa/tnl/t_vb_arbprogram.h
index fd2f09f1da..6279f098f6 100644
--- a/src/mesa/tnl/t_vb_arbprogram.h
+++ b/src/mesa/tnl/t_vb_arbprogram.h
@@ -55,11 +55,11 @@
#define REG_OUT0 17
#define REG_OUT14 31
#define REG_IN0 32
-#define REG_IN15 47
-#define REG_ID 48 /* 0,0,0,1 */
-#define REG_ONES 49 /* 1,1,1,1 */
-#define REG_SWZ 50 /* -1,1,0,0 */
-#define REG_NEG 51 /* -1,-1,-1,-1 */
+#define REG_IN31 63
+#define REG_ID 64 /* 0,0,0,1 */
+#define REG_ONES 65 /* 1,1,1,1 */
+#define REG_SWZ 66 /* -1,1,0,0 */
+#define REG_NEG 67 /* -1,-1,-1,-1 */
#define REG_UNDEF 127 /* special case - never used */
#define REG_MAX 128
#define REG_INVALID ~0
@@ -122,6 +122,8 @@ struct output {
GLfloat *data;
};
+
+
/*--------------------------------------------------------------------------- */
/*!
@@ -129,18 +131,13 @@ struct output {
*/
struct arb_vp_machine {
GLfloat (*File[4])[4]; /* All values referencable from the program. */
- GLint AddressReg;
- struct input input[16];
+ struct input input[_TNL_ATTRIB_MAX];
GLuint nr_inputs;
struct output output[15];
GLuint nr_outputs;
- union instruction store[1024];
- union instruction *instructions;
- GLint nr_instructions;
-
GLvector4f attribs[VERT_RESULT_MAX]; /**< result vectors. */
GLvector4f ndcCoords; /**< normalized device coords */
GLubyte *clipmask; /**< clip flags */
@@ -148,14 +145,23 @@ struct arb_vp_machine {
GLuint vtx_nr; /**< loop counter */
- void (*func)( struct arb_vp_machine * ); /**< codegen'd program? */
-
struct vertex_buffer *VB;
GLcontext *ctx;
GLboolean try_codegen;
};
+struct tnl_compiled_program {
+ union instruction instructions[1024];
+ GLint nr_instructions;
+ void (*compiled_func)( struct arb_vp_machine * ); /**< codegen'd program */
+};
+
+void _tnl_program_string_change( struct vertex_program * );
+void _tnl_program_destroy( struct vertex_program * );
+
void _tnl_disassem_vba_insn( union instruction op );
+GLboolean _tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p);
+
#endif
diff --git a/src/mesa/tnl/t_vb_arbprogram_sse.c b/src/mesa/tnl/t_vb_arbprogram_sse.c
index 83be1d2d9f..b6ffdda7d3 100644
--- a/src/mesa/tnl/t_vb_arbprogram_sse.c
+++ b/src/mesa/tnl/t_vb_arbprogram_sse.c
@@ -76,8 +76,7 @@ do { \
struct compilation {
struct x86_function func;
- struct arb_vp_machine *m;
-
+ struct tnl_compiled_program *p;
GLuint insn_counter;
struct {
@@ -788,6 +787,7 @@ static GLint get_offset( const void *a, const void *b )
static GLboolean build_vertex_program( struct compilation *cp )
{
+ struct arb_vp_machine *m = NULL;
GLuint j;
struct x86_reg regEAX = x86_make_reg(file_REG32, reg_AX);
@@ -796,11 +796,11 @@ static GLboolean build_vertex_program( struct compilation *cp )
x86_mov(&cp->func, regEAX, x86_fn_arg(&cp->func, 1));
x86_mov(&cp->func, parmECX, regEAX);
- x86_mov(&cp->func, regEAX, x86_make_disp(regEAX, get_offset(cp->m, cp->m->File + FILE_REG)));
- x86_mov(&cp->func, parmECX, x86_make_disp(parmECX, get_offset(cp->m, cp->m->File + FILE_STATE_PARAM)));
+ x86_mov(&cp->func, regEAX, x86_make_disp(regEAX, get_offset(m, m->File + FILE_REG)));
+ x86_mov(&cp->func, parmECX, x86_make_disp(parmECX, get_offset(m, m->File + FILE_STATE_PARAM)));
- for (j = 0; j < cp->m->nr_instructions; j++) {
- union instruction inst = cp->m->instructions[j];
+ for (j = 0; j < cp->p->nr_instructions; j++) {
+ union instruction inst = cp->p->instructions[j];
cp->insn_counter = j+1; /* avoid zero */
if (DISASSEM) {
@@ -842,27 +842,30 @@ static GLboolean build_vertex_program( struct compilation *cp )
* struct arb_vertex_machine.
*/
GLboolean
-_tnl_sse_codegen_vertex_program(struct arb_vp_machine *m)
+_tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p)
{
struct compilation cp;
memset(&cp, 0, sizeof(cp));
- cp.m = m;
+ cp.p = p;
cp.have_sse2 = 1;
- if (m->func) {
- free((void *)m->func);
- m->func = NULL;
+ if (p->compiled_func) {
+ free((void *)p->compiled_func);
+ p->compiled_func = NULL;
}
x86_init_func(&cp.func);
+ /* Note ctx state is not referenced in building the function, so it
+ * depends only on the list of instructions:
+ */
if (!build_vertex_program(&cp)) {
x86_release_func( &cp.func );
return GL_FALSE;
}
- m->func = (void (*)(struct arb_vp_machine *))x86_get_func( &cp.func );
+ p->compiled_func = (void (*)(struct arb_vp_machine *))x86_get_func( &cp.func );
return GL_TRUE;
}
@@ -871,7 +874,7 @@ _tnl_sse_codegen_vertex_program(struct arb_vp_machine *m)
#else
GLboolean
-_tnl_sse_codegen_vertex_program( GLcontext *ctx )
+_tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p)
{
/* Dummy version for when USE_SSE_ASM not defined */
return GL_FALSE;
diff --git a/src/mesa/tnl/t_vb_program.c b/src/mesa/tnl/t_vb_program.c
index 9cf5df7cae..d77f5424c1 100644
--- a/src/mesa/tnl/t_vb_program.c
+++ b/src/mesa/tnl/t_vb_program.c
@@ -80,7 +80,8 @@ run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
struct vertex_program *program = ctx->VertexProgram.Current;
GLuint i;
- if (!ctx->VertexProgram._Enabled)
+ if (!ctx->VertexProgram._Enabled ||
+ !program->IsNVProgram)
return GL_TRUE;
/* load program parameter registers (they're read-only) */
diff --git a/src/mesa/tnl/t_vp_build.h b/src/mesa/tnl/t_vp_build.h
index 39c0348dd7..8a66976755 100644
--- a/src/mesa/tnl/t_vp_build.h
+++ b/src/mesa/tnl/t_vp_build.h
@@ -28,10 +28,6 @@
#include "mtypes.h"
-/* Define to 1 to test fixed-function execution via vertex programs:
- */
-#define TNL_FIXED_FUNCTION_PROGRAM 0
-
extern void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx );
#endif