mesa: dynamically grow the fixed function vertex program as needed
authorBrian Paul <brian.paul@tungstengraphics.com>
Thu, 28 Aug 2008 21:11:04 +0000 (15:11 -0600)
committerBrian Paul <brian.paul@tungstengraphics.com>
Thu, 28 Aug 2008 21:11:04 +0000 (15:11 -0600)
Don't use a fixed-size array.  Saves memory in most cases and avoids
potential overflow for long programs.

src/mesa/main/ffvertex_prog.c

index b93376a564c1d5c7be2c351330c639936abf812f..e9ddc069808797c4d4b913e961ed2706bfcbb7bc 100644 (file)
@@ -319,7 +319,6 @@ static struct state_key *make_state_key( GLcontext *ctx )
  */
 #define PREFER_DP4 0
 
-#define MAX_INSN 300
 
 /* Use uregs to represent registers internally, translate to Mesa's
  * expected formats on emit.  
@@ -335,16 +334,18 @@ static struct state_key *make_state_key( GLcontext *ctx )
  */
 struct ureg {
    GLuint file:4;
-   GLint idx:8;      /* relative addressing may be negative */
+   GLint idx:9;      /* relative addressing may be negative */
+                     /* sizeof(idx) should == sizeof(prog_src_reg::Index) */
    GLuint negate:1;
    GLuint swz:12;
-   GLuint pad:7;
+   GLuint pad:6;
 };
 
 
 struct tnl_program {
    const struct state_key *state;
    struct gl_vertex_program *program;
+   GLint max_inst;  /** number of instructions allocated for program */
    
    GLuint temp_in_use;
    GLuint temp_reserved;
@@ -362,7 +363,7 @@ struct tnl_program {
 
 static const struct ureg undef = { 
    PROGRAM_UNDEFINED,
-   ~0,
+   0,
    0,
    0,
    0
@@ -558,6 +559,8 @@ static void emit_arg( struct prog_src_register *src,
    src->Abs = 0;
    src->NegateAbs = 0;
    src->RelAddr = 0;
+   /* Check that bitfield sizes aren't exceeded */
+   ASSERT(src->Index == reg.idx);
 }
 
 static void emit_dst( struct prog_dst_register *dst,
@@ -571,6 +574,8 @@ static void emit_dst( struct prog_dst_register *dst,
    dst->CondSwizzle = SWIZZLE_NOOP;
    dst->CondSrc = 0;
    dst->pad = 0;
+   /* Check that bitfield sizes aren't exceeded */
+   ASSERT(dst->Index == reg.idx);
 }
 
 static void debug_insn( struct prog_instruction *inst, const char *fn,
@@ -600,14 +605,37 @@ static void emit_op3fn(struct tnl_program *p,
                       const char *fn,
                       GLuint line)
 {
-   GLuint nr = p->program->Base.NumInstructions++;
-   struct prog_instruction *inst = &p->program->Base.Instructions[nr];
+   GLuint nr;
+   struct prog_instruction *inst;
       
-   if (p->program->Base.NumInstructions > MAX_INSN) {
-      _mesa_problem(0, "Out of instructions in emit_op3fn\n");
-      return;
+   assert(p->program->Base.NumInstructions <= p->max_inst);
+
+   if (p->program->Base.NumInstructions == p->max_inst) {
+      /* need to extend the program's instruction array */
+      struct prog_instruction *newInst;
+
+      /* double the size */
+      p->max_inst *= 2;
+
+      newInst = _mesa_alloc_instructions(p->max_inst);
+      if (!newInst) {
+         _mesa_error(NULL, GL_OUT_OF_MEMORY, "vertex program build");
+         return;
+      }
+
+      _mesa_copy_instructions(newInst,
+                              p->program->Base.Instructions,
+                              p->program->Base.NumInstructions);
+
+      _mesa_free_instructions(p->program->Base.Instructions,
+                              p->program->Base.NumInstructions);
+
+      p->program->Base.Instructions = newInst;
    }
       
+   nr = p->program->Base.NumInstructions++;
+
+   inst = &p->program->Base.Instructions[nr];
    inst->Opcode = (enum prog_opcode) op; 
    inst->StringPos = 0;
    inst->Data = 0;
@@ -1621,12 +1649,16 @@ static void build_tnl_program( struct tnl_program *p )
 #if 0
    else
       build_constant_pointsize(p);
+#else
+   (void) build_constant_pointsize;
 #endif
 
    /* Finish up:
     */
    emit_op1(p, OPCODE_END, undef, 0, undef);
 
+   _mesa_print_program(&p->program->Base);
+
    /* Disassemble:
     */
    if (DISASSEM) {
@@ -1657,7 +1689,11 @@ create_new_program( const struct state_key *key,
    else
       p.temp_reserved = ~((1<<max_temps)-1);
 
-   p.program->Base.Instructions = _mesa_alloc_instructions(MAX_INSN);
+   /* Start by allocating 32 instructions.
+    * If we need more, we'll grow the instruction array as needed.
+    */
+   p.max_inst = 32;
+   p.program->Base.Instructions = _mesa_alloc_instructions(p.max_inst);
    p.program->Base.String = NULL;
    p.program->Base.NumInstructions =
    p.program->Base.NumTemporaries =