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