📄 texmem.c
字号:
*/ if ( (i * sz) > heap->size ) { nr = heap->nrRegions; break; } if (list[i].age > heap->local_age) driTexturesGone( heap, i * sz, sz, list[i].in_use); } /* Loop or uninitialized heap detected. Reset. */ if (nr == heap->nrRegions) { driTexturesGone( heap, 0, heap->size, 0); resetGlobalLRU( heap ); } if ( 0 ) { printGlobalLRU( heap, __FUNCTION__ ); printLocalLRU( heap, __FUNCTION__ ); } heap->local_age = heap->global_age[0];}#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 * specified by \c heap_array in order. That is, first it will try to * allocate from \c heap_array[0], then \c heap_array[1], and so on. * * \param heap_array Array of pointers to texture heaps to use * \param nr_heaps Number of heap pointer in \a heap_array * \param t Texture object for which space is needed * \return The ID of the heap from which memory was allocated, or -1 if * memory could not be allocated. * * \bug The replacement policy implemented by this function is horrible. */intdriAllocateTexture( driTexHeap * const * heap_array, unsigned nr_heaps, driTextureObject * t ){ driTexHeap * heap; driTextureObject * temp; driTextureObject * cursor; unsigned id; /* In case it already has texture space, initialize heap. This also * prevents GCC from issuing a warning that heap might be used * uninitialized. */ heap = t->heap; /* Run through each of the existing heaps and try to allocate a buffer * to hold the texture. */ for ( id = 0 ; (t->memBlock == NULL) && (id < nr_heaps) ; id++ ) { heap = heap_array[ id ]; if ( heap != NULL ) { t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize, heap->alignmentShift, 0 ); } } /* Kick textures out until the requested texture fits. */ if ( t->memBlock == NULL ) { 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 && t->totalSize <= heap->size ) { unsigned j; for ( j = 0 ; j < nrGoodHeaps; j++ ) { if ( heap->duty > heap_array[ index[ j ] ]->duty ) break; } if ( j < nrGoodHeaps ) { memmove( &index[ j+1 ], &index[ j ], sizeof(index[ 0 ]) * (nrGoodHeaps - j) ); } index[ j ] = id; 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 ( 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; } } if ( t->memBlock != NULL ) { /* id and heap->heapId may or may not be the same value here. */ assert( heap != NULL ); assert( (t->heap == NULL) || (t->heap == heap) ); t->heap = heap; return heap->heapId; } else { assert( t->heap == NULL ); fprintf( stderr, "[%s:%d] unable to allocate texture\n", __FUNCTION__, __LINE__ ); return -1; }}/** * Set the location where the texture-swap counter is stored. */voiddriSetTextureSwapCounterLocation( driTexHeap * heap, unsigned * counter ){ heap->texture_swaps = (counter == NULL) ? & dummy_swap_counter : counter;}/** * Create a new heap for texture data. * * \param heap_id Device-dependent heap identifier. This value * will returned by driAllocateTexture when memory * is allocated from this heap. * \param context Device-dependent driver context. This is * supplied as the first parameter to the * \c destroy_tex_obj function. * \param size Size, in bytes, of the texture region * \param alignmentShift Alignment requirement for textures. If textures * must be allocated on a 4096 byte boundry, this * would be 12. * \param nr_regions Number of regions into which this texture space * should be partitioned * \param global_regions Array of \c drmTextureRegion structures in the SAREA * \param global_age Pointer to the global texture age in the SAREA * \param swapped_objects Pointer to the list of texture objects that are * not in texture memory (i.e., have been swapped * out). * \param texture_object_size Size, in bytes, of a device-dependent texture * object * \param destroy_tex_obj Function used to destroy a device-dependent * texture object * * \sa driDestroyTextureHeap */driTexHeap *driCreateTextureHeap( unsigned heap_id, void * context, unsigned size, unsigned alignmentShift, unsigned nr_regions, drmTextureRegionPtr global_regions, unsigned * global_age, driTextureObject * swapped_objects, unsigned texture_object_size, destroy_texture_object_t * destroy_tex_obj ){ driTexHeap * heap; unsigned l; if ( 0 ) fprintf( stderr, "%s( %u, %p, %u, %u, %u )\n", __FUNCTION__, heap_id, (void *)context, size, alignmentShift, nr_regions ); heap = (driTexHeap *) CALLOC( sizeof( driTexHeap ) ); if ( heap != NULL ) { l = driLog2( (size - 1) / nr_regions ); if ( l < alignmentShift ) { l = alignmentShift; } heap->logGranularity = l; heap->size = size & ~((1L << l) - 1); heap->memory_heap = mmInit( 0, heap->size ); if ( heap->memory_heap != NULL ) { heap->heapId = heap_id; heap->driverContext = context; heap->alignmentShift = alignmentShift; heap->nrRegions = nr_regions; heap->global_regions = global_regions; heap->global_age = global_age; heap->swapped_objects = swapped_objects; heap->texture_object_size = texture_object_size; heap->destroy_texture_object = destroy_tex_obj; /* Force global heap init */ if (heap->global_age[0] == 0) heap->local_age = ~0; else heap->local_age = 0; make_empty_list( & heap->texture_objects ); driSetTextureSwapCounterLocation( heap, NULL ); heap->weight = heap->size; heap->duty = 0; } else { FREE( heap ); heap = NULL; } } if ( 0 ) fprintf( stderr, "%s returning %p\n", __FUNCTION__, (void *)heap ); return heap;}/** Destroys a texture heap * * \param heap Texture heap to be destroyed */voiddriDestroyTextureHeap( driTexHeap * heap ){ driTextureObject * t; driTextureObject * temp; if ( heap != NULL ) { foreach_s( t, temp, & heap->texture_objects ) { driDestroyTextureObject( t ); } foreach_s( t, temp, heap->swapped_objects ) { driDestroyTextureObject( t ); } mmDestroy( heap->memory_heap ); FREE( heap ); }}/****************************************************************************//** * Determine how many texels (including all mipmap levels) would be required * for a texture map of size \f$2^^\c base_size_log2\f$ would require. * * \param base_size_log2 \f$log_2\f$ of the size of a side of the texture * \param dimensions Number of dimensions of the texture. Either 2 or 3. * \param faces Number of faces of the texture. Either 1 or 6 (for cube maps). * \return Number of texels */static unsignedtexels_this_map_size( int base_size_log2, unsigned dimensions, unsigned faces ){ unsigned texels; assert( (faces == 1) || (faces == 6) ); assert( (dimensions == 2) || (dimensions == 3) ); texels = 0; if ( base_size_log2 >= 0 ) { texels = (1U << (dimensions * base_size_log2)); /* See http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg03636.html * for the complete explaination of why this formulation is used. * Basically, the smaller mipmap levels sum to 0.333 the size of the * level 0 map. The total size is therefore the size of the map * multipled by 1.333. The +2 is there to round up. */ texels = (texels * 4 * faces + 2) / 3; } return texels;}struct maps_per_heap { unsigned c[32];};static voidfill_in_maximums( driTexHeap * const * heaps, unsigned nr_heaps, unsigned max_bytes_per_texel, unsigned max_size, unsigned mipmaps_at_once, unsigned dimensions, unsigned faces, struct maps_per_heap * max_textures ){ unsigned heap; unsigned log2_size; unsigned mask; /* Determine how many textures of each size can be stored in each * texture heap. */ for ( heap = 0 ; heap < nr_heaps ; heap++ ) { if ( heaps[ heap ] == NULL ) { (void) memset( max_textures[ heap ].c, 0, sizeof( max_textures[ heap ].c ) ); continue; } mask = (1U << heaps[ heap ]->logGranularity) - 1; if ( 0 ) { fprintf( stderr, "[%s:%d] heap[%u] = %u bytes, mask = 0x%08x\n", __FILE__, __LINE__, heap, heaps[ heap ]->size, mask ); } for ( log2_size = max_size ; log2_size > 0 ; log2_size-- ) { unsigned total; /* Determine the total number of bytes required by a texture of * size log2_size. */ total = texels_this_map_size( log2_size, dimensions, faces ) - texels_this_map_size( log2_size - mipmaps_at_once, dimensions, faces ); total *= max_bytes_per_texel; total = (total + mask) & ~mask; /* The number of textures of a given size that will fit in a heap * is equal to the size of the heap divided by the size of the * texture. */ max_textures[ heap ].c[ log2_size ] = heaps[ heap ]->size / total; if ( 0 ) { fprintf( stderr, "[%s:%d] max_textures[%u].c[%02u] " "= 0x%08x / 0x%08x " "= %u (%u)\n", __FILE__, __LINE__, heap, log2_size, heaps[ heap ]->size, total, heaps[ heap ]->size / total, max_textures[ heap ].c[ log2_size ] ); } } }}static unsignedget_max_size( unsigned nr_heaps, unsigned texture_units, unsigned max_size, int all_textures_one_heap, struct maps_per_heap * max_textures )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -