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
46 #include "main/simple_list.h"
47 #include "main/imports.h"
48 #include "main/macros.h"
49 #include "main/texformat.h"
55 static unsigned dummy_swap_counter
;
59 * Calculate \f$\log_2\f$ of a value. This is a particularly poor
60 * implementation of this function. However, since system performance is in
61 * no way dependent on this function, the slowness of the implementation is
64 * \param n Value whose \f$\log_2\f$ is to be calculated
72 for ( log2
= 1 ; n
> 1 ; log2
++ ) {
83 * Determine if a texture is resident in textureable memory. Depending on
84 * the driver, this may or may not be on-card memory. It could be AGP memory
85 * or anyother type of memory from which the hardware can directly read
88 * This function is intended to be used as the \c IsTextureResident function
89 * in the device's \c dd_function_table.
91 * \param ctx GL context pointer (currently unused)
92 * \param texObj Texture object to be tested
96 driIsTextureResident( GLcontext
* ctx
,
97 struct gl_texture_object
* texObj
)
102 t
= (driTextureObject
*) texObj
->DriverData
;
103 return( (t
!= NULL
) && (t
->memBlock
!= NULL
) );
110 * (Re)initialize the global circular LRU list. The last element
111 * in the array (\a heap->nrRegions) is the sentinal. Keeping it
112 * at the end of the array allows the other elements of the array
113 * to be addressed rationally when looking up objects at a particular
114 * location in texture memory.
116 * \param heap Texture heap to be reset
119 static void resetGlobalLRU( driTexHeap
* heap
)
121 drmTextureRegionPtr list
= heap
->global_regions
;
122 unsigned sz
= 1U << heap
->logGranularity
;
125 for (i
= 0 ; (i
+1) * sz
<= heap
->size
; i
++) {
132 list
[0].prev
= heap
->nrRegions
;
134 list
[i
].next
= heap
->nrRegions
;
135 list
[heap
->nrRegions
].prev
= i
;
136 list
[heap
->nrRegions
].next
= 0;
137 heap
->global_age
[0] = 0;
141 * Print out debugging information about the local texture LRU.
143 * \param heap Texture heap to be printed
144 * \param callername Name of calling function
146 static void printLocalLRU( driTexHeap
* heap
, const char *callername
)
149 unsigned sz
= 1U << heap
->logGranularity
;
151 fprintf( stderr
, "%s in %s:\nLocal LRU, heap %d:\n",
152 __FUNCTION__
, callername
, heap
->heapId
);
154 foreach ( t
, &heap
->texture_objects
) {
158 fprintf( stderr
, "Placeholder (%p) %d at 0x%x sz 0x%x\n",
160 t
->memBlock
->ofs
/ sz
,
164 fprintf( stderr
, "Texture (%p) at 0x%x sz 0x%x\n",
170 foreach ( t
, heap
->swapped_objects
) {
172 fprintf( stderr
, "Swapped Placeholder (%p)\n", (void *)t
);
174 fprintf( stderr
, "Swapped Texture (%p)\n", (void *)t
);
178 fprintf( stderr
, "\n" );
182 * Print out debugging information about the global texture LRU.
184 * \param heap Texture heap to be printed
185 * \param callername Name of calling function
187 static void printGlobalLRU( driTexHeap
* heap
, const char *callername
)
189 drmTextureRegionPtr list
= heap
->global_regions
;
192 fprintf( stderr
, "%s in %s:\nGlobal LRU, heap %d list %p:\n",
193 __FUNCTION__
, callername
, heap
->heapId
, (void *)list
);
195 for ( i
= 0, j
= heap
->nrRegions
; i
< heap
->nrRegions
; i
++ ) {
196 fprintf( stderr
, "list[%d] age %d next %d prev %d in_use %d\n",
197 j
, list
[j
].age
, list
[j
].next
, list
[j
].prev
, list
[j
].in_use
);
199 if ( j
== heap
->nrRegions
) break;
202 if ( j
!= heap
->nrRegions
) {
203 fprintf( stderr
, "Loop detected in global LRU\n" );
204 for ( i
= 0 ; i
< heap
->nrRegions
; i
++ ) {
205 fprintf( stderr
, "list[%d] age %d next %d prev %d in_use %d\n",
206 i
, list
[i
].age
, list
[i
].next
, list
[i
].prev
, list
[i
].in_use
);
210 fprintf( stderr
, "\n" );
215 * Called by the client whenever it touches a local texture.
217 * \param t Texture object that the client has accessed
220 void driUpdateTextureLRU( driTextureObject
* t
)
223 drmTextureRegionPtr list
;
231 if ( heap
!= NULL
) {
232 shift
= heap
->logGranularity
;
233 start
= t
->memBlock
->ofs
>> shift
;
234 end
= (t
->memBlock
->ofs
+ t
->memBlock
->size
- 1) >> shift
;
237 heap
->local_age
= ++heap
->global_age
[0];
238 list
= heap
->global_regions
;
241 /* Update the context's local LRU
244 move_to_head( & heap
->texture_objects
, t
);
247 for (i
= start
; i
<= end
; i
++) {
248 list
[i
].age
= heap
->local_age
;
250 /* remove_from_list(i)
252 list
[(unsigned)list
[i
].next
].prev
= list
[i
].prev
;
253 list
[(unsigned)list
[i
].prev
].next
= list
[i
].next
;
255 /* insert_at_head(list, i)
257 list
[i
].prev
= heap
->nrRegions
;
258 list
[i
].next
= list
[heap
->nrRegions
].next
;
259 list
[(unsigned)list
[heap
->nrRegions
].next
].prev
= i
;
260 list
[heap
->nrRegions
].next
= i
;
264 printGlobalLRU( heap
, __FUNCTION__
);
265 printLocalLRU( heap
, __FUNCTION__
);
274 * Keep track of swapped out texture objects.
276 * \param t Texture object to be "swapped" out of its texture heap
279 void driSwapOutTextureObject( driTextureObject
* t
)
284 if ( t
->memBlock
!= NULL
) {
285 assert( t
->heap
!= NULL
);
286 mmFreeMem( t
->memBlock
);
289 if (t
->timestamp
> t
->heap
->timestamp
)
290 t
->heap
->timestamp
= t
->timestamp
;
292 t
->heap
->texture_swaps
[0]++;
293 move_to_tail( t
->heap
->swapped_objects
, t
);
297 assert( t
->heap
== NULL
);
301 for ( face
= 0 ; face
< 6 ; face
++ ) {
302 t
->dirty_images
[face
] = ~0;
310 * Destroy hardware state associated with texture \a t. Calls the
311 * \a destroy_texture_object method associated with the heap from which
312 * \a t was allocated.
314 * \param t Texture object to be destroyed
317 void driCleanupTextureObject( driTextureObject
* t
)
322 fprintf( stderr
, "[%s:%d] freeing %p (tObj = %p, DriverData = %p)\n",
325 (void *)((t
!= NULL
) ? t
->tObj
: NULL
),
326 (void *)((t
!= NULL
&& t
->tObj
!= NULL
) ? t
->tObj
->DriverData
: NULL
));
332 assert( heap
!= NULL
);
334 heap
->texture_swaps
[0]++;
336 mmFreeMem( t
->memBlock
);
339 if (t
->timestamp
> t
->heap
->timestamp
)
340 t
->heap
->timestamp
= t
->timestamp
;
342 heap
->destroy_texture_object( heap
->driverContext
, t
);
346 if ( t
->tObj
!= NULL
) {
347 assert( t
->tObj
->DriverData
== t
);
348 t
->tObj
->DriverData
= NULL
;
351 remove_from_list( t
);
355 fprintf( stderr
, "[%s:%d] done freeing %p\n", __FILE__
, __LINE__
, (void *)t
);
360 void driDestroyTextureObject( driTextureObject
* t
)
367 driCleanupTextureObject(t
);
375 * Update the local heap's representation of texture memory based on
376 * data in the SAREA. This is done each time it is detected that some other
377 * direct rendering client has held the lock. This pertains to both our local
378 * textures and the textures belonging to other clients. Keep track of other
379 * client's textures by pushing a placeholder texture onto the LRU list --
380 * these are denoted by \a tObj being \a NULL.
382 * \param heap Heap whose state is to be updated
383 * \param offset Byte offset in the heap that has been stolen
384 * \param size Size, in bytes, of the stolen block
385 * \param in_use Non-zero if the block is pinned/reserved by the kernel
388 static void driTexturesGone( driTexHeap
* heap
, int offset
, int size
,
391 driTextureObject
* t
;
392 driTextureObject
* tmp
;
395 foreach_s ( t
, tmp
, & heap
->texture_objects
) {
396 if ( (t
->memBlock
->ofs
< (offset
+ size
))
397 && ((t
->memBlock
->ofs
+ t
->memBlock
->size
) > offset
) ) {
398 /* It overlaps - kick it out. If the texture object is just a
399 * place holder, then destroy it all together. Otherwise, mark
400 * it as being swapped out.
403 if ( t
->tObj
!= NULL
) {
404 driSwapOutTextureObject( t
);
407 driDestroyTextureObject( t
);
414 t
= (driTextureObject
*) CALLOC( heap
->texture_object_size
);
415 if ( t
== NULL
) return;
417 t
->memBlock
= mmAllocMem( heap
->memory_heap
, size
, 0, offset
);
418 if ( t
->memBlock
== NULL
) {
419 fprintf( stderr
, "Couldn't alloc placeholder: heap %u sz %x ofs %x\n", heap
->heapId
,
420 (int)size
, (int)offset
);
421 mmDumpMemInfo( heap
->memory_heap
);
428 insert_at_head( & heap
->texture_objects
, t
);
436 * Called by the client on lock contention to determine whether textures have
437 * been stolen. If another client has modified a region in which we have
438 * textures, then we need to figure out which of our textures have been
439 * removed and update our global LRU.
441 * \param heap Texture heap to be updated
444 void driAgeTextures( driTexHeap
* heap
)
446 drmTextureRegionPtr list
= heap
->global_regions
;
447 unsigned sz
= 1U << (heap
->logGranularity
);
451 /* Have to go right round from the back to ensure stuff ends up
452 * LRU in the local list... Fix with a cursor pointer.
455 for (i
= list
[heap
->nrRegions
].prev
;
456 i
!= heap
->nrRegions
&& nr
< heap
->nrRegions
;
457 i
= list
[i
].prev
, nr
++) {
458 /* If switching texturing schemes, then the SAREA might not have been
459 * properly cleared, so we need to reset the global texture LRU.
462 if ( (i
* sz
) > heap
->size
) {
463 nr
= heap
->nrRegions
;
467 if (list
[i
].age
> heap
->local_age
)
468 driTexturesGone( heap
, i
* sz
, sz
, list
[i
].in_use
);
471 /* Loop or uninitialized heap detected. Reset.
474 if (nr
== heap
->nrRegions
) {
475 driTexturesGone( heap
, 0, heap
->size
, 0);
476 resetGlobalLRU( heap
);
480 printGlobalLRU( heap
, __FUNCTION__
);
481 printLocalLRU( heap
, __FUNCTION__
);
484 heap
->local_age
= heap
->global_age
[0];
490 #define INDEX_ARRAY_SIZE 6 /* I'm not aware of driver with more than 2 heaps */
493 * Allocate memory from a texture heap to hold a texture object. This
494 * routine will attempt to allocate memory for the texture from the heaps
495 * specified by \c heap_array in order. That is, first it will try to
496 * allocate from \c heap_array[0], then \c heap_array[1], and so on.
498 * \param heap_array Array of pointers to texture heaps to use
499 * \param nr_heaps Number of heap pointer in \a heap_array
500 * \param t Texture object for which space is needed
501 * \return The ID of the heap from which memory was allocated, or -1 if
502 * memory could not be allocated.
504 * \bug The replacement policy implemented by this function is horrible.
509 driAllocateTexture( driTexHeap
* const * heap_array
, unsigned nr_heaps
,
510 driTextureObject
* t
)
513 driTextureObject
* temp
;
514 driTextureObject
* cursor
;
518 /* In case it already has texture space, initialize heap. This also
519 * prevents GCC from issuing a warning that heap might be used
526 /* Run through each of the existing heaps and try to allocate a buffer
527 * to hold the texture.
530 for ( id
= 0 ; (t
->memBlock
== NULL
) && (id
< nr_heaps
) ; id
++ ) {
531 heap
= heap_array
[ id
];
532 if ( heap
!= NULL
) {
533 t
->memBlock
= mmAllocMem( heap
->memory_heap
, t
->totalSize
,
534 heap
->alignmentShift
, 0 );
539 /* Kick textures out until the requested texture fits.
542 if ( t
->memBlock
== NULL
) {
543 unsigned index
[INDEX_ARRAY_SIZE
];
544 unsigned nrGoodHeaps
= 0;
546 /* Trying to avoid dynamic memory allocation. If you have more
547 * heaps, increase INDEX_ARRAY_SIZE. I'm not aware of any
548 * drivers with more than 2 tex heaps. */
549 assert( nr_heaps
< INDEX_ARRAY_SIZE
);
551 /* Sort large enough heaps by duty. Insertion sort should be
552 * fast enough for such a short array. */
553 for ( id
= 0 ; id
< nr_heaps
; id
++ ) {
554 heap
= heap_array
[ id
];
556 if ( heap
!= NULL
&& t
->totalSize
<= heap
->size
) {
559 for ( j
= 0 ; j
< nrGoodHeaps
; j
++ ) {
560 if ( heap
->duty
> heap_array
[ index
[ j
] ]->duty
)
564 if ( j
< nrGoodHeaps
) {
565 memmove( &index
[ j
+1 ], &index
[ j
],
566 sizeof(index
[ 0 ]) * (nrGoodHeaps
- j
) );
575 for ( id
= 0 ; (t
->memBlock
== NULL
) && (id
< nrGoodHeaps
) ; id
++ ) {
576 heap
= heap_array
[ index
[ id
] ];
578 for ( cursor
= heap
->texture_objects
.prev
, temp
= cursor
->prev
;
579 cursor
!= &heap
->texture_objects
;
580 cursor
= temp
, temp
= cursor
->prev
) {
582 /* The the LRU element. If the texture is bound to one of
583 * the texture units, then we cannot kick it out.
585 if ( cursor
->bound
|| cursor
->reserved
) {
589 if ( cursor
->memBlock
)
590 heap
->duty
-= cursor
->memBlock
->size
;
592 /* If this is a placeholder, there's no need to keep it */
594 driSwapOutTextureObject( cursor
);
596 driDestroyTextureObject( cursor
);
598 t
->memBlock
= mmAllocMem( heap
->memory_heap
, t
->totalSize
,
599 heap
->alignmentShift
, 0 );
606 /* Rebalance duties. If a heap kicked more data than its duty,
607 * then all other heaps get that amount multiplied with their
608 * relative weight added to their duty. The negative duty is
609 * reset to 0. In the end all heaps have a duty >= 0.
611 * CAUTION: we must not change the heap pointer here, because it
612 * is used below to update the texture object.
614 for ( id
= 0 ; id
< nr_heaps
; id
++ )
615 if ( heap_array
[ id
] != NULL
&& heap_array
[ id
]->duty
< 0) {
616 int duty
= -heap_array
[ id
]->duty
;
617 double weight
= heap_array
[ id
]->weight
;
620 for ( j
= 0 ; j
< nr_heaps
; j
++ )
621 if ( j
!= id
&& heap_array
[ j
] != NULL
) {
622 heap_array
[ j
]->duty
+= (double) duty
*
623 heap_array
[ j
]->weight
/ weight
;
626 heap_array
[ id
]->duty
= 0;
631 if ( t
->memBlock
!= NULL
) {
632 /* id and heap->heapId may or may not be the same value here.
635 assert( heap
!= NULL
);
636 assert( (t
->heap
== NULL
) || (t
->heap
== heap
) );
642 assert( t
->heap
== NULL
);
644 fprintf( stderr
, "[%s:%d] unable to allocate texture\n",
645 __FUNCTION__
, __LINE__
);
656 * Set the location where the texture-swap counter is stored.
660 driSetTextureSwapCounterLocation( driTexHeap
* heap
, unsigned * counter
)
662 heap
->texture_swaps
= (counter
== NULL
) ? & dummy_swap_counter
: counter
;
669 * Create a new heap for texture data.
671 * \param heap_id Device-dependent heap identifier. This value
672 * will returned by driAllocateTexture when memory
673 * is allocated from this heap.
674 * \param context Device-dependent driver context. This is
675 * supplied as the first parameter to the
676 * \c destroy_tex_obj function.
677 * \param size Size, in bytes, of the texture region
678 * \param alignmentShift Alignment requirement for textures. If textures
679 * must be allocated on a 4096 byte boundry, this
681 * \param nr_regions Number of regions into which this texture space
682 * should be partitioned
683 * \param global_regions Array of \c drmTextureRegion structures in the SAREA
684 * \param global_age Pointer to the global texture age in the SAREA
685 * \param swapped_objects Pointer to the list of texture objects that are
686 * not in texture memory (i.e., have been swapped
688 * \param texture_object_size Size, in bytes, of a device-dependent texture
690 * \param destroy_tex_obj Function used to destroy a device-dependent
693 * \sa driDestroyTextureHeap
697 driCreateTextureHeap( unsigned heap_id
, void * context
, unsigned size
,
698 unsigned alignmentShift
, unsigned nr_regions
,
699 drmTextureRegionPtr global_regions
, unsigned * global_age
,
700 driTextureObject
* swapped_objects
,
701 unsigned texture_object_size
,
702 destroy_texture_object_t
* destroy_tex_obj
710 fprintf( stderr
, "%s( %u, %p, %u, %u, %u )\n",
712 heap_id
, (void *)context
, size
, alignmentShift
, nr_regions
);
714 heap
= (driTexHeap
*) CALLOC( sizeof( driTexHeap
) );
715 if ( heap
!= NULL
) {
716 l
= driLog2( (size
- 1) / nr_regions
);
717 if ( l
< alignmentShift
)
722 heap
->logGranularity
= l
;
723 heap
->size
= size
& ~((1L << l
) - 1);
725 heap
->memory_heap
= mmInit( 0, heap
->size
);
726 if ( heap
->memory_heap
!= NULL
) {
727 heap
->heapId
= heap_id
;
728 heap
->driverContext
= context
;
730 heap
->alignmentShift
= alignmentShift
;
731 heap
->nrRegions
= nr_regions
;
732 heap
->global_regions
= global_regions
;
733 heap
->global_age
= global_age
;
734 heap
->swapped_objects
= swapped_objects
;
735 heap
->texture_object_size
= texture_object_size
;
736 heap
->destroy_texture_object
= destroy_tex_obj
;
738 /* Force global heap init */
739 if (heap
->global_age
[0] == 0)
740 heap
->local_age
= ~0;
744 make_empty_list( & heap
->texture_objects
);
745 driSetTextureSwapCounterLocation( heap
, NULL
);
747 heap
->weight
= heap
->size
;
758 fprintf( stderr
, "%s returning %p\n", __FUNCTION__
, (void *)heap
);
766 /** Destroys a texture heap
768 * \param heap Texture heap to be destroyed
772 driDestroyTextureHeap( driTexHeap
* heap
)
774 driTextureObject
* t
;
775 driTextureObject
* temp
;
778 if ( heap
!= NULL
) {
779 foreach_s( t
, temp
, & heap
->texture_objects
) {
780 driDestroyTextureObject( t
);
782 foreach_s( t
, temp
, heap
->swapped_objects
) {
783 driDestroyTextureObject( t
);
786 mmDestroy( heap
->memory_heap
);
794 /****************************************************************************/
796 * Determine how many texels (including all mipmap levels) would be required
797 * for a texture map of size \f$2^^\c base_size_log2\f$ would require.
799 * \param base_size_log2 \f$log_2\f$ of the size of a side of the texture
800 * \param dimensions Number of dimensions of the texture. Either 2 or 3.
801 * \param faces Number of faces of the texture. Either 1 or 6 (for cube maps).
802 * \return Number of texels
806 texels_this_map_size( int base_size_log2
, unsigned dimensions
, unsigned faces
)
811 assert( (faces
== 1) || (faces
== 6) );
812 assert( (dimensions
== 2) || (dimensions
== 3) );
815 if ( base_size_log2
>= 0 ) {
816 texels
= (1U << (dimensions
* base_size_log2
));
818 /* See http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg03636.html
819 * for the complete explaination of why this formulation is used.
820 * Basically, the smaller mipmap levels sum to 0.333 the size of the
821 * level 0 map. The total size is therefore the size of the map
822 * multipled by 1.333. The +2 is there to round up.
825 texels
= (texels
* 4 * faces
+ 2) / 3;
834 struct maps_per_heap
{
839 fill_in_maximums( driTexHeap
* const * heaps
, unsigned nr_heaps
,
840 unsigned max_bytes_per_texel
, unsigned max_size
,
841 unsigned mipmaps_at_once
, unsigned dimensions
,
842 unsigned faces
, struct maps_per_heap
* max_textures
)
849 /* Determine how many textures of each size can be stored in each
853 for ( heap
= 0 ; heap
< nr_heaps
; heap
++ ) {
854 if ( heaps
[ heap
] == NULL
) {
855 (void) memset( max_textures
[ heap
].c
, 0,
856 sizeof( max_textures
[ heap
].c
) );
860 mask
= (1U << heaps
[ heap
]->logGranularity
) - 1;
863 fprintf( stderr
, "[%s:%d] heap[%u] = %u bytes, mask = 0x%08x\n",
865 heap
, heaps
[ heap
]->size
, mask
);
868 for ( log2_size
= max_size
; log2_size
> 0 ; log2_size
-- ) {
872 /* Determine the total number of bytes required by a texture of
876 total
= texels_this_map_size( log2_size
, dimensions
, faces
)
877 - texels_this_map_size( log2_size
- mipmaps_at_once
,
879 total
*= max_bytes_per_texel
;
880 total
= (total
+ mask
) & ~mask
;
882 /* The number of textures of a given size that will fit in a heap
883 * is equal to the size of the heap divided by the size of the
887 max_textures
[ heap
].c
[ log2_size
] = heaps
[ heap
]->size
/ total
;
890 fprintf( stderr
, "[%s:%d] max_textures[%u].c[%02u] "
895 heaps
[ heap
]->size
, total
,
896 heaps
[ heap
]->size
/ total
,
897 max_textures
[ heap
].c
[ log2_size
] );
905 get_max_size( unsigned nr_heaps
,
906 unsigned texture_units
,
908 int all_textures_one_heap
,
909 struct maps_per_heap
* max_textures
)
915 /* Determine the largest texture size such that a texture of that size
916 * can be bound to each texture unit at the same time. Some hardware
917 * may require that all textures be in the same texture heap for
921 for ( log2_size
= max_size
; log2_size
> 0 ; log2_size
-- ) {
924 for ( heap
= 0 ; heap
< nr_heaps
; heap
++ )
926 total
+= max_textures
[ heap
].c
[ log2_size
];
929 fprintf( stderr
, "[%s:%d] max_textures[%u].c[%02u] = %u, "
930 "total = %u\n", __FILE__
, __LINE__
, heap
, log2_size
,
931 max_textures
[ heap
].c
[ log2_size
], total
);
934 if ( (max_textures
[ heap
].c
[ log2_size
] >= texture_units
)
935 || (!all_textures_one_heap
&& (total
>= texture_units
)) ) {
936 /* The number of mipmap levels is the log-base-2 of the
937 * maximum texture size plus 1. If the maximum texture size
938 * is 1x1, the log-base-2 is 0 and 1 mipmap level (the base
939 * level) is available.
942 return log2_size
+ 1;
947 /* This should NEVER happen. It should always be possible to have at
948 * *least* a 1x1 texture in memory!
950 assert( log2_size
!= 0 );
954 #define SET_MAX(f,v) \
955 do { if ( max_sizes[v] != 0 ) { limits-> f = max_sizes[v]; } } while( 0 )
957 #define SET_MAX_RECT(f,v) \
958 do { if ( max_sizes[v] != 0 ) { limits-> f = 1 << (max_sizes[v] - 1); } } while( 0 )
962 * Given the amount of texture memory, the number of texture units, and the
963 * maximum size of a texel, calculate the maximum texture size the driver can
966 * \param heaps Texture heaps for this card
967 * \param nr_heap Number of texture heaps
968 * \param limits OpenGL contants. MaxTextureUnits must be set.
969 * \param max_bytes_per_texel Maximum size of a single texel, in bytes
970 * \param max_2D_size \f$\log_2\f$ of the maximum 2D texture size (i.e.,
971 * 1024x1024 textures, this would be 10)
972 * \param max_3D_size \f$\log_2\f$ of the maximum 3D texture size (i.e.,
973 * 1024x1024x1024 textures, this would be 10)
974 * \param max_cube_size \f$\log_2\f$ of the maximum cube texture size (i.e.,
975 * 1024x1024 textures, this would be 10)
976 * \param max_rect_size \f$\log_2\f$ of the maximum texture rectangle size
977 * (i.e., 1024x1024 textures, this would be 10). This is a power-of-2
978 * even though texture rectangles need not be a power-of-2.
979 * \param mipmaps_at_once Total number of mipmaps that can be used
980 * at one time. For most hardware this will be \f$\c max_size + 1\f$.
981 * For hardware that does not support mipmapping, this will be 1.
982 * \param all_textures_one_heap True if the hardware requires that all
983 * textures be in a single texture heap for multitexturing.
984 * \param allow_larger_textures 0 conservative, 1 calculate limits
985 * so at least one worst-case texture can fit, 2 just use hw limits.
989 driCalculateMaxTextureLevels( driTexHeap
* const * heaps
,
991 struct gl_constants
* limits
,
992 unsigned max_bytes_per_texel
,
993 unsigned max_2D_size
,
994 unsigned max_3D_size
,
995 unsigned max_cube_size
,
996 unsigned max_rect_size
,
997 unsigned mipmaps_at_once
,
998 int all_textures_one_heap
,
999 int allow_larger_textures
)
1001 struct maps_per_heap max_textures
[8];
1003 const unsigned dimensions
[4] = { 2, 3, 2, 2 };
1004 const unsigned faces
[4] = { 1, 1, 6, 1 };
1005 unsigned max_sizes
[4];
1006 unsigned mipmaps
[4];
1009 max_sizes
[0] = max_2D_size
;
1010 max_sizes
[1] = max_3D_size
;
1011 max_sizes
[2] = max_cube_size
;
1012 max_sizes
[3] = max_rect_size
;
1014 mipmaps
[0] = mipmaps_at_once
;
1015 mipmaps
[1] = mipmaps_at_once
;
1016 mipmaps
[2] = mipmaps_at_once
;
1020 /* Calculate the maximum number of texture levels in two passes. The
1021 * first pass determines how many textures of each power-of-two size
1022 * (including all mipmap levels for that size) can fit in each texture
1023 * heap. The second pass finds the largest texture size that allows
1024 * a texture of that size to be bound to every texture unit.
1027 for ( i
= 0 ; i
< 4 ; i
++ ) {
1028 if ( (allow_larger_textures
!= 2) && (max_sizes
[ i
] != 0) ) {
1029 fill_in_maximums( heaps
, nr_heaps
, max_bytes_per_texel
,
1030 max_sizes
[ i
], mipmaps
[ i
],
1031 dimensions
[ i
], faces
[ i
],
1034 max_sizes
[ i
] = get_max_size( nr_heaps
,
1035 allow_larger_textures
== 1 ?
1036 1 : limits
->MaxTextureUnits
,
1038 all_textures_one_heap
,
1041 else if (max_sizes
[ i
] != 0) {
1042 max_sizes
[ i
] += 1;
1046 SET_MAX( MaxTextureLevels
, 0 );
1047 SET_MAX( Max3DTextureLevels
, 1 );
1048 SET_MAX( MaxCubeTextureLevels
, 2 );
1049 SET_MAX_RECT( MaxTextureRectSize
, 3 );
1056 * Perform initial binding of default textures objects on a per unit, per
1057 * texture target basis.
1059 * \param ctx Current OpenGL context
1060 * \param swapped List of swapped-out textures
1061 * \param targets Bit-mask of value texture targets
1064 void driInitTextureObjects( GLcontext
*ctx
, driTextureObject
* swapped
,
1067 struct gl_texture_object
*texObj
;
1068 GLuint tmp
= ctx
->Texture
.CurrentUnit
;
1072 for ( i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++ ) {
1073 ctx
->Texture
.CurrentUnit
= i
;
1075 if ( (targets
& DRI_TEXMGR_DO_TEXTURE_1D
) != 0 ) {
1076 texObj
= ctx
->Texture
.Unit
[i
].Current1D
;
1077 ctx
->Driver
.BindTexture( ctx
, GL_TEXTURE_1D
, texObj
);
1078 move_to_tail( swapped
, (driTextureObject
*) texObj
->DriverData
);
1081 if ( (targets
& DRI_TEXMGR_DO_TEXTURE_2D
) != 0 ) {
1082 texObj
= ctx
->Texture
.Unit
[i
].Current2D
;
1083 ctx
->Driver
.BindTexture( ctx
, GL_TEXTURE_2D
, texObj
);
1084 move_to_tail( swapped
, (driTextureObject
*) texObj
->DriverData
);
1087 if ( (targets
& DRI_TEXMGR_DO_TEXTURE_3D
) != 0 ) {
1088 texObj
= ctx
->Texture
.Unit
[i
].Current3D
;
1089 ctx
->Driver
.BindTexture( ctx
, GL_TEXTURE_3D
, texObj
);
1090 move_to_tail( swapped
, (driTextureObject
*) texObj
->DriverData
);
1093 if ( (targets
& DRI_TEXMGR_DO_TEXTURE_CUBE
) != 0 ) {
1094 texObj
= ctx
->Texture
.Unit
[i
].CurrentCubeMap
;
1095 ctx
->Driver
.BindTexture( ctx
, GL_TEXTURE_CUBE_MAP_ARB
, texObj
);
1096 move_to_tail( swapped
, (driTextureObject
*) texObj
->DriverData
);
1099 if ( (targets
& DRI_TEXMGR_DO_TEXTURE_RECT
) != 0 ) {
1100 texObj
= ctx
->Texture
.Unit
[i
].CurrentRect
;
1101 ctx
->Driver
.BindTexture( ctx
, GL_TEXTURE_RECTANGLE_NV
, texObj
);
1102 move_to_tail( swapped
, (driTextureObject
*) texObj
->DriverData
);
1106 ctx
->Texture
.CurrentUnit
= tmp
;
1113 * Verify that the specified texture is in the specificed heap.
1115 * \param tex Texture to be tested.
1116 * \param heap Texture memory heap to be tested.
1117 * \return True if the texture is in the heap, false otherwise.
1121 check_in_heap( const driTextureObject
* tex
, const driTexHeap
* heap
)
1124 return tex
->heap
== heap
;
1126 driTextureObject
* curr
;
1128 foreach( curr
, & heap
->texture_objects
) {
1129 if ( curr
== tex
) {
1140 /****************************************************************************/
1142 * Validate the consistency of a set of texture heaps.
1143 * Original version by Keith Whitwell in r200/r200_sanity.c.
1147 driValidateTextureHeaps( driTexHeap
* const * texture_heaps
,
1148 unsigned nr_heaps
, const driTextureObject
* swapped
)
1150 driTextureObject
*t
;
1153 for ( i
= 0 ; i
< nr_heaps
; i
++ ) {
1155 unsigned textures_in_heap
= 0;
1156 unsigned blocks_in_mempool
= 0;
1157 const driTexHeap
* heap
= texture_heaps
[i
];
1158 const struct mem_block
*p
= heap
->memory_heap
;
1160 /* Check each texture object has a MemBlock, and is linked into
1163 * Check the texobj base address corresponds to the MemBlock
1164 * range. Check the texobj size (recalculate?) fits within
1167 * Count the number of texobj's using this heap.
1170 foreach ( t
, &heap
->texture_objects
) {
1171 if ( !check_in_heap( t
, heap
) ) {
1172 fprintf( stderr
, "%s memory block for texture object @ %p not "
1173 "found in heap #%d\n",
1174 __FUNCTION__
, (void *)t
, i
);
1179 if ( t
->totalSize
> t
->memBlock
->size
) {
1180 fprintf( stderr
, "%s: Memory block for texture object @ %p is "
1181 "only %u bytes, but %u are required\n",
1182 __FUNCTION__
, (void *)t
, t
->totalSize
, t
->memBlock
->size
);
1189 /* Validate the contents of the heap:
1195 while ( p
!= NULL
) {
1197 fprintf( stderr
, "%s: Block (%08x,%x), is reserved?!\n",
1198 __FUNCTION__
, p
->ofs
, p
->size
);
1202 if (p
->ofs
!= last_end
) {
1203 fprintf( stderr
, "%s: blocks_in_mempool = %d, last_end = %d, p->ofs = %d\n",
1204 __FUNCTION__
, blocks_in_mempool
, last_end
, p
->ofs
);
1208 if (!p
->reserved
&& !p
->free
) {
1209 blocks_in_mempool
++;
1212 last_end
= p
->ofs
+ p
->size
;
1216 if (textures_in_heap
!= blocks_in_mempool
) {
1217 fprintf( stderr
, "%s: Different number of textures objects (%u) and "
1218 "inuse memory blocks (%u)\n",
1219 __FUNCTION__
, textures_in_heap
, blocks_in_mempool
);
1224 fprintf( stderr
, "%s: textures_in_heap = %u\n",
1225 __FUNCTION__
, textures_in_heap
);
1230 /* Check swapped texobj's have zero memblocks
1233 foreach ( t
, swapped
) {
1234 if ( t
->memBlock
!= NULL
) {
1235 fprintf( stderr
, "%s: Swapped texobj %p has non-NULL memblock %p\n",
1236 __FUNCTION__
, (void *)t
, (void *)t
->memBlock
);
1243 fprintf( stderr
, "%s: swapped texture count = %u\n", __FUNCTION__
, i
);
1252 /****************************************************************************/
1254 * Compute which mipmap levels that really need to be sent to the hardware.
1255 * This depends on the base image size, GL_TEXTURE_MIN_LOD,
1256 * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
1260 driCalculateTextureFirstLastLevel( driTextureObject
* t
)
1262 struct gl_texture_object
* const tObj
= t
->tObj
;
1263 const struct gl_texture_image
* const baseImage
=
1264 tObj
->Image
[0][tObj
->BaseLevel
];
1266 /* These must be signed values. MinLod and MaxLod can be negative numbers,
1267 * and having firstLevel and lastLevel as signed prevents the need for
1268 * extra sign checks.
1273 /* Yes, this looks overly complicated, but it's all needed.
1276 switch (tObj
->Target
) {
1280 case GL_TEXTURE_CUBE_MAP
:
1281 if (tObj
->MinFilter
== GL_NEAREST
|| tObj
->MinFilter
== GL_LINEAR
) {
1282 /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
1285 firstLevel
= lastLevel
= tObj
->BaseLevel
;
1288 firstLevel
= tObj
->BaseLevel
+ (GLint
)(tObj
->MinLod
+ 0.5);
1289 firstLevel
= MAX2(firstLevel
, tObj
->BaseLevel
);
1290 firstLevel
= MIN2(firstLevel
, tObj
->BaseLevel
+ baseImage
->MaxLog2
);
1291 lastLevel
= tObj
->BaseLevel
+ (GLint
)(tObj
->MaxLod
+ 0.5);
1292 lastLevel
= MAX2(lastLevel
, t
->tObj
->BaseLevel
);
1293 lastLevel
= MIN2(lastLevel
, t
->tObj
->BaseLevel
+ baseImage
->MaxLog2
);
1294 lastLevel
= MIN2(lastLevel
, t
->tObj
->MaxLevel
);
1295 lastLevel
= MAX2(firstLevel
, lastLevel
); /* need at least one level */
1298 case GL_TEXTURE_RECTANGLE_NV
:
1299 case GL_TEXTURE_4D_SGIS
:
1300 firstLevel
= lastLevel
= 0;
1306 /* save these values */
1307 t
->firstLevel
= firstLevel
;
1308 t
->lastLevel
= lastLevel
;
1315 * \name DRI texture formats. Pointers initialized to either the big- or
1316 * little-endian Mesa formats.
1319 const struct gl_texture_format
*_dri_texformat_rgba8888
= NULL
;
1320 const struct gl_texture_format
*_dri_texformat_argb8888
= NULL
;
1321 const struct gl_texture_format
*_dri_texformat_rgb565
= NULL
;
1322 const struct gl_texture_format
*_dri_texformat_argb4444
= NULL
;
1323 const struct gl_texture_format
*_dri_texformat_argb1555
= NULL
;
1324 const struct gl_texture_format
*_dri_texformat_al88
= NULL
;
1325 const struct gl_texture_format
*_dri_texformat_a8
= &_mesa_texformat_a8
;
1326 const struct gl_texture_format
*_dri_texformat_ci8
= &_mesa_texformat_ci8
;
1327 const struct gl_texture_format
*_dri_texformat_i8
= &_mesa_texformat_i8
;
1328 const struct gl_texture_format
*_dri_texformat_l8
= &_mesa_texformat_l8
;
1333 * Initialize little endian target, host byte order independent texture formats
1336 driInitTextureFormats(void)
1338 const GLuint ui
= 1;
1339 const GLubyte littleEndian
= *((const GLubyte
*) &ui
);
1342 _dri_texformat_rgba8888
= &_mesa_texformat_rgba8888
;
1343 _dri_texformat_argb8888
= &_mesa_texformat_argb8888
;
1344 _dri_texformat_rgb565
= &_mesa_texformat_rgb565
;
1345 _dri_texformat_argb4444
= &_mesa_texformat_argb4444
;
1346 _dri_texformat_argb1555
= &_mesa_texformat_argb1555
;
1347 _dri_texformat_al88
= &_mesa_texformat_al88
;
1350 _dri_texformat_rgba8888
= &_mesa_texformat_rgba8888_rev
;
1351 _dri_texformat_argb8888
= &_mesa_texformat_argb8888_rev
;
1352 _dri_texformat_rgb565
= &_mesa_texformat_rgb565_rev
;
1353 _dri_texformat_argb4444
= &_mesa_texformat_argb4444_rev
;
1354 _dri_texformat_argb1555
= &_mesa_texformat_argb1555_rev
;
1355 _dri_texformat_al88
= &_mesa_texformat_al88_rev
;