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"
39 #include "tdfx_texman.h"
40 #include "main/texobj.h"
41 #include "main/hash.h"
44 #define BAD_ADDRESS ((FxU32) -1)
49 * Verify the consistancy of the texture memory manager.
51 * Traversing all texture objects and computing total memory used.
52 * Traverse the free block list and computing total memory free.
53 * Compare the total free and total used amounts to the total memory size.
54 * Make various assertions about the results.
57 VerifyFreeList(tdfxContextPtr fxMesa
, FxU32 tmu
)
59 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
60 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
62 int prevStart
= -1, prevEnd
= -1;
64 int numObj
= 0, numRes
= 0;
67 for (block
= shared
->tmFree
[tmu
]; block
; block
= block
->next
) {
68 assert( block
->endAddr
> 0 );
69 assert( block
->startAddr
<= shared
->totalTexMem
[tmu
] );
70 assert( block
->endAddr
<= shared
->totalTexMem
[tmu
] );
71 assert( (int) block
->startAddr
> prevStart
);
72 assert( (int) block
->startAddr
>= prevEnd
);
73 prevStart
= (int) block
->startAddr
;
74 prevEnd
= (int) block
->endAddr
;
75 totalFree
+= (block
->endAddr
- block
->startAddr
);
77 assert(totalFree
== shared
->freeTexMem
[tmu
]);
80 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
82 for (id
= _mesa_HashFirstEntry(textures
);
84 id
= _mesa_HashNextEntry(textures
, id
)) {
85 struct gl_texture_object
*tObj
86 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
87 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
93 totalUsed
+= (ti
->tm
[tmu
]->endAddr
- ti
->tm
[tmu
]->startAddr
);
102 printf("totalFree: %d totalUsed: %d totalMem: %d #objs=%d #res=%d\n",
103 shared
->freeTexMem
[tmu
], totalUsed
, shared
->totalTexMem
[tmu
],
106 assert(totalUsed
+ totalFree
== shared
->totalTexMem
[tmu
]);
111 dump_texmem(tdfxContextPtr fxMesa
)
113 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
114 struct _mesa_HashTable
*textures
= mesaShared
->TexObjects
;
115 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
120 printf("DUMP Objects:\n");
121 for (id
= _mesa_HashFirstEntry(textures
);
123 id
= _mesa_HashNextEntry(textures
, id
)) {
124 struct gl_texture_object
*obj
125 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
126 tdfxTexInfo
*info
= TDFX_TEXTURE_DATA(obj
);
128 if (info
&& info
->isInTM
) {
129 printf("Obj %8p: %4d info = %p\n", obj
, obj
->Name
, info
);
131 printf(" isInTM=%d whichTMU=%d lastTimeUsed=%d\n",
132 info
->isInTM
, info
->whichTMU
, info
->lastTimeUsed
);
133 printf(" tm[0] = %p", info
->tm
[0]);
136 printf(" tm startAddr = %d endAddr = %d",
137 info
->tm
[0]->startAddr
,
138 info
->tm
[0]->endAddr
);
141 printf(" tm[1] = %p", info
->tm
[1]);
143 printf(" tm startAddr = %d endAddr = %d",
144 info
->tm
[1]->startAddr
,
145 info
->tm
[1]->endAddr
);
151 VerifyFreeList(fxMesa
, 0);
152 VerifyFreeList(fxMesa
, 1);
154 printf("Free memory unit 0: %d bytes\n", shared
->freeTexMem
[0]);
156 for (r
= shared
->tmFree
[0]; r
; r
= r
->next
) {
157 printf("%8p: start %8d end %8d size %8d gap %8d\n", r
, r
->startAddr
, r
->endAddr
, r
->endAddr
- r
->startAddr
, r
->startAddr
- prev
);
161 printf("Free memory unit 1: %d bytes\n", shared
->freeTexMem
[1]);
163 for (r
= shared
->tmFree
[1]; r
; r
= r
->next
) {
164 printf("%8p: start %8d end %8d size %8d gap %8d\n", r
, r
->startAddr
, r
->endAddr
, r
->endAddr
- r
->startAddr
, r
->startAddr
- prev
);
183 sanity(tdfxContextPtr fxMesa
)
185 tdfxMemRange
*tmp
, *prev
, *pos
;
188 tmp
= fxMesa
->tmFree
[0];
190 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
191 fprintf(stderr
, "Textures fubar\n");
194 if (tmp
->startAddr
>= tmp
->endAddr
) {
195 fprintf(stderr
, "Node fubar\n");
198 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
199 prev
->endAddr
> tmp
->startAddr
)) {
200 fprintf(stderr
, "Sorting fubar\n");
207 tmp
= fxMesa
->tmFree
[1];
209 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
210 fprintf(stderr
, "Textures fubar\n");
213 if (tmp
->startAddr
>= tmp
->endAddr
) {
214 fprintf(stderr
, "Node fubar\n");
217 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
218 prev
->endAddr
> tmp
->startAddr
)) {
219 fprintf(stderr
, "Sorting fubar\n");
233 * Allocate and initialize a new MemRange struct.
234 * Try to allocate it from the pool of free MemRange nodes rather than malloc.
236 static tdfxMemRange
*
237 NewRangeNode(tdfxContextPtr fxMesa
, FxU32 start
, FxU32 end
)
239 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
240 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
241 tdfxMemRange
*result
;
243 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
244 if (shared
&& shared
->tmPool
) {
245 result
= shared
->tmPool
;
246 shared
->tmPool
= shared
->tmPool
->next
;
249 result
= MALLOC(sizeof(tdfxMemRange
));
252 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
255 /*fprintf(stderr, "fxDriver: out of memory!\n");*/
259 result
->startAddr
= start
;
260 result
->endAddr
= end
;
268 * Initialize texture memory.
269 * We take care of one or both TMU's here.
272 tdfxTMInit(tdfxContextPtr fxMesa
)
274 if (!fxMesa
->glCtx
->Shared
->DriverData
) {
275 const char *extensions
;
276 struct tdfxSharedState
*shared
= CALLOC_STRUCT(tdfxSharedState
);
280 LOCK_HARDWARE(fxMesa
);
281 extensions
= fxMesa
->Glide
.grGetString(GR_EXTENSION
);
282 UNLOCK_HARDWARE(fxMesa
);
283 if (strstr(extensions
, "TEXUMA")) {
285 shared
->umaTexMemory
= GL_TRUE
;
286 LOCK_HARDWARE(fxMesa
);
287 fxMesa
->Glide
.grEnable(GR_TEXTURE_UMA_EXT
);
288 start
= fxMesa
->Glide
.grTexMinAddress(0);
289 end
= fxMesa
->Glide
.grTexMaxAddress(0);
290 UNLOCK_HARDWARE(fxMesa
);
291 shared
->totalTexMem
[0] = end
- start
;
292 shared
->totalTexMem
[1] = 0;
293 shared
->freeTexMem
[0] = end
- start
;
294 shared
->freeTexMem
[1] = 0;
295 shared
->tmFree
[0] = NewRangeNode(fxMesa
, start
, end
);
296 shared
->tmFree
[1] = NULL
;
297 /*printf("UMA tex memory: %d\n", (int) (end - start));*/
300 const int numTMUs
= fxMesa
->haveTwoTMUs
? 2 : 1;
302 shared
->umaTexMemory
= GL_FALSE
;
303 LOCK_HARDWARE(fxMesa
);
304 for (tmu
= 0; tmu
< numTMUs
; tmu
++) {
305 FxU32 start
= fxMesa
->Glide
.grTexMinAddress(tmu
);
306 FxU32 end
= fxMesa
->Glide
.grTexMaxAddress(tmu
);
307 shared
->totalTexMem
[tmu
] = end
- start
;
308 shared
->freeTexMem
[tmu
] = end
- start
;
309 shared
->tmFree
[tmu
] = NewRangeNode(fxMesa
, start
, end
);
310 /*printf("Split tex memory: %d\n", (int) (end - start));*/
312 UNLOCK_HARDWARE(fxMesa
);
315 shared
->tmPool
= NULL
;
316 fxMesa
->glCtx
->Shared
->DriverData
= shared
;
317 /*printf("Texture memory init UMA: %d\n", shared->umaTexMemory);*/
323 * Clean-up texture memory before destroying context.
326 tdfxTMClose(tdfxContextPtr fxMesa
)
328 if (fxMesa
->glCtx
->Shared
->RefCount
== 1 && fxMesa
->driDrawable
) {
329 /* refcount will soon go to zero, free our 3dfx stuff */
330 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) fxMesa
->glCtx
->Shared
->DriverData
;
332 const int numTMUs
= fxMesa
->haveTwoTMUs
? 2 : 1;
334 tdfxMemRange
*tmp
, *next
;
336 /* Deallocate the pool of free tdfxMemRange nodes */
337 tmp
= shared
->tmPool
;
344 /* Delete the texture memory block tdfxMemRange nodes */
345 for (tmu
= 0; tmu
< numTMUs
; tmu
++) {
346 tmp
= shared
->tmFree
[tmu
];
355 fxMesa
->glCtx
->Shared
->DriverData
= NULL
;
362 * Delete a tdfxMemRange struct.
363 * We keep a linked list of free/available tdfxMemRange structs to
364 * avoid extra malloc/free calls.
368 DeleteRangeNode_NoLock(struct TdfxSharedState
*shared
, tdfxMemRange
*range
)
370 /* insert at head of list */
371 range
->next
= shared
->tmPool
;
372 shared
->tmPool
= range
;
376 #define DELETE_RANGE_NODE(shared, range) \
377 (range)->next = (shared)->tmPool; \
378 (shared)->tmPool = (range)
383 * When we've run out of texture memory we have to throw out an
384 * existing texture to make room for the new one. This function
385 * determins the texture to throw out.
387 static struct gl_texture_object
*
388 FindOldestObject(tdfxContextPtr fxMesa
, FxU32 tmu
)
390 const GLuint bindnumber
= fxMesa
->texBindNumber
;
391 struct gl_texture_object
*oldestObj
, *lowestPriorityObj
;
392 GLfloat lowestPriority
;
395 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
400 lowestPriority
= 1.0F
;
401 lowestPriorityObj
= NULL
;
403 for (id
= _mesa_HashFirstEntry(textures
);
405 id
= _mesa_HashNextEntry(textures
, id
)) {
406 struct gl_texture_object
*obj
407 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
408 tdfxTexInfo
*info
= TDFX_TEXTURE_DATA(obj
);
410 if (info
&& info
->isInTM
&&
411 ((info
->whichTMU
== tmu
) || (info
->whichTMU
== TDFX_TMU_BOTH
) ||
412 (info
->whichTMU
== TDFX_TMU_SPLIT
))) {
413 GLuint age
, lasttime
;
416 lasttime
= info
->lastTimeUsed
;
418 if (lasttime
> bindnumber
)
419 age
= bindnumber
+ (UINT_MAX
- lasttime
+ 1); /* TO DO: check wrap around */
421 age
= bindnumber
- lasttime
;
423 if (age
>= oldestAge
) {
428 /* examine priority */
429 if (obj
->Priority
< lowestPriority
) {
430 lowestPriority
= obj
->Priority
;
431 lowestPriorityObj
= obj
;
436 if (lowestPriority
< 1.0) {
437 ASSERT(lowestPriorityObj
);
439 printf("discard %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
441 return lowestPriorityObj
;
445 printf("discard %d age=%d\n", oldestObj->Name, oldestAge);
454 FlushTexMemory(tdfxContextPtr fxMesa
)
456 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
459 for (id
= _mesa_HashFirstEntry(textures
);
461 id
= _mesa_HashNextEntry(textures
, id
)) {
462 struct gl_texture_object
*obj
463 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
464 if (obj
->RefCount
< 2) {
465 /* don't flush currently bound textures */
466 tdfxTMMoveOutTM_NoLock(fxMesa
, obj
);
474 * Find the address (offset?) at which we can store a new texture.
475 * <tmu> is the texture unit.
476 * <size> is the texture size in bytes.
479 FindStartAddr(tdfxContextPtr fxMesa
, FxU32 tmu
, FxU32 size
)
481 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
482 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
483 tdfxMemRange
*prev
, *block
;
486 int discardedCount
= 0;
487 #define MAX_DISCARDS 10
490 if (shared
->umaTexMemory
) {
491 assert(tmu
== TDFX_TMU0
);
494 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
497 block
= shared
->tmFree
[tmu
];
499 if (block
->endAddr
- block
->startAddr
>= size
) {
500 /* The texture will fit here */
501 result
= block
->startAddr
;
502 block
->startAddr
+= size
;
503 if (block
->startAddr
== block
->endAddr
) {
504 /* Remove this node since it's empty */
506 prev
->next
= block
->next
;
509 shared
->tmFree
[tmu
] = block
->next
;
511 DELETE_RANGE_NODE(shared
, block
);
513 shared
->freeTexMem
[tmu
] -= size
;
514 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
520 /* We failed to find a block large enough to accomodate <size> bytes.
521 * Find the oldest texObject and free it.
525 if (discardedCount
> MAX_DISCARDS
+ 1) {
526 _mesa_problem(NULL
, "%s: extreme texmem fragmentation", __FUNCTION__
);
527 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
530 else if (discardedCount
> MAX_DISCARDS
) {
531 /* texture memory is probably really fragmented, flush it */
532 FlushTexMemory(fxMesa
);
537 struct gl_texture_object
*obj
= FindOldestObject(fxMesa
, tmu
);
539 tdfxTMMoveOutTM_NoLock(fxMesa
, obj
);
540 fxMesa
->stats
.texSwaps
++;
543 _mesa_problem(NULL
, "%s: extreme texmem fragmentation", __FUNCTION__
);
544 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
550 /* never get here, but play it safe */
551 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
557 * Remove the given tdfxMemRange node from hardware texture memory.
560 RemoveRange_NoLock(tdfxContextPtr fxMesa
, FxU32 tmu
, tdfxMemRange
*range
)
562 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
563 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
564 tdfxMemRange
*block
, *prev
;
566 if (shared
->umaTexMemory
) {
567 assert(tmu
== TDFX_TMU0
);
573 if (range
->startAddr
== range
->endAddr
) {
574 DELETE_RANGE_NODE(shared
, range
);
577 shared
->freeTexMem
[tmu
] += range
->endAddr
- range
->startAddr
;
579 /* find position in linked list to insert this tdfxMemRange node */
581 block
= shared
->tmFree
[tmu
];
583 assert(range
->startAddr
!= block
->startAddr
);
584 if (range
->startAddr
> block
->startAddr
) {
593 /* Insert the free block, combine with adjacent blocks when possible */
596 if (range
->endAddr
== block
->startAddr
) {
598 block
->startAddr
= range
->startAddr
;
599 DELETE_RANGE_NODE(shared
, range
);
604 if (prev
->endAddr
== range
->startAddr
) {
606 prev
->endAddr
= range
->endAddr
;
607 prev
->next
= range
->next
;
608 DELETE_RANGE_NODE(shared
, range
);
615 shared
->tmFree
[tmu
] = range
;
622 RemoveRange(tdfxContextPtr fxMesa
, FxU32 tmu
, tdfxMemRange
*range
)
624 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
625 _glthread_LOCK_MUTEX(mesaShared
->Mutex
);
626 RemoveRange_NoLock(fxMesa
, tmu
, range
);
627 _glthread_UNLOCK_MUTEX(mesaShared
->Mutex
);
633 * Allocate space for a texture image.
634 * <tmu> is the texture unit
635 * <texmemsize> is the number of bytes to allocate
637 static tdfxMemRange
*
638 AllocTexMem(tdfxContextPtr fxMesa
, FxU32 tmu
, FxU32 texmemsize
)
641 startAddr
= FindStartAddr(fxMesa
, tmu
, texmemsize
);
642 if (startAddr
== BAD_ADDRESS
) {
643 _mesa_problem(fxMesa
->glCtx
, "%s returned NULL! tmu=%d texmemsize=%d",
644 __FUNCTION__
, (int) tmu
, (int) texmemsize
);
649 range
= NewRangeNode(fxMesa
, startAddr
, startAddr
+ texmemsize
);
656 * Download (copy) the given texture data (all mipmap levels) into the
657 * Voodoo's texture memory.
658 * The texture memory must have already been allocated.
661 tdfxTMDownloadTexture(tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
668 ti
= TDFX_TEXTURE_DATA(tObj
);
670 targetTMU
= ti
->whichTMU
;
675 if (ti
->tm
[targetTMU
]) {
676 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
677 && tObj
->Image
[0][l
]->Data
; l
++) {
678 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
679 fxMesa
->Glide
.grTexDownloadMipMapLevel(targetTMU
,
680 ti
->tm
[targetTMU
]->startAddr
,
682 ti
->info
.largeLodLog2
,
683 ti
->info
.aspectRatioLog2
,
685 GR_MIPMAPLEVELMASK_BOTH
,
686 tObj
->Image
[0][l
]->Data
);
691 if (ti
->tm
[TDFX_TMU0
] && ti
->tm
[TDFX_TMU1
]) {
692 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
693 && tObj
->Image
[0][l
]->Data
; l
++) {
694 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
695 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
696 ti
->tm
[TDFX_TMU0
]->startAddr
,
698 ti
->info
.largeLodLog2
,
699 ti
->info
.aspectRatioLog2
,
701 GR_MIPMAPLEVELMASK_ODD
,
702 tObj
->Image
[0][l
]->Data
);
704 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
705 ti
->tm
[TDFX_TMU1
]->startAddr
,
707 ti
->info
.largeLodLog2
,
708 ti
->info
.aspectRatioLog2
,
710 GR_MIPMAPLEVELMASK_EVEN
,
711 tObj
->Image
[0][l
]->Data
);
716 if (ti
->tm
[TDFX_TMU0
] && ti
->tm
[TDFX_TMU1
]) {
717 for (l
= ti
->minLevel
; l
<= ti
->maxLevel
718 && tObj
->Image
[0][l
]->Data
; l
++) {
719 GrLOD_t glideLod
= ti
->info
.largeLodLog2
- l
+ tObj
->BaseLevel
;
720 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
721 ti
->tm
[TDFX_TMU0
]->startAddr
,
723 ti
->info
.largeLodLog2
,
724 ti
->info
.aspectRatioLog2
,
726 GR_MIPMAPLEVELMASK_BOTH
,
727 tObj
->Image
[0][l
]->Data
);
729 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
730 ti
->tm
[TDFX_TMU1
]->startAddr
,
732 ti
->info
.largeLodLog2
,
733 ti
->info
.aspectRatioLog2
,
735 GR_MIPMAPLEVELMASK_BOTH
,
736 tObj
->Image
[0][l
]->Data
);
741 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)targetTMU
);
748 tdfxTMReloadMipMapLevel(GLcontext
*ctx
, struct gl_texture_object
*tObj
,
751 tdfxContextPtr fxMesa
= TDFX_CONTEXT(ctx
);
752 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
757 glideLod
= ti
->info
.largeLodLog2
- level
+ tObj
->BaseLevel
;
760 LOCK_HARDWARE(fxMesa
);
765 fxMesa
->Glide
.grTexDownloadMipMapLevel(tmu
,
766 ti
->tm
[tmu
]->startAddr
,
768 ti
->info
.largeLodLog2
,
769 ti
->info
.aspectRatioLog2
,
771 GR_MIPMAPLEVELMASK_BOTH
,
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_ODD
,
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_EVEN
,
791 tObj
->Image
[0][level
]->Data
);
794 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU0
,
795 ti
->tm
[GR_TMU0
]->startAddr
,
797 ti
->info
.largeLodLog2
,
798 ti
->info
.aspectRatioLog2
,
800 GR_MIPMAPLEVELMASK_BOTH
,
801 tObj
->Image
[0][level
]->Data
);
803 fxMesa
->Glide
.grTexDownloadMipMapLevel(GR_TMU1
,
804 ti
->tm
[GR_TMU1
]->startAddr
,
806 ti
->info
.largeLodLog2
,
807 ti
->info
.aspectRatioLog2
,
809 GR_MIPMAPLEVELMASK_BOTH
,
810 tObj
->Image
[0][level
]->Data
);
814 _mesa_problem(ctx
, "%s: bad tmu (%d)", __FUNCTION__
, (int)tmu
);
817 UNLOCK_HARDWARE(fxMesa
);
822 * Allocate space for the given texture in texture memory then
823 * download (copy) it into that space.
826 tdfxTMMoveInTM_NoLock( tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
,
829 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
832 fxMesa
->stats
.reqTexUpload
++;
835 if (ti
->whichTMU
== targetTMU
)
837 if (targetTMU
== TDFX_TMU_SPLIT
|| ti
->whichTMU
== TDFX_TMU_SPLIT
) {
838 tdfxTMMoveOutTM_NoLock(fxMesa
, tObj
);
841 if (ti
->whichTMU
== TDFX_TMU_BOTH
)
843 targetTMU
= TDFX_TMU_BOTH
;
847 ti
->whichTMU
= targetTMU
;
852 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,
854 ti
->tm
[targetTMU
] = AllocTexMem(fxMesa
, targetTMU
, texmemsize
);
857 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD
,
859 ti
->tm
[TDFX_TMU0
] = AllocTexMem(fxMesa
, TDFX_TMU0
, texmemsize
);
860 if (ti
->tm
[TDFX_TMU0
])
861 fxMesa
->stats
.memTexUpload
+= texmemsize
;
863 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN
,
865 ti
->tm
[TDFX_TMU1
] = AllocTexMem(fxMesa
, TDFX_TMU1
, texmemsize
);
868 texmemsize
= fxMesa
->Glide
.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,
870 ti
->tm
[TDFX_TMU0
] = AllocTexMem(fxMesa
, TDFX_TMU0
, texmemsize
);
871 if (ti
->tm
[TDFX_TMU0
])
872 fxMesa
->stats
.memTexUpload
+= texmemsize
;
874 /*texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
876 ti
->tm
[TDFX_TMU1
] = AllocTexMem(fxMesa
, TDFX_TMU1
, texmemsize
);
879 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)targetTMU
);
883 ti
->reloadImages
= GL_TRUE
;
884 ti
->isInTM
= GL_TRUE
;
886 fxMesa
->stats
.texUpload
++;
891 * Move the given texture out of hardware texture memory.
892 * This deallocates the texture's memory space.
895 tdfxTMMoveOutTM_NoLock( tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
897 struct gl_shared_state
*mesaShared
= fxMesa
->glCtx
->Shared
;
898 struct tdfxSharedState
*shared
= (struct tdfxSharedState
*) mesaShared
->DriverData
;
899 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
901 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
902 fprintf(stderr
, "fxmesa: %s(%p (%d))\n", __FUNCTION__
, (void *)tObj
, tObj
->Name
);
906 VerifyFreeList(fxMesa, 0);
907 VerifyFreeList(fxMesa, 1);
910 if (!ti
|| !ti
->isInTM
)
913 switch (ti
->whichTMU
) {
916 RemoveRange_NoLock(fxMesa
, ti
->whichTMU
, ti
->tm
[ti
->whichTMU
]);
920 assert(!shared
->umaTexMemory
);
921 RemoveRange_NoLock(fxMesa
, TDFX_TMU0
, ti
->tm
[TDFX_TMU0
]);
922 RemoveRange_NoLock(fxMesa
, TDFX_TMU1
, ti
->tm
[TDFX_TMU1
]);
925 _mesa_problem(NULL
, "%s: bad tmu (%d)", __FUNCTION__
, (int)ti
->whichTMU
);
929 ti
->isInTM
= GL_FALSE
;
932 ti
->whichTMU
= TDFX_TMU_NONE
;
935 VerifyFreeList(fxMesa, 0);
936 VerifyFreeList(fxMesa, 1);
942 * Called via glDeleteTexture to delete a texture object.
945 tdfxTMFreeTexture(tdfxContextPtr fxMesa
, struct gl_texture_object
*tObj
)
947 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA(tObj
);
949 tdfxTMMoveOutTM(fxMesa
, tObj
);
951 tObj
->DriverData
= NULL
;
954 VerifyFreeList(fxMesa, 0);
955 VerifyFreeList(fxMesa, 1);
962 * After a context switch this function will be called to restore
963 * texture memory for the new context.
965 void tdfxTMRestoreTextures_NoLock( tdfxContextPtr fxMesa
)
967 GLcontext
*ctx
= fxMesa
->glCtx
;
968 struct _mesa_HashTable
*textures
= fxMesa
->glCtx
->Shared
->TexObjects
;
971 for (id
= _mesa_HashFirstEntry(textures
);
973 id
= _mesa_HashNextEntry(textures
, id
)) {
974 struct gl_texture_object
*tObj
975 = _mesa_lookup_texture(fxMesa
->glCtx
, id
);
976 tdfxTexInfo
*ti
= TDFX_TEXTURE_DATA( tObj
);
977 if ( ti
&& ti
->isInTM
) {
979 for ( i
= 0 ; i
< MAX_TEXTURE_UNITS
; i
++ ) {
980 if ( ctx
->Texture
.Unit
[i
]._Current
== tObj
) {
981 tdfxTMDownloadTexture( fxMesa
, tObj
);
985 if ( i
== MAX_TEXTURE_UNITS
) {
986 tdfxTMMoveOutTM_NoLock( fxMesa
, tObj
);
991 VerifyFreeList(fxMesa, 0);
992 VerifyFreeList(fxMesa, 1);