1 /* -*- mode: c; c-basic-offset: 3 -*-
3 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
23 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
32 * Gareth Hughes <gareth@valinux.com>
33 * Brian Paul <brianp@valinux.com>
37 #include "tdfx_context.h"
38 #include "tdfx_texman.h"
39 #include "main/texobj.h"
40 #include "main/hash.h"
43 #define BAD_ADDRESS ((FxU32) -1)
48 * Verify the consistancy of the texture memory manager.
50 * Traversing all texture objects and computing total memory used.
51 * Traverse the free block list and computing total memory free.
52 * Compare the total free and total used amounts to the total memory size.
53 * Make various assertions about the results.
56 VerifyFreeList(tdfxContextPtr fxMesa
, FxU32 tmu
)
58 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
59 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
61 int prevStart
= -1, prevEnd
= -1;
63 int numObj
= 0, numRes
= 0;
66 for (block
= shared
->tmFree
[tmu
]; block
; block
= block
->next
) {
67 assert( block
->endAddr
> 0 );
68 assert( block
->startAddr
<= shared
->totalTexMem
[tmu
] );
69 assert( block
->endAddr
<= shared
->totalTexMem
[tmu
] );
70 assert( (int) block
->startAddr
> prevStart
);
71 assert( (int) block
->startAddr
>= prevEnd
);
72 prevStart
= (int) block
->startAddr
;
73 prevEnd
= (int) block
->endAddr
;
74 totalFree
+= (block
->endAddr
- block
->startAddr
);
76 assert(totalFree
== shared
->freeTexMem
[tmu
]);
79 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
81 for (id
= _mesa_HashFirstEntry(textures
);
83 id
= _mesa_HashNextEntry(textures
, id
)) {
84 struct gl_texture_object
*tObj
85 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
86 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
92 totalUsed
+= (ti
->tm
[tmu
]->endAddr
- ti
->tm
[tmu
]->startAddr
);
101 printf("totalFree: %d totalUsed: %d totalMem: %d #objs=%d #res=%d\n",
102 shared
->freeTexMem
[tmu
], totalUsed
, shared
->totalTexMem
[tmu
],
105 assert(totalUsed
+ totalFree
== shared
->totalTexMem
[tmu
]);
110 dump_texmem(tdfxContextPtr fxMesa
)
112 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
113 struct _mesa_HashTable
*textures
= mesaShared
->TexObjects
;
114 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
119 printf("DUMP Objects:\n");
120 for (id
= _mesa_HashFirstEntry(textures
);
122 id
= _mesa_HashNextEntry(textures
, id
)) {
123 struct gl_texture_object
*obj
124 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
125 tdfxTexInfo
*info
= TDFX_TEXTURE_DATA(obj
);
127 if (info
&& info
->isInTM
) {
128 printf("Obj %8p: %4d info = %p\n", obj
, obj
->Name
, info
);
130 printf(" isInTM=%d whichTMU=%d lastTimeUsed=%d\n",
131 info
->isInTM
, info
->whichTMU
, info
->lastTimeUsed
);
132 printf(" tm[0] = %p", info
->tm
[0]);
135 printf(" tm startAddr = %d endAddr = %d",
136 info
->tm
[0]->startAddr
,
137 info
->tm
[0]->endAddr
);
140 printf(" tm[1] = %p", info
->tm
[1]);
142 printf(" tm startAddr = %d endAddr = %d",
143 info
->tm
[1]->startAddr
,
144 info
->tm
[1]->endAddr
);
150 VerifyFreeList(fxMesa
, 0);
151 VerifyFreeList(fxMesa
, 1);
153 printf("Free memory unit 0: %d bytes\n", shared
->freeTexMem
[0]);
155 for (r
= shared
->tmFree
[0]; r
; r
= r
->next
) {
156 printf("%8p: start %8d end %8d size %8d gap %8d\n", r
, r
->startAddr
, r
->endAddr
, r
->endAddr
- r
->startAddr
, r
->startAddr
- prev
);
160 printf("Free memory unit 1: %d bytes\n", shared
->freeTexMem
[1]);
162 for (r
= shared
->tmFree
[1]; r
; r
= r
->next
) {
163 printf("%8p: start %8d end %8d size %8d gap %8d\n", r
, r
->startAddr
, r
->endAddr
, r
->endAddr
- r
->startAddr
, r
->startAddr
- prev
);
182 sanity(tdfxContextPtr fxMesa
)
184 tdfxMemRange
*tmp
, *prev
, *pos
;
187 tmp
= fxMesa
->tmFree
[0];
189 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
190 fprintf(stderr
, "Textures fubar\n");
193 if (tmp
->startAddr
>= tmp
->endAddr
) {
194 fprintf(stderr
, "Node fubar\n");
197 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
198 prev
->endAddr
> tmp
->startAddr
)) {
199 fprintf(stderr
, "Sorting fubar\n");
206 tmp
= fxMesa
->tmFree
[1];
208 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
209 fprintf(stderr
, "Textures fubar\n");
212 if (tmp
->startAddr
>= tmp
->endAddr
) {
213 fprintf(stderr
, "Node fubar\n");
216 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
217 prev
->endAddr
> tmp
->startAddr
)) {
218 fprintf(stderr
, "Sorting fubar\n");
232 * Allocate and initialize a new MemRange struct.
233 * Try to allocate it from the pool of free MemRange nodes rather than malloc.
235 static tdfxMemRange
*
236 NewRangeNode(tdfxContextPtr fxMesa
, FxU32 start
, FxU32 end
)
238 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
239 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
240 tdfxMemRange
*result
;
242 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
243 if (shared
&& shared
->tmPool
) {
244 result
= shared
->tmPool
;
245 shared
->tmPool
= shared
->tmPool
->next
;
248 result
= MALLOC(sizeof(tdfxMemRange
));
251 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
254 /*fprintf(stderr, "fxDriver: out of memory!\n");*/
258 result
->startAddr
= start
;
259 result
->endAddr
= end
;
267 * Initialize texture memory.
268 * We take care of one or both TMU's here.
271 tdfxTMInit(tdfxContextPtr fxMesa
)
273 if (!fxMesa
->glCtx
->Shared
->DriverData
) {
274 const char *extensions
;
275 struct tdfxSharedState
*shared
= CALLOC_STRUCT(tdfxSharedState
);
279 LOCK_HARDWARE(fxMesa
);
280 extensions
= fxMesa
->Glide
.grGetString(GR_EXTENSION
);
281 UNLOCK_HARDWARE(fxMesa
);
282 if (strstr(extensions
, "TEXUMA")) {
284 shared
->umaTexMemory
= GL_TRUE
;
285 LOCK_HARDWARE(fxMesa
);
286 fxMesa
->Glide
.grEnable(GR_TEXTURE_UMA_EXT
);
287 start
= fxMesa
->Glide
.grTexMinAddress(0);
288 end
= fxMesa
->Glide
.grTexMaxAddress(0);
289 UNLOCK_HARDWARE(fxMesa
);
290 shared
->totalTexMem
[0] = end
- start
;
291 shared
->totalTexMem
[1] = 0;
292 shared
->freeTexMem
[0] = end
- start
;
293 shared
->freeTexMem
[1] = 0;
294 shared
->tmFree
[0] = NewRangeNode(fxMesa
, start
, end
);
295 shared
->tmFree
[1] = NULL
;
296 /*printf("UMA tex memory: %d\n", (int) (end - start));*/
299 const int numTMUs
= fxMesa
->haveTwoTMUs
? 2 : 1;
301 shared
->umaTexMemory
= GL_FALSE
;
302 LOCK_HARDWARE(fxMesa
);
303 for (tmu
= 0; tmu
< numTMUs
; tmu
++) {
304 FxU32 start
= fxMesa
->Glide
.grTexMinAddress(tmu
);
305 FxU32 end
= fxMesa
->Glide
.grTexMaxAddress(tmu
);
306 shared
->totalTexMem
[tmu
] = end
- start
;
307 shared
->freeTexMem
[tmu
] = end
- start
;
308 shared
->tmFree
[tmu
] = NewRangeNode(fxMesa
, start
, end
);
309 /*printf("Split tex memory: %d\n", (int) (end - start));*/
311 UNLOCK_HARDWARE(fxMesa
);
314 shared
->tmPool
= NULL
;
315 fxMesa
->glCtx
->Shared
->DriverData
= shared
;
316 /*printf("Texture memory init UMA: %d\n", shared->umaTexMemory);*/
322 * Clean-up texture memory before destroying context.
325 tdfxTMClose(tdfxContextPtr fxMesa
)
327 if (fxMesa
->glCtx
->Shared
->RefCount
== 1 && fxMesa
->driDrawable
) {
328 /* refcount will soon go to zero, free our 3dfx stuff */
329 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) fxMesa
->glCtx
->Shared
->DriverData
;
331 const int numTMUs
= fxMesa
->haveTwoTMUs
? 2 : 1;
333 tdfxMemRange
*tmp
, *next
;
335 /* Deallocate the pool of free tdfxMemRange nodes */
336 tmp
= shared
->tmPool
;
343 /* Delete the texture memory block tdfxMemRange nodes */
344 for (tmu
= 0; tmu
< numTMUs
; tmu
++) {
345 tmp
= shared
->tmFree
[tmu
];
354 fxMesa
->glCtx
->Shared
->DriverData
= NULL
;
361 * Delete a tdfxMemRange struct.
362 * We keep a linked list of free/available tdfxMemRange structs to
363 * avoid extra malloc/free calls.
367 DeleteRangeNode_NoLock(struct TdfxSharedState
*shared
, tdfxMemRange
*range
)
369 /* insert at head of list */
370 range
->next
= shared
->tmPool
;
371 shared
->tmPool
= range
;
375 #define DELETE_RANGE_NODE(shared, range) \
376 (range)->next = (shared)->tmPool; \
377 (shared)->tmPool = (range)
382 * When we've run out of texture memory we have to throw out an
383 * existing texture to make room for the new one. This function
384 * determins the texture to throw out.
386 static struct gl_texture_object
*
387 FindOldestObject(tdfxContextPtr fxMesa
, FxU32 tmu
)
389 const GLuint bindnumber
= fxMesa
->texBindNumber
;
390 struct gl_texture_object
*oldestObj
, *lowestPriorityObj
;
391 GLfloat lowestPriority
;
394 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
399 lowestPriority
= 1.0F
;
400 lowestPriorityObj
= NULL
;
402 for (id
= _mesa_HashFirstEntry(textures
);
404 id
= _mesa_HashNextEntry(textures
, id
)) {
405 struct gl_texture_object
*obj
406 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
407 tdfxTexInfo
*info
= TDFX_TEXTURE_DATA(obj
);
409 if (info
&& info
->isInTM
&&
410 ((info
->whichTMU
== tmu
) || (info
->whichTMU
== TDFX_TMU_BOTH
) ||
411 (info
->whichTMU
== TDFX_TMU_SPLIT
))) {
412 GLuint age
, lasttime
;
415 lasttime
= info
->lastTimeUsed
;
417 if (lasttime
> bindnumber
)
418 age
= bindnumber
+ (UINT_MAX
- lasttime
+ 1); /* TO DO: check wrap around */
420 age
= bindnumber
- lasttime
;
422 if (age
>= oldestAge
) {
427 /* examine priority */
428 if (obj
->Priority
< lowestPriority
) {
429 lowestPriority
= obj
->Priority
;
430 lowestPriorityObj
= obj
;
435 if (lowestPriority
< 1.0) {
436 ASSERT(lowestPriorityObj
);
438 printf("discard %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
440 return lowestPriorityObj
;
444 printf("discard %d age=%d\n", oldestObj->Name, oldestAge);
453 FlushTexMemory(tdfxContextPtr fxMesa
)
455 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
458 for (id
= _mesa_HashFirstEntry(textures
);
460 id
= _mesa_HashNextEntry(textures
, id
)) {
461 struct gl_texture_object
*obj
462 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
463 if (obj
->RefCount
< 2) {
464 /* don't flush currently bound textures */
465 tdfxTMMoveOutTM_NoLock(fxMesa
, obj
);
473 * Find the address (offset?) at which we can store a new texture.
474 * <tmu> is the texture unit.
475 * <size> is the texture size in bytes.
478 FindStartAddr(tdfxContextPtr fxMesa
, FxU32 tmu
, FxU32 size
)
480 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
481 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
482 tdfxMemRange
*prev
, *block
;
485 int discardedCount
= 0;
486 #define MAX_DISCARDS 10
489 if (shared
->umaTexMemory
) {
490 assert(tmu
== TDFX_TMU0
);
493 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
496 block
= shared
->tmFree
[tmu
];
498 if (block
->endAddr
- block
->startAddr
>= size
) {
499 /* The texture will fit here */
500 result
= block
->startAddr
;
501 block
->startAddr
+= size
;
502 if (block
->startAddr
== block
->endAddr
) {
503 /* Remove this node since it's empty */
505 prev
->next
= block
->next
;
508 shared
->tmFree
[tmu
] = block
->next
;
510 DELETE_RANGE_NODE(shared
, block
);
512 shared
->freeTexMem
[tmu
] -= size
;
513 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
519 /* We failed to find a block large enough to accomodate <size> bytes.
520 * Find the oldest texObject and free it.
524 if (discardedCount
> MAX_DISCARDS
+ 1) {
525 _mesa_problem(NULL
, "%s: extreme texmem fragmentation", __FUNCTION__
);
526 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
529 else if (discardedCount
> MAX_DISCARDS
) {
530 /* texture memory is probably really fragmented, flush it */
531 FlushTexMemory(fxMesa
);
536 struct gl_texture_object
*obj
= FindOldestObject(fxMesa
, tmu
);
538 tdfxTMMoveOutTM_NoLock(fxMesa
, obj
);
539 fxMesa
->stats
.texSwaps
++;
542 _mesa_problem(NULL
, "%s: extreme texmem fragmentation", __FUNCTION__
);
543 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
549 /* never get here, but play it safe */
550 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
556 * Remove the given tdfxMemRange node from hardware texture memory.
559 RemoveRange_NoLock(tdfxContextPtr fxMesa
, FxU32 tmu
, tdfxMemRange
*range
)
561 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
562 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
563 tdfxMemRange
*block
, *prev
;
565 if (shared
->umaTexMemory
) {
566 assert(tmu
== TDFX_TMU0
);
572 if (range
->startAddr
== range
->endAddr
) {
573 DELETE_RANGE_NODE(shared
, range
);
576 shared
->freeTexMem
[tmu
] += range
->endAddr
- range
->startAddr
;
578 /* find position in linked list to insert this tdfxMemRange node */
580 block
= shared
->tmFree
[tmu
];
582 assert(range
->startAddr
!= block
->startAddr
);
583 if (range
->startAddr
> block
->startAddr
) {
592 /* Insert the free block, combine with adjacent blocks when possible */
595 if (range
->endAddr
== block
->startAddr
) {
597 block
->startAddr
= range
->startAddr
;
598 DELETE_RANGE_NODE(shared
, range
);
603 if (prev
->endAddr
== range
->startAddr
) {
605 prev
->endAddr
= range
->endAddr
;
606 prev
->next
= range
->next
;
607 DELETE_RANGE_NODE(shared
, range
);
614 shared
->tmFree
[tmu
] = range
;
621 RemoveRange(tdfxContextPtr fxMesa
, FxU32 tmu
, tdfxMemRange
*range
)
623 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
624 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
625 RemoveRange_NoLock(fxMesa
, tmu
, range
);
626 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
632 * Allocate space for a texture image.
633 * <tmu> is the texture unit
634 * <texmemsize> is the number of bytes to allocate
636 static tdfxMemRange
*
637 AllocTexMem(tdfxContextPtr fxMesa
, FxU32 tmu
, FxU32 texmemsize
)
640 startAddr
= FindStartAddr(fxMesa
, tmu
, texmemsize
);
641 if (startAddr
== BAD_ADDRESS
) {
642 _mesa_problem(fxMesa
->glCtx
, "%s returned NULL! tmu=%d texmemsize=%d",
643 __FUNCTION__
, (int) tmu
, (int) texmemsize
);
648 range
= NewRangeNode(fxMesa
, startAddr
, startAddr
+ texmemsize
);
655 * Download (copy) the given texture data (all mipmap levels) into the
656 * Voodoo's texture memory.
657 * The texture memory must have already been allocated.
660 tdfxTMDownloadTexture(tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
667 ti
= TDFX_TEXTURE_DATA(tObj
);
669 targetTMU
= ti
->whichTMU
;
674 if (ti
->tm
[targetTMU
]) {
675 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
676 && tObj
->Image
[0][l
]->Data
; l
++) {
677 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
678 fxMesa
->Glide
.grTexDownloadMipMapLevel(targetTMU
,
679 ti
->tm
[targetTMU
]->startAddr
,
681 ti
->info
.largeLodLog2
,
682 ti
->info
.aspectRatioLog2
,
684 GR_MIPMAPLEVELMASK_BOTH
,
685 tObj
->Image
[0][l
]->Data
);
690 if (ti
->tm
[TDFX_TMU0
] && ti
->tm
[TDFX_TMU1
]) {
691 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
692 && tObj
->Image
[0][l
]->Data
; l
++) {
693 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
694 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
695 ti
->tm
[TDFX_TMU0
]->startAddr
,
697 ti
->info
.largeLodLog2
,
698 ti
->info
.aspectRatioLog2
,
700 GR_MIPMAPLEVELMASK_ODD
,
701 tObj
->Image
[0][l
]->Data
);
703 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
704 ti
->tm
[TDFX_TMU1
]->startAddr
,
706 ti
->info
.largeLodLog2
,
707 ti
->info
.aspectRatioLog2
,
709 GR_MIPMAPLEVELMASK_EVEN
,
710 tObj
->Image
[0][l
]->Data
);
715 if (ti
->tm
[TDFX_TMU0
] && ti
->tm
[TDFX_TMU1
]) {
716 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
717 && tObj
->Image
[0][l
]->Data
; l
++) {
718 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
719 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
720 ti
->tm
[TDFX_TMU0
]->startAddr
,
722 ti
->info
.largeLodLog2
,
723 ti
->info
.aspectRatioLog2
,
725 GR_MIPMAPLEVELMASK_BOTH
,
726 tObj
->Image
[0][l
]->Data
);
728 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
729 ti
->tm
[TDFX_TMU1
]->startAddr
,
731 ti
->info
.largeLodLog2
,
732 ti
->info
.aspectRatioLog2
,
734 GR_MIPMAPLEVELMASK_BOTH
,
735 tObj
->Image
[0][l
]->Data
);
740 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)targetTMU
);
747 tdfxTMReloadMipMapLevel(GLcontext
*ctx
, struct gl_texture_object
*tObj
,
750 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
751 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
756 glideLod
= ti
->info
.largeLodLog2
- level
+ tObj
->BaseLevel
;
759 LOCK_HARDWARE(fxMesa
);
764 fxMesa
->Glide
.grTexDownloadMipMapLevel(tmu
,
765 ti
->tm
[tmu
]->startAddr
,
767 ti
->info
.largeLodLog2
,
768 ti
->info
.aspectRatioLog2
,
770 GR_MIPMAPLEVELMASK_BOTH
,
771 tObj
->Image
[0][level
]->Data
);
774 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
775 ti
->tm
[GR_TMU0
]->startAddr
,
777 ti
->info
.largeLodLog2
,
778 ti
->info
.aspectRatioLog2
,
780 GR_MIPMAPLEVELMASK_ODD
,
781 tObj
->Image
[0][level
]->Data
);
783 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
784 ti
->tm
[GR_TMU1
]->startAddr
,
786 ti
->info
.largeLodLog2
,
787 ti
->info
.aspectRatioLog2
,
789 GR_MIPMAPLEVELMASK_EVEN
,
790 tObj
->Image
[0][level
]->Data
);
793 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
794 ti
->tm
[GR_TMU0
]->startAddr
,
796 ti
->info
.largeLodLog2
,
797 ti
->info
.aspectRatioLog2
,
799 GR_MIPMAPLEVELMASK_BOTH
,
800 tObj
->Image
[0][level
]->Data
);
802 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
803 ti
->tm
[GR_TMU1
]->startAddr
,
805 ti
->info
.largeLodLog2
,
806 ti
->info
.aspectRatioLog2
,
808 GR_MIPMAPLEVELMASK_BOTH
,
809 tObj
->Image
[0][level
]->Data
);
813 _mesa_problem(ctx
, "%s: bad tmu (%d)", __FUNCTION__
, (int)tmu
);
816 UNLOCK_HARDWARE(fxMesa
);
821 * Allocate space for the given texture in texture memory then
822 * download (copy) it into that space.
825 tdfxTMMoveInTM_NoLock( tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
,
828 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
831 fxMesa
->stats
.reqTexUpload
++;
834 if (ti
->whichTMU
== targetTMU
)
836 if (targetTMU
== TDFX_TMU_SPLIT
|| ti
->whichTMU
== TDFX_TMU_SPLIT
) {
837 tdfxTMMoveOutTM_NoLock(fxMesa
, tObj
);
840 if (ti
->whichTMU
== TDFX_TMU_BOTH
)
842 targetTMU
= TDFX_TMU_BOTH
;
846 ti
->whichTMU
= targetTMU
;
851 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,
853 ti
->tm
[targetTMU
] = AllocTexMem(fxMesa
, targetTMU
, texmemsize
);
856 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD
,
858 ti
->tm
[TDFX_TMU0
] = AllocTexMem(fxMesa
, TDFX_TMU0
, texmemsize
);
859 if (ti
->tm
[TDFX_TMU0
])
860 fxMesa
->stats
.memTexUpload
+= texmemsize
;
862 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN
,
864 ti
->tm
[TDFX_TMU1
] = AllocTexMem(fxMesa
, TDFX_TMU1
, texmemsize
);
867 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,
869 ti
->tm
[TDFX_TMU0
] = AllocTexMem(fxMesa
, TDFX_TMU0
, texmemsize
);
870 if (ti
->tm
[TDFX_TMU0
])
871 fxMesa
->stats
.memTexUpload
+= texmemsize
;
873 /*texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
875 ti
->tm
[TDFX_TMU1
] = AllocTexMem(fxMesa
, TDFX_TMU1
, texmemsize
);
878 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)targetTMU
);
882 ti
->reloadImages
= GL_TRUE
;
883 ti
->isInTM
= GL_TRUE
;
885 fxMesa
->stats
.texUpload
++;
890 * Move the given texture out of hardware texture memory.
891 * This deallocates the texture's memory space.
894 tdfxTMMoveOutTM_NoLock( tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
896 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
897 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
898 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
900 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
901 fprintf(stderr
, "fxmesa: %s(%p (%d))\n", __FUNCTION__
, (void *)tObj
, tObj
->Name
);
905 VerifyFreeList(fxMesa, 0);
906 VerifyFreeList(fxMesa, 1);
909 if (!ti
|| !ti
->isInTM
)
912 switch (ti
->whichTMU
) {
915 RemoveRange_NoLock(fxMesa
, ti
->whichTMU
, ti
->tm
[ti
->whichTMU
]);
919 assert(!shared
->umaTexMemory
);
920 RemoveRange_NoLock(fxMesa
, TDFX_TMU0
, ti
->tm
[TDFX_TMU0
]);
921 RemoveRange_NoLock(fxMesa
, TDFX_TMU1
, ti
->tm
[TDFX_TMU1
]);
924 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)ti
->whichTMU
);
928 ti
->isInTM
= GL_FALSE
;
931 ti
->whichTMU
= TDFX_TMU_NONE
;
934 VerifyFreeList(fxMesa, 0);
935 VerifyFreeList(fxMesa, 1);
941 * Called via glDeleteTexture to delete a texture object.
944 tdfxTMFreeTexture(tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
946 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
948 tdfxTMMoveOutTM(fxMesa
, tObj
);
950 tObj
->DriverData
= NULL
;
953 VerifyFreeList(fxMesa, 0);
954 VerifyFreeList(fxMesa, 1);
961 * After a context switch this function will be called to restore
962 * texture memory for the new context.
964 void tdfxTMRestoreTextures_NoLock( tdfxContextPtr fxMesa
)
966 GLcontext
*ctx
= fxMesa
->glCtx
;
967 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
970 for (id
= _mesa_HashFirstEntry(textures
);
972 id
= _mesa_HashNextEntry(textures
, id
)) {
973 struct gl_texture_object
*tObj
974 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
975 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA( tObj
);
976 if ( ti
&& ti
->isInTM
) {
978 for ( i
= 0 ; i
< MAX_TEXTURE_UNITS
; i
++ ) {
979 if ( ctx
->Texture
.Unit
[i
]._Current
== tObj
) {
980 tdfxTMDownloadTexture( fxMesa
, tObj
);
984 if ( i
== MAX_TEXTURE_UNITS
) {
985 tdfxTMMoveOutTM_NoLock( fxMesa
, tObj
);
990 VerifyFreeList(fxMesa, 0);
991 VerifyFreeList(fxMesa, 1);