Hi,

The attached patch is my first cut at implementing a fair strategy for
using all texture heaps. This solves my texture trashing problems with
Torcs on Savage4 and ProSavageDDR. Testing and comments are welcome. I'm
especially interested if anyone sees any performance regressions with
this.

Heaps are now weighted by their sizes. That is, the bigger a heap, the
more data will be kicked from/uploaded to it. If upload performance
differs greatly then it would be quite easy to multiply a heap-specific
factor to that weight in order to introduce a heap preference. This
could be done either directly in the driver just after allocating a
texture heap (heap->weight *= factor) or by adding a new parameter to
driCreateTextureHeap.

Note that the new code in my patch will not be active as long as there
is enough free space on any texture heap. So in order to see any
performance difference you will either have to test with a very
texture-hungry application or artificially reduce the amount of texture
memory on one or both heaps. Also note that you need at least two
texture heaps, so r200 is a bad candidate. ;-)

Regards,
  Felix

-- 
| Felix Kühling <[EMAIL PROTECTED]>                     http://fxk.de.vu |
| PGP Fingerprint: 6A3C 9566 5B30 DDED 73C3  B152 151C 5CC1 D888 E595 |
--- ./texmem.c.~1.7.~	2004-07-10 13:26:36.000000000 +0200
+++ ./texmem.c	2005-01-25 23:27:51.000000000 +0100
@@ -477,6 +477,8 @@
 
 
 
+#define INDEX_ARRAY_SIZE 6 /* I'm not aware of driver with more than 2 heaps */
+
 /**
  * Allocate memory from a texture heap to hold a texture object.  This
  * routine will attempt to allocate memory for the texture from the heaps
@@ -528,35 +530,91 @@
     */
 
    if ( t->memBlock == NULL ) {
-      for ( id = 0 ; (t->memBlock == NULL) && (id < nr_heaps) ; id++ ) {
+      unsigned index[INDEX_ARRAY_SIZE];
+      unsigned nrGoodHeaps = 0;
+
+      /* Trying to avoid dynamic memory allocation. If you have more
+       * heaps, increase INDEX_ARRAY_SIZE. I'm not aware of any
+       * drivers with more than 2 tex heaps. */
+      assert( nr_neaps < INDEX_ARRAY_SIZE );
+
+      /* Sort large enough heaps by duty. Insertion sort should be
+       * fast enough for such a short array. */
+      for ( id = 0 ; id < nr_heaps ; id++ ) {
 	 heap = heap_array[ id ];
-	 if ( t->totalSize <= heap->size ) { 
 
-	    for ( cursor = heap->texture_objects.prev, temp = cursor->prev;
-		  cursor != &heap->texture_objects ; 
-		  cursor = temp, temp = cursor->prev ) {
-	       
-	       /* The the LRU element.  If the texture is bound to one of
-		* the texture units, then we cannot kick it out.
-		*/
-	       if ( cursor->bound /* || cursor->reserved */ ) {
-		  continue;
-	       }
+	 if ( t->totalSize <= heap->size ) {
+	    unsigned j;
+
+	    for ( j = 0 ; j < nrGoodHeaps; j++ ) {
+	       if ( heap->duty > heap_array[ index[ j ] ]->duty )
+		  break;
+	    }
 
-	       /* If this is a placeholder, there's no need to keep it */
-	       if (cursor->tObj)
-		   driSwapOutTextureObject( cursor );
-	       else
-		   driDestroyTextureObject( cursor );
+	    if ( j < nrGoodHeaps ) {
+	       memmove( &index[ j+1 ], &index[ j ],
+			sizeof(index[ 0 ]) * (nrGoodHeaps - j) );
+	    }
 
-	       t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize, 
-					 heap->alignmentShift, 0 );
+	    index[ j ] = id;
 
-	       if (t->memBlock)
-		  break;
+	    nrGoodHeaps++;
+	 }
+      }
+
+      for ( id = 0 ; (t->memBlock == NULL) && (id < nrGoodHeaps) ; id++ ) {
+	 heap = heap_array[ index[ id ] ];
+
+	 for ( cursor = heap->texture_objects.prev, temp = cursor->prev;
+	       cursor != &heap->texture_objects ; 
+	       cursor = temp, temp = cursor->prev ) {
+	       
+	    /* The the LRU element.  If the texture is bound to one of
+	     * the texture units, then we cannot kick it out.
+	     */
+	    if ( cursor->bound /* || cursor->reserved */ ) {
+	       continue;
 	    }
-	 }     /* if ( t->totalSize <= heap->size ) ... */
+
+	    if ( cursor->memBlock )
+	       heap->duty -= cursor->memBlock->size;
+
+	    /* If this is a placeholder, there's no need to keep it */
+	    if (cursor->tObj)
+	       driSwapOutTextureObject( cursor );
+	    else
+	       driDestroyTextureObject( cursor );
+
+	    t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize, 
+				      heap->alignmentShift, 0 );
+
+	    if (t->memBlock)
+	       break;
+	 }
       }
+
+      /* Rebalance duties. If a heap kicked more data than its duty,
+       * then all other heaps get that amount multiplied with their
+       * relative weight added to their duty. The negative duty is
+       * reset to 0. In the end all heaps have a duty >= 0.
+       *
+       * CAUTION: we must not change the heap pointer here, because it
+       * is used below to update the texture object.
+       */
+      for ( id = 0 ; id < nr_heaps ; id++ )
+	 if ( heap_array[ id ]->duty < 0) {
+	    int duty = -heap_array[ id ]->duty;
+	    double weight = heap_array[ id ]->weight;
+	    unsigned j;
+
+	    for ( j = 0 ; j < nr_heaps ; j++ )
+	       if ( j != id ) {
+		  heap_array[ j ]->duty += (double) duty *
+		     heap_array[ j ]->weight / weight;
+	       }
+
+	    heap_array[ id ]->duty = 0;
+	 }
    }
 
 
@@ -675,6 +733,9 @@
 
 	 make_empty_list( & heap->texture_objects );
 	 driSetTextureSwapCounterLocation( heap, NULL );
+
+	 heap->weight = heap->size;
+	 heap->duty = 0;
       }
       else {
 	 FREE( heap );
--- ./texmem.h.~1.5.~	2004-07-10 13:26:36.000000000 +0200
+++ ./texmem.h	2005-01-25 23:27:44.000000000 +0100
@@ -216,6 +216,23 @@
 	 * framebuffer.  
 	 */
         unsigned timestamp;
+
+	/** \brief Kick/upload weight
+	 *
+	 * When not enough free space is available this weight
+	 * influences the choice of the heap from which textures are
+	 * kicked. By default the weight is equal to the heap size.
+	 */
+	double weight;
+
+	/** \brief Kick/upload duty
+	 *
+	 * The heap with the highest duty will be chosen for kicking
+	 * textures if not enough free space is available. The duty is
+	 * reduced by the amount of data kicked. Rebalancing of
+	 * negative duties takes the weights into account.
+	 */
+	int duty;
 };
 
 

Reply via email to