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
26 /* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_texman.c,v 1.5 2002/02/22 21:45:04 dawes Exp $ */
30 * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
33 * Gareth Hughes <gareth@valinux.com>
34 * Brian Paul <brianp@valinux.com>
38 #include "tdfx_context.h"
40 #include "tdfx_texman.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 gl_texture_object
*obj
;
80 for (obj
= mesaShared
->TexObjectList
; obj
; obj
= obj
->Next
) {
81 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(obj
);
88 totalUsed
+= (ti
->tm
[tmu
]->endAddr
- ti
->tm
[tmu
]->startAddr
);
97 printf("totalFree: %d totalUsed: %d totalMem: %d #objs=%d #res=%d\n",
98 shared
->freeTexMem
[tmu
], totalUsed
, shared
->totalTexMem
[tmu
],
101 assert(totalUsed
+ totalFree
== shared
->totalTexMem
[tmu
]);
106 dump_texmem(tdfxContextPtr fxMesa
)
108 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
109 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
110 struct gl_texture_object
*oldestObj
, *obj
, *lowestPriorityObj
;
114 printf("DUMP Objects:\n");
115 for (obj
= mesaShared
->TexObjectList
; obj
; obj
= obj
->Next
) {
116 tdfxTexInfo
*info
= TDFX_TEXTURE_DATA(obj
);
118 if (info
&& info
->isInTM
) {
119 printf("Obj %8p: %4d info = %p\n", obj
, obj
->Name
, info
);
121 printf(" isInTM=%d whichTMU=%d lastTimeUsed=%d\n",
122 info
->isInTM
, info
->whichTMU
, info
->lastTimeUsed
);
123 printf(" tm[0] = %p", info
->tm
[0]);
126 printf(" tm startAddr = %d endAddr = %d",
127 info
->tm
[0]->startAddr
,
128 info
->tm
[0]->endAddr
);
131 printf(" tm[1] = %p", info
->tm
[1]);
133 printf(" tm startAddr = %d endAddr = %d",
134 info
->tm
[1]->startAddr
,
135 info
->tm
[1]->endAddr
);
141 VerifyFreeList(fxMesa
, 0);
142 VerifyFreeList(fxMesa
, 1);
144 printf("Free memory unit 0: %d bytes\n", shared
->freeTexMem
[0]);
146 for (r
= shared
->tmFree
[0]; r
; r
= r
->next
) {
147 printf("%8p: start %8d end %8d size %8d gap %8d\n", r
, r
->startAddr
, r
->endAddr
, r
->endAddr
- r
->startAddr
, r
->startAddr
- prev
);
151 printf("Free memory unit 1: %d bytes\n", shared
->freeTexMem
[1]);
153 for (r
= shared
->tmFree
[1]; r
; r
= r
->next
) {
154 printf("%8p: start %8d end %8d size %8d gap %8d\n", r
, r
->startAddr
, r
->endAddr
, r
->endAddr
- r
->startAddr
, r
->startAddr
- prev
);
173 sanity(tdfxContextPtr fxMesa
)
175 tdfxMemRange
*tmp
, *prev
, *pos
;
178 tmp
= fxMesa
->tmFree
[0];
180 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
181 fprintf(stderr
, "Textures fubar\n");
184 if (tmp
->startAddr
>= tmp
->endAddr
) {
185 fprintf(stderr
, "Node fubar\n");
188 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
189 prev
->endAddr
> tmp
->startAddr
)) {
190 fprintf(stderr
, "Sorting fubar\n");
197 tmp
= fxMesa
->tmFree
[1];
199 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
200 fprintf(stderr
, "Textures fubar\n");
203 if (tmp
->startAddr
>= tmp
->endAddr
) {
204 fprintf(stderr
, "Node fubar\n");
207 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
208 prev
->endAddr
> tmp
->startAddr
)) {
209 fprintf(stderr
, "Sorting fubar\n");
223 * Allocate and initialize a new MemRange struct.
224 * Try to allocate it from the pool of free MemRange nodes rather than malloc.
226 static tdfxMemRange
*
227 NewRangeNode(tdfxContextPtr fxMesa
, FxU32 start
, FxU32 end
)
229 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
230 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
231 tdfxMemRange
*result
;
233 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
234 if (shared
&& shared
->tmPool
) {
235 result
= shared
->tmPool
;
236 shared
->tmPool
= shared
->tmPool
->next
;
239 result
= MALLOC(sizeof(tdfxMemRange
));
242 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
245 /*fprintf(stderr, "fxDriver: out of memory!\n");*/
249 result
->startAddr
= start
;
250 result
->endAddr
= end
;
258 * Initialize texture memory.
259 * We take care of one or both TMU's here.
262 tdfxTMInit(tdfxContextPtr fxMesa
)
264 if (!fxMesa
->glCtx
->Shared
->DriverData
) {
265 const char *extensions
;
266 struct tdfxSharedState
*shared
= CALLOC_STRUCT(tdfxSharedState
);
270 LOCK_HARDWARE(fxMesa
);
271 extensions
= fxMesa
->Glide
.grGetString(GR_EXTENSION
);
272 UNLOCK_HARDWARE(fxMesa
);
273 if (strstr(extensions
, "TEXUMA")) {
275 shared
->umaTexMemory
= GL_TRUE
;
276 LOCK_HARDWARE(fxMesa
);
277 fxMesa
->Glide
.grEnable(GR_TEXTURE_UMA_EXT
);
278 start
= fxMesa
->Glide
.grTexMinAddress(0);
279 end
= fxMesa
->Glide
.grTexMaxAddress(0);
280 UNLOCK_HARDWARE(fxMesa
);
281 shared
->totalTexMem
[0] = end
- start
;
282 shared
->totalTexMem
[1] = 0;
283 shared
->freeTexMem
[0] = end
- start
;
284 shared
->freeTexMem
[1] = 0;
285 shared
->tmFree
[0] = NewRangeNode(fxMesa
, start
, end
);
286 shared
->tmFree
[1] = NULL
;
287 /*printf("UMA tex memory: %d\n", (int) (end - start));*/
290 const int numTMUs
= fxMesa
->haveTwoTMUs
? 2 : 1;
292 shared
->umaTexMemory
= GL_FALSE
;
293 LOCK_HARDWARE(fxMesa
);
294 for (tmu
= 0; tmu
< numTMUs
; tmu
++) {
295 FxU32 start
= fxMesa
->Glide
.grTexMinAddress(tmu
);
296 FxU32 end
= fxMesa
->Glide
.grTexMaxAddress(tmu
);
297 shared
->totalTexMem
[tmu
] = end
- start
;
298 shared
->freeTexMem
[tmu
] = end
- start
;
299 shared
->tmFree
[tmu
] = NewRangeNode(fxMesa
, start
, end
);
300 /*printf("Split tex memory: %d\n", (int) (end - start));*/
302 UNLOCK_HARDWARE(fxMesa
);
305 shared
->tmPool
= NULL
;
306 fxMesa
->glCtx
->Shared
->DriverData
= shared
;
307 /*printf("Texture memory init UMA: %d\n", shared->umaTexMemory);*/
313 * Clean-up texture memory before destroying context.
316 tdfxTMClose(tdfxContextPtr fxMesa
)
318 if (fxMesa
->glCtx
->Shared
->RefCount
== 1 && fxMesa
->driDrawable
) {
319 /* refcount will soon go to zero, free our 3dfx stuff */
320 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) fxMesa
->glCtx
->Shared
->DriverData
;
322 const int numTMUs
= fxMesa
->haveTwoTMUs
? 2 : 1;
324 tdfxMemRange
*tmp
, *next
;
326 /* Deallocate the pool of free tdfxMemRange nodes */
327 tmp
= shared
->tmPool
;
334 /* Delete the texture memory block tdfxMemRange nodes */
335 for (tmu
= 0; tmu
< numTMUs
; tmu
++) {
336 tmp
= shared
->tmFree
[tmu
];
345 fxMesa
->glCtx
->Shared
->DriverData
= NULL
;
352 * Delete a tdfxMemRange struct.
353 * We keep a linked list of free/available tdfxMemRange structs to
354 * avoid extra malloc/free calls.
358 DeleteRangeNode_NoLock(struct TdfxSharedState
*shared
, tdfxMemRange
*range
)
360 /* insert at head of list */
361 range
->next
= shared
->tmPool
;
362 shared
->tmPool
= range
;
366 #define DELETE_RANGE_NODE(shared, range) \
367 (range)->next = (shared)->tmPool; \
368 (shared)->tmPool = (range)
373 * When we've run out of texture memory we have to throw out an
374 * existing texture to make room for the new one. This function
375 * determins the texture to throw out.
377 static struct gl_texture_object
*
378 FindOldestObject(tdfxContextPtr fxMesa
, FxU32 tmu
)
380 const GLuint bindnumber
= fxMesa
->texBindNumber
;
381 struct gl_texture_object
*oldestObj
, *obj
, *lowestPriorityObj
;
382 GLfloat lowestPriority
;
388 lowestPriority
= 1.0F
;
389 lowestPriorityObj
= NULL
;
391 for (obj
= fxMesa
->glCtx
->Shared
->TexObjectList
; obj
; obj
= obj
->Next
) {
392 tdfxTexInfo
*info
= TDFX_TEXTURE_DATA(obj
);
394 if (info
&& info
->isInTM
&&
395 ((info
->whichTMU
== tmu
) || (info
->whichTMU
== TDFX_TMU_BOTH
) ||
396 (info
->whichTMU
== TDFX_TMU_SPLIT
))) {
397 GLuint age
, lasttime
;
400 lasttime
= info
->lastTimeUsed
;
402 if (lasttime
> bindnumber
)
403 age
= bindnumber
+ (UINT_MAX
- lasttime
+ 1); /* TO DO: check wrap around */
405 age
= bindnumber
- lasttime
;
407 if (age
>= oldestAge
) {
412 /* examine priority */
413 if (obj
->Priority
< lowestPriority
) {
414 lowestPriority
= obj
->Priority
;
415 lowestPriorityObj
= obj
;
420 if (lowestPriority
< 1.0) {
421 ASSERT(lowestPriorityObj
);
423 printf("discard %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
425 return lowestPriorityObj
;
429 printf("discard %d age=%d\n", oldestObj->Name, oldestAge);
438 FlushTexMemory(tdfxContextPtr fxMesa
)
440 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
441 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
442 struct gl_texture_object
*obj
;
444 for (obj
= mesaShared
->TexObjectList
; obj
; obj
= obj
->Next
) {
445 if (obj
->RefCount
< 2) {
446 /* don't flush currently bound textures */
447 tdfxTMMoveOutTM_NoLock(fxMesa
, obj
);
455 * Find the address (offset?) at which we can store a new texture.
456 * <tmu> is the texture unit.
457 * <size> is the texture size in bytes.
460 FindStartAddr(tdfxContextPtr fxMesa
, FxU32 tmu
, FxU32 size
)
462 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
463 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
464 tdfxMemRange
*prev
, *block
;
467 int discardedCount
= 0;
468 #define MAX_DISCARDS 10
471 if (shared
->umaTexMemory
) {
472 assert(tmu
== TDFX_TMU0
);
475 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
478 block
= shared
->tmFree
[tmu
];
480 if (block
->endAddr
- block
->startAddr
>= size
) {
481 /* The texture will fit here */
482 result
= block
->startAddr
;
483 block
->startAddr
+= size
;
484 if (block
->startAddr
== block
->endAddr
) {
485 /* Remove this node since it's empty */
487 prev
->next
= block
->next
;
490 shared
->tmFree
[tmu
] = block
->next
;
492 DELETE_RANGE_NODE(shared
, block
);
494 shared
->freeTexMem
[tmu
] -= size
;
495 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
501 /* We failed to find a block large enough to accomodate <size> bytes.
502 * Find the oldest texObject and free it.
506 if (discardedCount
> MAX_DISCARDS
+ 1) {
507 _mesa_problem(NULL
, "%s: extreme texmem fragmentation", __FUNCTION__
);
508 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
511 else if (discardedCount
> MAX_DISCARDS
) {
512 /* texture memory is probably really fragmented, flush it */
513 FlushTexMemory(fxMesa
);
518 struct gl_texture_object
*obj
= FindOldestObject(fxMesa
, tmu
);
520 tdfxTMMoveOutTM_NoLock(fxMesa
, obj
);
521 fxMesa
->stats
.texSwaps
++;
524 _mesa_problem(NULL
, "%s: extreme texmem fragmentation", __FUNCTION__
);
525 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
531 /* never get here, but play it safe */
532 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
538 * Remove the given tdfxMemRange node from hardware texture memory.
541 RemoveRange_NoLock(tdfxContextPtr fxMesa
, FxU32 tmu
, tdfxMemRange
*range
)
543 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
544 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
545 tdfxMemRange
*block
, *prev
;
547 if (shared
->umaTexMemory
) {
548 assert(tmu
== TDFX_TMU0
);
554 if (range
->startAddr
== range
->endAddr
) {
555 DELETE_RANGE_NODE(shared
, range
);
558 shared
->freeTexMem
[tmu
] += range
->endAddr
- range
->startAddr
;
560 /* find position in linked list to insert this tdfxMemRange node */
562 block
= shared
->tmFree
[tmu
];
564 assert(range
->startAddr
!= block
->startAddr
);
565 if (range
->startAddr
> block
->startAddr
) {
574 /* Insert the free block, combine with adjacent blocks when possible */
577 if (range
->endAddr
== block
->startAddr
) {
579 block
->startAddr
= range
->startAddr
;
580 DELETE_RANGE_NODE(shared
, range
);
585 if (prev
->endAddr
== range
->startAddr
) {
587 prev
->endAddr
= range
->endAddr
;
588 prev
->next
= range
->next
;
589 DELETE_RANGE_NODE(shared
, range
);
596 shared
->tmFree
[tmu
] = range
;
603 RemoveRange(tdfxContextPtr fxMesa
, FxU32 tmu
, tdfxMemRange
*range
)
605 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
606 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
607 RemoveRange_NoLock(fxMesa
, tmu
, range
);
608 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
614 * Allocate space for a texture image.
615 * <tmu> is the texture unit
616 * <texmemsize> is the number of bytes to allocate
618 static tdfxMemRange
*
619 AllocTexMem(tdfxContextPtr fxMesa
, FxU32 tmu
, FxU32 texmemsize
)
622 startAddr
= FindStartAddr(fxMesa
, tmu
, texmemsize
);
623 if (startAddr
== BAD_ADDRESS
) {
624 _mesa_problem(fxMesa
->glCtx
, "%s returned NULL! tmu=%d texmemsize=%d",
625 __FUNCTION__
, (int) tmu
, (int) texmemsize
);
630 range
= NewRangeNode(fxMesa
, startAddr
, startAddr
+ texmemsize
);
637 * Download (copy) the given texture data (all mipmap levels) into the
638 * Voodoo's texture memory.
639 * The texture memory must have already been allocated.
642 tdfxTMDownloadTexture(tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
649 ti
= TDFX_TEXTURE_DATA(tObj
);
651 targetTMU
= ti
->whichTMU
;
656 if (ti
->tm
[targetTMU
]) {
657 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
658 && tObj
->Image
[0][l
]->Data
; l
++) {
659 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
660 fxMesa
->Glide
.grTexDownloadMipMapLevel(targetTMU
,
661 ti
->tm
[targetTMU
]->startAddr
,
663 ti
->info
.largeLodLog2
,
664 ti
->info
.aspectRatioLog2
,
666 GR_MIPMAPLEVELMASK_BOTH
,
667 tObj
->Image
[0][l
]->Data
);
672 if (ti
->tm
[TDFX_TMU0
] && ti
->tm
[TDFX_TMU1
]) {
673 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
674 && tObj
->Image
[0][l
]->Data
; l
++) {
675 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
676 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
677 ti
->tm
[TDFX_TMU0
]->startAddr
,
679 ti
->info
.largeLodLog2
,
680 ti
->info
.aspectRatioLog2
,
682 GR_MIPMAPLEVELMASK_ODD
,
683 tObj
->Image
[0][l
]->Data
);
685 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
686 ti
->tm
[TDFX_TMU1
]->startAddr
,
688 ti
->info
.largeLodLog2
,
689 ti
->info
.aspectRatioLog2
,
691 GR_MIPMAPLEVELMASK_EVEN
,
692 tObj
->Image
[0][l
]->Data
);
697 if (ti
->tm
[TDFX_TMU0
] && ti
->tm
[TDFX_TMU1
]) {
698 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
699 && tObj
->Image
[0][l
]->Data
; l
++) {
700 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
701 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
702 ti
->tm
[TDFX_TMU0
]->startAddr
,
704 ti
->info
.largeLodLog2
,
705 ti
->info
.aspectRatioLog2
,
707 GR_MIPMAPLEVELMASK_BOTH
,
708 tObj
->Image
[0][l
]->Data
);
710 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
711 ti
->tm
[TDFX_TMU1
]->startAddr
,
713 ti
->info
.largeLodLog2
,
714 ti
->info
.aspectRatioLog2
,
716 GR_MIPMAPLEVELMASK_BOTH
,
717 tObj
->Image
[0][l
]->Data
);
722 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)targetTMU
);
729 tdfxTMReloadMipMapLevel(GLcontext
*ctx
, struct gl_texture_object
*tObj
,
732 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
733 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
738 glideLod
= ti
->info
.largeLodLog2
- level
+ tObj
->BaseLevel
;
741 LOCK_HARDWARE(fxMesa
);
746 fxMesa
->Glide
.grTexDownloadMipMapLevel(tmu
,
747 ti
->tm
[tmu
]->startAddr
,
749 ti
->info
.largeLodLog2
,
750 ti
->info
.aspectRatioLog2
,
752 GR_MIPMAPLEVELMASK_BOTH
,
753 tObj
->Image
[0][level
]->Data
);
756 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
757 ti
->tm
[GR_TMU0
]->startAddr
,
759 ti
->info
.largeLodLog2
,
760 ti
->info
.aspectRatioLog2
,
762 GR_MIPMAPLEVELMASK_ODD
,
763 tObj
->Image
[0][level
]->Data
);
765 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
766 ti
->tm
[GR_TMU1
]->startAddr
,
768 ti
->info
.largeLodLog2
,
769 ti
->info
.aspectRatioLog2
,
771 GR_MIPMAPLEVELMASK_EVEN
,
772 tObj
->Image
[0][level
]->Data
);
775 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
776 ti
->tm
[GR_TMU0
]->startAddr
,
778 ti
->info
.largeLodLog2
,
779 ti
->info
.aspectRatioLog2
,
781 GR_MIPMAPLEVELMASK_BOTH
,
782 tObj
->Image
[0][level
]->Data
);
784 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
785 ti
->tm
[GR_TMU1
]->startAddr
,
787 ti
->info
.largeLodLog2
,
788 ti
->info
.aspectRatioLog2
,
790 GR_MIPMAPLEVELMASK_BOTH
,
791 tObj
->Image
[0][level
]->Data
);
795 _mesa_problem(ctx
, "%s: bad tmu (%d)", __FUNCTION__
, (int)tmu
);
798 UNLOCK_HARDWARE(fxMesa
);
803 * Allocate space for the given texture in texture memory then
804 * download (copy) it into that space.
807 tdfxTMMoveInTM_NoLock( tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
,
810 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
813 fxMesa
->stats
.reqTexUpload
++;
816 if (ti
->whichTMU
== targetTMU
)
818 if (targetTMU
== TDFX_TMU_SPLIT
|| ti
->whichTMU
== TDFX_TMU_SPLIT
) {
819 tdfxTMMoveOutTM_NoLock(fxMesa
, tObj
);
822 if (ti
->whichTMU
== TDFX_TMU_BOTH
)
824 targetTMU
= TDFX_TMU_BOTH
;
828 ti
->whichTMU
= targetTMU
;
833 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,
835 ti
->tm
[targetTMU
] = AllocTexMem(fxMesa
, targetTMU
, texmemsize
);
838 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD
,
840 ti
->tm
[TDFX_TMU0
] = AllocTexMem(fxMesa
, TDFX_TMU0
, texmemsize
);
841 if (ti
->tm
[TDFX_TMU0
])
842 fxMesa
->stats
.memTexUpload
+= texmemsize
;
844 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN
,
846 ti
->tm
[TDFX_TMU1
] = AllocTexMem(fxMesa
, TDFX_TMU1
, texmemsize
);
849 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,
851 ti
->tm
[TDFX_TMU0
] = AllocTexMem(fxMesa
, TDFX_TMU0
, texmemsize
);
852 if (ti
->tm
[TDFX_TMU0
])
853 fxMesa
->stats
.memTexUpload
+= texmemsize
;
855 /*texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
857 ti
->tm
[TDFX_TMU1
] = AllocTexMem(fxMesa
, TDFX_TMU1
, texmemsize
);
860 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)targetTMU
);
864 ti
->reloadImages
= GL_TRUE
;
865 ti
->isInTM
= GL_TRUE
;
867 fxMesa
->stats
.texUpload
++;
872 * Move the given texture out of hardware texture memory.
873 * This deallocates the texture's memory space.
876 tdfxTMMoveOutTM_NoLock( tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
878 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
879 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
880 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
882 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
883 fprintf(stderr
, "fxmesa: %s(%p (%d))\n", __FUNCTION__
, (void *)tObj
, tObj
->Name
);
887 VerifyFreeList(fxMesa, 0);
888 VerifyFreeList(fxMesa, 1);
891 if (!ti
|| !ti
->isInTM
)
894 switch (ti
->whichTMU
) {
897 RemoveRange_NoLock(fxMesa
, ti
->whichTMU
, ti
->tm
[ti
->whichTMU
]);
901 assert(!shared
->umaTexMemory
);
902 RemoveRange_NoLock(fxMesa
, TDFX_TMU0
, ti
->tm
[TDFX_TMU0
]);
903 RemoveRange_NoLock(fxMesa
, TDFX_TMU1
, ti
->tm
[TDFX_TMU1
]);
906 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)ti
->whichTMU
);
910 ti
->isInTM
= GL_FALSE
;
913 ti
->whichTMU
= TDFX_TMU_NONE
;
916 VerifyFreeList(fxMesa, 0);
917 VerifyFreeList(fxMesa, 1);
923 * Called via glDeleteTexture to delete a texture object.
926 tdfxTMFreeTexture(tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
928 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
930 tdfxTMMoveOutTM(fxMesa
, tObj
);
932 tObj
->DriverData
= NULL
;
935 VerifyFreeList(fxMesa, 0);
936 VerifyFreeList(fxMesa, 1);
943 * After a context switch this function will be called to restore
944 * texture memory for the new context.
946 void tdfxTMRestoreTextures_NoLock( tdfxContextPtr fxMesa
)
948 GLcontext
*ctx
= fxMesa
->glCtx
;
949 struct gl_texture_object
*tObj
;
952 for ( tObj
= ctx
->Shared
->TexObjectList
; tObj
; tObj
= tObj
->Next
) {
953 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA( tObj
);
954 if ( ti
&& ti
->isInTM
) {
955 for ( i
= 0 ; i
< MAX_TEXTURE_UNITS
; i
++ ) {
956 if ( ctx
->Texture
.Unit
[i
]._Current
== tObj
) {
957 tdfxTMDownloadTexture( fxMesa
, tObj
);
961 if ( i
== MAX_TEXTURE_UNITS
) {
962 tdfxTMMoveOutTM_NoLock( fxMesa
, tObj
);
967 VerifyFreeList(fxMesa, 0);
968 VerifyFreeList(fxMesa, 1);