b43b40e3855ad25107e889dcbcdbe68538da36b0
[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 TMU%d configuration:\n", tmu);
156 }
157
158 fxMesa->freeTexMem[tmu] = end - start;
159 fxMesa->tmFree[tmu] = NULL;
160
161 last = 0;
162 blockstart = start;
163 while (blockstart < end) {
164 if (blockstart + chunk > end)
165 blockend = end;
166 else
167 blockend = blockstart + chunk;
168
169 if (fxMesa->verbose)
170 fprintf(stderr, "Voodoo %08u-%08u\n",
171 (unsigned int) blockstart, (unsigned int) blockend);
172
173 tmn = fxTMNewRangeNode(fxMesa, blockstart, blockend);
174 tmn->next = NULL;
175
176
177 if (last)
178 last->next = tmn;
179 else
180 fxMesa->tmFree[tmu] = tmn;
181 last = tmn;
182
183 blockstart += chunk;
184 }
185 }
186
187 static int
188 fxTMFindStartAddr(fxMesaContext fxMesa, GLint tmu, int size)
189 {
190 MemRange *prev, *tmp;
191 int result;
192 struct gl_texture_object *obj;
193
194 if (fxMesa->HaveTexUma) {
195 tmu = FX_TMU0;
196 }
197
198 while (1) {
199 prev = 0;
200 tmp = fxMesa->tmFree[tmu];
201 while (tmp) {
202 if (tmp->endAddr - tmp->startAddr >= size) { /* Fits here */
203 result = tmp->startAddr;
204 tmp->startAddr += size;
205 if (tmp->startAddr == tmp->endAddr) { /* Empty */
206 if (prev) {
207 prev->next = tmp->next;
208 }
209 else {
210 fxMesa->tmFree[tmu] = tmp->next;
211 }
212 fxTMDeleteRangeNode(fxMesa, tmp);
213 }
214 fxMesa->freeTexMem[tmu] -= size;
215 return result;
216 }
217 prev = tmp;
218 tmp = tmp->next;
219 }
220 /* No free space. Discard oldest */
221 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
222 fprintf(stderr, "fxTMFindStartAddr: No free space. Discard oldest\n");
223 }
224 obj = fxTMFindOldestObject(fxMesa, tmu);
225 if (!obj) {
226 fprintf(stderr, "fxTMFindStartAddr: ERROR: No space for texture\n");
227 return -1;
228 }
229 fxTMMoveOutTM(fxMesa, obj);
230 texSwaps++;
231 }
232 }
233
234 int fxTMCheckStartAddr (fxMesaContext fxMesa, GLint tmu, tfxTexInfo *ti)
235 {
236 MemRange *tmp;
237 int size;
238
239 if (fxMesa->HaveTexUma) {
240 return FXTRUE;
241 }
242
243 size = grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
244
245 tmp = fxMesa->tmFree[tmu];
246 while (tmp) {
247 if (tmp->endAddr - tmp->startAddr >= size) { /* Fits here */
248 return FXTRUE;
249 }
250 tmp = tmp->next;
251 }
252
253 return FXFALSE;
254 }
255
256 static void
257 fxTMRemoveRange(fxMesaContext fxMesa, GLint tmu, MemRange * range)
258 {
259 MemRange *tmp, *prev;
260
261 if (fxMesa->HaveTexUma) {
262 tmu = FX_TMU0;
263 }
264
265 if (range->startAddr == range->endAddr) {
266 fxTMDeleteRangeNode(fxMesa, range);
267 return;
268 }
269 fxMesa->freeTexMem[tmu] += range->endAddr - range->startAddr;
270 prev = 0;
271 tmp = fxMesa->tmFree[tmu];
272 while (tmp) {
273 if (range->startAddr > tmp->startAddr) {
274 prev = tmp;
275 tmp = tmp->next;
276 }
277 else
278 break;
279 }
280 /* When we create the regions, we make a split at the 2MB boundary.
281 Now we have to make sure we don't join those 2MB boundary regions
282 back together again. */
283 range->next = tmp;
284 if (tmp) {
285 if (range->endAddr == tmp->startAddr
286 && tmp->startAddr & texBoundMask) {
287 /* Combine */
288 tmp->startAddr = range->startAddr;
289 fxTMDeleteRangeNode(fxMesa, range);
290 range = tmp;
291 }
292 }
293 if (prev) {
294 if (prev->endAddr == range->startAddr
295 && range->startAddr & texBoundMask) {
296 /* Combine */
297 prev->endAddr = range->endAddr;
298 prev->next = range->next;
299 fxTMDeleteRangeNode(fxMesa, range);
300 }
301 else
302 prev->next = range;
303 }
304 else {
305 fxMesa->tmFree[tmu] = range;
306 }
307 }
308
309 static struct gl_texture_object *
310 fxTMFindOldestObject(fxMesaContext fxMesa, int tmu)
311 {
312 GLuint age, old, lasttime, bindnumber;
313 GLfloat lowestPriority;
314 tfxTexInfo *info;
315 struct gl_texture_object *obj, *tmp, *lowestPriorityObj;
316
317 tmp = fxMesa->glCtx->Shared->TexObjectList;
318 if (!tmp)
319 return 0;
320 obj = NULL;
321 old = 0;
322
323 lowestPriorityObj = NULL;
324 lowestPriority = 1.0F;
325
326 bindnumber = fxMesa->texBindNumber;
327 while (tmp) {
328 info = fxTMGetTexInfo(tmp);
329
330 if (info && info->isInTM &&
331 ((info->whichTMU == tmu) ||
332 (info->whichTMU == FX_TMU_BOTH) ||
333 (info->whichTMU == FX_TMU_SPLIT) ||
334 fxMesa->HaveTexUma
335 )
336 ) {
337 lasttime = info->lastTimeUsed;
338
339 if (lasttime > bindnumber)
340 age = bindnumber + (UINT_MAX - lasttime + 1); /* TO DO: check wrap around */
341 else
342 age = bindnumber - lasttime;
343
344 if (age >= old) {
345 old = age;
346 obj = tmp;
347 }
348
349 /* examine priority */
350 if (tmp->Priority < lowestPriority) {
351 lowestPriority = tmp->Priority;
352 lowestPriorityObj = tmp;
353 }
354 }
355 tmp = tmp->Next;
356 }
357
358 if (lowestPriorityObj != NULL) {
359 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
360 fprintf(stderr, "fxTMFindOldestObject: %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
361 }
362 return lowestPriorityObj;
363 }
364 else {
365 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
366 if (obj != NULL) {
367 fprintf(stderr, "fxTMFindOldestObject: %d age=%d\n", obj->Name, old);
368 }
369 }
370 return obj;
371 }
372 }
373
374 static MemRange *
375 fxTMAddObj(fxMesaContext fxMesa,
376 struct gl_texture_object *tObj, GLint tmu, int texmemsize)
377 {
378 FxI32 startAddr;
379 MemRange *range;
380
381 startAddr = fxTMFindStartAddr(fxMesa, tmu, texmemsize);
382 if (startAddr < 0)
383 return 0;
384 range = fxTMNewRangeNode(fxMesa, startAddr, startAddr + texmemsize);
385 return range;
386 }
387
388 /* External Functions */
389
390 void
391 fxTMMoveInTM_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj,
392 GLint where)
393 {
394 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
395 int i, l;
396 int texmemsize;
397
398 if (TDFX_DEBUG & VERBOSE_DRIVER) {
399 fprintf(stderr, "fxTMMoveInTM_NoLock(%d)\n", tObj->Name);
400 }
401
402 fxMesa->stats.reqTexUpload++;
403
404 if (!ti->validated) {
405 fprintf(stderr, "fxTMMoveInTM_NoLock: INTERNAL ERROR: not validated\n");
406 fxCloseHardware();
407 exit(-1);
408 }
409
410 if (ti->isInTM) {
411 if (ti->whichTMU == where)
412 return;
413 if (where == FX_TMU_SPLIT || ti->whichTMU == FX_TMU_SPLIT)
414 fxTMMoveOutTM_NoLock(fxMesa, tObj);
415 else {
416 if (ti->whichTMU == FX_TMU_BOTH)
417 return;
418 where = FX_TMU_BOTH;
419 }
420 }
421
422 if (TDFX_DEBUG & (VERBOSE_DRIVER | VERBOSE_TEXTURE)) {
423 fprintf(stderr, "fxTMMoveInTM_NoLock: downloading %p (%d) in texture memory in %d\n",
424 (void *)tObj, tObj->Name, where);
425 }
426
427 ti->whichTMU = (FxU32) where;
428
429 switch (where) {
430 case FX_TMU0:
431 case FX_TMU1:
432 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
433 ti->tm[where] = fxTMAddObj(fxMesa, tObj, where, texmemsize);
434 fxMesa->stats.memTexUpload += texmemsize;
435
436 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
437 i <= FX_smallLodValue(ti->info); i++, l++) {
438 struct gl_texture_image *texImage = tObj->Image[0][l];
439 grTexDownloadMipMapLevel(where,
440 ti->tm[where]->startAddr,
441 FX_valueToLod(i),
442 FX_largeLodLog2(ti->info),
443 FX_aspectRatioLog2(ti->info),
444 ti->info.format,
445 GR_MIPMAPLEVELMASK_BOTH,
446 texImage->Data);
447 }
448 break;
449 case FX_TMU_SPLIT:
450 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD, &(ti->info));
451 ti->tm[FX_TMU0] = fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
452 fxMesa->stats.memTexUpload += texmemsize;
453
454 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN, &(ti->info));
455 ti->tm[FX_TMU1] = fxTMAddObj(fxMesa, tObj, FX_TMU1, texmemsize);
456 fxMesa->stats.memTexUpload += texmemsize;
457
458 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
459 i <= FX_smallLodValue(ti->info); i++, l++) {
460 struct gl_texture_image *texImage = tObj->Image[0][l];
461
462 grTexDownloadMipMapLevel(GR_TMU0,
463 ti->tm[FX_TMU0]->startAddr,
464 FX_valueToLod(i),
465 FX_largeLodLog2(ti->info),
466 FX_aspectRatioLog2(ti->info),
467 ti->info.format,
468 GR_MIPMAPLEVELMASK_ODD,
469 texImage->Data);
470
471 grTexDownloadMipMapLevel(GR_TMU1,
472 ti->tm[FX_TMU1]->startAddr,
473 FX_valueToLod(i),
474 FX_largeLodLog2(ti->info),
475 FX_aspectRatioLog2(ti->info),
476 ti->info.format,
477 GR_MIPMAPLEVELMASK_EVEN,
478 texImage->Data);
479 }
480 break;
481 case FX_TMU_BOTH:
482 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
483 ti->tm[FX_TMU0] = fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
484 fxMesa->stats.memTexUpload += texmemsize;
485
486 /*texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));*/
487 ti->tm[FX_TMU1] = fxTMAddObj(fxMesa, tObj, FX_TMU1, texmemsize);
488 fxMesa->stats.memTexUpload += texmemsize;
489
490 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
491 i <= FX_smallLodValue(ti->info); i++, l++) {
492 struct gl_texture_image *texImage = tObj->Image[0][l];
493 grTexDownloadMipMapLevel(GR_TMU0,
494 ti->tm[FX_TMU0]->startAddr,
495 FX_valueToLod(i),
496 FX_largeLodLog2(ti->info),
497 FX_aspectRatioLog2(ti->info),
498 ti->info.format,
499 GR_MIPMAPLEVELMASK_BOTH,
500 texImage->Data);
501
502 grTexDownloadMipMapLevel(GR_TMU1,
503 ti->tm[FX_TMU1]->startAddr,
504 FX_valueToLod(i),
505 FX_largeLodLog2(ti->info),
506 FX_aspectRatioLog2(ti->info),
507 ti->info.format,
508 GR_MIPMAPLEVELMASK_BOTH,
509 texImage->Data);
510 }
511 break;
512 default:
513 fprintf(stderr, "fxTMMoveInTM_NoLock: INTERNAL ERROR: wrong tmu (%d)\n", where);
514 fxCloseHardware();
515 exit(-1);
516 }
517
518 fxMesa->stats.texUpload++;
519
520 ti->isInTM = GL_TRUE;
521 }
522
523
524 void
525 fxTMMoveInTM(fxMesaContext fxMesa, struct gl_texture_object *tObj,
526 GLint where)
527 {
528 BEGIN_BOARD_LOCK();
529 fxTMMoveInTM_NoLock(fxMesa, tObj, where);
530 END_BOARD_LOCK();
531 }
532
533
534 void
535 fxTMReloadMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj,
536 GLint level)
537 {
538 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
539 GrLOD_t lodlevel;
540 GLint tmu;
541 struct gl_texture_image *texImage = tObj->Image[0][level];
542 tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
543
544 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
545 fprintf(stderr, "fxTMReloadMipMapLevel(%p (%d), %d)\n", (void *)tObj, tObj->Name, level);
546 }
547
548 assert(mml);
549 assert(mml->width > 0);
550 assert(mml->height > 0);
551 assert(mml->glideFormat > 0);
552 assert(ti->isInTM);
553
554 if (!ti->validated) {
555 fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: not validated\n");
556 fxCloseHardware();
557 exit(-1);
558 }
559
560 tmu = (int) ti->whichTMU;
561 fxMesa->stats.reqTexUpload++;
562 fxMesa->stats.texUpload++;
563
564 lodlevel = ti->info.largeLodLog2 - (level - ti->minLevel);
565
566 switch (tmu) {
567 case FX_TMU0:
568 case FX_TMU1:
569 grTexDownloadMipMapLevel(tmu,
570 ti->tm[tmu]->startAddr,
571 lodlevel,
572 FX_largeLodLog2(ti->info),
573 FX_aspectRatioLog2(ti->info),
574 ti->info.format,
575 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
576 break;
577 case FX_TMU_SPLIT:
578 grTexDownloadMipMapLevel(GR_TMU0,
579 ti->tm[GR_TMU0]->startAddr,
580 lodlevel,
581 FX_largeLodLog2(ti->info),
582 FX_aspectRatioLog2(ti->info),
583 ti->info.format,
584 GR_MIPMAPLEVELMASK_ODD, texImage->Data);
585
586 grTexDownloadMipMapLevel(GR_TMU1,
587 ti->tm[GR_TMU1]->startAddr,
588 lodlevel,
589 FX_largeLodLog2(ti->info),
590 FX_aspectRatioLog2(ti->info),
591 ti->info.format,
592 GR_MIPMAPLEVELMASK_EVEN, texImage->Data);
593 break;
594 case FX_TMU_BOTH:
595 grTexDownloadMipMapLevel(GR_TMU0,
596 ti->tm[GR_TMU0]->startAddr,
597 lodlevel,
598 FX_largeLodLog2(ti->info),
599 FX_aspectRatioLog2(ti->info),
600 ti->info.format,
601 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
602
603 grTexDownloadMipMapLevel(GR_TMU1,
604 ti->tm[GR_TMU1]->startAddr,
605 lodlevel,
606 FX_largeLodLog2(ti->info),
607 FX_aspectRatioLog2(ti->info),
608 ti->info.format,
609 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
610 break;
611
612 default:
613 fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
614 fxCloseHardware();
615 exit(-1);
616 }
617 }
618
619 void
620 fxTMReloadSubMipMapLevel(fxMesaContext fxMesa,
621 struct gl_texture_object *tObj,
622 GLint level, GLint yoffset, GLint height)
623 {
624 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
625 GrLOD_t lodlevel;
626 unsigned short *data;
627 GLint tmu;
628 struct gl_texture_image *texImage = tObj->Image[0][level];
629 tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
630
631 assert(mml);
632
633 if (!ti->validated) {
634 fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: not validated\n");
635 fxCloseHardware();
636 exit(-1);
637 }
638
639 tmu = (int) ti->whichTMU;
640 fxTMMoveInTM(fxMesa, tObj, tmu);
641
642 fxTexGetInfo(mml->width, mml->height,
643 &lodlevel, NULL, NULL, NULL, NULL, NULL);
644
645 if ((ti->info.format == GR_TEXFMT_INTENSITY_8) ||
646 (ti->info.format == GR_TEXFMT_P_8) ||
647 (ti->info.format == GR_TEXFMT_ALPHA_8))
648 data = (GLushort *) texImage->Data + ((yoffset * mml->width) >> 1);
649 else
650 data = (GLushort *) texImage->Data + yoffset * mml->width;
651
652 switch (tmu) {
653 case FX_TMU0:
654 case FX_TMU1:
655 grTexDownloadMipMapLevelPartial(tmu,
656 ti->tm[tmu]->startAddr,
657 FX_valueToLod(FX_lodToValue(lodlevel)
658 + level),
659 FX_largeLodLog2(ti->info),
660 FX_aspectRatioLog2(ti->info),
661 ti->info.format,
662 GR_MIPMAPLEVELMASK_BOTH, data,
663 yoffset, yoffset + height - 1);
664 break;
665 case FX_TMU_SPLIT:
666 grTexDownloadMipMapLevelPartial(GR_TMU0,
667 ti->tm[FX_TMU0]->startAddr,
668 FX_valueToLod(FX_lodToValue(lodlevel)
669 + level),
670 FX_largeLodLog2(ti->info),
671 FX_aspectRatioLog2(ti->info),
672 ti->info.format,
673 GR_MIPMAPLEVELMASK_ODD, data,
674 yoffset, yoffset + height - 1);
675
676 grTexDownloadMipMapLevelPartial(GR_TMU1,
677 ti->tm[FX_TMU1]->startAddr,
678 FX_valueToLod(FX_lodToValue(lodlevel)
679 + level),
680 FX_largeLodLog2(ti->info),
681 FX_aspectRatioLog2(ti->info),
682 ti->info.format,
683 GR_MIPMAPLEVELMASK_EVEN, data,
684 yoffset, yoffset + height - 1);
685 break;
686 case FX_TMU_BOTH:
687 grTexDownloadMipMapLevelPartial(GR_TMU0,
688 ti->tm[FX_TMU0]->startAddr,
689 FX_valueToLod(FX_lodToValue(lodlevel)
690 + level),
691 FX_largeLodLog2(ti->info),
692 FX_aspectRatioLog2(ti->info),
693 ti->info.format,
694 GR_MIPMAPLEVELMASK_BOTH, data,
695 yoffset, yoffset + height - 1);
696
697 grTexDownloadMipMapLevelPartial(GR_TMU1,
698 ti->tm[FX_TMU1]->startAddr,
699 FX_valueToLod(FX_lodToValue(lodlevel)
700 + level),
701 FX_largeLodLog2(ti->info),
702 FX_aspectRatioLog2(ti->info),
703 ti->info.format,
704 GR_MIPMAPLEVELMASK_BOTH, data,
705 yoffset, yoffset + height - 1);
706 break;
707 default:
708 fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
709 fxCloseHardware();
710 exit(-1);
711 }
712 }
713
714 void
715 fxTMMoveOutTM(fxMesaContext fxMesa, struct gl_texture_object *tObj)
716 {
717 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
718
719 if (TDFX_DEBUG & VERBOSE_DRIVER) {
720 fprintf(stderr, "fxTMMoveOutTM(%p (%d))\n", (void *)tObj, tObj->Name);
721 }
722
723 if (!ti->isInTM)
724 return;
725
726 switch (ti->whichTMU) {
727 case FX_TMU0:
728 case FX_TMU1:
729 fxTMRemoveRange(fxMesa, (int) ti->whichTMU, ti->tm[ti->whichTMU]);
730 break;
731 case FX_TMU_SPLIT:
732 case FX_TMU_BOTH:
733 fxTMRemoveRange(fxMesa, FX_TMU0, ti->tm[FX_TMU0]);
734 fxTMRemoveRange(fxMesa, FX_TMU1, ti->tm[FX_TMU1]);
735 break;
736 default:
737 fprintf(stderr, "fxTMMoveOutTM: INTERNAL ERROR: bad TMU (%ld)\n", ti->whichTMU);
738 fxCloseHardware();
739 exit(-1);
740 }
741
742 ti->isInTM = GL_FALSE;
743 ti->whichTMU = FX_TMU_NONE;
744 }
745
746 void
747 fxTMFreeTexture(fxMesaContext fxMesa, struct gl_texture_object *tObj)
748 {
749 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
750 int i;
751
752 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
753 fprintf(stderr, "fxTMFreeTexture(%p (%d))\n", (void *)tObj, tObj->Name);
754 }
755
756 fxTMMoveOutTM(fxMesa, tObj);
757
758 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
759 struct gl_texture_image *texImage = tObj->Image[0][i];
760 if (texImage) {
761 if (texImage->DriverData) {
762 FREE(texImage->DriverData);
763 texImage->DriverData = NULL;
764 }
765 }
766 }
767 switch (ti->whichTMU) {
768 case FX_TMU0:
769 case FX_TMU1:
770 fxTMDeleteRangeNode(fxMesa, ti->tm[ti->whichTMU]);
771 break;
772 case FX_TMU_SPLIT:
773 case FX_TMU_BOTH:
774 fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU0]);
775 fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU1]);
776 break;
777 }
778 }
779
780 void
781 fxTMInit(fxMesaContext fxMesa)
782 {
783 fxMesa->texBindNumber = 0;
784 fxMesa->tmPool = 0;
785
786 if (fxMesa->HaveTexUma) {
787 grEnable(GR_TEXTURE_UMA_EXT);
788 }
789
790 fxTMUInit(fxMesa, FX_TMU0);
791
792 if (!fxMesa->HaveTexUma && fxMesa->haveTwoTMUs)
793 fxTMUInit(fxMesa, FX_TMU1);
794
795 texBoundMask = (fxMesa->type >= GR_SSTTYPE_Banshee) ? -1 : (FX_2MB_SPLIT - 1);
796 }
797
798 void
799 fxTMClose(fxMesaContext fxMesa)
800 {
801 MemRange *tmp, *next;
802
803 tmp = fxMesa->tmPool;
804 while (tmp) {
805 next = tmp->next;
806 FREE(tmp);
807 tmp = next;
808 }
809 tmp = fxMesa->tmFree[FX_TMU0];
810 while (tmp) {
811 next = tmp->next;
812 FREE(tmp);
813 tmp = next;
814 }
815 if (fxMesa->haveTwoTMUs) {
816 tmp = fxMesa->tmFree[FX_TMU1];
817 while (tmp) {
818 next = tmp->next;
819 FREE(tmp);
820 tmp = next;
821 }
822 }
823 }
824
825 void
826 fxTMRestoreTextures_NoLock(fxMesaContext ctx)
827 {
828 tfxTexInfo *ti;
829 struct gl_texture_object *tObj;
830 int i, where;
831
832 tObj = ctx->glCtx->Shared->TexObjectList;
833 while (tObj) {
834 ti = fxTMGetTexInfo(tObj);
835 if (ti && ti->isInTM) {
836 for (i = 0; i < MAX_TEXTURE_UNITS; i++)
837 if (ctx->glCtx->Texture.Unit[i]._Current == tObj) {
838 /* Force the texture onto the board, as it could be in use */
839 where = ti->whichTMU;
840 fxTMMoveOutTM_NoLock(ctx, tObj);
841 fxTMMoveInTM_NoLock(ctx, tObj, where);
842 break;
843 }
844 if (i == MAX_TEXTURE_UNITS) /* Mark the texture as off the board */
845 fxTMMoveOutTM_NoLock(ctx, tObj);
846 }
847 tObj = tObj->Next;
848 }
849 }
850
851 #else
852
853
854 /*
855 * Need this to provide at least one external definition.
856 */
857
858 extern int gl_fx_dummy_function_texman(void);
859 int
860 gl_fx_dummy_function_texman(void)
861 {
862 return 0;
863 }
864
865 #endif /* FX */