From c3626a91cee5034528f3f92c802a8e5947ea5f92 Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Tue, 1 Nov 2005 17:25:49 +0000 Subject: [PATCH] Several fp and vp tweaks: - Renumber VERT_RESULT_* values so that they match the numbers of the corresponding FRAG_ATTRIB_ values. - Add ctx->VertexProgram._Current and FragmentProgram._Current values which point to either the current client-supplied program if enabled, or otherwise to the current mesa-internal program. Thus this program is always the correct one for the current state, providing that the mesa flags to turn on automatic generation are enabled. - Add callbacks to ctx->Driver.BindProgram() in texenvprogram.c and t_vp_build.c so that the driver knows when the generated program changes. This is cleaner than trying to code all the possible _NEW_* flags into the driver, and more precise as well. - Add a UsesKill flag to identify fragment programs with that instruction, as these can require special treatment. - Move the FRAG_OUTPUT values to mtypes.h, near to similar defn's. --- src/mesa/main/mtypes.h | 43 ++++++++---- src/mesa/main/texenvprogram.c | 49 ++++++++------ src/mesa/shader/arbprogparse.c | 3 + src/mesa/shader/arbprogparse.h | 2 + src/mesa/shader/nvfragprog.h | 9 --- src/mesa/shader/nvvertparse.c | 5 +- src/mesa/tnl/t_vp_build.c | 145 +++++++++++++++++++++++++---------------- 7 files changed, 156 insertions(+), 100 deletions(-) diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index aadd0a7..d77759d 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -195,18 +195,18 @@ enum #define VERT_RESULT_HPOS 0 #define VERT_RESULT_COL0 1 #define VERT_RESULT_COL1 2 -#define VERT_RESULT_BFC0 3 -#define VERT_RESULT_BFC1 4 -#define VERT_RESULT_FOGC 5 -#define VERT_RESULT_PSIZ 6 -#define VERT_RESULT_TEX0 7 -#define VERT_RESULT_TEX1 8 -#define VERT_RESULT_TEX2 9 -#define VERT_RESULT_TEX3 10 -#define VERT_RESULT_TEX4 11 -#define VERT_RESULT_TEX5 12 -#define VERT_RESULT_TEX6 13 -#define VERT_RESULT_TEX7 14 +#define VERT_RESULT_FOGC 3 +#define VERT_RESULT_TEX0 4 +#define VERT_RESULT_TEX1 5 +#define VERT_RESULT_TEX2 6 +#define VERT_RESULT_TEX3 7 +#define VERT_RESULT_TEX4 8 +#define VERT_RESULT_TEX5 9 +#define VERT_RESULT_TEX6 10 +#define VERT_RESULT_TEX7 11 +#define VERT_RESULT_PSIZ 12 +#define VERT_RESULT_BFC0 13 +#define VERT_RESULT_BFC1 14 #define VERT_RESULT_MAX 15 @@ -226,7 +226,9 @@ enum FRAG_ATTRIB_TEX4 = 8, FRAG_ATTRIB_TEX5 = 9, FRAG_ATTRIB_TEX6 = 10, - FRAG_ATTRIB_TEX7 = 11 + FRAG_ATTRIB_TEX7 = 11, + + FRAG_ATTRIB_MAX = 12 }; /* @@ -257,6 +259,14 @@ enum /*@}*/ +/* Fragment program results + */ +#define FRAG_OUTPUT_COLR 0 +#define FRAG_OUTPUT_COLH 1 +#define FRAG_OUTPUT_DEPR 2 +#define FRAG_OUTPUT_MAX 3 + + /** * Indexes for all renderbuffers */ @@ -1791,6 +1801,7 @@ struct fragment_program GLuint NumNativeTexIndirections; GLenum FogOption; struct program_parameter_list *Parameters; /**< array [NumParameters] */ + GLboolean UsesKill; #ifdef USE_TCC char c_str[4096]; /* experimental... */ @@ -1835,6 +1846,9 @@ struct gl_vertex_program_state GLboolean PointSizeEnabled; /**< GL_VERTEX_PROGRAM_POINT_SIZE_NV */ GLboolean TwoSideEnabled; /**< GL_VERTEX_PROGRAM_TWO_SIDE_NV */ struct vertex_program *Current; /**< ptr to currently bound program */ + struct vertex_program *_Current; /**< ptr to currently bound + program, including internal + (t_vp_build.c) programs */ GLenum TrackMatrix[MAX_NV_VERTEX_PROGRAM_PARAMS / 4]; GLenum TrackMatrixTransform[MAX_NV_VERTEX_PROGRAM_PARAMS / 4]; @@ -1865,7 +1879,8 @@ struct gl_fragment_program_state GLboolean _Enabled; /* Really enabled? */ GLboolean _Active; /* Really really enabled? */ struct fragment_program *Current; /* ptr to currently bound program */ - struct fragment_program *_Current; /* ptr to currently active program */ + struct fragment_program *_Current; /* ptr to currently active program + (including internal programs) */ struct fp_machine Machine; /* machine state */ GLfloat Parameters[MAX_NV_FRAGMENT_PROGRAM_PARAMS][4]; /* Env params */ diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index 18d704c..43dda28 100644 --- a/src/mesa/main/texenvprogram.c +++ b/src/mesa/main/texenvprogram.c @@ -1130,32 +1130,41 @@ void _mesa_UpdateTexEnvProgram( GLcontext *ctx ) { struct state_key *key; GLuint hash; + struct fragment_program *prev = ctx->FragmentProgram._Current; - if (ctx->FragmentProgram._Enabled) - return; - - key = make_state_key(ctx); - hash = hash_key(key); - - ctx->FragmentProgram._Current = ctx->_TexEnvProgram = - (struct fragment_program *) - search_cache(ctx->Texture.env_fp_cache, hash, key, sizeof(*key)); + if (!ctx->FragmentProgram._Enabled) { + key = make_state_key(ctx); + hash = hash_key(key); + + ctx->FragmentProgram._Current = ctx->_TexEnvProgram = + (struct fragment_program *) + search_cache(ctx->Texture.env_fp_cache, hash, key, sizeof(*key)); - if (!ctx->_TexEnvProgram) { - if (0) _mesa_printf("Building new texenv proggy for key %x\n", hash); + if (!ctx->_TexEnvProgram) { + if (1) _mesa_printf("Building new texenv proggy for key %x\n", hash); - ctx->FragmentProgram._Current = ctx->_TexEnvProgram = - (struct fragment_program *) - ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + ctx->FragmentProgram._Current = ctx->_TexEnvProgram = + (struct fragment_program *) + ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); - create_new_program(key, ctx, ctx->_TexEnvProgram); + create_new_program(key, ctx, ctx->_TexEnvProgram); - cache_item(&ctx->Texture.env_fp_cache, hash, key, ctx->_TexEnvProgram); - } else { - FREE(key); - if (0) _mesa_printf("Found existing texenv program for key %x\n", hash); + cache_item(&ctx->Texture.env_fp_cache, hash, key, ctx->_TexEnvProgram); + } else { + FREE(key); + if (1) _mesa_printf("Found existing texenv program for key %x\n", hash); + } + } + else { + ctx->FragmentProgram._Current = ctx->FragmentProgram.Current; } - + + /* Tell the driver about the change. Could define a new target for + * this? + */ + if (ctx->FragmentProgram._Current != prev) + ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, (struct program *) + ctx->FragmentProgram._Current); } void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx ) diff --git a/src/mesa/shader/arbprogparse.c b/src/mesa/shader/arbprogparse.c index e8fe869..19c38b6 100644 --- a/src/mesa/shader/arbprogparse.c +++ b/src/mesa/shader/arbprogparse.c @@ -3013,6 +3013,7 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst, break; case OP_TEX_KIL: + Program->UsesKill = 1; if (parse_fp_vector_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[0])) return 1; fp->Opcode = FP_OPCODE_KIL; @@ -4014,6 +4015,8 @@ _mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len, program->NumTexInstructions = program->NumTexIndirections = 0; + program->UsesKill = 0; + program->FPInstructions = NULL; program->VPInstructions = NULL; diff --git a/src/mesa/shader/arbprogparse.h b/src/mesa/shader/arbprogparse.h index ececfaf..947c22e 100644 --- a/src/mesa/shader/arbprogparse.h +++ b/src/mesa/shader/arbprogparse.h @@ -65,6 +65,8 @@ struct arb_program GLuint NumAluInstructions; GLuint NumTexInstructions; GLuint NumTexIndirections; + + GLboolean UsesKill; }; diff --git a/src/mesa/shader/nvfragprog.h b/src/mesa/shader/nvfragprog.h index 99ec20b..bd9c8bb 100644 --- a/src/mesa/shader/nvfragprog.h +++ b/src/mesa/shader/nvfragprog.h @@ -37,15 +37,6 @@ #include "mtypes.h" -/** - * Fragment program output registers. - * Note: when we fully suppport GL_ARB_draw_buffers we'll have more than - * one output color. - */ -#define FRAG_OUTPUT_COLR 0 /* fragment color */ -#define FRAG_OUTPUT_COLH 1 /* fragment color, half precision (NV) */ -#define FRAG_OUTPUT_DEPR 2 /* depth/Z */ - /* condition codes */ #define COND_GT 1 /* greater than zero */ diff --git a/src/mesa/shader/nvvertparse.c b/src/mesa/shader/nvvertparse.c index c48a4cb..24882a2 100644 --- a/src/mesa/shader/nvvertparse.c +++ b/src/mesa/shader/nvvertparse.c @@ -288,8 +288,9 @@ static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = { }; static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = { - "HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ", - "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL + "HPOS", "COL0", "COL1", "FOGC", + "TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", + "PSIZ", "BFC0", "BFC1", NULL }; /* NOTE: the order here must match opcodes in nvvertprog.h */ diff --git a/src/mesa/tnl/t_vp_build.c b/src/mesa/tnl/t_vp_build.c index 02e5a2a..0fc4f6c 100644 --- a/src/mesa/tnl/t_vp_build.c +++ b/src/mesa/tnl/t_vp_build.c @@ -53,10 +53,10 @@ struct state_key { unsigned fog_source_is_depth:1; unsigned tnl_do_vertex_fog:1; unsigned separate_specular:1; - unsigned fog_enabled:1; unsigned fog_mode:2; unsigned point_attenuated:1; unsigned texture_enabled_global:1; + unsigned fragprog_inputs_read:12; struct { unsigned light_enabled:1; @@ -75,10 +75,10 @@ struct state_key { -#define FOG_LINEAR 0 -#define FOG_EXP 1 -#define FOG_EXP2 2 -#define FOG_UNKNOWN 3 +#define FOG_NONE 0 +#define FOG_LINEAR 1 +#define FOG_EXP 2 +#define FOG_EXP2 3 static GLuint translate_fog_mode( GLenum mode ) { @@ -86,7 +86,7 @@ static GLuint translate_fog_mode( GLenum mode ) case GL_LINEAR: return FOG_LINEAR; case GL_EXP: return FOG_EXP; case GL_EXP2: return FOG_EXP2; - default: return FOG_UNKNOWN; + default: return FOG_NONE; } } @@ -116,9 +116,16 @@ static struct state_key *make_state_key( GLcontext *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; + struct fragment_program *fp = ctx->FragmentProgram._Current; struct state_key *key = CALLOC_STRUCT(state_key); GLuint i; + /* This now relies on texenvprogram.c being active: + */ + assert(fp); + + key->fragprog_inputs_read = fp->InputsRead; + key->separate_specular = (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR); @@ -166,18 +173,13 @@ static struct state_key *make_state_key( GLcontext *ctx ) if (ctx->Transform.RescaleNormals) key->rescale_normals = 1; - if (ctx->Fog.Enabled) - key->fog_enabled = 1; - - if (key->fog_enabled) { - if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) - key->fog_source_is_depth = 1; - - if (tnl->_DoVertexFog) - key->tnl_do_vertex_fog = 1; - - key->fog_mode = translate_fog_mode(ctx->Fog.Mode); - } + key->fog_mode = translate_fog_mode(fp->FogOption); + + if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) + key->fog_source_is_depth = 1; + + if (tnl->_DoVertexFog) + key->tnl_do_vertex_fog = 1; if (ctx->Point._Attenuated) key->point_attenuated = 1; @@ -332,6 +334,9 @@ static struct ureg get_temp( struct tnl_program *p ) _mesa_exit(1); } + if (bit > p->program->Base.NumTemporaries) + p->program->Base.NumTemporaries = bit; + p->temp_in_use |= 1<<(bit-1); return make_ureg(PROGRAM_TEMPORARY, bit-1); } @@ -710,6 +715,8 @@ static GLuint material_attrib( GLuint side, GLuint property ) side); } +/* Get a bitmask of which material values vary on a per-vertex basis. + */ static void set_material_flags( struct tnl_program *p ) { p->color_materials = 0; @@ -1194,9 +1201,14 @@ static void build_texture_transform( struct tnl_program *p ) GLuint i, j; for (i = 0; i < MAX_TEXTURE_UNITS; i++) { - GLuint texmat_enabled = p->state->unit[i].texmat_enabled; - if (p->state->unit[i].texgen_enabled || texmat_enabled) { + if (!(p->state->fragprog_inputs_read & (FRAG_BIT_TEX0<state->unit[i].texgen_enabled || + p->state->unit[i].texmat_enabled) { + + GLuint texmat_enabled = p->state->unit[i].texmat_enabled; struct ureg out = register_output(p, VERT_RESULT_TEX0 + i); struct ureg out_texgen = undef; @@ -1293,10 +1305,7 @@ static void build_texture_transform( struct tnl_program *p ) release_temps(p); } - else if (p->state->unit[i].texunit_really_enabled) { - /* KW: _ReallyEnabled isn't sufficient? Need to know whether - * this texture unit is referenced by the fragment shader. - */ + else { emit_passthrough(p, VERT_ATTRIB_TEX0+i, VERT_RESULT_TEX0+i); } } @@ -1338,15 +1347,23 @@ static void build_tnl_program( struct tnl_program *p ) /* Lighting calculations: */ - if (p->state->light_global_enabled) - build_lighting(p); - else - emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL0); + if (p->state->fragprog_inputs_read & (FRAG_BIT_COL0|FRAG_BIT_COL1)) { + if (p->state->light_global_enabled) + build_lighting(p); + else { + if (p->state->fragprog_inputs_read & FRAG_BIT_COL0) + emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL0); + + if (p->state->fragprog_inputs_read & FRAG_BIT_COL1) + emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL1); + } + } - if (p->state->fog_enabled) + if ((p->state->fragprog_inputs_read & FRAG_BIT_FOGC) || + p->state->fog_mode != FOG_NONE) build_fog(p); - if (p->state->texture_enabled_global) + if (p->state->fragprog_inputs_read & FRAG_BITS_TEX_ANY) build_texture_transform(p); if (p->state->point_attenuated) @@ -1470,42 +1487,60 @@ void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx ) TNLcontext *tnl = TNL_CONTEXT(ctx); struct state_key *key; GLuint hash; + struct vertex_program *prev = ctx->VertexProgram._Current; - if (ctx->VertexProgram._Enabled) - return; - - /* Grab all the relevent state and put it in a single structure: - */ - key = make_state_key(ctx); - hash = hash_key(key); + if (ctx->VertexProgram._Enabled) { + /* Grab all the relevent state and put it in a single structure: + */ + key = make_state_key(ctx); + hash = hash_key(key); + + if (tnl->vp_cache == NULL) { + tnl->vp_cache = MALLOC(sizeof(*tnl->vp_cache)); + tnl->vp_cache->size = 5; + tnl->vp_cache->n_items = 0; + tnl->vp_cache->items = MALLOC(tnl->vp_cache->size * + sizeof(*tnl->vp_cache->items)); + _mesa_memset(tnl->vp_cache->items, 0, tnl->vp_cache->size * + sizeof(*tnl->vp_cache->items)); + } - /* Look for an already-prepared program for this state: - */ - ctx->_TnlProgram = (struct vertex_program *) - search_cache( tnl->vp_cache, hash, key, sizeof(*key) ); + /* Look for an already-prepared program for this state: + */ + ctx->_TnlProgram = (struct vertex_program *) + search_cache( tnl->vp_cache, hash, key, sizeof(*key) ); - /* OK, we'll have to build a new one: - */ - if (!ctx->_TnlProgram) { - if (0) - _mesa_printf("Build new TNL program\n"); + /* OK, we'll have to build a new one: + */ + if (!ctx->_TnlProgram) { + if (0) + _mesa_printf("Build new TNL program\n"); + + ctx->_TnlProgram = (struct vertex_program *) + ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); - ctx->_TnlProgram = (struct vertex_program *) - ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); + create_new_program( key, ctx->_TnlProgram, + ctx->Const.VertexProgram.MaxTemps ); - create_new_program( key, ctx->_TnlProgram, - ctx->Const.VertexProgram.MaxTemps ); - cache_item(tnl->vp_cache, hash, key, ctx->_TnlProgram ); + cache_item(tnl->vp_cache, hash, key, ctx->_TnlProgram ); + } + else { + FREE(key); + if (0) + _mesa_printf("Found existing TNL program for key %x\n", hash); + } } else { - FREE(key); - if (0) - _mesa_printf("Found existing TNL program for key %x\n", hash); + ctx->VertexProgram._Current = ctx->VertexProgram.Current; } - /* Need a BindProgram callback for the driver? + /* Tell the driver about the change. Could define a new target for + * this? */ + if (ctx->VertexProgram._Current != prev) + ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB, (struct program *) + ctx->VertexProgram._Current); } -- 2.7.4