Browse Source

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.
tags/mesa_20050610
Keith Whitwell 20 years ago
parent
commit
81032030ff

+ 1
- 0
src/mesa/Makefile View 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)

+ 1
- 1
src/mesa/main/imports.c View 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
}


+ 1
- 0
src/mesa/main/mtypes.h View 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 */
};



+ 7
- 1
src/mesa/tnl/t_context.c View 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;
}

+ 11
- 0
src/mesa/tnl/t_context.h View 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;



+ 10
- 8
src/mesa/tnl/t_pipeline.c View 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
};

+ 1
- 0
src/mesa/tnl/t_pipeline.h View 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:

+ 52
- 38
src/mesa/tnl/t_vb_arbprogram.c View 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;
}

+ 19
- 13
src/mesa/tnl/t_vb_arbprogram.h View File

@@ -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

+ 16
- 13
src/mesa/tnl/t_vb_arbprogram_sse.c View 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;

+ 2
- 1
src/mesa/tnl/t_vb_program.c View 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) */

+ 0
- 4
src/mesa/tnl/t_vp_build.h View File

@@ -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

Loading…
Cancel
Save