Store compiled vertex program representations in a pointer in the
authorKeith Whitwell <keith@tungstengraphics.com>
Thu, 9 Jun 2005 14:55:34 +0000 (14:55 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Thu, 9 Jun 2005 14:55:34 +0000 (14:55 +0000)
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.

12 files changed:
src/mesa/Makefile
src/mesa/main/imports.c
src/mesa/main/mtypes.h
src/mesa/tnl/t_context.c
src/mesa/tnl/t_context.h
src/mesa/tnl/t_pipeline.c
src/mesa/tnl/t_pipeline.h
src/mesa/tnl/t_vb_arbprogram.c
src/mesa/tnl/t_vb_arbprogram.h
src/mesa/tnl/t_vb_arbprogram_sse.c
src/mesa/tnl/t_vb_program.c
src/mesa/tnl/t_vp_build.h

index 3ff8da7e4d6fc9e09a81fa4f3a5d51780b74dd40..6e13f5289c5ec825456d544c623026436210f3b0 100644 (file)
@@ -220,6 +220,7 @@ tags:
 
 clean:
        -rm -f */*.o
+       -rm -f */*/*.o
        -rm -f depend depend.bak mesa.a
        -rm -f drivers/*/*.o
        (cd drivers/dri ; $(MAKE) clean)
index 767cef59e2e3cc53c4362ee9a95733e20043c78c..1972826a756a92fd26b0879d0d6fb5349206864d 100644 (file)
@@ -842,7 +842,7 @@ _mesa_printf( const char *fmtString, ... )
 #if defined(XFree86LOADER) && defined(IN_MODULE)
    xf86printf("%s", s);
 #else
-   printf("%s", s);
+   fprintf(stderr,"%s", s);
 #endif
 }
 
index 62a8c76aa1478d1b8656b43061e644d9af2e3491..1733c43bce0f118397c7bc88197c62c482149d14 100644 (file)
@@ -1770,6 +1770,7 @@ struct vertex_program
    GLuint InputsRead;     /* Bitmask of which input regs are read */
    GLuint OutputsWritten; /* Bitmask of which output regs are written to */
    struct program_parameter_list *Parameters; /**< array [NumParameters] */
+   void *TnlData;              /* should probably use Base.DriverData */
 };
 
 
index 48119d2d58e5d97124e07ee3f934c27ab218664b..a6a7cdc738b091b9d04e42349646e5f89aae37b0 100644 (file)
@@ -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;
 }
index 4988920cf258c603b03a4101159cd7727d29a8c2..cdaa252e8fca4b9a91c4eb8005d1ce6d119f7e73 100644 (file)
@@ -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;
 
 
index 6b0ea815e2bde3cd7a0514d7f76d57b6a58d30ed..61bfed290e9ed717b5a7ecf8b194f1cb520b14d8 100644 (file)
@@ -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
+};
index a9d8c7e48995148ab73d9e9419fb2b59aea22673..6c7a0814c56c2321ff4e2e820a14cda8517c29c0 100644 (file)
@@ -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:
index 07dc34d2668beb4a7681dbe74b2be3955677ab95..4789b7901752a3f9c45e64f92d7a01328d46d143 100644 (file)
@@ -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;
 }
index fd2f09f1da6d59d312b9ce06243c5f65a8a05e19..6279f098f6fff3b9fc0d02327e6993472c35f00c 100644 (file)
 #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
index 83be1d2d9f98a9a225c3fde48a63e8107a8b011c..b6ffdda7d3a36d26ac9b17522bb09ec69157f63e 100644 (file)
@@ -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;
index 9cf5df7cae586f9668bbc009c2c965e1879be7b5..d77f5424c141c1da4dc57fa382cc4aefbb919c31 100644 (file)
@@ -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) */
index 39c0348dd7a52aaa83c21fbeb7eca2400a1daee1..8a6697675509c22188284683192a65e789f16dbb 100644 (file)
 
 #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