* Kevin E. Martin <kem@users.sourceforge.net>
* Gareth Hughes <gareth@nvidia.com>
*/
-/* $XFree86:$ */
/** \file texmem.c
* Implements all of the device-independent texture memory management.
*/
#include "texmem.h"
-#include "simple_list.h"
-#include "imports.h"
-#include "macros.h"
-#include "texformat.h"
+#include "main/simple_list.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/texformat.h"
#include <assert.h>
static void printGlobalLRU( driTexHeap * heap, const char *callername )
{
drmTextureRegionPtr list = heap->global_regions;
- int i, j;
+ unsigned int i, j;
fprintf( stderr, "%s in %s:\nGlobal LRU, heap %d list %p:\n",
__FUNCTION__, callername, heap->heapId, (void *)list );
fprintf( stderr, "Couldn't alloc placeholder: heap %u sz %x ofs %x\n", heap->heapId,
(int)size, (int)offset );
mmDumpMemInfo( heap->memory_heap );
+ FREE(t);
return;
}
t->heap = heap;
if (in_use)
- t->bound = 99;
+ t->reserved = 1;
insert_at_head( & heap->texture_objects, t );
}
}
+#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
*/
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_heaps < 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 ( heap == NULL )
- continue;
+ if ( heap != NULL && t->totalSize <= heap->size ) {
+ unsigned j;
- if ( t->totalSize <= heap->size ) {
+ for ( j = 0 ; j < nrGoodHeaps; j++ ) {
+ if ( heap->duty > heap_array[ index[ j ] ]->duty )
+ break;
+ }
- 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 ( j < nrGoodHeaps ) {
+ memmove( &index[ j+1 ], &index[ j ],
+ sizeof(index[ 0 ]) * (nrGoodHeaps - j) );
+ }
- /* If this is a placeholder, there's no need to keep it */
- if (cursor->tObj)
- driSwapOutTextureObject( cursor );
- else
- driDestroyTextureObject( cursor );
+ index[ j ] = id;
- t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize,
- heap->alignmentShift, 0 );
+ nrGoodHeaps++;
+ }
+ }
- if (t->memBlock)
- break;
+ 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 ] != NULL && 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 ] != NULL ) {
+ heap_array[ j ]->duty += (double) duty *
+ heap_array[ j ]->weight / weight;
+ }
+
+ heap_array[ id ]->duty = 0;
+ }
}
make_empty_list( & heap->texture_objects );
driSetTextureSwapCounterLocation( heap, NULL );
+
+ heap->weight = heap->size;
+ heap->duty = 0;
}
else {
FREE( heap );
do { if ( max_sizes[v] != 0 ) { limits-> f = max_sizes[v]; } } while( 0 )
#define SET_MAX_RECT(f,v) \
- do { if ( max_sizes[v] != 0 ) { limits-> f = 1 << max_sizes[v]; } } while( 0 )
+ do { if ( max_sizes[v] != 0 ) { limits-> f = 1 << (max_sizes[v] - 1); } } while( 0 )
/**
* For hardware that does not support mipmapping, this will be 1.
* \param all_textures_one_heap True if the hardware requires that all
* textures be in a single texture heap for multitexturing.
+ * \param allow_larger_textures 0 conservative, 1 calculate limits
+ * so at least one worst-case texture can fit, 2 just use hw limits.
*/
void
driCalculateMaxTextureLevels( driTexHeap * const * heaps,
unsigned nr_heaps,
struct gl_constants * limits,
- unsigned max_bytes_per_texel,
+ unsigned max_bytes_per_texel,
unsigned max_2D_size,
unsigned max_3D_size,
unsigned max_cube_size,
unsigned max_rect_size,
unsigned mipmaps_at_once,
- int all_textures_one_heap )
+ int all_textures_one_heap,
+ int allow_larger_textures )
{
struct maps_per_heap max_textures[8];
unsigned i;
mipmaps[0] = mipmaps_at_once;
mipmaps[1] = mipmaps_at_once;
- mipmaps[2] = 1;
- mipmaps[3] = mipmaps_at_once;
+ mipmaps[2] = mipmaps_at_once;
+ mipmaps[3] = 1;
/* Calculate the maximum number of texture levels in two passes. The
*/
for ( i = 0 ; i < 4 ; i++ ) {
- if ( max_sizes[ i ] != 0 ) {
- fill_in_maximums( heaps, nr_heaps, max_bytes_per_texel,
+ if ( (allow_larger_textures != 2) && (max_sizes[ i ] != 0) ) {
+ fill_in_maximums( heaps, nr_heaps, max_bytes_per_texel,
max_sizes[ i ], mipmaps[ i ],
dimensions[ i ], faces[ i ],
max_textures );
- max_sizes[ i ] = get_max_size( nr_heaps,
- limits->MaxTextureUnits,
+ max_sizes[ i ] = get_max_size( nr_heaps,
+ allow_larger_textures == 1 ?
+ 1 : limits->MaxTextureUnits,
max_sizes[ i ],
all_textures_one_heap,
max_textures );
}
+ else if (max_sizes[ i ] != 0) {
+ max_sizes[ i ] += 1;
+ }
}
SET_MAX( MaxTextureLevels, 0 );
unsigned textures_in_heap = 0;
unsigned blocks_in_mempool = 0;
const driTexHeap * heap = texture_heaps[i];
- const memHeap_t * p = heap->memory_heap;
+ const struct mem_block *p = heap->memory_heap;
/* Check each texture object has a MemBlock, and is linked into
* the correct heap.
else {
firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5);
firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+ firstLevel = MIN2(firstLevel, tObj->BaseLevel + baseImage->MaxLog2);
lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5);
lastLevel = MAX2(lastLevel, t->tObj->BaseLevel);
lastLevel = MIN2(lastLevel, t->tObj->BaseLevel + baseImage->MaxLog2);