Several fp and vp tweaks:
authorKeith Whitwell <keith@tungstengraphics.com>
Tue, 1 Nov 2005 17:25:49 +0000 (17:25 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Tue, 1 Nov 2005 17:25:49 +0000 (17:25 +0000)
- 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
src/mesa/main/texenvprogram.c
src/mesa/shader/arbprogparse.c
src/mesa/shader/arbprogparse.h
src/mesa/shader/nvfragprog.h
src/mesa/shader/nvvertparse.c
src/mesa/tnl/t_vp_build.c

index aadd0a7..d77759d 100644 (file)
@@ -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 */
 
index 18d704c..43dda28 100644 (file)
@@ -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 )
index e8fe869..19c38b6 100644 (file)
@@ -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;
 
index ececfaf..947c22e 100644 (file)
@@ -65,6 +65,8 @@ struct arb_program
    GLuint NumAluInstructions; 
    GLuint NumTexInstructions;
    GLuint NumTexIndirections;
+
+   GLboolean UsesKill;
 };
 
 
index 99ec20b..bd9c8bb 100644 (file)
 #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 */
index c48a4cb..24882a2 100644 (file)
@@ -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 */
index 02e5a2a..0fc4f6c 100644 (file)
@@ -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_EXP    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<<i)))
+        continue;
+                                                            
+      if (p->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);   
 }