Removed _swrast_validate_pbo_access().
[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;
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 assert(ti->isInTM);
554
555 if (!ti->validated) {
556 fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: not validated\n");
557 fxCloseHardware();
558 exit(-1);
559 }
560
561 tmu = (int) ti->whichTMU;
562 fxMesa->stats.reqTexUpload++;
563 fxMesa->stats.texUpload++;
564
565 lodlevel = ti->info.largeLodLog2 - (level - ti->minLevel);
566
567 switch (tmu) {
568 case FX_TMU0:
569 case FX_TMU1:
570 grTexDownloadMipMapLevel(tmu,
571 ti->tm[tmu]->startAddr,
572 lodlevel,
573 FX_largeLodLog2(ti->info),
574 FX_aspectRatioLog2(ti->info),
575 ti->info.format,
576 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
577 break;
578 case FX_TMU_SPLIT:
579 grTexDownloadMipMapLevel(GR_TMU0,
580 ti->tm[GR_TMU0]->startAddr,
581 lodlevel,
582 FX_largeLodLog2(ti->info),
583 FX_aspectRatioLog2(ti->info),
584 ti->info.format,
585 GR_MIPMAPLEVELMASK_ODD, texImage->Data);
586
587 grTexDownloadMipMapLevel(GR_TMU1,
588 ti->tm[GR_TMU1]->startAddr,
589 lodlevel,
590 FX_largeLodLog2(ti->info),
591 FX_aspectRatioLog2(ti->info),
592 ti->info.format,
593 GR_MIPMAPLEVELMASK_EVEN, texImage->Data);
594 break;
595 case FX_TMU_BOTH:
596 grTexDownloadMipMapLevel(GR_TMU0,
597 ti->tm[GR_TMU0]->startAddr,
598 lodlevel,
599 FX_largeLodLog2(ti->info),
600 FX_aspectRatioLog2(ti->info),
601 ti->info.format,
602 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
603
604 grTexDownloadMipMapLevel(GR_TMU1,
605 ti->tm[GR_TMU1]->startAddr,
606 lodlevel,
607 FX_largeLodLog2(ti->info),
608 FX_aspectRatioLog2(ti->info),
609 ti->info.format,
610 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
611 break;
612
613 default:
614 fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
615 fxCloseHardware();
616 exit(-1);
617 }
618 }
619
620 void
621 fxTMReloadSubMipMapLevel(fxMesaContext fxMesa,
622 struct gl_texture_object *tObj,
623 GLint level, GLint yoffset, GLint height)
624 {
625 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
626 GrLOD_t lodlevel;
627 unsigned short *data;
628 GLint tmu;
629 struct gl_texture_image *texImage = tObj->Image[0][level];
630 tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
631
632 assert(mml);
633
634 if (!ti->validated) {
635 fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: not validated\n");
636 fxCloseHardware();
637 exit(-1);
638 }
639
640 tmu = (int) ti->whichTMU;
641 fxTMMoveInTM(fxMesa, tObj, tmu);
642
643 fxTexGetInfo(mml->width, mml->height,
644 &lodlevel, NULL, NULL, NULL, NULL, NULL);
645
646 if ((ti->info.format == GR_TEXFMT_INTENSITY_8) ||
647 (ti->info.format == GR_TEXFMT_P_8) ||
648 (ti->info.format == GR_TEXFMT_ALPHA_8))
649 data = (GLushort *) texImage->Data + ((yoffset * mml->width) >> 1);
650 else
651 data = (GLushort *) texImage->Data + yoffset * mml->width;
652
653 switch (tmu) {
654 case FX_TMU0:
655 case FX_TMU1:
656 grTexDownloadMipMapLevelPartial(tmu,
657 ti->tm[tmu]->startAddr,
658 FX_valueToLod(FX_lodToValue(lodlevel)
659 + level),
660 FX_largeLodLog2(ti->info),
661 FX_aspectRatioLog2(ti->info),
662 ti->info.format,
663 GR_MIPMAPLEVELMASK_BOTH, data,
664 yoffset, yoffset + height - 1);
665 break;
666 case FX_TMU_SPLIT:
667 grTexDownloadMipMapLevelPartial(GR_TMU0,
668 ti->tm[FX_TMU0]->startAddr,
669 FX_valueToLod(FX_lodToValue(lodlevel)
670 + level),
671 FX_largeLodLog2(ti->info),
672 FX_aspectRatioLog2(ti->info),
673 ti->info.format,
674 GR_MIPMAPLEVELMASK_ODD, data,
675 yoffset, yoffset + height - 1);
676
677 grTexDownloadMipMapLevelPartial(GR_TMU1,
678 ti->tm[FX_TMU1]->startAddr,
679 FX_valueToLod(FX_lodToValue(lodlevel)
680 + level),
681 FX_largeLodLog2(ti->info),
682 FX_aspectRatioLog2(ti->info),
683 ti->info.format,
684 GR_MIPMAPLEVELMASK_EVEN, data,
685 yoffset, yoffset + height - 1);
686 break;
687 case FX_TMU_BOTH:
688 grTexDownloadMipMapLevelPartial(GR_TMU0,
689 ti->tm[FX_TMU0]->startAddr,
690 FX_valueToLod(FX_lodToValue(lodlevel)
691 + level),
692 FX_largeLodLog2(ti->info),
693 FX_aspectRatioLog2(ti->info),
694 ti->info.format,
695 GR_MIPMAPLEVELMASK_BOTH, data,
696 yoffset, yoffset + height - 1);
697
698 grTexDownloadMipMapLevelPartial(GR_TMU1,
699 ti->tm[FX_TMU1]->startAddr,
700 FX_valueToLod(FX_lodToValue(lodlevel)
701 + level),
702 FX_largeLodLog2(ti->info),
703 FX_aspectRatioLog2(ti->info),
704 ti->info.format,
705 GR_MIPMAPLEVELMASK_BOTH, data,
706 yoffset, yoffset + height - 1);
707 break;
708 default:
709 fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
710 fxCloseHardware();
711 exit(-1);
712 }
713 }
714
715 void
716 fxTMMoveOutTM(fxMesaContext fxMesa, struct gl_texture_object *tObj)
717 {
718 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
719
720 if (TDFX_DEBUG & VERBOSE_DRIVER) {
721 fprintf(stderr, "fxTMMoveOutTM(%p (%d))\n", (void *)tObj, tObj->Name);
722 }
723
724 if (!ti->isInTM)
725 return;
726
727 switch (ti->whichTMU) {
728 case FX_TMU0:
729 case FX_TMU1:
730 fxTMRemoveRange(fxMesa, (int) ti->whichTMU, ti->tm[ti->whichTMU]);
731 break;
732 case FX_TMU_SPLIT:
733 case FX_TMU_BOTH:
734 fxTMRemoveRange(fxMesa, FX_TMU0, ti->tm[FX_TMU0]);
735 fxTMRemoveRange(fxMesa, FX_TMU1, ti->tm[FX_TMU1]);
736 break;
737 default:
738 fprintf(stderr, "fxTMMoveOutTM: INTERNAL ERROR: bad TMU (%ld)\n", ti->whichTMU);
739 fxCloseHardware();
740 exit(-1);
741 }
742
743 ti->isInTM = GL_FALSE;
744 ti->whichTMU = FX_TMU_NONE;
745 }
746
747 void
748 fxTMFreeTexture(fxMesaContext fxMesa, struct gl_texture_object *tObj)
749 {
750 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
751 int i;
752
753 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
754 fprintf(stderr, "fxTMFreeTexture(%p (%d))\n", (void *)tObj, tObj->Name);
755 }
756
757 fxTMMoveOutTM(fxMesa, tObj);
758
759 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
760 struct gl_texture_image *texImage = tObj->Image[0][i];
761 if (texImage) {
762 if (texImage->DriverData) {
763 FREE(texImage->DriverData);
764 texImage->DriverData = NULL;
765 }
766 }
767 }
768 switch (ti->whichTMU) {
769 case FX_TMU0:
770 case FX_TMU1:
771 fxTMDeleteRangeNode(fxMesa, ti->tm[ti->whichTMU]);
772 break;
773 case FX_TMU_SPLIT:
774 case FX_TMU_BOTH:
775 fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU0]);
776 fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU1]);
777 break;
778 }
779 }
780
781 void
782 fxTMInit(fxMesaContext fxMesa)
783 {
784 fxMesa->texBindNumber = 0;
785 fxMesa->tmPool = 0;
786
787 if (fxMesa->HaveTexUma) {
788 grEnable(GR_TEXTURE_UMA_EXT);
789 }
790
791 fxTMUInit(fxMesa, FX_TMU0);
792
793 if (!fxMesa->HaveTexUma && fxMesa->haveTwoTMUs)
794 fxTMUInit(fxMesa, FX_TMU1);
795
796 texBoundMask = (fxMesa->type >= GR_SSTTYPE_Banshee) ? -1 : (FX_2MB_SPLIT - 1);
797 }
798
799 void
800 fxTMClose(fxMesaContext fxMesa)
801 {
802 MemRange *tmp, *next;
803
804 tmp = fxMesa->tmPool;
805 while (tmp) {
806 next = tmp->next;
807 FREE(tmp);
808 tmp = next;
809 }
810 tmp = fxMesa->tmFree[FX_TMU0];
811 while (tmp) {
812 next = tmp->next;
813 FREE(tmp);
814 tmp = next;
815 }
816 if (fxMesa->haveTwoTMUs) {
817 tmp = fxMesa->tmFree[FX_TMU1];
818 while (tmp) {
819 next = tmp->next;
820 FREE(tmp);
821 tmp = next;
822 }
823 }
824 }
825
826 void
827 fxTMRestoreTextures_NoLock(fxMesaContext ctx)
828 {
829 tfxTexInfo *ti;
830 struct gl_texture_object *tObj;
831 int i, where;
832
833 tObj = ctx->glCtx->Shared->TexObjectList;
834 while (tObj) {
835 ti = fxTMGetTexInfo(tObj);
836 if (ti && ti->isInTM) {
837 for (i = 0; i < MAX_TEXTURE_UNITS; i++)
838 if (ctx->glCtx->Texture.Unit[i]._Current == tObj) {
839 /* Force the texture onto the board, as it could be in use */
840 where = ti->whichTMU;
841 fxTMMoveOutTM_NoLock(ctx, tObj);
842 fxTMMoveInTM_NoLock(ctx, tObj, where);
843 break;
844 }
845 if (i == MAX_TEXTURE_UNITS) /* Mark the texture as off the board */
846 fxTMMoveOutTM_NoLock(ctx, tObj);
847 }
848 tObj = tObj->Next;
849 }
850 }
851
852 #else
853
854
855 /*
856 * Need this to provide at least one external definition.
857 */
858
859 extern int gl_fx_dummy_function_texman(void);
860 int
861 gl_fx_dummy_function_texman(void)
862 {
863 return 0;
864 }
865
866 #endif /* FX */