draw: vertex cache rework
authorKeith Whitwell <keith@tungstengraphics.com>
Fri, 15 Feb 2008 18:56:41 +0000 (18:56 +0000)
committerKeith Whitwell <keith@tungstengraphics.com>
Thu, 21 Feb 2008 19:17:27 +0000 (19:17 +0000)
Take a baby step to straightening out vertex paths.

src/gallium/auxiliary/draw/draw_context.c
src/gallium/auxiliary/draw/draw_prim.c
src/gallium/auxiliary/draw/draw_private.h
src/gallium/auxiliary/draw/draw_vertex_cache.c
src/gallium/auxiliary/draw/draw_vertex_shader.c

index a7f3b4aecb24df506a82eb192e027faa2ad95480..b90a9f474de8f4877bf477bf55b1ace3b7a67628 100644 (file)
@@ -72,10 +72,10 @@ struct draw_context *draw_create( void )
    {
       uint i;
       const unsigned size = (MAX_VERTEX_SIZE + 0x0f) & ~0x0f;
-      char *tmp = align_malloc(Elements(draw->vcache.vertex) * size, 16);
+      char *tmp = align_malloc(Elements(draw->vs.queue) * size, 16);
 
-      for (i = 0; i < Elements(draw->vcache.vertex); i++)
-        draw->vcache.vertex[i] = (struct vertex_header *)(tmp + i * size);
+      for (i = 0; i < Elements(draw->vs.queue); i++)
+        draw->vs.queue[i].vertex = (struct vertex_header *)(tmp + i * size);
    }
 
    draw->shader_queue_flush = draw_vertex_shader_queue_flush;
@@ -108,7 +108,7 @@ void draw_destroy( struct draw_context *draw )
    if (draw->pipeline.rasterize)
       draw->pipeline.rasterize->destroy( draw->pipeline.rasterize );
    tgsi_exec_machine_free_data(&draw->machine);
-   align_free( draw->vcache.vertex[0] ); /* Frees all the vertices. */
+   align_free( draw->vs.queue[0].vertex ); /* Frees all the vertices. */
    FREE( draw );
 }
 
index dd9a848863746bb8e0042e218293be629475bf23..7d6cd43410cabb852772f921767d2afc9a52c59f 100644 (file)
@@ -114,6 +114,7 @@ static void draw_prim_queue_flush( struct draw_context *draw )
    }
 
    draw->pq.queue_nr = 0;   
+   draw->vs.post_nr = 0;   
    draw_vertex_cache_unreference( draw );
 }
 
@@ -226,6 +227,7 @@ static void do_triangle( struct draw_context *draw,
 {
    struct prim_header *prim = get_queued_prim( draw, 3 );
    
+//   _mesa_printf("tri %d %d %d\n", i0, i1, i2);
    prim->reset_line_stipple = 1;
    prim->edgeflags = ~0;
    prim->pad = 0;
index 6c7e860861e496e0590b312171c0373793dd2b24..492c152ff98503b9d28de901a9c659ccab3b0aad 100644 (file)
@@ -120,7 +120,7 @@ struct draw_stage
 };
 
 
-#define PRIM_QUEUE_LENGTH      16
+#define PRIM_QUEUE_LENGTH      32
 #define VCACHE_SIZE            32
 #define VCACHE_OVERFLOW        4
 #define VS_QUEUE_LENGTH        (VCACHE_SIZE + VCACHE_OVERFLOW + 1)     /* can never fill up */
@@ -244,8 +244,12 @@ struct draw_context
     */
    struct {
       unsigned referenced;  /**< bitfield */
-      unsigned idx[VCACHE_SIZE + VCACHE_OVERFLOW];
-      struct vertex_header *vertex[VCACHE_SIZE + VCACHE_OVERFLOW];
+
+      struct {
+        unsigned in;           /* client array element */
+        unsigned out;          /* index in vs queue/array */
+      } idx[VCACHE_SIZE + VCACHE_OVERFLOW];
+
       unsigned overflow;
 
       /** To find space in the vertex cache: */
@@ -258,9 +262,10 @@ struct draw_context
    struct {
       struct {
         unsigned elt;   /**< index into the user's vertex arrays */
-        struct vertex_header *dest; /**< points into vcache.vertex[] array */
+        struct vertex_header *vertex;
       } queue[VS_QUEUE_LENGTH];
       unsigned queue_nr;
+      unsigned post_nr;
    } vs;
 
    /**
index 44427999ccfb20b585492629e6a6a606f0ef3582..53f8bbec4458223606692b9417a9aae8e2c2c2f4 100644 (file)
@@ -41,7 +41,7 @@ void draw_vertex_cache_invalidate( struct draw_context *draw )
    assert(draw->vs.queue_nr == 0);
    assert(draw->vcache.referenced == 0);
 
-   memset(draw->vcache.idx, ~0, sizeof(draw->vcache.idx));
+//   memset(draw->vcache.idx, ~0, sizeof(draw->vcache.idx));
 }
 
 
@@ -62,43 +62,51 @@ static struct vertex_header *get_vertex( struct draw_context *draw,
    
    assert(slot < 32); /* so we don't exceed the bitfield size below */
 
-   /* Cache miss?
-    */
-   if (draw->vcache.idx[slot] != i) {
-
-      /* If slot is in use, use the overflow area:
+   if (draw->vcache.referenced & (1<<slot))
+   {
+      /* Cache hit?
        */
-      if (draw->vcache.referenced & (1 << slot)) {
-        slot = VCACHE_SIZE + draw->vcache.overflow++;
+      if (draw->vcache.idx[slot].in == i) {
+//      _mesa_printf("HIT %d %d\n", slot, i);
+        assert(draw->vcache.idx[slot].out < draw->vs.queue_nr);
+        return draw->vs.queue[draw->vcache.idx[slot].out].vertex;
       }
 
+      /* Otherwise a collision
+       */
+      slot = VCACHE_SIZE + draw->vcache.overflow++;
+//      _mesa_printf("XXX %d --> %d\n", i, slot);
+   }
+
+   /* Deal with the cache miss: 
+    */
+   {
+      unsigned out;
+      
       assert(slot < Elements(draw->vcache.idx));
 
-      draw->vcache.idx[slot] = i;
+//      _mesa_printf("NEW %d %d\n", slot, i);
+      draw->vcache.idx[slot].in = i;
+      draw->vcache.idx[slot].out = out = draw->vs.queue_nr++;
+      draw->vcache.referenced |= (1 << slot);
+
 
       /* Add to vertex shader queue:
        */
       assert(draw->vs.queue_nr < VS_QUEUE_LENGTH);
-      draw->vs.queue[draw->vs.queue_nr].dest = draw->vcache.vertex[slot];
-      draw->vs.queue[draw->vs.queue_nr].elt = i;
-      draw->vs.queue_nr++;
+
+      draw->vs.queue[out].elt = i;
+      draw->vs.queue[out].vertex->clipmask = 0;
+      draw->vs.queue[out].vertex->edgeflag = 1; /*XXX use user's edge flag! */
+      draw->vs.queue[out].vertex->pad = 0;
+      draw->vs.queue[out].vertex->vertex_id = UNDEFINED_VERTEX_ID;
 
       /* Need to set the vertex's edge flag here.  If we're being called
        * by do_ef_triangle(), that function needs edge flag info!
        */
-      draw->vcache.vertex[slot]->clipmask = 0;
-      draw->vcache.vertex[slot]->edgeflag = 1; /*XXX use user's edge flag! */
-      draw->vcache.vertex[slot]->pad = 0;
-      draw->vcache.vertex[slot]->vertex_id = UNDEFINED_VERTEX_ID;
-   }
 
-
-   /* primitive flushing may have cleared the bitfield but did not
-    * clear the idx[] array values.  Set the bit now.  This fixes a
-    * bug found when drawing long triangle fans.
-    */
-   draw->vcache.referenced |= (1 << slot);
-   return draw->vcache.vertex[slot];
+      return draw->vs.queue[draw->vcache.idx[slot].out].vertex;
+   }
 }
 
 
@@ -130,8 +138,8 @@ void draw_vertex_cache_reset_vertex_ids( struct draw_context *draw )
 {
    unsigned i;
 
-   for (i = 0; i < Elements(draw->vcache.vertex); i++)
-      draw->vcache.vertex[i]->vertex_id = UNDEFINED_VERTEX_ID;
+   for (i = 0; i < draw->vs.post_nr; i++)
+      draw->vs.queue[i].vertex->vertex_id = UNDEFINED_VERTEX_ID;
 }
 
 
index f68f6e32440cc910cf354822cdd8bc01fec06f57..5d2f5c9c43aee6d2e9b7d18b80fc3ef0af1efc0b 100644 (file)
@@ -55,7 +55,7 @@ draw_vertex_shader_queue_flush(struct draw_context *draw)
     */
    shader->prepare( shader, draw );
 
-//   fprintf(stderr, " q(%d) ", draw->vs.queue_nr );
+//   fprintf(stderr, "%s %d\n", __FUNCTION__, draw->vs.queue_nr );
 
    /* run vertex shader on vertex cache entries, four per invokation */
    for (i = 0; i < draw->vs.queue_nr; i += 4) {
@@ -65,12 +65,12 @@ draw_vertex_shader_queue_flush(struct draw_context *draw)
 
       for (j = 0; j < n; j++) {
          elts[j] = draw->vs.queue[i + j].elt;
-         dests[j] = draw->vs.queue[i + j].dest;
+         dests[j] = draw->vs.queue[i + j].vertex;
       }
 
       for ( ; j < 4; j++) {
         elts[j] = elts[0];
-        dests[j] = dests[0];
+         dests[j] = draw->vs.queue[i + j].vertex;
       }
 
       assert(n > 0);
@@ -79,6 +79,7 @@ draw_vertex_shader_queue_flush(struct draw_context *draw)
       shader->run(shader, draw, elts, n, dests);
    }
 
+   draw->vs.post_nr = draw->vs.queue_nr;
    draw->vs.queue_nr = 0;
 }