66f6f443e14e8982976efab4c968f0957949c2b1
[mesa.git] / src / mesa / drivers / glide / fxtexman.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 4.0
4 *
5 * Copyright (C) 1999-2001 Brian Paul 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 shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /* Authors:
26 * David Bucciarelli
27 * Brian Paul
28 * Daryll Strauss
29 * Keith Whitwell
30 * Daniel Borca
31 * Hiroshi Morii
32 */
33
34 /* fxtexman.c - 3Dfx VooDoo texture memory functions */
35
36
37 #ifdef HAVE_CONFIG_H
38 #include "conf.h"
39 #endif
40
41 #if defined(FX)
42
43 #include "fxdrv.h"
44
45 int texSwaps = 0;
46 static FxU32 texBoundMask;
47
48 #define FX_2MB_SPLIT 0x200000
49
50 static struct gl_texture_object *fxTMFindOldestObject(fxMesaContext fxMesa,
51 int tmu);
52
53
54 #ifdef TEXSANITY
55 static void
56 fubar()
57 {
58 }
59
60 /* Sanity Check */
61 static void
62 sanity(fxMesaContext fxMesa)
63 {
64 MemRange *tmp, *prev, *pos;
65
66 prev = 0;
67 tmp = fxMesa->tmFree[0];
68 while (tmp) {
69 if (!tmp->startAddr && !tmp->endAddr) {
70 fprintf(stderr, "Textures fubar\n");
71 fubar();
72 }
73 if (tmp->startAddr >= tmp->endAddr) {
74 fprintf(stderr, "Node fubar\n");
75 fubar();
76 }
77 if (prev && (prev->startAddr >= tmp->startAddr ||
78 prev->endAddr > tmp->startAddr)) {
79 fprintf(stderr, "Sorting fubar\n");
80 fubar();
81 }
82 prev = tmp;
83 tmp = tmp->next;
84 }
85 prev = 0;
86 tmp = fxMesa->tmFree[1];
87 while (tmp) {
88 if (!tmp->startAddr && !tmp->endAddr) {
89 fprintf(stderr, "Textures fubar\n");
90 fubar();
91 }
92 if (tmp->startAddr >= tmp->endAddr) {
93 fprintf(stderr, "Node fubar\n");
94 fubar();
95 }
96 if (prev && (prev->startAddr >= tmp->startAddr ||
97 prev->endAddr > tmp->startAddr)) {
98 fprintf(stderr, "Sorting fubar\n");
99 fubar();
100 }
101 prev = tmp;
102 tmp = tmp->next;
103 }
104 }
105 #endif
106
107 static MemRange *
108 fxTMNewRangeNode(fxMesaContext fxMesa, FxU32 start, FxU32 end)
109 {
110 MemRange *result = 0;
111
112 if (fxMesa->tmPool) {
113 result = fxMesa->tmPool;
114 fxMesa->tmPool = fxMesa->tmPool->next;
115 }
116 else {
117 if (!(result = MALLOC(sizeof(MemRange)))) {
118 fprintf(stderr, "fxTMNewRangeNode: ERROR: out of memory!\n");
119 fxCloseHardware();
120 exit(-1);
121 }
122 }
123 result->startAddr = start;
124 result->endAddr = end;
125 return result;
126 }
127
128 #if 1
129 #define fxTMDeleteRangeNode(fxMesa, range) \
130 do { \
131 range->next = fxMesa->tmPool; \
132 fxMesa->tmPool = range; \
133 } while (0);
134 #else
135 static void
136 fxTMDeleteRangeNode(fxMesaContext fxMesa, MemRange * range)
137 {
138 range->next = fxMesa->tmPool;
139 fxMesa->tmPool = range;
140 }
141 #endif
142
143 static void
144 fxTMUInit(fxMesaContext fxMesa, int tmu)
145 {
146 MemRange *tmn, *last;
147 FxU32 start, end, blockstart, blockend, chunk;
148
149 start = grTexMinAddress(tmu);
150 end = grTexMaxAddress(tmu);
151
152 chunk = (fxMesa->type >= GR_SSTTYPE_Banshee) ? (end - start) : FX_2MB_SPLIT;
153
154 if (fxMesa->verbose) {
155 fprintf(stderr, "Voodoo %s configuration:\n",
156 (tmu == FX_TMU0) ? "TMU0" : "TMU1");
157 fprintf(stderr, "Voodoo Lower texture memory address (%u)\n",
158 (unsigned int) start);
159 fprintf(stderr, "Voodoo Higher texture memory address (%u)\n",
160 (unsigned int) end);
161 fprintf(stderr, "Voodoo Splitting Texture memory in %luMB blocks:\n", chunk >> 20);
162 }
163
164 fxMesa->freeTexMem[tmu] = end - start;
165 fxMesa->tmFree[tmu] = NULL;
166
167 last = 0;
168 blockstart = start;
169 while (blockstart < end) {
170 if (blockstart + chunk > end)
171 blockend = end;
172 else
173 blockend = blockstart + chunk;
174
175 if (fxMesa->verbose)
176 fprintf(stderr, "Voodoo %07u-%07u\n",
177 (unsigned int) blockstart, (unsigned int) blockend);
178
179 tmn = fxTMNewRangeNode(fxMesa, blockstart, blockend);
180 tmn->next = NULL;
181
182
183 if (last)
184 last->next = tmn;
185 else
186 fxMesa->tmFree[tmu] = tmn;
187 last = tmn;
188
189 blockstart += chunk;
190 }
191 }
192
193 static int
194 fxTMFindStartAddr(fxMesaContext fxMesa, GLint tmu, int size)
195 {
196 MemRange *prev, *tmp;
197 int result;
198 struct gl_texture_object *obj;
199
200 if (fxMesa->HaveTexUma) {
201 tmu = FX_TMU0;
202 }
203
204 while (1) {
205 prev = 0;
206 tmp = fxMesa->tmFree[tmu];
207 while (tmp) {
208 if (tmp->endAddr - tmp->startAddr >= size) { /* Fits here */
209 result = tmp->startAddr;
210 tmp->startAddr += size;
211 if (tmp->startAddr == tmp->endAddr) { /* Empty */
212 if (prev) {
213 prev->next = tmp->next;
214 }
215 else {
216 fxMesa->tmFree[tmu] = tmp->next;
217 }
218 fxTMDeleteRangeNode(fxMesa, tmp);
219 }
220 fxMesa->freeTexMem[tmu] -= size;
221 return result;
222 }
223 prev = tmp;
224 tmp = tmp->next;
225 }
226 /* No free space. Discard oldest */
227 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
228 fprintf(stderr, "fxTMFindStartAddr: No free space. Discard oldest\n");
229 }
230 obj = fxTMFindOldestObject(fxMesa, tmu);
231 if (!obj) {
232 fprintf(stderr, "fxTMFindStartAddr: ERROR: No space for texture\n");
233 return -1;
234 }
235 fxTMMoveOutTM(fxMesa, obj);
236 texSwaps++;
237 }
238 }
239
240 int fxTMCheckStartAddr (fxMesaContext fxMesa, GLint tmu, tfxTexInfo *ti)
241 {
242 MemRange *prev, *tmp;
243 int size;
244 struct gl_texture_object *obj;
245
246 if (fxMesa->HaveTexUma) {
247 return FXTRUE;
248 }
249
250 size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
251
252 tmp = fxMesa->tmFree[tmu];
253 while (tmp) {
254 if (tmp->endAddr - tmp->startAddr >= size) { /* Fits here */
255 return FXTRUE;
256 }
257 tmp = tmp->next;
258 }
259
260 return FXFALSE;
261 }
262
263 static void
264 fxTMRemoveRange(fxMesaContext fxMesa, GLint tmu, MemRange * range)
265 {
266 MemRange *tmp, *prev;
267
268 if (fxMesa->HaveTexUma) {
269 tmu = FX_TMU0;
270 }
271
272 if (range->startAddr == range->endAddr) {
273 fxTMDeleteRangeNode(fxMesa, range);
274 return;
275 }
276 fxMesa->freeTexMem[tmu] += range->endAddr - range->startAddr;
277 prev = 0;
278 tmp = fxMesa->tmFree[tmu];
279 while (tmp) {
280 if (range->startAddr > tmp->startAddr) {
281 prev = tmp;
282 tmp = tmp->next;
283 }
284 else
285 break;
286 }
287 /* When we create the regions, we make a split at the 2MB boundary.
288 Now we have to make sure we don't join those 2MB boundary regions
289 back together again. */
290 range->next = tmp;
291 if (tmp) {
292 if (range->endAddr == tmp->startAddr
293 && tmp->startAddr & texBoundMask) {
294 /* Combine */
295 tmp->startAddr = range->startAddr;
296 fxTMDeleteRangeNode(fxMesa, range);
297 range = tmp;
298 }
299 }
300 if (prev) {
301 if (prev->endAddr == range->startAddr
302 && range->startAddr & texBoundMask) {
303 /* Combine */
304 prev->endAddr = range->endAddr;
305 prev->next = range->next;
306 fxTMDeleteRangeNode(fxMesa, range);
307 }
308 else
309 prev->next = range;
310 }
311 else {
312 fxMesa->tmFree[tmu] = range;
313 }
314 }
315
316 static struct gl_texture_object *
317 fxTMFindOldestObject(fxMesaContext fxMesa, int tmu)
318 {
319 GLuint age, old, lasttime, bindnumber;
320 GLfloat lowestPriority;
321 tfxTexInfo *info;
322 struct gl_texture_object *obj, *tmp, *lowestPriorityObj;
323
324 tmp = fxMesa->glCtx->Shared->TexObjectList;
325 if (!tmp)
326 return 0;
327 obj = NULL;
328 old = 0;
329
330 lowestPriorityObj = NULL;
331 lowestPriority = 1.0F;
332
333 bindnumber = fxMesa->texBindNumber;
334 while (tmp) {
335 info = fxTMGetTexInfo(tmp);
336
337 if (info && info->isInTM &&
338 ((info->whichTMU == tmu) ||
339 (info->whichTMU == FX_TMU_BOTH) ||
340 (info->whichTMU == FX_TMU_SPLIT) ||
341 fxMesa->HaveTexUma
342 )
343 ) {
344 lasttime = info->lastTimeUsed;
345
346 if (lasttime > bindnumber)
347 age = bindnumber + (UINT_MAX - lasttime + 1); /* TO DO: check wrap around */
348 else
349 age = bindnumber - lasttime;
350
351 if (age >= old) {
352 old = age;
353 obj = tmp;
354 }
355
356 /* examine priority */
357 if (tmp->Priority < lowestPriority) {
358 lowestPriority = tmp->Priority;
359 lowestPriorityObj = tmp;
360 }
361 }
362 tmp = tmp->Next;
363 }
364
365 if (lowestPriorityObj != NULL) {
366 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
367 fprintf(stderr, "fxTMFindOldestObject: %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
368 }
369 return lowestPriorityObj;
370 }
371 else {
372 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
373 if (obj != NULL) {
374 fprintf(stderr, "fxTMFindOldestObject: %d age=%d\n", obj->Name, old);
375 }
376 }
377 return obj;
378 }
379 }
380
381 static MemRange *
382 fxTMAddObj(fxMesaContext fxMesa,
383 struct gl_texture_object *tObj, GLint tmu, int texmemsize)
384 {
385 FxI32 startAddr;
386 MemRange *range;
387
388 startAddr = fxTMFindStartAddr(fxMesa, tmu, texmemsize);
389 if (startAddr < 0)
390 return 0;
391 range = fxTMNewRangeNode(fxMesa, startAddr, startAddr + texmemsize);
392 return range;
393 }
394
395 /* External Functions */
396
397 void
398 fxTMMoveInTM_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj,
399 GLint where)
400 {
401 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
402 int i, l;
403 int texmemsize;
404
405 if (TDFX_DEBUG & VERBOSE_DRIVER) {
406 fprintf(stderr, "fxTMMoveInTM_NoLock(%d)\n", tObj->Name);
407 }
408
409 fxMesa->stats.reqTexUpload++;
410
411 if (!ti->validated) {
412 fprintf(stderr, "fxTMMoveInTM_NoLock: INTERNAL ERROR: not validated\n");
413 fxCloseHardware();
414 exit(-1);
415 }
416
417 if (ti->isInTM) {
418 if (ti->whichTMU == where)
419 return;
420 if (where == FX_TMU_SPLIT || ti->whichTMU == FX_TMU_SPLIT)
421 fxTMMoveOutTM_NoLock(fxMesa, tObj);
422 else {
423 if (ti->whichTMU == FX_TMU_BOTH)
424 return;
425 where = FX_TMU_BOTH;
426 }
427 }
428
429 if (TDFX_DEBUG & (VERBOSE_DRIVER | VERBOSE_TEXTURE)) {
430 fprintf(stderr, "fxTMMoveInTM_NoLock: downloading %p (%d) in texture memory in %d\n",
431 (void *)tObj, tObj->Name, where);
432 }
433
434 ti->whichTMU = (FxU32) where;
435
436 switch (where) {
437 case FX_TMU0:
438 case FX_TMU1:
439 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
440 ti->tm[where] = fxTMAddObj(fxMesa, tObj, where, texmemsize);
441 fxMesa->stats.memTexUpload += texmemsize;
442
443 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
444 i <= FX_smallLodValue(ti->info); i++, l++) {
445 struct gl_texture_image *texImage = tObj->Image[l];
446 grTexDownloadMipMapLevel(where,
447 ti->tm[where]->startAddr,
448 FX_valueToLod(i),
449 FX_largeLodLog2(ti->info),
450 FX_aspectRatioLog2(ti->info),
451 ti->info.format,
452 GR_MIPMAPLEVELMASK_BOTH,
453 texImage->Data);
454 }
455 break;
456 case FX_TMU_SPLIT:
457 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD, &(ti->info));
458 ti->tm[FX_TMU0] = fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
459 fxMesa->stats.memTexUpload += texmemsize;
460
461 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN, &(ti->info));
462 ti->tm[FX_TMU1] = fxTMAddObj(fxMesa, tObj, FX_TMU1, texmemsize);
463 fxMesa->stats.memTexUpload += texmemsize;
464
465 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
466 i <= FX_smallLodValue(ti->info); i++, l++) {
467 struct gl_texture_image *texImage = tObj->Image[l];
468
469 grTexDownloadMipMapLevel(GR_TMU0,
470 ti->tm[FX_TMU0]->startAddr,
471 FX_valueToLod(i),
472 FX_largeLodLog2(ti->info),
473 FX_aspectRatioLog2(ti->info),
474 ti->info.format,
475 GR_MIPMAPLEVELMASK_ODD,
476 texImage->Data);
477
478 grTexDownloadMipMapLevel(GR_TMU1,
479 ti->tm[FX_TMU1]->startAddr,
480 FX_valueToLod(i),
481 FX_largeLodLog2(ti->info),
482 FX_aspectRatioLog2(ti->info),
483 ti->info.format,
484 GR_MIPMAPLEVELMASK_EVEN,
485 texImage->Data);
486 }
487 break;
488 case FX_TMU_BOTH:
489 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
490 ti->tm[FX_TMU0] = fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
491 fxMesa->stats.memTexUpload += texmemsize;
492
493 /*texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));*/
494 ti->tm[FX_TMU1] = fxTMAddObj(fxMesa, tObj, FX_TMU1, texmemsize);
495 fxMesa->stats.memTexUpload += texmemsize; /* ZZZ: required? */
496
497 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
498 i <= FX_smallLodValue(ti->info); i++, l++) {
499 struct gl_texture_image *texImage = tObj->Image[l];
500 grTexDownloadMipMapLevel(GR_TMU0,
501 ti->tm[FX_TMU0]->startAddr,
502 FX_valueToLod(i),
503 FX_largeLodLog2(ti->info),
504 FX_aspectRatioLog2(ti->info),
505 ti->info.format,
506 GR_MIPMAPLEVELMASK_BOTH,
507 texImage->Data);
508
509 grTexDownloadMipMapLevel(GR_TMU1,
510 ti->tm[FX_TMU1]->startAddr,
511 FX_valueToLod(i),
512 FX_largeLodLog2(ti->info),
513 FX_aspectRatioLog2(ti->info),
514 ti->info.format,
515 GR_MIPMAPLEVELMASK_BOTH,
516 texImage->Data);
517 }
518 break;
519 default:
520 fprintf(stderr, "fxTMMoveInTM_NoLock: INTERNAL ERROR: wrong tmu (%d)\n", where);
521 fxCloseHardware();
522 exit(-1);
523 }
524
525 fxMesa->stats.texUpload++;
526
527 ti->isInTM = GL_TRUE;
528 }
529
530
531 void
532 fxTMMoveInTM(fxMesaContext fxMesa, struct gl_texture_object *tObj,
533 GLint where)
534 {
535 BEGIN_BOARD_LOCK();
536 fxTMMoveInTM_NoLock(fxMesa, tObj, where);
537 END_BOARD_LOCK();
538 }
539
540
541 void
542 fxTMReloadMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj,
543 GLint level)
544 {
545 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
546 GrLOD_t lodlevel;
547 GLint tmu;
548 struct gl_texture_image *texImage = tObj->Image[level];
549 tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
550
551 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
552 fprintf(stderr, "fxTMReloadMipMapLevel(%p (%d), %d)\n", (void *)tObj, tObj->Name, level);
553 }
554
555 assert(mml);
556 assert(mml->width > 0);
557 assert(mml->height > 0);
558 assert(mml->glideFormat > 0);
559
560 if (!ti->validated) {
561 fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: not validated\n");
562 fxCloseHardware();
563 exit(-1);
564 }
565
566 tmu = (int) ti->whichTMU;
567 #if 0
568 /* [dBorca]
569 * We get here by (see Tex[Sub]Image2D), thus we are in TMU.
570 * Also, we just set the correct TMU above. fxTMMoveInTM will
571 * bail early, so don't bother...
572 */
573 fxTMMoveInTM(fxMesa, tObj, tmu);
574 #else
575 fxMesa->stats.reqTexUpload++;
576 fxMesa->stats.texUpload++;
577 #endif
578
579 lodlevel = ti->info.largeLodLog2 - (level - ti->minLevel);
580
581 switch (tmu) {
582 case FX_TMU0:
583 case FX_TMU1:
584 grTexDownloadMipMapLevel(tmu,
585 ti->tm[tmu]->startAddr,
586 lodlevel,
587 FX_largeLodLog2(ti->info),
588 FX_aspectRatioLog2(ti->info),
589 ti->info.format,
590 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
591 break;
592 case FX_TMU_SPLIT:
593 grTexDownloadMipMapLevel(GR_TMU0,
594 ti->tm[GR_TMU0]->startAddr,
595 lodlevel,
596 FX_largeLodLog2(ti->info),
597 FX_aspectRatioLog2(ti->info),
598 ti->info.format,
599 GR_MIPMAPLEVELMASK_ODD, texImage->Data);
600
601 grTexDownloadMipMapLevel(GR_TMU1,
602 ti->tm[GR_TMU1]->startAddr,
603 lodlevel,
604 FX_largeLodLog2(ti->info),
605 FX_aspectRatioLog2(ti->info),
606 ti->info.format,
607 GR_MIPMAPLEVELMASK_EVEN, texImage->Data);
608 break;
609 case FX_TMU_BOTH:
610 grTexDownloadMipMapLevel(GR_TMU0,
611 ti->tm[GR_TMU0]->startAddr,
612 lodlevel,
613 FX_largeLodLog2(ti->info),
614 FX_aspectRatioLog2(ti->info),
615 ti->info.format,
616 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
617
618 grTexDownloadMipMapLevel(GR_TMU1,
619 ti->tm[GR_TMU1]->startAddr,
620 lodlevel,
621 FX_largeLodLog2(ti->info),
622 FX_aspectRatioLog2(ti->info),
623 ti->info.format,
624 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
625 break;
626
627 default:
628 fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
629 fxCloseHardware();
630 exit(-1);
631 }
632 }
633
634 void
635 fxTMReloadSubMipMapLevel(fxMesaContext fxMesa,
636 struct gl_texture_object *tObj,
637 GLint level, GLint yoffset, GLint height)
638 {
639 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
640 GrLOD_t lodlevel;
641 unsigned short *data;
642 GLint tmu;
643 struct gl_texture_image *texImage = tObj->Image[level];
644 tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
645
646 assert(mml);
647
648 if (!ti->validated) {
649 fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: not validated\n");
650 fxCloseHardware();
651 exit(-1);
652 }
653
654 tmu = (int) ti->whichTMU;
655 fxTMMoveInTM(fxMesa, tObj, tmu);
656
657 fxTexGetInfo(mml->width, mml->height,
658 &lodlevel, NULL, NULL, NULL, NULL, NULL);
659
660 if ((ti->info.format == GR_TEXFMT_INTENSITY_8) ||
661 (ti->info.format == GR_TEXFMT_P_8) ||
662 (ti->info.format == GR_TEXFMT_ALPHA_8))
663 data = (GLushort *) texImage->Data + ((yoffset * mml->width) >> 1);
664 else
665 data = (GLushort *) texImage->Data + yoffset * mml->width;
666
667 switch (tmu) {
668 case FX_TMU0:
669 case FX_TMU1:
670 grTexDownloadMipMapLevelPartial(tmu,
671 ti->tm[tmu]->startAddr,
672 FX_valueToLod(FX_lodToValue(lodlevel)
673 + level),
674 FX_largeLodLog2(ti->info),
675 FX_aspectRatioLog2(ti->info),
676 ti->info.format,
677 GR_MIPMAPLEVELMASK_BOTH, data,
678 yoffset, yoffset + height - 1);
679 break;
680 case FX_TMU_SPLIT:
681 grTexDownloadMipMapLevelPartial(GR_TMU0,
682 ti->tm[FX_TMU0]->startAddr,
683 FX_valueToLod(FX_lodToValue(lodlevel)
684 + level),
685 FX_largeLodLog2(ti->info),
686 FX_aspectRatioLog2(ti->info),
687 ti->info.format,
688 GR_MIPMAPLEVELMASK_ODD, data,
689 yoffset, yoffset + height - 1);
690
691 grTexDownloadMipMapLevelPartial(GR_TMU1,
692 ti->tm[FX_TMU1]->startAddr,
693 FX_valueToLod(FX_lodToValue(lodlevel)
694 + level),
695 FX_largeLodLog2(ti->info),
696 FX_aspectRatioLog2(ti->info),
697 ti->info.format,
698 GR_MIPMAPLEVELMASK_EVEN, data,
699 yoffset, yoffset + height - 1);
700 break;
701 case FX_TMU_BOTH:
702 grTexDownloadMipMapLevelPartial(GR_TMU0,
703 ti->tm[FX_TMU0]->startAddr,
704 FX_valueToLod(FX_lodToValue(lodlevel)
705 + level),
706 FX_largeLodLog2(ti->info),
707 FX_aspectRatioLog2(ti->info),
708 ti->info.format,
709 GR_MIPMAPLEVELMASK_BOTH, data,
710 yoffset, yoffset + height - 1);
711
712 grTexDownloadMipMapLevelPartial(GR_TMU1,
713 ti->tm[FX_TMU1]->startAddr,
714 FX_valueToLod(FX_lodToValue(lodlevel)
715 + level),
716 FX_largeLodLog2(ti->info),
717 FX_aspectRatioLog2(ti->info),
718 ti->info.format,
719 GR_MIPMAPLEVELMASK_BOTH, data,
720 yoffset, yoffset + height - 1);
721 break;
722 default:
723 fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
724 fxCloseHardware();
725 exit(-1);
726 }
727 }
728
729 void
730 fxTMMoveOutTM(fxMesaContext fxMesa, struct gl_texture_object *tObj)
731 {
732 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
733
734 if (TDFX_DEBUG & VERBOSE_DRIVER) {
735 fprintf(stderr, "fxTMMoveOutTM(%p (%d))\n", (void *)tObj, tObj->Name);
736 }
737
738 if (!ti->isInTM)
739 return;
740
741 switch (ti->whichTMU) {
742 case FX_TMU0:
743 case FX_TMU1:
744 fxTMRemoveRange(fxMesa, (int) ti->whichTMU, ti->tm[ti->whichTMU]);
745 break;
746 case FX_TMU_SPLIT:
747 case FX_TMU_BOTH:
748 fxTMRemoveRange(fxMesa, FX_TMU0, ti->tm[FX_TMU0]);
749 fxTMRemoveRange(fxMesa, FX_TMU1, ti->tm[FX_TMU1]);
750 break;
751 default:
752 fprintf(stderr, "fxTMMoveOutTM: INTERNAL ERROR: bad TMU (%ld)\n", ti->whichTMU);
753 fxCloseHardware();
754 exit(-1);
755 }
756
757 ti->isInTM = GL_FALSE;
758 ti->whichTMU = FX_TMU_NONE;
759 }
760
761 void
762 fxTMFreeTexture(fxMesaContext fxMesa, struct gl_texture_object *tObj)
763 {
764 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
765 int i;
766
767 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
768 fprintf(stderr, "fxTMFreeTexture(%p (%d))\n", (void *)tObj, tObj->Name);
769 }
770
771 fxTMMoveOutTM(fxMesa, tObj);
772
773 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
774 struct gl_texture_image *texImage = tObj->Image[i];
775 if (texImage) {
776 if (texImage->DriverData) {
777 FREE(texImage->DriverData);
778 texImage->DriverData = NULL;
779 }
780 }
781 }
782 switch (ti->whichTMU) {
783 case FX_TMU0:
784 case FX_TMU1:
785 fxTMDeleteRangeNode(fxMesa, ti->tm[ti->whichTMU]);
786 break;
787 case FX_TMU_SPLIT:
788 case FX_TMU_BOTH:
789 fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU0]);
790 fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU1]);
791 break;
792 }
793 }
794
795 void
796 fxTMInit(fxMesaContext fxMesa)
797 {
798 fxMesa->texBindNumber = 0;
799 fxMesa->tmPool = 0;
800
801 if (fxMesa->HaveTexUma) {
802 grEnable(GR_TEXTURE_UMA_EXT);
803 }
804
805 fxTMUInit(fxMesa, FX_TMU0);
806
807 if (!fxMesa->HaveTexUma && fxMesa->haveTwoTMUs)
808 fxTMUInit(fxMesa, FX_TMU1);
809
810 texBoundMask = (fxMesa->type >= GR_SSTTYPE_Banshee) ? -1 : (FX_2MB_SPLIT - 1);
811 }
812
813 void
814 fxTMClose(fxMesaContext fxMesa)
815 {
816 MemRange *tmp, *next;
817
818 tmp = fxMesa->tmPool;
819 while (tmp) {
820 next = tmp->next;
821 FREE(tmp);
822 tmp = next;
823 }
824 tmp = fxMesa->tmFree[FX_TMU0];
825 while (tmp) {
826 next = tmp->next;
827 FREE(tmp);
828 tmp = next;
829 }
830 if (fxMesa->haveTwoTMUs) {
831 tmp = fxMesa->tmFree[FX_TMU1];
832 while (tmp) {
833 next = tmp->next;
834 FREE(tmp);
835 tmp = next;
836 }
837 }
838 }
839
840 void
841 fxTMRestoreTextures_NoLock(fxMesaContext ctx)
842 {
843 tfxTexInfo *ti;
844 struct gl_texture_object *tObj;
845 int i, where;
846
847 tObj = ctx->glCtx->Shared->TexObjectList;
848 while (tObj) {
849 ti = fxTMGetTexInfo(tObj);
850 if (ti && ti->isInTM) {
851 for (i = 0; i < MAX_TEXTURE_UNITS; i++)
852 if (ctx->glCtx->Texture.Unit[i]._Current == tObj) {
853 /* Force the texture onto the board, as it could be in use */
854 where = ti->whichTMU;
855 fxTMMoveOutTM_NoLock(ctx, tObj);
856 fxTMMoveInTM_NoLock(ctx, tObj, where);
857 break;
858 }
859 if (i == MAX_TEXTURE_UNITS) /* Mark the texture as off the board */
860 fxTMMoveOutTM_NoLock(ctx, tObj);
861 }
862 tObj = tObj->Next;
863 }
864 }
865
866 #else
867
868
869 /*
870 * Need this to provide at least one external definition.
871 */
872
873 extern int gl_fx_dummy_function_texman(void);
874 int
875 gl_fx_dummy_function_texman(void)
876 {
877 return 0;
878 }
879
880 #endif /* FX */