Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / mesa / drivers / dri / tdfx / tdfx_texman.c
1 /* -*- mode: c; c-basic-offset: 3 -*-
2 *
3 * Copyright 2000 VA Linux Systems Inc., Fremont, California.
4 *
5 * All Rights Reserved.
6 *
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:
13 *
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
16 * Software.
17 *
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
24 * SOFTWARE.
25 */
26
27 /*
28 * Original rewrite:
29 * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
30 *
31 * Authors:
32 * Gareth Hughes <gareth@valinux.com>
33 * Brian Paul <brianp@valinux.com>
34 *
35 */
36
37 #include "tdfx_context.h"
38 #include "tdfx_tex.h"
39 #include "tdfx_texman.h"
40 #include "main/texobj.h"
41 #include "main/hash.h"
42
43
44 #define BAD_ADDRESS ((FxU32) -1)
45
46
47 #if 0 /* DEBUG use */
48 /*
49 * Verify the consistancy of the texture memory manager.
50 * This involves:
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.
55 */
56 static void
57 VerifyFreeList(tdfxContextPtr fxMesa, FxU32 tmu)
58 {
59 struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
60 struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
61 tdfxMemRange *block;
62 int prevStart = -1, prevEnd = -1;
63 int totalFree = 0;
64 int numObj = 0, numRes = 0;
65 int totalUsed = 0;
66
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);
76 }
77 assert(totalFree == shared->freeTexMem[tmu]);
78
79 {
80 struct _mesa_HashTable *textures = fxMesa->glCtx->Shared->TexObjects;
81 GLuint id;
82 for (id = _mesa_HashFirstEntry(textures);
83 id;
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);
88 if (ti) {
89 if (ti->isInTM) {
90 numRes++;
91 assert(ti->tm[0]);
92 if (ti->tm[tmu])
93 totalUsed += (ti->tm[tmu]->endAddr - ti->tm[tmu]->startAddr);
94 }
95 else {
96 assert(!ti->tm[0]);
97 }
98 }
99 }
100 }
101
102 printf("totalFree: %d totalUsed: %d totalMem: %d #objs=%d #res=%d\n",
103 shared->freeTexMem[tmu], totalUsed, shared->totalTexMem[tmu],
104 numObj, numRes);
105
106 assert(totalUsed + totalFree == shared->totalTexMem[tmu]);
107 }
108
109
110 static void
111 dump_texmem(tdfxContextPtr fxMesa)
112 {
113 struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
114 struct _mesa_HashTable *textures = mesaShared->TexObjects;
115 struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
116 tdfxMemRange *r;
117 FxU32 prev;
118 GLuint id;
119
120 printf("DUMP Objects:\n");
121 for (id = _mesa_HashFirstEntry(textures);
122 id;
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);
127
128 if (info && info->isInTM) {
129 printf("Obj %8p: %4d info = %p\n", obj, obj->Name, info);
130
131 printf(" isInTM=%d whichTMU=%d lastTimeUsed=%d\n",
132 info->isInTM, info->whichTMU, info->lastTimeUsed);
133 printf(" tm[0] = %p", info->tm[0]);
134 assert(info->tm[0]);
135 if (info->tm[0]) {
136 printf(" tm startAddr = %d endAddr = %d",
137 info->tm[0]->startAddr,
138 info->tm[0]->endAddr);
139 }
140 printf("\n");
141 printf(" tm[1] = %p", info->tm[1]);
142 if (info->tm[1]) {
143 printf(" tm startAddr = %d endAddr = %d",
144 info->tm[1]->startAddr,
145 info->tm[1]->endAddr);
146 }
147 printf("\n");
148 }
149 }
150
151 VerifyFreeList(fxMesa, 0);
152 VerifyFreeList(fxMesa, 1);
153
154 printf("Free memory unit 0: %d bytes\n", shared->freeTexMem[0]);
155 prev = 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);
158 prev = r->endAddr;
159 }
160
161 printf("Free memory unit 1: %d bytes\n", shared->freeTexMem[1]);
162 prev = 0;
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);
165 prev = r->endAddr;
166 }
167
168 }
169 #endif
170
171
172
173 #ifdef TEXSANITY
174 static void
175 fubar(void)
176 {
177 }
178
179 /*
180 * Sanity Check
181 */
182 static void
183 sanity(tdfxContextPtr fxMesa)
184 {
185 tdfxMemRange *tmp, *prev, *pos;
186
187 prev = 0;
188 tmp = fxMesa->tmFree[0];
189 while (tmp) {
190 if (!tmp->startAddr && !tmp->endAddr) {
191 fprintf(stderr, "Textures fubar\n");
192 fubar();
193 }
194 if (tmp->startAddr >= tmp->endAddr) {
195 fprintf(stderr, "Node fubar\n");
196 fubar();
197 }
198 if (prev && (prev->startAddr >= tmp->startAddr ||
199 prev->endAddr > tmp->startAddr)) {
200 fprintf(stderr, "Sorting fubar\n");
201 fubar();
202 }
203 prev = tmp;
204 tmp = tmp->next;
205 }
206 prev = 0;
207 tmp = fxMesa->tmFree[1];
208 while (tmp) {
209 if (!tmp->startAddr && !tmp->endAddr) {
210 fprintf(stderr, "Textures fubar\n");
211 fubar();
212 }
213 if (tmp->startAddr >= tmp->endAddr) {
214 fprintf(stderr, "Node fubar\n");
215 fubar();
216 }
217 if (prev && (prev->startAddr >= tmp->startAddr ||
218 prev->endAddr > tmp->startAddr)) {
219 fprintf(stderr, "Sorting fubar\n");
220 fubar();
221 }
222 prev = tmp;
223 tmp = tmp->next;
224 }
225 }
226 #endif
227
228
229
230
231
232 /*
233 * Allocate and initialize a new MemRange struct.
234 * Try to allocate it from the pool of free MemRange nodes rather than malloc.
235 */
236 static tdfxMemRange *
237 NewRangeNode(tdfxContextPtr fxMesa, FxU32 start, FxU32 end)
238 {
239 struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
240 struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
241 tdfxMemRange *result;
242
243 _glthread_LOCK_MUTEX(mesaShared->Mutex);
244 if (shared && shared->tmPool) {
245 result = shared->tmPool;
246 shared->tmPool = shared->tmPool->next;
247 }
248 else {
249 result = MALLOC(sizeof(tdfxMemRange));
250
251 }
252 _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
253
254 if (!result) {
255 /*fprintf(stderr, "fxDriver: out of memory!\n");*/
256 return NULL;
257 }
258
259 result->startAddr = start;
260 result->endAddr = end;
261 result->next = NULL;
262
263 return result;
264 }
265
266
267 /*
268 * Initialize texture memory.
269 * We take care of one or both TMU's here.
270 */
271 void
272 tdfxTMInit(tdfxContextPtr fxMesa)
273 {
274 if (!fxMesa->glCtx->Shared->DriverData) {
275 const char *extensions;
276 struct tdfxSharedState *shared = CALLOC_STRUCT(tdfxSharedState);
277 if (!shared)
278 return;
279
280 LOCK_HARDWARE(fxMesa);
281 extensions = fxMesa->Glide.grGetString(GR_EXTENSION);
282 UNLOCK_HARDWARE(fxMesa);
283 if (strstr(extensions, "TEXUMA")) {
284 FxU32 start, end;
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));*/
298 }
299 else {
300 const int numTMUs = fxMesa->haveTwoTMUs ? 2 : 1;
301 int tmu;
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));*/
311 }
312 UNLOCK_HARDWARE(fxMesa);
313 }
314
315 shared->tmPool = NULL;
316 fxMesa->glCtx->Shared->DriverData = shared;
317 /*printf("Texture memory init UMA: %d\n", shared->umaTexMemory);*/
318 }
319 }
320
321
322 /*
323 * Clean-up texture memory before destroying context.
324 */
325 void
326 tdfxTMClose(tdfxContextPtr fxMesa)
327 {
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;
331
332 const int numTMUs = fxMesa->haveTwoTMUs ? 2 : 1;
333 int tmu;
334 tdfxMemRange *tmp, *next;
335
336 /* Deallocate the pool of free tdfxMemRange nodes */
337 tmp = shared->tmPool;
338 while (tmp) {
339 next = tmp->next;
340 FREE(tmp);
341 tmp = next;
342 }
343
344 /* Delete the texture memory block tdfxMemRange nodes */
345 for (tmu = 0; tmu < numTMUs; tmu++) {
346 tmp = shared->tmFree[tmu];
347 while (tmp) {
348 next = tmp->next;
349 FREE(tmp);
350 tmp = next;
351 }
352 }
353
354 FREE(shared);
355 fxMesa->glCtx->Shared->DriverData = NULL;
356 }
357 }
358
359
360
361 /*
362 * Delete a tdfxMemRange struct.
363 * We keep a linked list of free/available tdfxMemRange structs to
364 * avoid extra malloc/free calls.
365 */
366 #if 0
367 static void
368 DeleteRangeNode_NoLock(struct TdfxSharedState *shared, tdfxMemRange *range)
369 {
370 /* insert at head of list */
371 range->next = shared->tmPool;
372 shared->tmPool = range;
373 }
374 #endif
375
376 #define DELETE_RANGE_NODE(shared, range) \
377 (range)->next = (shared)->tmPool; \
378 (shared)->tmPool = (range)
379
380
381
382 /*
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.
386 */
387 static struct gl_texture_object *
388 FindOldestObject(tdfxContextPtr fxMesa, FxU32 tmu)
389 {
390 const GLuint bindnumber = fxMesa->texBindNumber;
391 struct gl_texture_object *oldestObj, *lowestPriorityObj;
392 GLfloat lowestPriority;
393 GLuint oldestAge;
394 GLuint id;
395 struct _mesa_HashTable *textures = fxMesa->glCtx->Shared->TexObjects;
396
397 oldestObj = NULL;
398 oldestAge = 0;
399
400 lowestPriority = 1.0F;
401 lowestPriorityObj = NULL;
402
403 for (id = _mesa_HashFirstEntry(textures);
404 id;
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);
409
410 if (info && info->isInTM &&
411 ((info->whichTMU == tmu) || (info->whichTMU == TDFX_TMU_BOTH) ||
412 (info->whichTMU == TDFX_TMU_SPLIT))) {
413 GLuint age, lasttime;
414
415 assert(info->tm[0]);
416 lasttime = info->lastTimeUsed;
417
418 if (lasttime > bindnumber)
419 age = bindnumber + (UINT_MAX - lasttime + 1); /* TO DO: check wrap around */
420 else
421 age = bindnumber - lasttime;
422
423 if (age >= oldestAge) {
424 oldestAge = age;
425 oldestObj = obj;
426 }
427
428 /* examine priority */
429 if (obj->Priority < lowestPriority) {
430 lowestPriority = obj->Priority;
431 lowestPriorityObj = obj;
432 }
433 }
434 }
435
436 if (lowestPriority < 1.0) {
437 ASSERT(lowestPriorityObj);
438 /*
439 printf("discard %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
440 */
441 return lowestPriorityObj;
442 }
443 else {
444 /*
445 printf("discard %d age=%d\n", oldestObj->Name, oldestAge);
446 */
447 return oldestObj;
448 }
449 }
450
451
452 #if 0
453 static void
454 FlushTexMemory(tdfxContextPtr fxMesa)
455 {
456 struct _mesa_HashTable *textures = fxMesa->glCtx->Shared->TexObjects;
457 GLuint id;
458
459 for (id = _mesa_HashFirstEntry(textures);
460 id;
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);
467 }
468 }
469 }
470 #endif
471
472
473 /*
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.
477 */
478 static FxU32
479 FindStartAddr(tdfxContextPtr fxMesa, FxU32 tmu, FxU32 size)
480 {
481 struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
482 struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
483 tdfxMemRange *prev, *block;
484 FxU32 result;
485 #if 0
486 int discardedCount = 0;
487 #define MAX_DISCARDS 10
488 #endif
489
490 if (shared->umaTexMemory) {
491 assert(tmu == TDFX_TMU0);
492 }
493
494 _glthread_LOCK_MUTEX(mesaShared->Mutex);
495 while (1) {
496 prev = NULL;
497 block = shared->tmFree[tmu];
498 while (block) {
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 */
505 if (prev) {
506 prev->next = block->next;
507 }
508 else {
509 shared->tmFree[tmu] = block->next;
510 }
511 DELETE_RANGE_NODE(shared, block);
512 }
513 shared->freeTexMem[tmu] -= size;
514 _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
515 return result;
516 }
517 prev = block;
518 block = block->next;
519 }
520 /* We failed to find a block large enough to accomodate <size> bytes.
521 * Find the oldest texObject and free it.
522 */
523 #if 0
524 discardedCount++;
525 if (discardedCount > MAX_DISCARDS + 1) {
526 _mesa_problem(NULL, "%s: extreme texmem fragmentation", __FUNCTION__);
527 _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
528 return BAD_ADDRESS;
529 }
530 else if (discardedCount > MAX_DISCARDS) {
531 /* texture memory is probably really fragmented, flush it */
532 FlushTexMemory(fxMesa);
533 }
534 else
535 #endif
536 {
537 struct gl_texture_object *obj = FindOldestObject(fxMesa, tmu);
538 if (obj) {
539 tdfxTMMoveOutTM_NoLock(fxMesa, obj);
540 fxMesa->stats.texSwaps++;
541 }
542 else {
543 _mesa_problem(NULL, "%s: extreme texmem fragmentation", __FUNCTION__);
544 _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
545 return BAD_ADDRESS;
546 }
547 }
548 }
549
550 /* never get here, but play it safe */
551 _glthread_UNLOCK_MUTEX(mesaShared->Mutex);
552 return BAD_ADDRESS;
553 }
554
555
556 /*
557 * Remove the given tdfxMemRange node from hardware texture memory.
558 */
559 static void
560 RemoveRange_NoLock(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range)
561 {
562 struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
563 struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
564 tdfxMemRange *block, *prev;
565
566 if (shared->umaTexMemory) {
567 assert(tmu == TDFX_TMU0);
568 }
569
570 if (!range)
571 return;
572
573 if (range->startAddr == range->endAddr) {
574 DELETE_RANGE_NODE(shared, range);
575 return;
576 }
577 shared->freeTexMem[tmu] += range->endAddr - range->startAddr;
578
579 /* find position in linked list to insert this tdfxMemRange node */
580 prev = NULL;
581 block = shared->tmFree[tmu];
582 while (block) {
583 assert(range->startAddr != block->startAddr);
584 if (range->startAddr > block->startAddr) {
585 prev = block;
586 block = block->next;
587 }
588 else {
589 break;
590 }
591 }
592
593 /* Insert the free block, combine with adjacent blocks when possible */
594 range->next = block;
595 if (block) {
596 if (range->endAddr == block->startAddr) {
597 /* Combine */
598 block->startAddr = range->startAddr;
599 DELETE_RANGE_NODE(shared, range);
600 range = block;
601 }
602 }
603 if (prev) {
604 if (prev->endAddr == range->startAddr) {
605 /* Combine */
606 prev->endAddr = range->endAddr;
607 prev->next = range->next;
608 DELETE_RANGE_NODE(shared, range);
609 }
610 else {
611 prev->next = range;
612 }
613 }
614 else {
615 shared->tmFree[tmu] = range;
616 }
617 }
618
619
620 #if 0 /* NOT USED */
621 static void
622 RemoveRange(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range)
623 {
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);
628 }
629 #endif
630
631
632 /*
633 * Allocate space for a texture image.
634 * <tmu> is the texture unit
635 * <texmemsize> is the number of bytes to allocate
636 */
637 static tdfxMemRange *
638 AllocTexMem(tdfxContextPtr fxMesa, FxU32 tmu, FxU32 texmemsize)
639 {
640 FxU32 startAddr;
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);
645 return NULL;
646 }
647 else {
648 tdfxMemRange *range;
649 range = NewRangeNode(fxMesa, startAddr, startAddr + texmemsize);
650 return range;
651 }
652 }
653
654
655 /*
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.
659 */
660 void
661 tdfxTMDownloadTexture(tdfxContextPtr fxMesa, struct gl_texture_object *tObj)
662 {
663 tdfxTexInfo *ti;
664 GLint l;
665 FxU32 targetTMU;
666
667 assert(tObj);
668 ti = TDFX_TEXTURE_DATA(tObj);
669 assert(ti);
670 targetTMU = ti->whichTMU;
671
672 switch (targetTMU) {
673 case TDFX_TMU0:
674 case TDFX_TMU1:
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,
681 glideLod,
682 ti->info.largeLodLog2,
683 ti->info.aspectRatioLog2,
684 ti->info.format,
685 GR_MIPMAPLEVELMASK_BOTH,
686 tObj->Image[0][l]->Data);
687 }
688 }
689 break;
690 case TDFX_TMU_SPLIT:
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,
697 glideLod,
698 ti->info.largeLodLog2,
699 ti->info.aspectRatioLog2,
700 ti->info.format,
701 GR_MIPMAPLEVELMASK_ODD,
702 tObj->Image[0][l]->Data);
703
704 fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
705 ti->tm[TDFX_TMU1]->startAddr,
706 glideLod,
707 ti->info.largeLodLog2,
708 ti->info.aspectRatioLog2,
709 ti->info.format,
710 GR_MIPMAPLEVELMASK_EVEN,
711 tObj->Image[0][l]->Data);
712 }
713 }
714 break;
715 case TDFX_TMU_BOTH:
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,
722 glideLod,
723 ti->info.largeLodLog2,
724 ti->info.aspectRatioLog2,
725 ti->info.format,
726 GR_MIPMAPLEVELMASK_BOTH,
727 tObj->Image[0][l]->Data);
728
729 fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
730 ti->tm[TDFX_TMU1]->startAddr,
731 glideLod,
732 ti->info.largeLodLog2,
733 ti->info.aspectRatioLog2,
734 ti->info.format,
735 GR_MIPMAPLEVELMASK_BOTH,
736 tObj->Image[0][l]->Data);
737 }
738 }
739 break;
740 default:
741 _mesa_problem(NULL, "%s: bad tmu (%d)", __FUNCTION__, (int)targetTMU);
742 return;
743 }
744 }
745
746
747 void
748 tdfxTMReloadMipMapLevel(GLcontext *ctx, struct gl_texture_object *tObj,
749 GLint level)
750 {
751 tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
752 tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
753 GrLOD_t glideLod;
754 FxU32 tmu;
755
756 tmu = ti->whichTMU;
757 glideLod = ti->info.largeLodLog2 - level + tObj->BaseLevel;
758 ASSERT(ti->isInTM);
759
760 LOCK_HARDWARE(fxMesa);
761
762 switch (tmu) {
763 case TDFX_TMU0:
764 case TDFX_TMU1:
765 fxMesa->Glide.grTexDownloadMipMapLevel(tmu,
766 ti->tm[tmu]->startAddr,
767 glideLod,
768 ti->info.largeLodLog2,
769 ti->info.aspectRatioLog2,
770 ti->info.format,
771 GR_MIPMAPLEVELMASK_BOTH,
772 tObj->Image[0][level]->Data);
773 break;
774 case TDFX_TMU_SPLIT:
775 fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
776 ti->tm[GR_TMU0]->startAddr,
777 glideLod,
778 ti->info.largeLodLog2,
779 ti->info.aspectRatioLog2,
780 ti->info.format,
781 GR_MIPMAPLEVELMASK_ODD,
782 tObj->Image[0][level]->Data);
783
784 fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
785 ti->tm[GR_TMU1]->startAddr,
786 glideLod,
787 ti->info.largeLodLog2,
788 ti->info.aspectRatioLog2,
789 ti->info.format,
790 GR_MIPMAPLEVELMASK_EVEN,
791 tObj->Image[0][level]->Data);
792 break;
793 case TDFX_TMU_BOTH:
794 fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU0,
795 ti->tm[GR_TMU0]->startAddr,
796 glideLod,
797 ti->info.largeLodLog2,
798 ti->info.aspectRatioLog2,
799 ti->info.format,
800 GR_MIPMAPLEVELMASK_BOTH,
801 tObj->Image[0][level]->Data);
802
803 fxMesa->Glide.grTexDownloadMipMapLevel(GR_TMU1,
804 ti->tm[GR_TMU1]->startAddr,
805 glideLod,
806 ti->info.largeLodLog2,
807 ti->info.aspectRatioLog2,
808 ti->info.format,
809 GR_MIPMAPLEVELMASK_BOTH,
810 tObj->Image[0][level]->Data);
811 break;
812
813 default:
814 _mesa_problem(ctx, "%s: bad tmu (%d)", __FUNCTION__, (int)tmu);
815 break;
816 }
817 UNLOCK_HARDWARE(fxMesa);
818 }
819
820
821 /*
822 * Allocate space for the given texture in texture memory then
823 * download (copy) it into that space.
824 */
825 void
826 tdfxTMMoveInTM_NoLock( tdfxContextPtr fxMesa, struct gl_texture_object *tObj,
827 FxU32 targetTMU )
828 {
829 tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
830 FxU32 texmemsize;
831
832 fxMesa->stats.reqTexUpload++;
833
834 if (ti->isInTM) {
835 if (ti->whichTMU == targetTMU)
836 return;
837 if (targetTMU == TDFX_TMU_SPLIT || ti->whichTMU == TDFX_TMU_SPLIT) {
838 tdfxTMMoveOutTM_NoLock(fxMesa, tObj);
839 }
840 else {
841 if (ti->whichTMU == TDFX_TMU_BOTH)
842 return;
843 targetTMU = TDFX_TMU_BOTH;
844 }
845 }
846
847 ti->whichTMU = targetTMU;
848
849 switch (targetTMU) {
850 case TDFX_TMU0:
851 case TDFX_TMU1:
852 texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
853 &(ti->info));
854 ti->tm[targetTMU] = AllocTexMem(fxMesa, targetTMU, texmemsize);
855 break;
856 case TDFX_TMU_SPLIT:
857 texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD,
858 &(ti->info));
859 ti->tm[TDFX_TMU0] = AllocTexMem(fxMesa, TDFX_TMU0, texmemsize);
860 if (ti->tm[TDFX_TMU0])
861 fxMesa->stats.memTexUpload += texmemsize;
862
863 texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN,
864 &(ti->info));
865 ti->tm[TDFX_TMU1] = AllocTexMem(fxMesa, TDFX_TMU1, texmemsize);
866 break;
867 case TDFX_TMU_BOTH:
868 texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
869 &(ti->info));
870 ti->tm[TDFX_TMU0] = AllocTexMem(fxMesa, TDFX_TMU0, texmemsize);
871 if (ti->tm[TDFX_TMU0])
872 fxMesa->stats.memTexUpload += texmemsize;
873
874 /*texmemsize = fxMesa->Glide.grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,
875 &(ti->info));*/
876 ti->tm[TDFX_TMU1] = AllocTexMem(fxMesa, TDFX_TMU1, texmemsize);
877 break;
878 default:
879 _mesa_problem(NULL, "%s: bad tmu (%d)", __FUNCTION__, (int)targetTMU);
880 return;
881 }
882
883 ti->reloadImages = GL_TRUE;
884 ti->isInTM = GL_TRUE;
885
886 fxMesa->stats.texUpload++;
887 }
888
889
890 /*
891 * Move the given texture out of hardware texture memory.
892 * This deallocates the texture's memory space.
893 */
894 void
895 tdfxTMMoveOutTM_NoLock( tdfxContextPtr fxMesa, struct gl_texture_object *tObj )
896 {
897 struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
898 struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
899 tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
900
901 if (MESA_VERBOSE & VERBOSE_DRIVER) {
902 fprintf(stderr, "fxmesa: %s(%p (%d))\n", __FUNCTION__, (void *)tObj, tObj->Name);
903 }
904
905 /*
906 VerifyFreeList(fxMesa, 0);
907 VerifyFreeList(fxMesa, 1);
908 */
909
910 if (!ti || !ti->isInTM)
911 return;
912
913 switch (ti->whichTMU) {
914 case TDFX_TMU0:
915 case TDFX_TMU1:
916 RemoveRange_NoLock(fxMesa, ti->whichTMU, ti->tm[ti->whichTMU]);
917 break;
918 case TDFX_TMU_SPLIT:
919 case TDFX_TMU_BOTH:
920 assert(!shared->umaTexMemory);
921 RemoveRange_NoLock(fxMesa, TDFX_TMU0, ti->tm[TDFX_TMU0]);
922 RemoveRange_NoLock(fxMesa, TDFX_TMU1, ti->tm[TDFX_TMU1]);
923 break;
924 default:
925 _mesa_problem(NULL, "%s: bad tmu (%d)", __FUNCTION__, (int)ti->whichTMU);
926 return;
927 }
928
929 ti->isInTM = GL_FALSE;
930 ti->tm[0] = NULL;
931 ti->tm[1] = NULL;
932 ti->whichTMU = TDFX_TMU_NONE;
933
934 /*
935 VerifyFreeList(fxMesa, 0);
936 VerifyFreeList(fxMesa, 1);
937 */
938 }
939
940
941 /*
942 * Called via glDeleteTexture to delete a texture object.
943 */
944 void
945 tdfxTMFreeTexture(tdfxContextPtr fxMesa, struct gl_texture_object *tObj)
946 {
947 tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
948 if (ti) {
949 tdfxTMMoveOutTM(fxMesa, tObj);
950 FREE(ti);
951 tObj->DriverData = NULL;
952 }
953 /*
954 VerifyFreeList(fxMesa, 0);
955 VerifyFreeList(fxMesa, 1);
956 */
957 }
958
959
960
961 /*
962 * After a context switch this function will be called to restore
963 * texture memory for the new context.
964 */
965 void tdfxTMRestoreTextures_NoLock( tdfxContextPtr fxMesa )
966 {
967 GLcontext *ctx = fxMesa->glCtx;
968 struct _mesa_HashTable *textures = fxMesa->glCtx->Shared->TexObjects;
969 GLuint id;
970
971 for (id = _mesa_HashFirstEntry(textures);
972 id;
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 ) {
978 int i;
979 for ( i = 0 ; i < MAX_TEXTURE_UNITS ; i++ ) {
980 if ( ctx->Texture.Unit[i]._Current == tObj ) {
981 tdfxTMDownloadTexture( fxMesa, tObj );
982 break;
983 }
984 }
985 if ( i == MAX_TEXTURE_UNITS ) {
986 tdfxTMMoveOutTM_NoLock( fxMesa, tObj );
987 }
988 }
989 }
990 /*
991 VerifyFreeList(fxMesa, 0);
992 VerifyFreeList(fxMesa, 1);
993 */
994 }