i965: Remove BRW_WM_LOCK dirty bit, introduced to work around lack of relocs.
[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 "hash.h"
44 #include "fxdrv.h"
45
46 int texSwaps = 0;
47 static FxU32 texBoundMask;
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, "fxTMNewRangeNode: ERROR: out of memory!\n");
120 fxCloseHardware();
121 exit(-1);
122 }
123 }
124 result->startAddr = start;
125 result->endAddr = end;
126 return result;
127 }
128
129 #if 1
130 #define fxTMDeleteRangeNode(fxMesa, range) \
131 do { \
132 range->next = fxMesa->tmPool; \
133 fxMesa->tmPool = range; \
134 } while (0);
135 #else
136 static void
137 fxTMDeleteRangeNode(fxMesaContext fxMesa, MemRange * range)
138 {
139 range->next = fxMesa->tmPool;
140 fxMesa->tmPool = range;
141 }
142 #endif
143
144 static void
145 fxTMUInit(fxMesaContext fxMesa, int tmu)
146 {
147 MemRange *tmn, *last;
148 FxU32 start, end, blockstart, blockend, chunk;
149
150 start = grTexMinAddress(tmu);
151 end = grTexMaxAddress(tmu);
152
153 chunk = (fxMesa->type >= GR_SSTTYPE_Banshee) ? (end - start) : FX_2MB_SPLIT;
154
155 if (fxMesa->verbose) {
156 fprintf(stderr, "Voodoo TMU%d configuration:\n", tmu);
157 }
158
159 fxMesa->freeTexMem[tmu] = end - start;
160 fxMesa->tmFree[tmu] = NULL;
161
162 last = 0;
163 blockstart = start;
164 while (blockstart < end) {
165 if (blockstart + chunk > end)
166 blockend = end;
167 else
168 blockend = blockstart + chunk;
169
170 if (fxMesa->verbose)
171 fprintf(stderr, "Voodoo %08u-%08u\n",
172 (unsigned int) blockstart, (unsigned int) blockend);
173
174 tmn = fxTMNewRangeNode(fxMesa, blockstart, blockend);
175 tmn->next = NULL;
176
177
178 if (last)
179 last->next = tmn;
180 else
181 fxMesa->tmFree[tmu] = tmn;
182 last = tmn;
183
184 blockstart += chunk;
185 }
186 }
187
188 static int
189 fxTMFindStartAddr(fxMesaContext fxMesa, GLint tmu, int size)
190 {
191 MemRange *prev, *tmp;
192 int result;
193 struct gl_texture_object *obj;
194
195 if (fxMesa->HaveTexUma) {
196 tmu = FX_TMU0;
197 }
198
199 while (1) {
200 prev = 0;
201 tmp = fxMesa->tmFree[tmu];
202 while (tmp) {
203 if (tmp->endAddr - tmp->startAddr >= size) { /* Fits here */
204 result = tmp->startAddr;
205 tmp->startAddr += size;
206 if (tmp->startAddr == tmp->endAddr) { /* Empty */
207 if (prev) {
208 prev->next = tmp->next;
209 }
210 else {
211 fxMesa->tmFree[tmu] = tmp->next;
212 }
213 fxTMDeleteRangeNode(fxMesa, tmp);
214 }
215 fxMesa->freeTexMem[tmu] -= size;
216 return result;
217 }
218 prev = tmp;
219 tmp = tmp->next;
220 }
221 /* No free space. Discard oldest */
222 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
223 fprintf(stderr, "fxTMFindStartAddr: No free space. Discard oldest\n");
224 }
225 obj = fxTMFindOldestObject(fxMesa, tmu);
226 if (!obj) {
227 fprintf(stderr, "fxTMFindStartAddr: ERROR: No space for texture\n");
228 return -1;
229 }
230 fxTMMoveOutTM(fxMesa, obj);
231 texSwaps++;
232 }
233 }
234
235 int fxTMCheckStartAddr (fxMesaContext fxMesa, GLint tmu, tfxTexInfo *ti)
236 {
237 MemRange *tmp;
238 int size;
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 struct gl_texture_object *obj, *lowestPriorityObj;
316 struct _mesa_HashTable *textures = fxMesa->glCtx->Shared->TexObjects;
317 GLuint id;
318
319 if (!_mesa_HashFirstEntry(textures))
320 return 0;
321
322 obj = NULL;
323 old = 0;
324
325 lowestPriorityObj = NULL;
326 lowestPriority = 1.0F;
327
328 bindnumber = fxMesa->texBindNumber;
329
330 for (id = _mesa_HashFirstEntry(textures);
331 id;
332 id = _mesa_HashNextEntry(textures, id)) {
333 struct gl_texture_object *tmp
334 = (struct gl_texture_object *) _mesa_HashLookup(textures, id);
335 tfxTexInfo *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 }
363
364 if (lowestPriorityObj != NULL) {
365 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
366 fprintf(stderr, "fxTMFindOldestObject: %d pri=%f\n", lowestPriorityObj->Name, lowestPriority);
367 }
368 return lowestPriorityObj;
369 }
370 else {
371 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
372 if (obj != NULL) {
373 fprintf(stderr, "fxTMFindOldestObject: %d age=%d\n", obj->Name, old);
374 }
375 }
376 return obj;
377 }
378 }
379
380 static MemRange *
381 fxTMAddObj(fxMesaContext fxMesa,
382 struct gl_texture_object *tObj, GLint tmu, int texmemsize)
383 {
384 FxI32 startAddr;
385 MemRange *range;
386
387 startAddr = fxTMFindStartAddr(fxMesa, tmu, texmemsize);
388 if (startAddr < 0)
389 return 0;
390 range = fxTMNewRangeNode(fxMesa, startAddr, startAddr + texmemsize);
391 return range;
392 }
393
394 /* External Functions */
395
396 void
397 fxTMMoveInTM_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj,
398 GLint where)
399 {
400 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
401 int i, l;
402 int texmemsize;
403
404 if (TDFX_DEBUG & VERBOSE_DRIVER) {
405 fprintf(stderr, "fxTMMoveInTM_NoLock(%d)\n", tObj->Name);
406 }
407
408 fxMesa->stats.reqTexUpload++;
409
410 if (!ti->validated) {
411 fprintf(stderr, "fxTMMoveInTM_NoLock: INTERNAL ERROR: not validated\n");
412 fxCloseHardware();
413 exit(-1);
414 }
415
416 if (ti->isInTM) {
417 if (ti->whichTMU == where)
418 return;
419 if (where == FX_TMU_SPLIT || ti->whichTMU == FX_TMU_SPLIT)
420 fxTMMoveOutTM_NoLock(fxMesa, tObj);
421 else {
422 if (ti->whichTMU == FX_TMU_BOTH)
423 return;
424 where = FX_TMU_BOTH;
425 }
426 }
427
428 if (TDFX_DEBUG & (VERBOSE_DRIVER | VERBOSE_TEXTURE)) {
429 fprintf(stderr, "fxTMMoveInTM_NoLock: downloading %p (%d) in texture memory in %d\n",
430 (void *)tObj, tObj->Name, where);
431 }
432
433 ti->whichTMU = (FxU32) where;
434
435 switch (where) {
436 case FX_TMU0:
437 case FX_TMU1:
438 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
439 ti->tm[where] = fxTMAddObj(fxMesa, tObj, where, texmemsize);
440 fxMesa->stats.memTexUpload += texmemsize;
441
442 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
443 i <= FX_smallLodValue(ti->info); i++, l++) {
444 struct gl_texture_image *texImage = tObj->Image[0][l];
445 grTexDownloadMipMapLevel(where,
446 ti->tm[where]->startAddr,
447 FX_valueToLod(i),
448 FX_largeLodLog2(ti->info),
449 FX_aspectRatioLog2(ti->info),
450 ti->info.format,
451 GR_MIPMAPLEVELMASK_BOTH,
452 texImage->Data);
453 }
454 break;
455 case FX_TMU_SPLIT:
456 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD, &(ti->info));
457 ti->tm[FX_TMU0] = fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
458 fxMesa->stats.memTexUpload += texmemsize;
459
460 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN, &(ti->info));
461 ti->tm[FX_TMU1] = fxTMAddObj(fxMesa, tObj, FX_TMU1, texmemsize);
462 fxMesa->stats.memTexUpload += texmemsize;
463
464 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
465 i <= FX_smallLodValue(ti->info); i++, l++) {
466 struct gl_texture_image *texImage = tObj->Image[0][l];
467
468 grTexDownloadMipMapLevel(GR_TMU0,
469 ti->tm[FX_TMU0]->startAddr,
470 FX_valueToLod(i),
471 FX_largeLodLog2(ti->info),
472 FX_aspectRatioLog2(ti->info),
473 ti->info.format,
474 GR_MIPMAPLEVELMASK_ODD,
475 texImage->Data);
476
477 grTexDownloadMipMapLevel(GR_TMU1,
478 ti->tm[FX_TMU1]->startAddr,
479 FX_valueToLod(i),
480 FX_largeLodLog2(ti->info),
481 FX_aspectRatioLog2(ti->info),
482 ti->info.format,
483 GR_MIPMAPLEVELMASK_EVEN,
484 texImage->Data);
485 }
486 break;
487 case FX_TMU_BOTH:
488 texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
489 ti->tm[FX_TMU0] = fxTMAddObj(fxMesa, tObj, FX_TMU0, texmemsize);
490 fxMesa->stats.memTexUpload += texmemsize;
491
492 /*texmemsize = (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH, &(ti->info));*/
493 ti->tm[FX_TMU1] = fxTMAddObj(fxMesa, tObj, FX_TMU1, texmemsize);
494 fxMesa->stats.memTexUpload += texmemsize;
495
496 for (i = FX_largeLodValue(ti->info), l = ti->minLevel;
497 i <= FX_smallLodValue(ti->info); i++, l++) {
498 struct gl_texture_image *texImage = tObj->Image[0][l];
499 grTexDownloadMipMapLevel(GR_TMU0,
500 ti->tm[FX_TMU0]->startAddr,
501 FX_valueToLod(i),
502 FX_largeLodLog2(ti->info),
503 FX_aspectRatioLog2(ti->info),
504 ti->info.format,
505 GR_MIPMAPLEVELMASK_BOTH,
506 texImage->Data);
507
508 grTexDownloadMipMapLevel(GR_TMU1,
509 ti->tm[FX_TMU1]->startAddr,
510 FX_valueToLod(i),
511 FX_largeLodLog2(ti->info),
512 FX_aspectRatioLog2(ti->info),
513 ti->info.format,
514 GR_MIPMAPLEVELMASK_BOTH,
515 texImage->Data);
516 }
517 break;
518 default:
519 fprintf(stderr, "fxTMMoveInTM_NoLock: INTERNAL ERROR: wrong tmu (%d)\n", where);
520 fxCloseHardware();
521 exit(-1);
522 }
523
524 fxMesa->stats.texUpload++;
525
526 ti->isInTM = GL_TRUE;
527 }
528
529
530 void
531 fxTMMoveInTM(fxMesaContext fxMesa, struct gl_texture_object *tObj,
532 GLint where)
533 {
534 BEGIN_BOARD_LOCK();
535 fxTMMoveInTM_NoLock(fxMesa, tObj, where);
536 END_BOARD_LOCK();
537 }
538
539
540 void
541 fxTMReloadMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj,
542 GLint level)
543 {
544 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
545 GrLOD_t lodlevel;
546 GLint tmu;
547 struct gl_texture_image *texImage = tObj->Image[0][level];
548 tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
549
550 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
551 fprintf(stderr, "fxTMReloadMipMapLevel(%p (%d), %d)\n", (void *)tObj, tObj->Name, level);
552 }
553
554 assert(mml);
555 assert(mml->width > 0);
556 assert(mml->height > 0);
557 assert(mml->glideFormat > 0);
558 assert(ti->isInTM);
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 fxMesa->stats.reqTexUpload++;
568 fxMesa->stats.texUpload++;
569
570 lodlevel = ti->info.largeLodLog2 - (level - ti->minLevel);
571
572 switch (tmu) {
573 case FX_TMU0:
574 case FX_TMU1:
575 grTexDownloadMipMapLevel(tmu,
576 ti->tm[tmu]->startAddr,
577 lodlevel,
578 FX_largeLodLog2(ti->info),
579 FX_aspectRatioLog2(ti->info),
580 ti->info.format,
581 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
582 break;
583 case FX_TMU_SPLIT:
584 grTexDownloadMipMapLevel(GR_TMU0,
585 ti->tm[GR_TMU0]->startAddr,
586 lodlevel,
587 FX_largeLodLog2(ti->info),
588 FX_aspectRatioLog2(ti->info),
589 ti->info.format,
590 GR_MIPMAPLEVELMASK_ODD, texImage->Data);
591
592 grTexDownloadMipMapLevel(GR_TMU1,
593 ti->tm[GR_TMU1]->startAddr,
594 lodlevel,
595 FX_largeLodLog2(ti->info),
596 FX_aspectRatioLog2(ti->info),
597 ti->info.format,
598 GR_MIPMAPLEVELMASK_EVEN, texImage->Data);
599 break;
600 case FX_TMU_BOTH:
601 grTexDownloadMipMapLevel(GR_TMU0,
602 ti->tm[GR_TMU0]->startAddr,
603 lodlevel,
604 FX_largeLodLog2(ti->info),
605 FX_aspectRatioLog2(ti->info),
606 ti->info.format,
607 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
608
609 grTexDownloadMipMapLevel(GR_TMU1,
610 ti->tm[GR_TMU1]->startAddr,
611 lodlevel,
612 FX_largeLodLog2(ti->info),
613 FX_aspectRatioLog2(ti->info),
614 ti->info.format,
615 GR_MIPMAPLEVELMASK_BOTH, texImage->Data);
616 break;
617
618 default:
619 fprintf(stderr, "fxTMReloadMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
620 fxCloseHardware();
621 exit(-1);
622 }
623 }
624
625 void
626 fxTMReloadSubMipMapLevel(fxMesaContext fxMesa,
627 struct gl_texture_object *tObj,
628 GLint level, GLint yoffset, GLint height)
629 {
630 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
631 GrLOD_t lodlevel;
632 unsigned short *data;
633 GLint tmu;
634 struct gl_texture_image *texImage = tObj->Image[0][level];
635 tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
636
637 assert(mml);
638
639 if (!ti->validated) {
640 fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: not validated\n");
641 fxCloseHardware();
642 exit(-1);
643 }
644
645 tmu = (int) ti->whichTMU;
646 fxTMMoveInTM(fxMesa, tObj, tmu);
647
648 fxTexGetInfo(mml->width, mml->height,
649 &lodlevel, NULL, NULL, NULL, NULL, NULL);
650
651 if ((ti->info.format == GR_TEXFMT_INTENSITY_8) ||
652 (ti->info.format == GR_TEXFMT_P_8) ||
653 (ti->info.format == GR_TEXFMT_ALPHA_8))
654 data = (GLushort *) texImage->Data + ((yoffset * mml->width) >> 1);
655 else
656 data = (GLushort *) texImage->Data + yoffset * mml->width;
657
658 switch (tmu) {
659 case FX_TMU0:
660 case FX_TMU1:
661 grTexDownloadMipMapLevelPartial(tmu,
662 ti->tm[tmu]->startAddr,
663 FX_valueToLod(FX_lodToValue(lodlevel)
664 + level),
665 FX_largeLodLog2(ti->info),
666 FX_aspectRatioLog2(ti->info),
667 ti->info.format,
668 GR_MIPMAPLEVELMASK_BOTH, data,
669 yoffset, yoffset + height - 1);
670 break;
671 case FX_TMU_SPLIT:
672 grTexDownloadMipMapLevelPartial(GR_TMU0,
673 ti->tm[FX_TMU0]->startAddr,
674 FX_valueToLod(FX_lodToValue(lodlevel)
675 + level),
676 FX_largeLodLog2(ti->info),
677 FX_aspectRatioLog2(ti->info),
678 ti->info.format,
679 GR_MIPMAPLEVELMASK_ODD, data,
680 yoffset, yoffset + height - 1);
681
682 grTexDownloadMipMapLevelPartial(GR_TMU1,
683 ti->tm[FX_TMU1]->startAddr,
684 FX_valueToLod(FX_lodToValue(lodlevel)
685 + level),
686 FX_largeLodLog2(ti->info),
687 FX_aspectRatioLog2(ti->info),
688 ti->info.format,
689 GR_MIPMAPLEVELMASK_EVEN, data,
690 yoffset, yoffset + height - 1);
691 break;
692 case FX_TMU_BOTH:
693 grTexDownloadMipMapLevelPartial(GR_TMU0,
694 ti->tm[FX_TMU0]->startAddr,
695 FX_valueToLod(FX_lodToValue(lodlevel)
696 + level),
697 FX_largeLodLog2(ti->info),
698 FX_aspectRatioLog2(ti->info),
699 ti->info.format,
700 GR_MIPMAPLEVELMASK_BOTH, data,
701 yoffset, yoffset + height - 1);
702
703 grTexDownloadMipMapLevelPartial(GR_TMU1,
704 ti->tm[FX_TMU1]->startAddr,
705 FX_valueToLod(FX_lodToValue(lodlevel)
706 + level),
707 FX_largeLodLog2(ti->info),
708 FX_aspectRatioLog2(ti->info),
709 ti->info.format,
710 GR_MIPMAPLEVELMASK_BOTH, data,
711 yoffset, yoffset + height - 1);
712 break;
713 default:
714 fprintf(stderr, "fxTMReloadSubMipMapLevel: INTERNAL ERROR: wrong tmu (%d)\n", tmu);
715 fxCloseHardware();
716 exit(-1);
717 }
718 }
719
720 void
721 fxTMMoveOutTM(fxMesaContext fxMesa, struct gl_texture_object *tObj)
722 {
723 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
724
725 if (TDFX_DEBUG & VERBOSE_DRIVER) {
726 fprintf(stderr, "fxTMMoveOutTM(%p (%d))\n", (void *)tObj, tObj->Name);
727 }
728
729 if (!ti->isInTM)
730 return;
731
732 switch (ti->whichTMU) {
733 case FX_TMU0:
734 case FX_TMU1:
735 fxTMRemoveRange(fxMesa, (int) ti->whichTMU, ti->tm[ti->whichTMU]);
736 break;
737 case FX_TMU_SPLIT:
738 case FX_TMU_BOTH:
739 fxTMRemoveRange(fxMesa, FX_TMU0, ti->tm[FX_TMU0]);
740 fxTMRemoveRange(fxMesa, FX_TMU1, ti->tm[FX_TMU1]);
741 break;
742 default:
743 fprintf(stderr, "fxTMMoveOutTM: INTERNAL ERROR: bad TMU (%ld)\n", ti->whichTMU);
744 fxCloseHardware();
745 exit(-1);
746 }
747
748 ti->isInTM = GL_FALSE;
749 ti->whichTMU = FX_TMU_NONE;
750 }
751
752 void
753 fxTMFreeTexture(fxMesaContext fxMesa, struct gl_texture_object *tObj)
754 {
755 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
756 int i;
757
758 if (TDFX_DEBUG & VERBOSE_TEXTURE) {
759 fprintf(stderr, "fxTMFreeTexture(%p (%d))\n", (void *)tObj, tObj->Name);
760 }
761
762 fxTMMoveOutTM(fxMesa, tObj);
763
764 for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
765 struct gl_texture_image *texImage = tObj->Image[0][i];
766 if (texImage) {
767 if (texImage->DriverData) {
768 FREE(texImage->DriverData);
769 texImage->DriverData = NULL;
770 }
771 }
772 }
773 switch (ti->whichTMU) {
774 case FX_TMU0:
775 case FX_TMU1:
776 fxTMDeleteRangeNode(fxMesa, ti->tm[ti->whichTMU]);
777 break;
778 case FX_TMU_SPLIT:
779 case FX_TMU_BOTH:
780 fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU0]);
781 fxTMDeleteRangeNode(fxMesa, ti->tm[FX_TMU1]);
782 break;
783 }
784 }
785
786 void
787 fxTMInit(fxMesaContext fxMesa)
788 {
789 fxMesa->texBindNumber = 0;
790 fxMesa->tmPool = 0;
791
792 if (fxMesa->HaveTexUma) {
793 grEnable(GR_TEXTURE_UMA_EXT);
794 }
795
796 fxTMUInit(fxMesa, FX_TMU0);
797
798 if (!fxMesa->HaveTexUma && fxMesa->haveTwoTMUs)
799 fxTMUInit(fxMesa, FX_TMU1);
800
801 texBoundMask = (fxMesa->type >= GR_SSTTYPE_Banshee) ? -1 : (FX_2MB_SPLIT - 1);
802 }
803
804 void
805 fxTMClose(fxMesaContext fxMesa)
806 {
807 MemRange *tmp, *next;
808
809 tmp = fxMesa->tmPool;
810 while (tmp) {
811 next = tmp->next;
812 FREE(tmp);
813 tmp = next;
814 }
815 tmp = fxMesa->tmFree[FX_TMU0];
816 while (tmp) {
817 next = tmp->next;
818 FREE(tmp);
819 tmp = next;
820 }
821 if (fxMesa->haveTwoTMUs) {
822 tmp = fxMesa->tmFree[FX_TMU1];
823 while (tmp) {
824 next = tmp->next;
825 FREE(tmp);
826 tmp = next;
827 }
828 }
829 }
830
831 void
832 fxTMRestoreTextures_NoLock(fxMesaContext ctx)
833 {
834 struct _mesa_HashTable *textures = ctx->glCtx->Shared->TexObjects;
835 GLuint id;
836
837 for (id = _mesa_HashFirstEntry(textures);
838 id;
839 id = _mesa_HashNextEntry(textures, id)) {
840 struct gl_texture_object *tObj
841 = (struct gl_texture_object *) _mesa_HashLookup(textures, id);
842 tfxTexInfo *ti = fxTMGetTexInfo(tObj);
843 if (ti && ti->isInTM) {
844 int i;
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 int where = ti->whichTMU;
849 fxTMMoveOutTM_NoLock(ctx, tObj);
850 fxTMMoveInTM_NoLock(ctx, tObj, where);
851 break;
852 }
853 }
854 if (i == MAX_TEXTURE_UNITS) /* Mark the texture as off the board */
855 fxTMMoveOutTM_NoLock(ctx, tObj);
856 }
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 */