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