2 * Copyright 2000-2001 VA Linux Systems, Inc.
3 * (C) Copyright IBM Corporation 2002, 2003
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * on the rights to use, copy, modify, merge, publish, distribute, sub
10 * license, and/or sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Ian Romanick <idr@us.ibm.com>
27 * Keith Whitwell <keithw@tungstengraphics.com>
28 * Kevin E. Martin <kem@users.sourceforge.net>
29 * Gareth Hughes <gareth@nvidia.com>
33 * Implements all of the device-independent texture memory management.
35 * Currently, only a simple LRU texture memory management policy is
36 * implemented. In the (hopefully very near) future, better policies will be
37 * implemented. The idea is that the DRI should be able to run in one of two
38 * modes. In the default mode the DRI will dynamically attempt to discover
39 * the best texture management policy for the running application. In the
40 * other mode, the user (via some sort of as yet TBD mechanism) will select
41 * a texture management policy that is known to work well with the
45 #include "main/imports.h"
46 #include "main/macros.h"
47 #include "main/simple_list.h"
51 static unsigned dummy_swap_counter;
55 * Calculate \f$\log_2\f$ of a value. This is a particularly poor
56 * implementation of this function. However, since system performance is in
57 * no way dependent on this function, the slowness of the implementation is
60 * \param n Value whose \f$\log_2\f$ is to be calculated
68 for ( log2 = 1 ; n > 1 ; log2++ ) {
79 * Determine if a texture is resident in textureable memory. Depending on
80 * the driver, this may or may not be on-card memory. It could be AGP memory
81 * or anyother type of memory from which the hardware can directly read
84 * This function is intended to be used as the \c IsTextureResident function
85 * in the device's \c dd_function_table.
87 * \param ctx GL context pointer (currently unused)
88 * \param texObj Texture object to be tested
92 driIsTextureResident( struct gl_context * ctx,
93 struct gl_texture_object * texObj )
98 t = (driTextureObject *) texObj->DriverData;
99 return( (t != NULL) && (t->memBlock != NULL) );
106 * (Re)initialize the global circular LRU list. The last element
107 * in the array (\a heap->nrRegions) is the sentinal. Keeping it
108 * at the end of the array allows the other elements of the array
109 * to be addressed rationally when looking up objects at a particular
110 * location in texture memory.
112 * \param heap Texture heap to be reset
115 static void resetGlobalLRU( driTexHeap * heap )
117 drmTextureRegionPtr list = heap->global_regions;
118 unsigned sz = 1U << heap->logGranularity;
121 for (i = 0 ; (i+1) * sz <= heap->size ; i++) {
128 list[0].prev = heap->nrRegions;
130 list[i].next = heap->nrRegions;
131 list[heap->nrRegions].prev = i;
132 list[heap->nrRegions].next = 0;
133 heap->global_age[0] = 0;
137 * Print out debugging information about the local texture LRU.
139 * \param heap Texture heap to be printed
140 * \param callername Name of calling function
142 static void printLocalLRU( driTexHeap * heap, const char *callername )
145 unsigned sz = 1U << heap->logGranularity;
147 fprintf( stderr, "%s in %s:\nLocal LRU, heap %d:\n",
148 __FUNCTION__, callername, heap->heapId );
150 foreach ( t, &heap->texture_objects ) {
154 fprintf( stderr, "Placeholder (%p) %d at 0x%x sz 0x%x\n",
156 t->memBlock->ofs / sz,
160 fprintf( stderr, "Texture (%p) at 0x%x sz 0x%x\n",
166 foreach ( t, heap->swapped_objects ) {
168 fprintf( stderr, "Swapped Placeholder (%p)\n", (void *)t );
170 fprintf( stderr, "Swapped Texture (%p)\n", (void *)t );
174 fprintf( stderr, "\n" );
178 * Print out debugging information about the global texture LRU.
180 * \param heap Texture heap to be printed
181 * \param callername Name of calling function
183 static void printGlobalLRU( driTexHeap * heap, const char *callername )
185 drmTextureRegionPtr list = heap->global_regions;
188 fprintf( stderr, "%s in %s:\nGlobal LRU, heap %d list %p:\n",
189 __FUNCTION__, callername, heap->heapId, (void *)list );
191 for ( i = 0, j = heap->nrRegions ; i < heap->nrRegions ; i++ ) {
192 fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n",
193 j, list[j].age, list[j].next, list[j].prev, list[j].in_use );
195 if ( j == heap->nrRegions ) break;
198 if ( j != heap->nrRegions ) {
199 fprintf( stderr, "Loop detected in global LRU\n" );
200 for ( i = 0 ; i < heap->nrRegions ; i++ ) {
201 fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n",
202 i, list[i].age, list[i].next, list[i].prev, list[i].in_use );
206 fprintf( stderr, "\n" );
211 * Called by the client whenever it touches a local texture.
213 * \param t Texture object that the client has accessed
216 void driUpdateTextureLRU( driTextureObject * t )
219 drmTextureRegionPtr list;
227 if ( heap != NULL ) {
228 shift = heap->logGranularity;
229 start = t->memBlock->ofs >> shift;
230 end = (t->memBlock->ofs + t->memBlock->size - 1) >> shift;
233 heap->local_age = ++heap->global_age[0];
234 list = heap->global_regions;
237 /* Update the context's local LRU
240 move_to_head( & heap->texture_objects, t );
243 for (i = start ; i <= end ; i++) {
244 list[i].age = heap->local_age;
246 /* remove_from_list(i)
248 list[(unsigned)list[i].next].prev = list[i].prev;
249 list[(unsigned)list[i].prev].next = list[i].next;
251 /* insert_at_head(list, i)
253 list[i].prev = heap->nrRegions;
254 list[i].next = list[heap->nrRegions].next;
255 list[(unsigned)list[heap->nrRegions].next].prev = i;
256 list[heap->nrRegions].next = i;
260 printGlobalLRU( heap, __FUNCTION__ );
261 printLocalLRU( heap, __FUNCTION__ );
270 * Keep track of swapped out texture objects.
272 * \param t Texture object to be "swapped" out of its texture heap
275 void driSwapOutTextureObject( driTextureObject * t )
280 if ( t->memBlock != NULL ) {
281 assert( t->heap != NULL );
282 mmFreeMem( t->memBlock );
285 if (t->timestamp > t->heap->timestamp)
286 t->heap->timestamp = t->timestamp;
288 t->heap->texture_swaps[0]++;
289 move_to_tail( t->heap->swapped_objects, t );
293 assert( t->heap == NULL );
297 for ( face = 0 ; face < 6 ; face++ ) {
298 t->dirty_images[face] = ~0;
306 * Destroy hardware state associated with texture \a t. Calls the
307 * \a destroy_texture_object method associated with the heap from which
308 * \a t was allocated.
310 * \param t Texture object to be destroyed
313 void driDestroyTextureObject( driTextureObject * t )
319 fprintf( stderr, "[%s:%d] freeing %p (tObj = %p, DriverData = %p)\n",
322 (void *)((t != NULL) ? t->tObj : NULL),
323 (void *)((t != NULL && t->tObj != NULL) ? t->tObj->DriverData : NULL ));
329 assert( heap != NULL );
331 heap->texture_swaps[0]++;
333 mmFreeMem( t->memBlock );
336 if (t->timestamp > t->heap->timestamp)
337 t->heap->timestamp = t->timestamp;
339 heap->destroy_texture_object( heap->driverContext, t );
343 if ( t->tObj != NULL ) {
344 assert( t->tObj->DriverData == t );
345 t->tObj->DriverData = NULL;
348 remove_from_list( t );
353 fprintf( stderr, "[%s:%d] done freeing %p\n", __FILE__, __LINE__, (void *)t );
361 * Update the local heap's representation of texture memory based on
362 * data in the SAREA. This is done each time it is detected that some other
363 * direct rendering client has held the lock. This pertains to both our local
364 * textures and the textures belonging to other clients. Keep track of other
365 * client's textures by pushing a placeholder texture onto the LRU list --
366 * these are denoted by \a tObj being \a NULL.
368 * \param heap Heap whose state is to be updated
369 * \param offset Byte offset in the heap that has been stolen
370 * \param size Size, in bytes, of the stolen block
371 * \param in_use Non-zero if the block is pinned/reserved by the kernel
374 static void driTexturesGone( driTexHeap * heap, int offset, int size,
377 driTextureObject * t;
378 driTextureObject * tmp;
381 foreach_s ( t, tmp, & heap->texture_objects ) {
382 if ( (t->memBlock->ofs < (offset + size))
383 && ((t->memBlock->ofs + t->memBlock->size) > offset) ) {
384 /* It overlaps - kick it out. If the texture object is just a
385 * place holder, then destroy it all together. Otherwise, mark
386 * it as being swapped out.
389 if ( t->tObj != NULL ) {
390 driSwapOutTextureObject( t );
393 driDestroyTextureObject( t );
400 t = (driTextureObject *) CALLOC( heap->texture_object_size );
401 if ( t == NULL ) return;
403 t->memBlock = mmAllocMem( heap->memory_heap, size, 0, offset );
404 if ( t->memBlock == NULL ) {
405 fprintf( stderr, "Couldn't alloc placeholder: heap %u sz %x ofs %x\n", heap->heapId,
406 (int)size, (int)offset );
407 mmDumpMemInfo( heap->memory_heap );
414 insert_at_head( & heap->texture_objects, t );
422 * Called by the client on lock contention to determine whether textures have
423 * been stolen. If another client has modified a region in which we have
424 * textures, then we need to figure out which of our textures have been
425 * removed and update our global LRU.
427 * \param heap Texture heap to be updated
430 void driAgeTextures( driTexHeap * heap )
432 drmTextureRegionPtr list = heap->global_regions;
433 unsigned sz = 1U << (heap->logGranularity);
437 /* Have to go right round from the back to ensure stuff ends up
438 * LRU in the local list... Fix with a cursor pointer.
441 for (i = list[heap->nrRegions].prev ;
442 i != heap->nrRegions && nr < heap->nrRegions ;
443 i = list[i].prev, nr++) {
444 /* If switching texturing schemes, then the SAREA might not have been
445 * properly cleared, so we need to reset the global texture LRU.
448 if ( (i * sz) > heap->size ) {
449 nr = heap->nrRegions;
453 if (list[i].age > heap->local_age)
454 driTexturesGone( heap, i * sz, sz, list[i].in_use);
457 /* Loop or uninitialized heap detected. Reset.
460 if (nr == heap->nrRegions) {
461 driTexturesGone( heap, 0, heap->size, 0);
462 resetGlobalLRU( heap );
466 printGlobalLRU( heap, __FUNCTION__ );
467 printLocalLRU( heap, __FUNCTION__ );
470 heap->local_age = heap->global_age[0];
476 #define INDEX_ARRAY_SIZE 6 /* I'm not aware of driver with more than 2 heaps */
479 * Allocate memory from a texture heap to hold a texture object. This
480 * routine will attempt to allocate memory for the texture from the heaps
481 * specified by \c heap_array in order. That is, first it will try to
482 * allocate from \c heap_array[0], then \c heap_array[1], and so on.
484 * \param heap_array Array of pointers to texture heaps to use
485 * \param nr_heaps Number of heap pointer in \a heap_array
486 * \param t Texture object for which space is needed
487 * \return The ID of the heap from which memory was allocated, or -1 if
488 * memory could not be allocated.
490 * \bug The replacement policy implemented by this function is horrible.
495 driAllocateTexture( driTexHeap * const * heap_array, unsigned nr_heaps,
496 driTextureObject * t )
499 driTextureObject * temp;
500 driTextureObject * cursor;
504 /* In case it already has texture space, initialize heap. This also
505 * prevents GCC from issuing a warning that heap might be used
512 /* Run through each of the existing heaps and try to allocate a buffer
513 * to hold the texture.
516 for ( id = 0 ; (t->memBlock == NULL) && (id < nr_heaps) ; id++ ) {
517 heap = heap_array[ id ];
518 if ( heap != NULL ) {
519 t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize,
520 heap->alignmentShift, 0 );
525 /* Kick textures out until the requested texture fits.
528 if ( t->memBlock == NULL ) {
529 unsigned index[INDEX_ARRAY_SIZE];
530 unsigned nrGoodHeaps = 0;
532 /* Trying to avoid dynamic memory allocation. If you have more
533 * heaps, increase INDEX_ARRAY_SIZE. I'm not aware of any
534 * drivers with more than 2 tex heaps. */
535 assert( nr_heaps < INDEX_ARRAY_SIZE );
537 /* Sort large enough heaps by duty. Insertion sort should be
538 * fast enough for such a short array. */
539 for ( id = 0 ; id < nr_heaps ; id++ ) {
540 heap = heap_array[ id ];
542 if ( heap != NULL && t->totalSize <= heap->size ) {
545 for ( j = 0 ; j < nrGoodHeaps; j++ ) {
546 if ( heap->duty > heap_array[ index[ j ] ]->duty )
550 if ( j < nrGoodHeaps ) {
551 memmove( &index[ j+1 ], &index[ j ],
552 sizeof(index[ 0 ]) * (nrGoodHeaps - j) );
561 for ( id = 0 ; (t->memBlock == NULL) && (id < nrGoodHeaps) ; id++ ) {
562 heap = heap_array[ index[ id ] ];
564 for ( cursor = heap->texture_objects.prev, temp = cursor->prev;
565 cursor != &heap->texture_objects ;
566 cursor = temp, temp = cursor->prev ) {
568 /* The the LRU element. If the texture is bound to one of
569 * the texture units, then we cannot kick it out.
571 if ( cursor->bound || cursor->reserved ) {
575 if ( cursor->memBlock )
576 heap->duty -= cursor->memBlock->size;
578 /* If this is a placeholder, there's no need to keep it */
580 driSwapOutTextureObject( cursor );
582 driDestroyTextureObject( cursor );
584 t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize,
585 heap->alignmentShift, 0 );
592 /* Rebalance duties. If a heap kicked more data than its duty,
593 * then all other heaps get that amount multiplied with their
594 * relative weight added to their duty. The negative duty is
595 * reset to 0. In the end all heaps have a duty >= 0.
597 * CAUTION: we must not change the heap pointer here, because it
598 * is used below to update the texture object.
600 for ( id = 0 ; id < nr_heaps ; id++ )
601 if ( heap_array[ id ] != NULL && heap_array[ id ]->duty < 0) {
602 int duty = -heap_array[ id ]->duty;
603 double weight = heap_array[ id ]->weight;
606 for ( j = 0 ; j < nr_heaps ; j++ )
607 if ( j != id && heap_array[ j ] != NULL ) {
608 heap_array[ j ]->duty += (double) duty *
609 heap_array[ j ]->weight / weight;
612 heap_array[ id ]->duty = 0;
617 if ( t->memBlock != NULL ) {
618 /* id and heap->heapId may or may not be the same value here.
621 assert( heap != NULL );
622 assert( (t->heap == NULL) || (t->heap == heap) );
628 assert( t->heap == NULL );
630 fprintf( stderr, "[%s:%d] unable to allocate texture\n",
631 __FUNCTION__, __LINE__ );
642 * Set the location where the texture-swap counter is stored.
646 driSetTextureSwapCounterLocation( driTexHeap * heap, unsigned * counter )
648 heap->texture_swaps = (counter == NULL) ? & dummy_swap_counter : counter;
655 * Create a new heap for texture data.
657 * \param heap_id Device-dependent heap identifier. This value
658 * will returned by driAllocateTexture when memory
659 * is allocated from this heap.
660 * \param context Device-dependent driver context. This is
661 * supplied as the first parameter to the
662 * \c destroy_tex_obj function.
663 * \param size Size, in bytes, of the texture region
664 * \param alignmentShift Alignment requirement for textures. If textures
665 * must be allocated on a 4096 byte boundry, this
667 * \param nr_regions Number of regions into which this texture space
668 * should be partitioned
669 * \param global_regions Array of \c drmTextureRegion structures in the SAREA
670 * \param global_age Pointer to the global texture age in the SAREA
671 * \param swapped_objects Pointer to the list of texture objects that are
672 * not in texture memory (i.e., have been swapped
674 * \param texture_object_size Size, in bytes, of a device-dependent texture
676 * \param destroy_tex_obj Function used to destroy a device-dependent
679 * \sa driDestroyTextureHeap
683 driCreateTextureHeap( unsigned heap_id, void * context, unsigned size,
684 unsigned alignmentShift, unsigned nr_regions,
685 drmTextureRegionPtr global_regions, unsigned * global_age,
686 driTextureObject * swapped_objects,
687 unsigned texture_object_size,
688 destroy_texture_object_t * destroy_tex_obj
696 fprintf( stderr, "%s( %u, %p, %u, %u, %u )\n",
698 heap_id, (void *)context, size, alignmentShift, nr_regions );
700 heap = (driTexHeap *) CALLOC( sizeof( driTexHeap ) );
701 if ( heap != NULL ) {
702 l = driLog2( (size - 1) / nr_regions );
703 if ( l < alignmentShift )
708 heap->logGranularity = l;
709 heap->size = size & ~((1L << l) - 1);
711 heap->memory_heap = mmInit( 0, heap->size );
712 if ( heap->memory_heap != NULL ) {
713 heap->heapId = heap_id;
714 heap->driverContext = context;
716 heap->alignmentShift = alignmentShift;
717 heap->nrRegions = nr_regions;
718 heap->global_regions = global_regions;
719 heap->global_age = global_age;
720 heap->swapped_objects = swapped_objects;
721 heap->texture_object_size = texture_object_size;
722 heap->destroy_texture_object = destroy_tex_obj;
724 /* Force global heap init */
725 if (heap->global_age[0] == 0)
726 heap->local_age = ~0;
730 make_empty_list( & heap->texture_objects );
731 driSetTextureSwapCounterLocation( heap, NULL );
733 heap->weight = heap->size;
744 fprintf( stderr, "%s returning %p\n", __FUNCTION__, (void *)heap );
752 /** Destroys a texture heap
754 * \param heap Texture heap to be destroyed
758 driDestroyTextureHeap( driTexHeap * heap )
760 driTextureObject * t;
761 driTextureObject * temp;
764 if ( heap != NULL ) {
765 foreach_s( t, temp, & heap->texture_objects ) {
766 driDestroyTextureObject( t );
768 foreach_s( t, temp, heap->swapped_objects ) {
769 driDestroyTextureObject( t );
772 mmDestroy( heap->memory_heap );
780 /****************************************************************************/
782 * Determine how many texels (including all mipmap levels) would be required
783 * for a texture map of size \f$2^^\c base_size_log2\f$ would require.
785 * \param base_size_log2 \f$log_2\f$ of the size of a side of the texture
786 * \param dimensions Number of dimensions of the texture. Either 2 or 3.
787 * \param faces Number of faces of the texture. Either 1 or 6 (for cube maps).
788 * \return Number of texels
792 texels_this_map_size( int base_size_log2, unsigned dimensions, unsigned faces )
797 assert( (faces == 1) || (faces == 6) );
798 assert( (dimensions == 2) || (dimensions == 3) );
801 if ( base_size_log2 >= 0 ) {
802 texels = (1U << (dimensions * base_size_log2));
804 /* See http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg03636.html
805 * for the complete explaination of why this formulation is used.
806 * Basically, the smaller mipmap levels sum to 0.333 the size of the
807 * level 0 map. The total size is therefore the size of the map
808 * multipled by 1.333. The +2 is there to round up.
811 texels = (texels * 4 * faces + 2) / 3;
820 struct maps_per_heap {
825 fill_in_maximums( driTexHeap * const * heaps, unsigned nr_heaps,
826 unsigned max_bytes_per_texel, unsigned max_size,
827 unsigned mipmaps_at_once, unsigned dimensions,
828 unsigned faces, struct maps_per_heap * max_textures )
835 /* Determine how many textures of each size can be stored in each
839 for ( heap = 0 ; heap < nr_heaps ; heap++ ) {
840 if ( heaps[ heap ] == NULL ) {
841 (void) memset( max_textures[ heap ].c, 0,
842 sizeof( max_textures[ heap ].c ) );
846 mask = (1U << heaps[ heap ]->logGranularity) - 1;
849 fprintf( stderr, "[%s:%d] heap[%u] = %u bytes, mask = 0x%08x\n",
851 heap, heaps[ heap ]->size, mask );
854 for ( log2_size = max_size ; log2_size > 0 ; log2_size-- ) {
858 /* Determine the total number of bytes required by a texture of
862 total = texels_this_map_size( log2_size, dimensions, faces )
863 - texels_this_map_size( log2_size - mipmaps_at_once,
865 total *= max_bytes_per_texel;
866 total = (total + mask) & ~mask;
868 /* The number of textures of a given size that will fit in a heap
869 * is equal to the size of the heap divided by the size of the
873 max_textures[ heap ].c[ log2_size ] = heaps[ heap ]->size / total;
876 fprintf( stderr, "[%s:%d] max_textures[%u].c[%02u] "
881 heaps[ heap ]->size, total,
882 heaps[ heap ]->size / total,
883 max_textures[ heap ].c[ log2_size ] );
891 get_max_size( unsigned nr_heaps,
892 unsigned texture_units,
894 int all_textures_one_heap,
895 struct maps_per_heap * max_textures )
901 /* Determine the largest texture size such that a texture of that size
902 * can be bound to each texture unit at the same time. Some hardware
903 * may require that all textures be in the same texture heap for
907 for ( log2_size = max_size ; log2_size > 0 ; log2_size-- ) {
910 for ( heap = 0 ; heap < nr_heaps ; heap++ )
912 total += max_textures[ heap ].c[ log2_size ];
915 fprintf( stderr, "[%s:%d] max_textures[%u].c[%02u] = %u, "
916 "total = %u\n", __FILE__, __LINE__, heap, log2_size,
917 max_textures[ heap ].c[ log2_size ], total );
920 if ( (max_textures[ heap ].c[ log2_size ] >= texture_units)
921 || (!all_textures_one_heap && (total >= texture_units)) ) {
922 /* The number of mipmap levels is the log-base-2 of the
923 * maximum texture size plus 1. If the maximum texture size
924 * is 1x1, the log-base-2 is 0 and 1 mipmap level (the base
925 * level) is available.
928 return log2_size + 1;
933 /* This should NEVER happen. It should always be possible to have at
934 * *least* a 1x1 texture in memory!
936 assert( log2_size != 0 );
940 #define SET_MAX(f,v) \
941 do { if ( max_sizes[v] != 0 ) { limits-> f = max_sizes[v]; } } while( 0 )
943 #define SET_MAX_RECT(f,v) \
944 do { if ( max_sizes[v] != 0 ) { limits-> f = 1 << (max_sizes[v] - 1); } } while( 0 )
948 * Given the amount of texture memory, the number of texture units, and the
949 * maximum size of a texel, calculate the maximum texture size the driver can
952 * \param heaps Texture heaps for this card
953 * \param nr_heap Number of texture heaps
954 * \param limits OpenGL contants. MaxTextureUnits must be set.
955 * \param max_bytes_per_texel Maximum size of a single texel, in bytes
956 * \param max_2D_size \f$\log_2\f$ of the maximum 2D texture size (i.e.,
957 * 1024x1024 textures, this would be 10)
958 * \param max_3D_size \f$\log_2\f$ of the maximum 3D texture size (i.e.,
959 * 1024x1024x1024 textures, this would be 10)
960 * \param max_cube_size \f$\log_2\f$ of the maximum cube texture size (i.e.,
961 * 1024x1024 textures, this would be 10)
962 * \param max_rect_size \f$\log_2\f$ of the maximum texture rectangle size
963 * (i.e., 1024x1024 textures, this would be 10). This is a power-of-2
964 * even though texture rectangles need not be a power-of-2.
965 * \param mipmaps_at_once Total number of mipmaps that can be used
966 * at one time. For most hardware this will be \f$\c max_size + 1\f$.
967 * For hardware that does not support mipmapping, this will be 1.
968 * \param all_textures_one_heap True if the hardware requires that all
969 * textures be in a single texture heap for multitexturing.
970 * \param allow_larger_textures 0 conservative, 1 calculate limits
971 * so at least one worst-case texture can fit, 2 just use hw limits.
975 driCalculateMaxTextureLevels( driTexHeap * const * heaps,
977 struct gl_constants * limits,
978 unsigned max_bytes_per_texel,
979 unsigned max_2D_size,
980 unsigned max_3D_size,
981 unsigned max_cube_size,
982 unsigned max_rect_size,
983 unsigned mipmaps_at_once,
984 int all_textures_one_heap,
985 int allow_larger_textures )
987 struct maps_per_heap max_textures[8];
989 const unsigned dimensions[4] = { 2, 3, 2, 2 };
990 const unsigned faces[4] = { 1, 1, 6, 1 };
991 unsigned max_sizes[4];
995 max_sizes[0] = max_2D_size;
996 max_sizes[1] = max_3D_size;
997 max_sizes[2] = max_cube_size;
998 max_sizes[3] = max_rect_size;
1000 mipmaps[0] = mipmaps_at_once;
1001 mipmaps[1] = mipmaps_at_once;
1002 mipmaps[2] = mipmaps_at_once;
1006 /* Calculate the maximum number of texture levels in two passes. The
1007 * first pass determines how many textures of each power-of-two size
1008 * (including all mipmap levels for that size) can fit in each texture
1009 * heap. The second pass finds the largest texture size that allows
1010 * a texture of that size to be bound to every texture unit.
1013 for ( i = 0 ; i < 4 ; i++ ) {
1014 if ( (allow_larger_textures != 2) && (max_sizes[ i ] != 0) ) {
1015 fill_in_maximums( heaps, nr_heaps, max_bytes_per_texel,
1016 max_sizes[ i ], mipmaps[ i ],
1017 dimensions[ i ], faces[ i ],
1020 max_sizes[ i ] = get_max_size( nr_heaps,
1021 allow_larger_textures == 1 ?
1022 1 : limits->MaxTextureUnits,
1024 all_textures_one_heap,
1027 else if (max_sizes[ i ] != 0) {
1028 max_sizes[ i ] += 1;
1032 SET_MAX( MaxTextureLevels, 0 );
1033 SET_MAX( Max3DTextureLevels, 1 );
1034 SET_MAX( MaxCubeTextureLevels, 2 );
1035 SET_MAX_RECT( MaxTextureRectSize, 3 );
1042 * Perform initial binding of default textures objects on a per unit, per
1043 * texture target basis.
1045 * \param ctx Current OpenGL context
1046 * \param swapped List of swapped-out textures
1047 * \param targets Bit-mask of value texture targets
1050 void driInitTextureObjects( struct gl_context *ctx, driTextureObject * swapped,
1053 struct gl_texture_object *texObj;
1054 GLuint tmp = ctx->Texture.CurrentUnit;
1058 for ( i = 0 ; i < ctx->Const.MaxTextureUnits ; i++ ) {
1059 ctx->Texture.CurrentUnit = i;
1061 if ( (targets & DRI_TEXMGR_DO_TEXTURE_1D) != 0 ) {
1062 texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_1D_INDEX];
1063 ctx->Driver.BindTexture( ctx, GL_TEXTURE_1D, texObj );
1064 move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
1067 if ( (targets & DRI_TEXMGR_DO_TEXTURE_2D) != 0 ) {
1068 texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_2D_INDEX];
1069 ctx->Driver.BindTexture( ctx, GL_TEXTURE_2D, texObj );
1070 move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
1073 if ( (targets & DRI_TEXMGR_DO_TEXTURE_3D) != 0 ) {
1074 texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_3D_INDEX];
1075 ctx->Driver.BindTexture( ctx, GL_TEXTURE_3D, texObj );
1076 move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
1079 if ( (targets & DRI_TEXMGR_DO_TEXTURE_CUBE) != 0 ) {
1080 texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_CUBE_INDEX];
1081 ctx->Driver.BindTexture( ctx, GL_TEXTURE_CUBE_MAP_ARB, texObj );
1082 move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
1085 if ( (targets & DRI_TEXMGR_DO_TEXTURE_RECT) != 0 ) {
1086 texObj = ctx->Texture.Unit[i].CurrentTex[TEXTURE_RECT_INDEX];
1087 ctx->Driver.BindTexture( ctx, GL_TEXTURE_RECTANGLE_NV, texObj );
1088 move_to_tail( swapped, (driTextureObject *) texObj->DriverData );
1092 ctx->Texture.CurrentUnit = tmp;
1099 * Verify that the specified texture is in the specificed heap.
1101 * \param tex Texture to be tested.
1102 * \param heap Texture memory heap to be tested.
1103 * \return True if the texture is in the heap, false otherwise.
1107 check_in_heap( const driTextureObject * tex, const driTexHeap * heap )
1110 return tex->heap == heap;
1112 driTextureObject * curr;
1114 foreach( curr, & heap->texture_objects ) {
1115 if ( curr == tex ) {
1126 /****************************************************************************/
1128 * Validate the consistency of a set of texture heaps.
1129 * Original version by Keith Whitwell in r200/r200_sanity.c.
1133 driValidateTextureHeaps( driTexHeap * const * texture_heaps,
1134 unsigned nr_heaps, const driTextureObject * swapped )
1136 driTextureObject *t;
1139 for ( i = 0 ; i < nr_heaps ; i++ ) {
1141 unsigned textures_in_heap = 0;
1142 unsigned blocks_in_mempool = 0;
1143 const driTexHeap * heap = texture_heaps[i];
1144 const struct mem_block *p = heap->memory_heap;
1146 /* Check each texture object has a MemBlock, and is linked into
1149 * Check the texobj base address corresponds to the MemBlock
1150 * range. Check the texobj size (recalculate?) fits within
1153 * Count the number of texobj's using this heap.
1156 foreach ( t, &heap->texture_objects ) {
1157 if ( !check_in_heap( t, heap ) ) {
1158 fprintf( stderr, "%s memory block for texture object @ %p not "
1159 "found in heap #%d\n",
1160 __FUNCTION__, (void *)t, i );
1165 if ( t->totalSize > t->memBlock->size ) {
1166 fprintf( stderr, "%s: Memory block for texture object @ %p is "
1167 "only %u bytes, but %u are required\n",
1168 __FUNCTION__, (void *)t, t->totalSize, t->memBlock->size );
1175 /* Validate the contents of the heap:
1181 while ( p != NULL ) {
1183 fprintf( stderr, "%s: Block (%08x,%x), is reserved?!\n",
1184 __FUNCTION__, p->ofs, p->size );
1188 if (p->ofs != last_end) {
1189 fprintf( stderr, "%s: blocks_in_mempool = %d, last_end = %d, p->ofs = %d\n",
1190 __FUNCTION__, blocks_in_mempool, last_end, p->ofs );
1194 if (!p->reserved && !p->free) {
1195 blocks_in_mempool++;
1198 last_end = p->ofs + p->size;
1202 if (textures_in_heap != blocks_in_mempool) {
1203 fprintf( stderr, "%s: Different number of textures objects (%u) and "
1204 "inuse memory blocks (%u)\n",
1205 __FUNCTION__, textures_in_heap, blocks_in_mempool );
1210 fprintf( stderr, "%s: textures_in_heap = %u\n",
1211 __FUNCTION__, textures_in_heap );
1216 /* Check swapped texobj's have zero memblocks
1219 foreach ( t, swapped ) {
1220 if ( t->memBlock != NULL ) {
1221 fprintf( stderr, "%s: Swapped texobj %p has non-NULL memblock %p\n",
1222 __FUNCTION__, (void *)t, (void *)t->memBlock );
1229 fprintf( stderr, "%s: swapped texture count = %u\n", __FUNCTION__, i );
1238 /****************************************************************************/
1240 * Compute which mipmap levels that really need to be sent to the hardware.
1241 * This depends on the base image size, GL_TEXTURE_MIN_LOD,
1242 * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
1246 driCalculateTextureFirstLastLevel( driTextureObject * t )
1248 struct gl_texture_object * const tObj = t->tObj;
1249 const struct gl_texture_image * const baseImage =
1250 tObj->Image[0][tObj->BaseLevel];
1252 /* These must be signed values. MinLod and MaxLod can be negative numbers,
1253 * and having firstLevel and lastLevel as signed prevents the need for
1254 * extra sign checks.
1259 /* Yes, this looks overly complicated, but it's all needed.
1262 switch (tObj->Target) {
1266 case GL_TEXTURE_CUBE_MAP:
1267 if (tObj->Sampler.MinFilter == GL_NEAREST ||
1268 tObj->Sampler.MinFilter == GL_LINEAR) {
1269 /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
1272 firstLevel = lastLevel = tObj->BaseLevel;
1275 firstLevel = tObj->BaseLevel + (GLint)(tObj->Sampler.MinLod + 0.5);
1276 firstLevel = MAX2(firstLevel, tObj->BaseLevel);
1277 firstLevel = MIN2(firstLevel, tObj->BaseLevel + baseImage->MaxLog2);
1278 lastLevel = tObj->BaseLevel + (GLint)(tObj->Sampler.MaxLod + 0.5);
1279 lastLevel = MAX2(lastLevel, t->tObj->BaseLevel);
1280 lastLevel = MIN2(lastLevel, t->tObj->BaseLevel + baseImage->MaxLog2);
1281 lastLevel = MIN2(lastLevel, t->tObj->MaxLevel);
1282 lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
1285 case GL_TEXTURE_RECTANGLE_NV:
1286 case GL_TEXTURE_4D_SGIS:
1287 firstLevel = lastLevel = 0;
1293 /* save these values */
1294 t->firstLevel = firstLevel;
1295 t->lastLevel = lastLevel;
1302 * \name DRI texture formats. These vars are initialized to either the
1303 * big- or little-endian Mesa formats.
1306 gl_format _dri_texformat_rgba8888 = MESA_FORMAT_NONE;
1307 gl_format _dri_texformat_argb8888 = MESA_FORMAT_NONE;
1308 gl_format _dri_texformat_rgb565 = MESA_FORMAT_NONE;
1309 gl_format _dri_texformat_argb4444 = MESA_FORMAT_NONE;
1310 gl_format _dri_texformat_argb1555 = MESA_FORMAT_NONE;
1311 gl_format _dri_texformat_al88 = MESA_FORMAT_NONE;
1312 gl_format _dri_texformat_a8 = MESA_FORMAT_A8;
1313 gl_format _dri_texformat_ci8 = MESA_FORMAT_CI8;
1314 gl_format _dri_texformat_i8 = MESA_FORMAT_I8;
1315 gl_format _dri_texformat_l8 = MESA_FORMAT_L8;
1320 * Initialize _dri_texformat_* vars according to whether we're on
1321 * a big or little endian system.
1324 driInitTextureFormats(void)
1326 if (_mesa_little_endian()) {
1327 _dri_texformat_rgba8888 = MESA_FORMAT_RGBA8888;
1328 _dri_texformat_argb8888 = MESA_FORMAT_ARGB8888;
1329 _dri_texformat_rgb565 = MESA_FORMAT_RGB565;
1330 _dri_texformat_argb4444 = MESA_FORMAT_ARGB4444;
1331 _dri_texformat_argb1555 = MESA_FORMAT_ARGB1555;
1332 _dri_texformat_al88 = MESA_FORMAT_AL88;
1335 _dri_texformat_rgba8888 = MESA_FORMAT_RGBA8888_REV;
1336 _dri_texformat_argb8888 = MESA_FORMAT_ARGB8888_REV;
1337 _dri_texformat_rgb565 = MESA_FORMAT_RGB565_REV;
1338 _dri_texformat_argb4444 = MESA_FORMAT_ARGB4444_REV;
1339 _dri_texformat_argb1555 = MESA_FORMAT_ARGB1555_REV;
1340 _dri_texformat_al88 = MESA_FORMAT_AL88_REV;