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"
45 #define BAD_ADDRESS ((FxU32) -1)
50 * Verify the consistancy of the texture memory manager.
52 * Traversing all texture objects and computing total memory used.
53 * Traverse the free block list and computing total memory free.
54 * Compare the total free and total used amounts to the total memory size.
55 * Make various assertions about the results.
58 VerifyFreeList(tdfxContextPtr fxMesa
, FxU32 tmu
)
60 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
61 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
63 int prevStart
= -1, prevEnd
= -1;
65 int numObj
= 0, numRes
= 0;
68 for (block
= shared
->tmFree
[tmu
]; block
; block
= block
->next
) {
69 assert( block
->endAddr
> 0 );
70 assert( block
->startAddr
<= shared
->totalTexMem
[tmu
] );
71 assert( block
->endAddr
<= shared
->totalTexMem
[tmu
] );
72 assert( (int) block
->startAddr
> prevStart
);
73 assert( (int) block
->startAddr
>= prevEnd
);
74 prevStart
= (int) block
->startAddr
;
75 prevEnd
= (int) block
->endAddr
;
76 totalFree
+= (block
->endAddr
- block
->startAddr
);
78 assert(totalFree
== shared
->freeTexMem
[tmu
]);
81 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
83 for (id
= _mesa_HashFirstEntry(textures
);
85 id
= _mesa_HashNextEntry(textures
, id
)) {
86 struct gl_texture_object
*tObj
87 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
88 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
94 totalUsed
+= (ti
->tm
[tmu
]->endAddr
- ti
->tm
[tmu
]->startAddr
);
103 printf("totalFree: %d totalUsed: %d totalMem: %d #objs=%d #res=%d\n",
104 shared
->freeTexMem
[tmu
], totalUsed
, shared
->totalTexMem
[tmu
],
107 assert(totalUsed
+ totalFree
== shared
->totalTexMem
[tmu
]);
112 dump_texmem(tdfxContextPtr fxMesa
)
114 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
115 struct _mesa_HashTable
*textures
= mesaShared
->TexObjects
;
116 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
121 printf("DUMP Objects:\n");
122 for (id
= _mesa_HashFirstEntry(textures
);
124 id
= _mesa_HashNextEntry(textures
, id
)) {
125 struct gl_texture_object
*obj
126 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
127 tdfxTexInfo
*info
= TDFX_TEXTURE_DATA(obj
);
129 if (info
&& info
->isInTM
) {
130 printf("Obj %8p: %4d info = %p\n", obj
, obj
->Name
, info
);
132 printf(" isInTM=%d whichTMU=%d lastTimeUsed=%d\n",
133 info
->isInTM
, info
->whichTMU
, info
->lastTimeUsed
);
134 printf(" tm[0] = %p", info
->tm
[0]);
137 printf(" tm startAddr = %d endAddr = %d",
138 info
->tm
[0]->startAddr
,
139 info
->tm
[0]->endAddr
);
142 printf(" tm[1] = %p", info
->tm
[1]);
144 printf(" tm startAddr = %d endAddr = %d",
145 info
->tm
[1]->startAddr
,
146 info
->tm
[1]->endAddr
);
152 VerifyFreeList(fxMesa
, 0);
153 VerifyFreeList(fxMesa
, 1);
155 printf("Free memory unit 0: %d bytes\n", shared
->freeTexMem
[0]);
157 for (r
= shared
->tmFree
[0]; r
; r
= r
->next
) {
158 printf("%8p: start %8d end %8d size %8d gap %8d\n", r
, r
->startAddr
, r
->endAddr
, r
->endAddr
- r
->startAddr
, r
->startAddr
- prev
);
162 printf("Free memory unit 1: %d bytes\n", shared
->freeTexMem
[1]);
164 for (r
= shared
->tmFree
[1]; r
; r
= r
->next
) {
165 printf("%8p: start %8d end %8d size %8d gap %8d\n", r
, r
->startAddr
, r
->endAddr
, r
->endAddr
- r
->startAddr
, r
->startAddr
- prev
);
184 sanity(tdfxContextPtr fxMesa
)
186 tdfxMemRange
*tmp
, *prev
, *pos
;
189 tmp
= fxMesa
->tmFree
[0];
191 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
192 fprintf(stderr
, "Textures fubar\n");
195 if (tmp
->startAddr
>= tmp
->endAddr
) {
196 fprintf(stderr
, "Node fubar\n");
199 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
200 prev
->endAddr
> tmp
->startAddr
)) {
201 fprintf(stderr
, "Sorting fubar\n");
208 tmp
= fxMesa
->tmFree
[1];
210 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
211 fprintf(stderr
, "Textures fubar\n");
214 if (tmp
->startAddr
>= tmp
->endAddr
) {
215 fprintf(stderr
, "Node fubar\n");
218 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
219 prev
->endAddr
> tmp
->startAddr
)) {
220 fprintf(stderr
, "Sorting fubar\n");
234 * Allocate and initialize a new MemRange struct.
235 * Try to allocate it from the pool of free MemRange nodes rather than malloc.
237 static tdfxMemRange
*
238 NewRangeNode(tdfxContextPtr fxMesa
, FxU32 start
, FxU32 end
)
240 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
241 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
242 tdfxMemRange
*result
;
244 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
245 if (shared
&& shared
->tmPool
) {
246 result
= shared
->tmPool
;
247 shared
->tmPool
= shared
->tmPool
->next
;
250 result
= MALLOC(sizeof(tdfxMemRange
));
253 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
256 /*fprintf(stderr, "fxDriver: out of memory!\n");*/
260 result
->startAddr
= start
;
261 result
->endAddr
= end
;
269 * Initialize texture memory.
270 * We take care of one or both TMU's here.
273 tdfxTMInit(tdfxContextPtr fxMesa
)
275 if (!fxMesa
->glCtx
->Shared
->DriverData
) {
276 const char *extensions
;
277 struct tdfxSharedState
*shared
= CALLOC_STRUCT(tdfxSharedState
);
281 LOCK_HARDWARE(fxMesa
);
282 extensions
= fxMesa
->Glide
.grGetString(GR_EXTENSION
);
283 UNLOCK_HARDWARE(fxMesa
);
284 if (strstr(extensions
, "TEXUMA")) {
286 shared
->umaTexMemory
= GL_TRUE
;
287 LOCK_HARDWARE(fxMesa
);
288 fxMesa
->Glide
.grEnable(GR_TEXTURE_UMA_EXT
);
289 start
= fxMesa
->Glide
.grTexMinAddress(0);
290 end
= fxMesa
->Glide
.grTexMaxAddress(0);
291 UNLOCK_HARDWARE(fxMesa
);
292 shared
->totalTexMem
[0] = end
- start
;
293 shared
->totalTexMem
[1] = 0;
294 shared
->freeTexMem
[0] = end
- start
;
295 shared
->freeTexMem
[1] = 0;
296 shared
->tmFree
[0] = NewRangeNode(fxMesa
, start
, end
);
297 shared
->tmFree
[1] = NULL
;
298 /*printf("UMA tex memory: %d\n", (int) (end - start));*/
301 const int numTMUs
= fxMesa
->haveTwoTMUs
? 2 : 1;
303 shared
->umaTexMemory
= GL_FALSE
;
304 LOCK_HARDWARE(fxMesa
);
305 for (tmu
= 0; tmu
< numTMUs
; tmu
++) {
306 FxU32 start
= fxMesa
->Glide
.grTexMinAddress(tmu
);
307 FxU32 end
= fxMesa
->Glide
.grTexMaxAddress(tmu
);
308 shared
->totalTexMem
[tmu
] = end
- start
;
309 shared
->freeTexMem
[tmu
] = end
- start
;
310 shared
->tmFree
[tmu
] = NewRangeNode(fxMesa
, start
, end
);
311 /*printf("Split tex memory: %d\n", (int) (end - start));*/
313 UNLOCK_HARDWARE(fxMesa
);
316 shared
->tmPool
= NULL
;
317 fxMesa
->glCtx
->Shared
->DriverData
= shared
;
318 /*printf("Texture memory init UMA: %d\n", shared->umaTexMemory);*/
324 * Clean-up texture memory before destroying context.
327 tdfxTMClose(tdfxContextPtr fxMesa
)
329 if (fxMesa
->glCtx
->Shared
->RefCount
== 1 && fxMesa
->driDrawable
) {
330 /* refcount will soon go to zero, free our 3dfx stuff */
331 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) fxMesa
->glCtx
->Shared
->DriverData
;
333 const int numTMUs
= fxMesa
->haveTwoTMUs
? 2 : 1;
335 tdfxMemRange
*tmp
, *next
;
337 /* Deallocate the pool of free tdfxMemRange nodes */
338 tmp
= shared
->tmPool
;
345 /* Delete the texture memory block tdfxMemRange nodes */
346 for (tmu
= 0; tmu
< numTMUs
; tmu
++) {
347 tmp
= shared
->tmFree
[tmu
];
356 fxMesa
->glCtx
->Shared
->DriverData
= NULL
;
363 * Delete a tdfxMemRange struct.
364 * We keep a linked list of free/available tdfxMemRange structs to
365 * avoid extra malloc/free calls.
369 DeleteRangeNode_NoLock(struct TdfxSharedState
*shared
, tdfxMemRange
*range
)
371 /* insert at head of list */
372 range
->next
= shared
->tmPool
;
373 shared
->tmPool
= range
;
377 #define DELETE_RANGE_NODE(shared, range) \
378 (range)->next = (shared)->tmPool; \
379 (shared)->tmPool = (range)
384 * When we've run out of texture memory we have to throw out an
385 * existing texture to make room for the new one. This function
386 * determins the texture to throw out.
388 static struct gl_texture_object
*
389 FindOldestObject(tdfxContextPtr fxMesa
, FxU32 tmu
)
391 const GLuint bindnumber
= fxMesa
->texBindNumber
;
392 struct gl_texture_object
*oldestObj
, *lowestPriorityObj
;
393 GLfloat lowestPriority
;
396 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
401 lowestPriority
= 1.0F
;
402 lowestPriorityObj
= NULL
;
404 for (id
= _mesa_HashFirstEntry(textures
);
406 id
= _mesa_HashNextEntry(textures
, id
)) {
407 struct gl_texture_object
*obj
408 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
409 tdfxTexInfo
*info
= TDFX_TEXTURE_DATA(obj
);
411 if (info
&& info
->isInTM
&&
412 ((info
->whichTMU
== tmu
) || (info
->whichTMU
== TDFX_TMU_BOTH
) ||
413 (info
->whichTMU
== TDFX_TMU_SPLIT
))) {
414 GLuint age
, lasttime
;
417 lasttime
= info
->lastTimeUsed
;
419 if (lasttime
> bindnumber
)
420 age
= bindnumber
+ (UINT_MAX
- lasttime
+ 1); /* TO DO: check wrap around */
422 age
= bindnumber
- lasttime
;
424 if (age
>= oldestAge
) {
429 /* examine priority */
430 if (obj
->Priority
< lowestPriority
) {
431 lowestPriority
= obj
->Priority
;
432 lowestPriorityObj
= obj
;
437 if (lowestPriority
< 1.0) {
438 ASSERT(lowestPriorityObj
);
440 printf("discard %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
442 return lowestPriorityObj
;
446 printf("discard %d age=%d\n", oldestObj->Name, oldestAge);
455 FlushTexMemory(tdfxContextPtr fxMesa
)
457 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
460 for (id
= _mesa_HashFirstEntry(textures
);
462 id
= _mesa_HashNextEntry(textures
, id
)) {
463 struct gl_texture_object
*obj
464 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
465 if (obj
->RefCount
< 2) {
466 /* don't flush currently bound textures */
467 tdfxTMMoveOutTM_NoLock(fxMesa
, obj
);
475 * Find the address (offset?) at which we can store a new texture.
476 * <tmu> is the texture unit.
477 * <size> is the texture size in bytes.
480 FindStartAddr(tdfxContextPtr fxMesa
, FxU32 tmu
, FxU32 size
)
482 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
483 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
484 tdfxMemRange
*prev
, *block
;
487 int discardedCount
= 0;
488 #define MAX_DISCARDS 10
491 if (shared
->umaTexMemory
) {
492 assert(tmu
== TDFX_TMU0
);
495 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
498 block
= shared
->tmFree
[tmu
];
500 if (block
->endAddr
- block
->startAddr
>= size
) {
501 /* The texture will fit here */
502 result
= block
->startAddr
;
503 block
->startAddr
+= size
;
504 if (block
->startAddr
== block
->endAddr
) {
505 /* Remove this node since it's empty */
507 prev
->next
= block
->next
;
510 shared
->tmFree
[tmu
] = block
->next
;
512 DELETE_RANGE_NODE(shared
, block
);
514 shared
->freeTexMem
[tmu
] -= size
;
515 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
521 /* We failed to find a block large enough to accomodate <size> bytes.
522 * Find the oldest texObject and free it.
526 if (discardedCount
> MAX_DISCARDS
+ 1) {
527 _mesa_problem(NULL
, "%s: extreme texmem fragmentation", __FUNCTION__
);
528 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
531 else if (discardedCount
> MAX_DISCARDS
) {
532 /* texture memory is probably really fragmented, flush it */
533 FlushTexMemory(fxMesa
);
538 struct gl_texture_object
*obj
= FindOldestObject(fxMesa
, tmu
);
540 tdfxTMMoveOutTM_NoLock(fxMesa
, obj
);
541 fxMesa
->stats
.texSwaps
++;
544 _mesa_problem(NULL
, "%s: extreme texmem fragmentation", __FUNCTION__
);
545 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
551 /* never get here, but play it safe */
552 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
558 * Remove the given tdfxMemRange node from hardware texture memory.
561 RemoveRange_NoLock(tdfxContextPtr fxMesa
, FxU32 tmu
, tdfxMemRange
*range
)
563 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
564 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
565 tdfxMemRange
*block
, *prev
;
567 if (shared
->umaTexMemory
) {
568 assert(tmu
== TDFX_TMU0
);
574 if (range
->startAddr
== range
->endAddr
) {
575 DELETE_RANGE_NODE(shared
, range
);
578 shared
->freeTexMem
[tmu
] += range
->endAddr
- range
->startAddr
;
580 /* find position in linked list to insert this tdfxMemRange node */
582 block
= shared
->tmFree
[tmu
];
584 assert(range
->startAddr
!= block
->startAddr
);
585 if (range
->startAddr
> block
->startAddr
) {
594 /* Insert the free block, combine with adjacent blocks when possible */
597 if (range
->endAddr
== block
->startAddr
) {
599 block
->startAddr
= range
->startAddr
;
600 DELETE_RANGE_NODE(shared
, range
);
605 if (prev
->endAddr
== range
->startAddr
) {
607 prev
->endAddr
= range
->endAddr
;
608 prev
->next
= range
->next
;
609 DELETE_RANGE_NODE(shared
, range
);
616 shared
->tmFree
[tmu
] = range
;
623 RemoveRange(tdfxContextPtr fxMesa
, FxU32 tmu
, tdfxMemRange
*range
)
625 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
626 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
627 RemoveRange_NoLock(fxMesa
, tmu
, range
);
628 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
634 * Allocate space for a texture image.
635 * <tmu> is the texture unit
636 * <texmemsize> is the number of bytes to allocate
638 static tdfxMemRange
*
639 AllocTexMem(tdfxContextPtr fxMesa
, FxU32 tmu
, FxU32 texmemsize
)
642 startAddr
= FindStartAddr(fxMesa
, tmu
, texmemsize
);
643 if (startAddr
== BAD_ADDRESS
) {
644 _mesa_problem(fxMesa
->glCtx
, "%s returned NULL! tmu=%d texmemsize=%d",
645 __FUNCTION__
, (int) tmu
, (int) texmemsize
);
650 range
= NewRangeNode(fxMesa
, startAddr
, startAddr
+ texmemsize
);
657 * Download (copy) the given texture data (all mipmap levels) into the
658 * Voodoo's texture memory.
659 * The texture memory must have already been allocated.
662 tdfxTMDownloadTexture(tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
669 ti
= TDFX_TEXTURE_DATA(tObj
);
671 targetTMU
= ti
->whichTMU
;
676 if (ti
->tm
[targetTMU
]) {
677 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
678 && tObj
->Image
[0][l
]->Data
; l
++) {
679 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
680 fxMesa
->Glide
.grTexDownloadMipMapLevel(targetTMU
,
681 ti
->tm
[targetTMU
]->startAddr
,
683 ti
->info
.largeLodLog2
,
684 ti
->info
.aspectRatioLog2
,
686 GR_MIPMAPLEVELMASK_BOTH
,
687 tObj
->Image
[0][l
]->Data
);
692 if (ti
->tm
[TDFX_TMU0
] && ti
->tm
[TDFX_TMU1
]) {
693 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
694 && tObj
->Image
[0][l
]->Data
; l
++) {
695 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
696 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
697 ti
->tm
[TDFX_TMU0
]->startAddr
,
699 ti
->info
.largeLodLog2
,
700 ti
->info
.aspectRatioLog2
,
702 GR_MIPMAPLEVELMASK_ODD
,
703 tObj
->Image
[0][l
]->Data
);
705 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
706 ti
->tm
[TDFX_TMU1
]->startAddr
,
708 ti
->info
.largeLodLog2
,
709 ti
->info
.aspectRatioLog2
,
711 GR_MIPMAPLEVELMASK_EVEN
,
712 tObj
->Image
[0][l
]->Data
);
717 if (ti
->tm
[TDFX_TMU0
] && ti
->tm
[TDFX_TMU1
]) {
718 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
719 && tObj
->Image
[0][l
]->Data
; l
++) {
720 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
721 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
722 ti
->tm
[TDFX_TMU0
]->startAddr
,
724 ti
->info
.largeLodLog2
,
725 ti
->info
.aspectRatioLog2
,
727 GR_MIPMAPLEVELMASK_BOTH
,
728 tObj
->Image
[0][l
]->Data
);
730 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
731 ti
->tm
[TDFX_TMU1
]->startAddr
,
733 ti
->info
.largeLodLog2
,
734 ti
->info
.aspectRatioLog2
,
736 GR_MIPMAPLEVELMASK_BOTH
,
737 tObj
->Image
[0][l
]->Data
);
742 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)targetTMU
);
749 tdfxTMReloadMipMapLevel(GLcontext
*ctx
, struct gl_texture_object
*tObj
,
752 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
753 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
758 glideLod
= ti
->info
.largeLodLog2
- level
+ tObj
->BaseLevel
;
761 LOCK_HARDWARE(fxMesa
);
766 fxMesa
->Glide
.grTexDownloadMipMapLevel(tmu
,
767 ti
->tm
[tmu
]->startAddr
,
769 ti
->info
.largeLodLog2
,
770 ti
->info
.aspectRatioLog2
,
772 GR_MIPMAPLEVELMASK_BOTH
,
773 tObj
->Image
[0][level
]->Data
);
776 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
777 ti
->tm
[GR_TMU0
]->startAddr
,
779 ti
->info
.largeLodLog2
,
780 ti
->info
.aspectRatioLog2
,
782 GR_MIPMAPLEVELMASK_ODD
,
783 tObj
->Image
[0][level
]->Data
);
785 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
786 ti
->tm
[GR_TMU1
]->startAddr
,
788 ti
->info
.largeLodLog2
,
789 ti
->info
.aspectRatioLog2
,
791 GR_MIPMAPLEVELMASK_EVEN
,
792 tObj
->Image
[0][level
]->Data
);
795 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
796 ti
->tm
[GR_TMU0
]->startAddr
,
798 ti
->info
.largeLodLog2
,
799 ti
->info
.aspectRatioLog2
,
801 GR_MIPMAPLEVELMASK_BOTH
,
802 tObj
->Image
[0][level
]->Data
);
804 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
805 ti
->tm
[GR_TMU1
]->startAddr
,
807 ti
->info
.largeLodLog2
,
808 ti
->info
.aspectRatioLog2
,
810 GR_MIPMAPLEVELMASK_BOTH
,
811 tObj
->Image
[0][level
]->Data
);
815 _mesa_problem(ctx
, "%s: bad tmu (%d)", __FUNCTION__
, (int)tmu
);
818 UNLOCK_HARDWARE(fxMesa
);
823 * Allocate space for the given texture in texture memory then
824 * download (copy) it into that space.
827 tdfxTMMoveInTM_NoLock( tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
,
830 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
833 fxMesa
->stats
.reqTexUpload
++;
836 if (ti
->whichTMU
== targetTMU
)
838 if (targetTMU
== TDFX_TMU_SPLIT
|| ti
->whichTMU
== TDFX_TMU_SPLIT
) {
839 tdfxTMMoveOutTM_NoLock(fxMesa
, tObj
);
842 if (ti
->whichTMU
== TDFX_TMU_BOTH
)
844 targetTMU
= TDFX_TMU_BOTH
;
848 ti
->whichTMU
= targetTMU
;
853 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,
855 ti
->tm
[targetTMU
] = AllocTexMem(fxMesa
, targetTMU
, texmemsize
);
858 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD
,
860 ti
->tm
[TDFX_TMU0
] = AllocTexMem(fxMesa
, TDFX_TMU0
, texmemsize
);
861 if (ti
->tm
[TDFX_TMU0
])
862 fxMesa
->stats
.memTexUpload
+= texmemsize
;
864 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN
,
866 ti
->tm
[TDFX_TMU1
] = AllocTexMem(fxMesa
, TDFX_TMU1
, texmemsize
);
869 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,
871 ti
->tm
[TDFX_TMU0
] = AllocTexMem(fxMesa
, TDFX_TMU0
, texmemsize
);
872 if (ti
->tm
[TDFX_TMU0
])
873 fxMesa
->stats
.memTexUpload
+= texmemsize
;
875 /*texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
877 ti
->tm
[TDFX_TMU1
] = AllocTexMem(fxMesa
, TDFX_TMU1
, texmemsize
);
880 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)targetTMU
);
884 ti
->reloadImages
= GL_TRUE
;
885 ti
->isInTM
= GL_TRUE
;
887 fxMesa
->stats
.texUpload
++;
892 * Move the given texture out of hardware texture memory.
893 * This deallocates the texture's memory space.
896 tdfxTMMoveOutTM_NoLock( tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
898 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
899 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
900 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
902 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
903 fprintf(stderr
, "fxmesa: %s(%p (%d))\n", __FUNCTION__
, (void *)tObj
, tObj
->Name
);
907 VerifyFreeList(fxMesa, 0);
908 VerifyFreeList(fxMesa, 1);
911 if (!ti
|| !ti
->isInTM
)
914 switch (ti
->whichTMU
) {
917 RemoveRange_NoLock(fxMesa
, ti
->whichTMU
, ti
->tm
[ti
->whichTMU
]);
921 assert(!shared
->umaTexMemory
);
922 RemoveRange_NoLock(fxMesa
, TDFX_TMU0
, ti
->tm
[TDFX_TMU0
]);
923 RemoveRange_NoLock(fxMesa
, TDFX_TMU1
, ti
->tm
[TDFX_TMU1
]);
926 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)ti
->whichTMU
);
930 ti
->isInTM
= GL_FALSE
;
933 ti
->whichTMU
= TDFX_TMU_NONE
;
936 VerifyFreeList(fxMesa, 0);
937 VerifyFreeList(fxMesa, 1);
943 * Called via glDeleteTexture to delete a texture object.
946 tdfxTMFreeTexture(tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
948 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
950 tdfxTMMoveOutTM(fxMesa
, tObj
);
952 tObj
->DriverData
= NULL
;
955 VerifyFreeList(fxMesa, 0);
956 VerifyFreeList(fxMesa, 1);
963 * After a context switch this function will be called to restore
964 * texture memory for the new context.
966 void tdfxTMRestoreTextures_NoLock( tdfxContextPtr fxMesa
)
968 GLcontext
*ctx
= fxMesa
->glCtx
;
969 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
972 for (id
= _mesa_HashFirstEntry(textures
);
974 id
= _mesa_HashNextEntry(textures
, id
)) {
975 struct gl_texture_object
*tObj
976 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
977 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA( tObj
);
978 if ( ti
&& ti
->isInTM
) {
980 for ( i
= 0 ; i
< MAX_TEXTURE_UNITS
; i
++ ) {
981 if ( ctx
->Texture
.Unit
[i
]._Current
== tObj
) {
982 tdfxTMDownloadTexture( fxMesa
, tObj
);
986 if ( i
== MAX_TEXTURE_UNITS
) {
987 tdfxTMMoveOutTM_NoLock( fxMesa
, tObj
);
992 VerifyFreeList(fxMesa, 0);
993 VerifyFreeList(fxMesa, 1);