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