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