1 /* $Id: fxtexman.c,v 1.16 2003/08/19 15:52:53 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
36 /* fxtexman.c - 3Dfx VooDoo texture memory functions */
49 #define FX_2MB_SPLIT 0x200000
51 static struct gl_texture_object
*fxTMFindOldestObject(fxMesaContext fxMesa
,
63 sanity(fxMesaContext fxMesa
)
65 MemRange
*tmp
, *prev
, *pos
;
68 tmp
= fxMesa
->tmFree
[0];
70 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
71 fprintf(stderr
, "Textures fubar\n");
74 if (tmp
->startAddr
>= tmp
->endAddr
) {
75 fprintf(stderr
, "Node fubar\n");
78 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
79 prev
->endAddr
> tmp
->startAddr
)) {
80 fprintf(stderr
, "Sorting fubar\n");
87 tmp
= fxMesa
->tmFree
[1];
89 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
90 fprintf(stderr
, "Textures fubar\n");
93 if (tmp
->startAddr
>= tmp
->endAddr
) {
94 fprintf(stderr
, "Node fubar\n");
97 if (prev
&& (prev
->startAddr
>= tmp
->startAddr
||
98 prev
->endAddr
> tmp
->startAddr
)) {
99 fprintf(stderr
, "Sorting fubar\n");
109 fxTMNewRangeNode(fxMesaContext fxMesa
, FxU32 start
, FxU32 end
)
111 MemRange
*result
= 0;
113 if (fxMesa
->tmPool
) {
114 result
= fxMesa
->tmPool
;
115 fxMesa
->tmPool
= fxMesa
->tmPool
->next
;
118 if (!(result
= MALLOC(sizeof(MemRange
)))) {
119 fprintf(stderr
, "fxDriver: out of memory!\n");
124 result
->startAddr
= start
;
125 result
->endAddr
= end
;
130 fxTMDeleteRangeNode(fxMesaContext fxMesa
, MemRange
* range
)
132 range
->next
= fxMesa
->tmPool
;
133 fxMesa
->tmPool
= range
;
137 fxTMUInit(fxMesaContext fxMesa
, int tmu
)
139 MemRange
*tmn
, *last
;
140 FxU32 start
, end
, blockstart
, blockend
;
142 start
= grTexMinAddress(tmu
);
143 end
= grTexMaxAddress(tmu
);
145 if (fxMesa
->verbose
) {
146 fprintf(stderr
, "Voodoo %s configuration:\n",
147 (tmu
== FX_TMU0
) ? "TMU0" : "TMU1");
148 fprintf(stderr
, "Voodoo Lower texture memory address (%u)\n",
149 (unsigned int) start
);
150 fprintf(stderr
, "Voodoo Higher texture memory address (%u)\n",
152 fprintf(stderr
, "Voodoo Splitting Texture memory in 2b blocks:\n");
155 fxMesa
->freeTexMem
[tmu
] = end
- start
;
156 fxMesa
->tmFree
[tmu
] = NULL
;
160 while (blockstart
< end
) {
161 if (blockstart
+ FX_2MB_SPLIT
> end
)
164 blockend
= blockstart
+ FX_2MB_SPLIT
;
167 fprintf(stderr
, "Voodoo %07u-%07u\n",
168 (unsigned int) blockstart
, (unsigned int) blockend
);
170 tmn
= fxTMNewRangeNode(fxMesa
, blockstart
, blockend
);
176 fxMesa
->tmFree
[tmu
] = tmn
;
179 blockstart
+= FX_2MB_SPLIT
;
184 fxTMFindStartAddr(fxMesaContext fxMesa
, GLint tmu
, int size
)
186 MemRange
*prev
, *tmp
;
188 struct gl_texture_object
*obj
;
192 tmp
= fxMesa
->tmFree
[tmu
];
194 if (tmp
->endAddr
- tmp
->startAddr
>= size
) { /* Fits here */
195 result
= tmp
->startAddr
;
196 tmp
->startAddr
+= size
;
197 if (tmp
->startAddr
== tmp
->endAddr
) { /* Empty */
199 prev
->next
= tmp
->next
;
202 fxMesa
->tmFree
[tmu
] = tmp
->next
;
204 fxTMDeleteRangeNode(fxMesa
, tmp
);
206 fxMesa
->freeTexMem
[tmu
] -= size
;
212 /* No free space. Discard oldest */
213 obj
= fxTMFindOldestObject(fxMesa
, tmu
);
215 fprintf(stderr
, "fx Driver: No space for texture\n");
218 fxTMMoveOutTM(fxMesa
, obj
);
224 fxTMRemoveRange(fxMesaContext fxMesa
, GLint tmu
, MemRange
* range
)
226 MemRange
*tmp
, *prev
;
228 if (range
->startAddr
== range
->endAddr
) {
229 fxTMDeleteRangeNode(fxMesa
, range
);
232 fxMesa
->freeTexMem
[tmu
] += range
->endAddr
- range
->startAddr
;
234 tmp
= fxMesa
->tmFree
[tmu
];
236 if (range
->startAddr
> tmp
->startAddr
) {
243 /* When we create the regions, we make a split at the 2MB boundary.
244 Now we have to make sure we don't join those 2MB boundary regions
245 back together again. */
248 if (range
->endAddr
== tmp
->startAddr
249 && tmp
->startAddr
& (FX_2MB_SPLIT
- 1)) {
251 tmp
->startAddr
= range
->startAddr
;
252 fxTMDeleteRangeNode(fxMesa
, range
);
257 if (prev
->endAddr
== range
->startAddr
258 && range
->startAddr
& (FX_2MB_SPLIT
- 1)) {
260 prev
->endAddr
= range
->endAddr
;
261 prev
->next
= range
->next
;
262 fxTMDeleteRangeNode(fxMesa
, range
);
268 fxMesa
->tmFree
[tmu
] = range
;
272 static struct gl_texture_object
*
273 fxTMFindOldestObject(fxMesaContext fxMesa
, int tmu
)
275 GLuint age
, old
, lasttime
, bindnumber
;
277 struct gl_texture_object
*obj
, *tmp
;
279 tmp
= fxMesa
->glCtx
->Shared
->TexObjectList
;
285 bindnumber
= fxMesa
->texBindNumber
;
287 info
= fxTMGetTexInfo(tmp
);
289 if (info
&& info
->isInTM
&&
290 ((info
->whichTMU
== tmu
) || (info
->whichTMU
== FX_TMU_BOTH
) ||
291 (info
->whichTMU
== FX_TMU_SPLIT
))) {
292 lasttime
= info
->lastTimeUsed
;
294 if (lasttime
> bindnumber
)
295 age
= bindnumber
+ (UINT_MAX
- lasttime
+ 1); /* TO DO: check wrap around */
297 age
= bindnumber
- lasttime
;
310 fxTMAddObj(fxMesaContext fxMesa
,
311 struct gl_texture_object
*tObj
, GLint tmu
, int texmemsize
)
316 startAddr
= fxTMFindStartAddr(fxMesa
, tmu
, texmemsize
);
319 range
= fxTMNewRangeNode(fxMesa
, startAddr
, startAddr
+ texmemsize
);
323 /* External Functions */
326 fxTMMoveInTM_NoLock(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
,
329 tfxTexInfo
*ti
= fxTMGetTexInfo(tObj
);
333 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
334 fprintf(stderr
, "fxmesa: fxTMMoveInTM(%d)\n", tObj
->Name
);
337 fxMesa
->stats
.reqTexUpload
++;
339 if (!ti
->validated
) {
341 "fx Driver: internal error in fxTMMoveInTM() -> not validated\n");
347 if (ti
->whichTMU
== where
)
349 if (where
== FX_TMU_SPLIT
|| ti
->whichTMU
== FX_TMU_SPLIT
)
350 fxTMMoveOutTM_NoLock(fxMesa
, tObj
);
352 if (ti
->whichTMU
== FX_TMU_BOTH
)
358 if (MESA_VERBOSE
& (VERBOSE_DRIVER
| VERBOSE_TEXTURE
)) {
359 fprintf(stderr
, "fxmesa: downloading %x (%d) in texture memory in %d\n",
360 (GLuint
) tObj
, tObj
->Name
, where
);
363 ti
->whichTMU
= (FxU32
) where
;
368 texmemsize
= (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
, &(ti
->info
));
369 ti
->tm
[where
] = fxTMAddObj(fxMesa
, tObj
, where
, texmemsize
);
370 fxMesa
->stats
.memTexUpload
+= texmemsize
;
372 for (i
= FX_largeLodValue(ti
->info
), l
= ti
->minLevel
;
373 i
<= FX_smallLodValue(ti
->info
); i
++, l
++) {
374 struct gl_texture_image
*texImage
= tObj
->Image
[l
];
375 grTexDownloadMipMapLevel(where
,
376 ti
->tm
[where
]->startAddr
,
378 FX_largeLodLog2(ti
->info
),
379 FX_aspectRatioLog2(ti
->info
),
381 GR_MIPMAPLEVELMASK_BOTH
,
386 texmemsize
= (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD
, &(ti
->info
));
387 ti
->tm
[FX_TMU0
] = fxTMAddObj(fxMesa
, tObj
, FX_TMU0
, texmemsize
);
388 fxMesa
->stats
.memTexUpload
+= texmemsize
;
390 texmemsize
= (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN
, &(ti
->info
));
391 ti
->tm
[FX_TMU1
] = fxTMAddObj(fxMesa
, tObj
, FX_TMU1
, texmemsize
);
392 fxMesa
->stats
.memTexUpload
+= texmemsize
;
394 for (i
= FX_largeLodValue(ti
->info
), l
= ti
->minLevel
;
395 i
<= FX_smallLodValue(ti
->info
); i
++, l
++) {
396 struct gl_texture_image
*texImage
= tObj
->Image
[l
];
398 grTexDownloadMipMapLevel(GR_TMU0
,
399 ti
->tm
[FX_TMU0
]->startAddr
,
401 FX_largeLodLog2(ti
->info
),
402 FX_aspectRatioLog2(ti
->info
),
404 GR_MIPMAPLEVELMASK_ODD
,
407 grTexDownloadMipMapLevel(GR_TMU1
,
408 ti
->tm
[FX_TMU1
]->startAddr
,
410 FX_largeLodLog2(ti
->info
),
411 FX_aspectRatioLog2(ti
->info
),
413 GR_MIPMAPLEVELMASK_EVEN
,
418 texmemsize
= (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
, &(ti
->info
));
419 ti
->tm
[FX_TMU0
] = fxTMAddObj(fxMesa
, tObj
, FX_TMU0
, texmemsize
);
420 fxMesa
->stats
.memTexUpload
+= texmemsize
;
422 texmemsize
= (int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
, &(ti
->info
));
423 ti
->tm
[FX_TMU1
] = fxTMAddObj(fxMesa
, tObj
, FX_TMU1
, texmemsize
);
424 fxMesa
->stats
.memTexUpload
+= texmemsize
;
426 for (i
= FX_largeLodValue(ti
->info
), l
= ti
->minLevel
;
427 i
<= FX_smallLodValue(ti
->info
); i
++, l
++) {
428 struct gl_texture_image
*texImage
= tObj
->Image
[l
];
429 grTexDownloadMipMapLevel(GR_TMU0
,
430 ti
->tm
[FX_TMU0
]->startAddr
,
432 FX_largeLodLog2(ti
->info
),
433 FX_aspectRatioLog2(ti
->info
),
435 GR_MIPMAPLEVELMASK_BOTH
,
438 grTexDownloadMipMapLevel(GR_TMU1
,
439 ti
->tm
[FX_TMU1
]->startAddr
,
441 FX_largeLodLog2(ti
->info
),
442 FX_aspectRatioLog2(ti
->info
),
444 GR_MIPMAPLEVELMASK_BOTH
,
450 "fx Driver: internal error in fxTMMoveInTM() -> wrong tmu (%d)\n",
456 fxMesa
->stats
.texUpload
++;
458 ti
->isInTM
= GL_TRUE
;
463 fxTMMoveInTM(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
,
467 fxTMMoveInTM_NoLock(fxMesa
, tObj
, where
);
473 fxTMReloadMipMapLevel(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
,
476 tfxTexInfo
*ti
= fxTMGetTexInfo(tObj
);
479 struct gl_texture_image
*texImage
= tObj
->Image
[level
];
480 tfxMipMapLevel
*mml
= FX_MIPMAP_DATA(texImage
);
483 assert(mml
->width
> 0);
484 assert(mml
->height
> 0);
485 assert(mml
->glideFormat
> 0);
487 if (!ti
->validated
) {
489 "fx Driver: internal error in fxTMReloadMipMapLevel() -> not validated\n");
494 tmu
= (int) ti
->whichTMU
;
495 fxTMMoveInTM(fxMesa
, tObj
, tmu
);
497 fxTexGetInfo(mml
->width
, mml
->height
,
498 &lodlevel
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
504 grTexDownloadMipMapLevel(tmu
,
505 ti
->tm
[tmu
]->startAddr
,
506 FX_valueToLod(FX_lodToValue(lodlevel
)),
507 FX_largeLodLog2(ti
->info
),
508 FX_aspectRatioLog2(ti
->info
),
510 GR_MIPMAPLEVELMASK_BOTH
, texImage
->Data
);
513 grTexDownloadMipMapLevel(GR_TMU0
,
514 ti
->tm
[GR_TMU0
]->startAddr
,
515 FX_valueToLod(FX_lodToValue(lodlevel
)),
516 FX_largeLodLog2(ti
->info
),
517 FX_aspectRatioLog2(ti
->info
),
519 GR_MIPMAPLEVELMASK_ODD
, texImage
->Data
);
521 grTexDownloadMipMapLevel(GR_TMU1
,
522 ti
->tm
[GR_TMU1
]->startAddr
,
523 FX_valueToLod(FX_lodToValue(lodlevel
)),
524 FX_largeLodLog2(ti
->info
),
525 FX_aspectRatioLog2(ti
->info
),
527 GR_MIPMAPLEVELMASK_EVEN
, texImage
->Data
);
530 grTexDownloadMipMapLevel(GR_TMU0
,
531 ti
->tm
[GR_TMU0
]->startAddr
,
532 FX_valueToLod(FX_lodToValue(lodlevel
)),
533 FX_largeLodLog2(ti
->info
),
534 FX_aspectRatioLog2(ti
->info
),
536 GR_MIPMAPLEVELMASK_BOTH
, texImage
->Data
);
538 grTexDownloadMipMapLevel(GR_TMU1
,
539 ti
->tm
[GR_TMU1
]->startAddr
,
540 FX_valueToLod(FX_lodToValue(lodlevel
)),
541 FX_largeLodLog2(ti
->info
),
542 FX_aspectRatioLog2(ti
->info
),
544 GR_MIPMAPLEVELMASK_BOTH
, texImage
->Data
);
549 "fx Driver: internal error in fxTMReloadMipMapLevel() -> wrong tmu (%d)\n",
557 fxTMReloadSubMipMapLevel(fxMesaContext fxMesa
,
558 struct gl_texture_object
*tObj
,
559 GLint level
, GLint yoffset
, GLint height
)
561 tfxTexInfo
*ti
= fxTMGetTexInfo(tObj
);
563 unsigned short *data
;
565 struct gl_texture_image
*texImage
= tObj
->Image
[level
];
566 tfxMipMapLevel
*mml
= FX_MIPMAP_DATA(texImage
);
570 if (!ti
->validated
) {
572 "fx Driver: internal error in fxTMReloadSubMipMapLevel() -> not validated\n");
577 tmu
= (int) ti
->whichTMU
;
578 fxTMMoveInTM(fxMesa
, tObj
, tmu
);
580 fxTexGetInfo(mml
->width
, mml
->height
,
581 &lodlevel
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
583 if ((ti
->info
.format
== GR_TEXFMT_INTENSITY_8
) ||
584 (ti
->info
.format
== GR_TEXFMT_P_8
) ||
585 (ti
->info
.format
== GR_TEXFMT_ALPHA_8
))
586 data
= (GLushort
*) texImage
->Data
+ ((yoffset
* mml
->width
) >> 1);
588 data
= (GLushort
*) texImage
->Data
+ yoffset
* mml
->width
;
593 grTexDownloadMipMapLevelPartial(tmu
,
594 ti
->tm
[tmu
]->startAddr
,
595 FX_valueToLod(FX_lodToValue(lodlevel
)
597 FX_largeLodLog2(ti
->info
),
598 FX_aspectRatioLog2(ti
->info
),
600 GR_MIPMAPLEVELMASK_BOTH
, data
,
601 yoffset
, yoffset
+ height
- 1);
604 grTexDownloadMipMapLevelPartial(GR_TMU0
,
605 ti
->tm
[FX_TMU0
]->startAddr
,
606 FX_valueToLod(FX_lodToValue(lodlevel
)
608 FX_largeLodLog2(ti
->info
),
609 FX_aspectRatioLog2(ti
->info
),
611 GR_MIPMAPLEVELMASK_ODD
, data
,
612 yoffset
, yoffset
+ height
- 1);
614 grTexDownloadMipMapLevelPartial(GR_TMU1
,
615 ti
->tm
[FX_TMU1
]->startAddr
,
616 FX_valueToLod(FX_lodToValue(lodlevel
)
618 FX_largeLodLog2(ti
->info
),
619 FX_aspectRatioLog2(ti
->info
),
621 GR_MIPMAPLEVELMASK_EVEN
, data
,
622 yoffset
, yoffset
+ height
- 1);
625 grTexDownloadMipMapLevelPartial(GR_TMU0
,
626 ti
->tm
[FX_TMU0
]->startAddr
,
627 FX_valueToLod(FX_lodToValue(lodlevel
)
629 FX_largeLodLog2(ti
->info
),
630 FX_aspectRatioLog2(ti
->info
),
632 GR_MIPMAPLEVELMASK_BOTH
, data
,
633 yoffset
, yoffset
+ height
- 1);
635 grTexDownloadMipMapLevelPartial(GR_TMU1
,
636 ti
->tm
[FX_TMU1
]->startAddr
,
637 FX_valueToLod(FX_lodToValue(lodlevel
)
639 FX_largeLodLog2(ti
->info
),
640 FX_aspectRatioLog2(ti
->info
),
642 GR_MIPMAPLEVELMASK_BOTH
, data
,
643 yoffset
, yoffset
+ height
- 1);
647 "fx Driver: internal error in fxTMReloadSubMipMapLevel() -> wrong tmu (%d)\n",
655 fxTMMoveOutTM(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
)
657 tfxTexInfo
*ti
= fxTMGetTexInfo(tObj
);
659 if (MESA_VERBOSE
& VERBOSE_DRIVER
) {
660 fprintf(stderr
, "fxmesa: fxTMMoveOutTM(%x (%d))\n", (GLuint
) tObj
,
667 switch (ti
->whichTMU
) {
670 fxTMRemoveRange(fxMesa
, (int) ti
->whichTMU
, ti
->tm
[ti
->whichTMU
]);
674 fxTMRemoveRange(fxMesa
, FX_TMU0
, ti
->tm
[FX_TMU0
]);
675 fxTMRemoveRange(fxMesa
, FX_TMU1
, ti
->tm
[FX_TMU1
]);
678 fprintf(stderr
, "fx Driver: internal error in fxTMMoveOutTM()\n");
683 ti
->isInTM
= GL_FALSE
;
684 ti
->whichTMU
= FX_TMU_NONE
;
688 fxTMFreeTexture(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
)
690 tfxTexInfo
*ti
= fxTMGetTexInfo(tObj
);
693 fxTMMoveOutTM(fxMesa
, tObj
);
695 for (i
= 0; i
< MAX_TEXTURE_LEVELS
; i
++) {
696 struct gl_texture_image
*texImage
= tObj
->Image
[i
];
698 if (texImage
->Data
) {
699 FREE(texImage
->Data
);
700 texImage
->Data
= NULL
;
702 if (texImage
->DriverData
) {
703 FREE(texImage
->DriverData
);
704 texImage
->DriverData
= NULL
;
708 switch (ti
->whichTMU
) {
711 fxTMDeleteRangeNode(fxMesa
, ti
->tm
[ti
->whichTMU
]);
715 fxTMDeleteRangeNode(fxMesa
, ti
->tm
[FX_TMU0
]);
716 fxTMDeleteRangeNode(fxMesa
, ti
->tm
[FX_TMU1
]);
722 fxTMInit(fxMesaContext fxMesa
)
724 fxMesa
->texBindNumber
= 0;
727 fxTMUInit(fxMesa
, FX_TMU0
);
729 if (fxMesa
->haveTwoTMUs
)
730 fxTMUInit(fxMesa
, FX_TMU1
);
734 fxTMClose(fxMesaContext fxMesa
)
736 MemRange
*tmp
, *next
;
738 tmp
= fxMesa
->tmPool
;
744 tmp
= fxMesa
->tmFree
[FX_TMU0
];
750 if (fxMesa
->haveTwoTMUs
) {
751 tmp
= fxMesa
->tmFree
[FX_TMU1
];
761 fxTMRestoreTextures_NoLock(fxMesaContext ctx
)
764 struct gl_texture_object
*tObj
;
767 tObj
= ctx
->glCtx
->Shared
->TexObjectList
;
769 ti
= fxTMGetTexInfo(tObj
);
770 if (ti
&& ti
->isInTM
) {
771 for (i
= 0; i
< MAX_TEXTURE_UNITS
; i
++)
772 if (ctx
->glCtx
->Texture
.Unit
[i
]._Current
== tObj
) {
773 /* Force the texture onto the board, as it could be in use */
774 where
= ti
->whichTMU
;
775 fxTMMoveOutTM_NoLock(ctx
, tObj
);
776 fxTMMoveInTM_NoLock(ctx
, tObj
, where
);
779 if (i
== MAX_TEXTURE_UNITS
) /* Mark the texture as off the board */
780 fxTMMoveOutTM_NoLock(ctx
, tObj
);
790 * Need this to provide at least one external definition.
793 extern int gl_fx_dummy_function_texman(void);
795 gl_fx_dummy_function_texman(void)