1 /* -*- mode: C; tab-width:8; c-basic-offset:2 -*- */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 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.
27 * Original Mesa / 3Dfx device driver (C) 1999 David Bucciarelli, by the
30 * Thank you for your contribution, David!
32 * Please make note of the above copyright/license statement. If you
33 * contributed code or bug fixes to this code under the previous (GNU
34 * Library) license and object to the new license, your code will be
35 * removed at your request. Please see the Mesa docs/COPYRIGHT file
36 * for more information.
38 * Additional Mesa/3Dfx driver developers:
39 * Daryll Strauss <daryll@precisioninsight.com>
40 * Keith Whitwell <keith@precisioninsight.com>
42 * See fxapi.h for more revision/author details.
46 /* fxtexman.c - 3Dfx VooDoo texture memory functions */
59 #define FX_2MB_SPLIT 0x200000
61 static struct gl_texture_object
*fxTMFindOldestObject(fxMesaContext fxMesa
,
71 static void sanity(fxMesaContext fxMesa
)
73 MemRange
*tmp
, *prev
, *pos
;
76 tmp
= fxMesa
->tmFree
[0];
78 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
79 fprintf(stderr
, "Textures fubar\n");
82 if (tmp
->startAddr
>=tmp
->endAddr
) {
83 fprintf(stderr
, "Node fubar\n");
86 if (prev
&& (prev
->startAddr
>=tmp
->startAddr
||
87 prev
->endAddr
>tmp
->startAddr
)) {
88 fprintf(stderr
, "Sorting fubar\n");
95 tmp
= fxMesa
->tmFree
[1];
97 if (!tmp
->startAddr
&& !tmp
->endAddr
) {
98 fprintf(stderr
, "Textures fubar\n");
101 if (tmp
->startAddr
>=tmp
->endAddr
) {
102 fprintf(stderr
, "Node fubar\n");
105 if (prev
&& (prev
->startAddr
>=tmp
->startAddr
||
106 prev
->endAddr
>tmp
->startAddr
)) {
107 fprintf(stderr
, "Sorting fubar\n");
116 static MemRange
*fxTMNewRangeNode(fxMesaContext fxMesa
, FxU32 start
, FxU32 end
) {
119 if (fxMesa
->tmPool
) {
120 result
=fxMesa
->tmPool
;
121 fxMesa
->tmPool
=fxMesa
->tmPool
->next
;
123 if (!(result
=MALLOC(sizeof(MemRange
)))) {
124 fprintf(stderr
, "fxDriver: out of memory!\n");
129 result
->startAddr
=start
;
134 static void fxTMDeleteRangeNode(fxMesaContext fxMesa
, MemRange
*range
)
136 range
->next
=fxMesa
->tmPool
;
137 fxMesa
->tmPool
=range
;
140 static void fxTMUInit(fxMesaContext fxMesa
, int tmu
)
142 MemRange
*tmn
, *last
;
143 FxU32 start
,end
,blockstart
,blockend
;
145 start
=FX_grTexMinAddress(tmu
);
146 end
=FX_grTexMaxAddress(tmu
);
148 if(fxMesa
->verbose
) {
149 fprintf(stderr
,"Voodoo %s configuration:",(tmu
==FX_TMU0
) ? "TMU0" : "TMU1");
150 fprintf(stderr
,"Voodoo Lower texture memory address (%u)\n",(unsigned int)start
);
151 fprintf(stderr
,"Voodoo Higher texture memory address (%u)\n",(unsigned int)end
);
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
) blockend
=end
;
162 else blockend
=blockstart
+FX_2MB_SPLIT
;
165 fprintf(stderr
,"Voodoo %07u-%07u\n",
166 (unsigned int)blockstart
,(unsigned int)blockend
);
168 tmn
=fxTMNewRangeNode(fxMesa
, blockstart
, blockend
);
171 if (last
) last
->next
=tmn
;
172 else fxMesa
->tmFree
[tmu
]=tmn
;
175 blockstart
+=FX_2MB_SPLIT
;
179 static int fxTMFindStartAddr(fxMesaContext fxMesa
, GLint tmu
, int size
)
181 MemRange
*prev
, *tmp
;
183 struct gl_texture_object
*obj
;
187 tmp
=fxMesa
->tmFree
[tmu
];
189 if (tmp
->endAddr
-tmp
->startAddr
>=size
) { /* Fits here */
190 result
=tmp
->startAddr
;
191 tmp
->startAddr
+=size
;
192 if (tmp
->startAddr
==tmp
->endAddr
) { /* Empty */
194 prev
->next
=tmp
->next
;
196 fxMesa
->tmFree
[tmu
]=tmp
->next
;
198 fxTMDeleteRangeNode(fxMesa
, tmp
);
200 fxMesa
->freeTexMem
[tmu
]-=size
;
206 /* No free space. Discard oldest */
207 obj
=fxTMFindOldestObject(fxMesa
, tmu
);
209 fprintf(stderr
, "fx Driver: No space for texture\n");
212 fxTMMoveOutTM(fxMesa
, obj
);
217 static void fxTMRemoveRange(fxMesaContext fxMesa
, GLint tmu
, MemRange
*range
)
219 MemRange
*tmp
, *prev
;
221 if (range
->startAddr
==range
->endAddr
) {
222 fxTMDeleteRangeNode(fxMesa
, range
);
225 fxMesa
->freeTexMem
[tmu
]+=range
->endAddr
-range
->startAddr
;
227 tmp
=fxMesa
->tmFree
[tmu
];
229 if (range
->startAddr
>tmp
->startAddr
) {
234 /* When we create the regions, we make a split at the 2MB boundary.
235 Now we have to make sure we don't join those 2MB boundary regions
236 back together again. */
239 if (range
->endAddr
==tmp
->startAddr
&& tmp
->startAddr
&(FX_2MB_SPLIT
-1)) {
241 tmp
->startAddr
=range
->startAddr
;
242 fxTMDeleteRangeNode(fxMesa
, range
);
247 if (prev
->endAddr
==range
->startAddr
&& range
->startAddr
&(FX_2MB_SPLIT
-1)) {
249 prev
->endAddr
=range
->endAddr
;
250 prev
->next
=range
->next
;
251 fxTMDeleteRangeNode(fxMesa
, range
);
252 } else prev
->next
=range
;
254 fxMesa
->tmFree
[tmu
]=range
;
258 static struct gl_texture_object
*fxTMFindOldestObject(fxMesaContext fxMesa
,
261 GLuint age
, old
, lasttime
, bindnumber
;
263 struct gl_texture_object
*obj
, *tmp
;
265 tmp
=fxMesa
->glCtx
->Shared
->TexObjectList
;
270 bindnumber
=fxMesa
->texBindNumber
;
272 info
=fxTMGetTexInfo(tmp
);
274 if (info
&& info
->isInTM
&&
275 ((info
->whichTMU
==tmu
) || (info
->whichTMU
==FX_TMU_BOTH
) ||
276 (info
->whichTMU
==FX_TMU_SPLIT
))) {
277 lasttime
=info
->lastTimeUsed
;
279 if (lasttime
>bindnumber
)
280 age
=bindnumber
+(UINT_MAX
-lasttime
+1); /* TO DO: check wrap around */
282 age
=bindnumber
-lasttime
;
294 static MemRange
*fxTMAddObj(fxMesaContext fxMesa
,
295 struct gl_texture_object
*tObj
,
296 GLint tmu
, int texmemsize
)
301 startAddr
=fxTMFindStartAddr(fxMesa
, tmu
, texmemsize
);
302 if (startAddr
<0) return 0;
303 range
=fxTMNewRangeNode(fxMesa
, startAddr
, startAddr
+texmemsize
);
307 /* External Functions */
309 void fxTMMoveInTM_NoLock(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
, GLint where
)
311 tfxTexInfo
*ti
=fxTMGetTexInfo(tObj
);
315 if (MESA_VERBOSE
&VERBOSE_DRIVER
) {
316 fprintf(stderr
,"fxmesa: fxTMMoveInTM(%d)\n",tObj
->Name
);
319 fxMesa
->stats
.reqTexUpload
++;
321 if (!ti
->validated
) {
322 fprintf(stderr
,"fx Driver: internal error in fxTMMoveInTM() -> not validated\n");
328 if (ti
->whichTMU
==where
) return;
329 if (where
==FX_TMU_SPLIT
|| ti
->whichTMU
==FX_TMU_SPLIT
)
330 fxTMMoveOutTM_NoLock(fxMesa
, tObj
);
332 if (ti
->whichTMU
==FX_TMU_BOTH
) return;
337 if (MESA_VERBOSE
&(VERBOSE_DRIVER
|VERBOSE_TEXTURE
)) {
338 fprintf(stderr
,"fxmesa: downloading %x (%d) in texture memory in %d\n",(GLuint
)tObj
,tObj
->Name
,where
);
341 ti
->whichTMU
=(FxU32
)where
;
346 texmemsize
=(int)FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_BOTH
,
348 ti
->tm
[where
]=fxTMAddObj(fxMesa
, tObj
, where
, texmemsize
);
349 fxMesa
->stats
.memTexUpload
+=texmemsize
;
351 for (i
=FX_largeLodValue(ti
->info
), l
=ti
->minLevel
;
352 i
<=FX_smallLodValue(ti
->info
);
354 FX_grTexDownloadMipMapLevel_NoLock(where
,
355 ti
->tm
[where
]->startAddr
,
357 FX_largeLodLog2(ti
->info
),
358 FX_aspectRatioLog2(ti
->info
),
360 GR_MIPMAPLEVELMASK_BOTH
,
361 ti
->mipmapLevel
[l
].data
);
364 texmemsize
=(int)FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_ODD
,
366 ti
->tm
[FX_TMU0
]=fxTMAddObj(fxMesa
, tObj
, FX_TMU0
, texmemsize
);
367 fxMesa
->stats
.memTexUpload
+=texmemsize
;
369 texmemsize
=(int)FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_EVEN
,
371 ti
->tm
[FX_TMU1
]=fxTMAddObj(fxMesa
, tObj
, FX_TMU1
, texmemsize
);
372 fxMesa
->stats
.memTexUpload
+=texmemsize
;
374 for (i
=FX_largeLodValue(ti
->info
),l
=ti
->minLevel
;
375 i
<=FX_smallLodValue(ti
->info
);
377 FX_grTexDownloadMipMapLevel_NoLock(GR_TMU0
,
378 ti
->tm
[FX_TMU0
]->startAddr
,
380 FX_largeLodLog2(ti
->info
),
381 FX_aspectRatioLog2(ti
->info
),
383 GR_MIPMAPLEVELMASK_ODD
,
384 ti
->mipmapLevel
[l
].data
);
386 FX_grTexDownloadMipMapLevel_NoLock(GR_TMU1
,
387 ti
->tm
[FX_TMU1
]->startAddr
,
389 FX_largeLodLog2(ti
->info
),
390 FX_aspectRatioLog2(ti
->info
),
392 GR_MIPMAPLEVELMASK_EVEN
,
393 ti
->mipmapLevel
[l
].data
);
397 texmemsize
=(int)FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_BOTH
,
399 ti
->tm
[FX_TMU0
]=fxTMAddObj(fxMesa
, tObj
, FX_TMU0
, texmemsize
);
400 fxMesa
->stats
.memTexUpload
+=texmemsize
;
402 texmemsize
=(int)FX_grTexTextureMemRequired_NoLock(GR_MIPMAPLEVELMASK_BOTH
,
404 ti
->tm
[FX_TMU1
]=fxTMAddObj(fxMesa
, tObj
, FX_TMU1
, texmemsize
);
405 fxMesa
->stats
.memTexUpload
+=texmemsize
;
407 for (i
=FX_largeLodValue(ti
->info
),l
=ti
->minLevel
;
408 i
<=FX_smallLodValue(ti
->info
);
410 FX_grTexDownloadMipMapLevel_NoLock(GR_TMU0
,
411 ti
->tm
[FX_TMU0
]->startAddr
,
413 FX_largeLodLog2(ti
->info
),
414 FX_aspectRatioLog2(ti
->info
),
416 GR_MIPMAPLEVELMASK_BOTH
,
417 ti
->mipmapLevel
[l
].data
);
419 FX_grTexDownloadMipMapLevel_NoLock(GR_TMU1
,
420 ti
->tm
[FX_TMU1
]->startAddr
,
422 FX_largeLodLog2(ti
->info
),
423 FX_aspectRatioLog2(ti
->info
),
425 GR_MIPMAPLEVELMASK_BOTH
,
426 ti
->mipmapLevel
[l
].data
);
430 fprintf(stderr
,"fx Driver: internal error in fxTMMoveInTM() -> wrong tmu (%d)\n",where
);
435 fxMesa
->stats
.texUpload
++;
440 void fxTMMoveInTM(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
, GLint where
) {
442 fxTMMoveInTM_NoLock(fxMesa
, tObj
, where
);
446 void fxTMReloadMipMapLevel(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
, GLint level
)
448 tfxTexInfo
*ti
=fxTMGetTexInfo(tObj
);
452 if (!ti
->validated
) {
453 fprintf(stderr
,"fx Driver: internal error in fxTMReloadMipMapLevel() -> not validated\n");
458 tmu
=(int)ti
->whichTMU
;
459 fxTMMoveInTM(fxMesa
, tObj
, tmu
);
461 fxTexGetInfo(ti
->mipmapLevel
[0].width
,ti
->mipmapLevel
[0].height
,
462 &lodlevel
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
472 FX_grTexDownloadMipMapLevel(tmu
,
473 ti
->tm
[tmu
]->startAddr
,
474 FX_valueToLod(FX_lodToValue(lodlevel
)),
475 FX_largeLodLog2(ti
->info
),
476 FX_aspectRatioLog2(ti
->info
),
478 GR_MIPMAPLEVELMASK_BOTH
,
479 ti
->mipmapLevel
[level
].data
);
482 FX_grTexDownloadMipMapLevel(GR_TMU0
,
483 ti
->tm
[GR_TMU0
]->startAddr
,
484 FX_valueToLod(FX_lodToValue(lodlevel
)),
485 FX_largeLodLog2(ti
->info
),
486 FX_aspectRatioLog2(ti
->info
),
488 GR_MIPMAPLEVELMASK_ODD
,
489 ti
->mipmapLevel
[level
].data
);
491 FX_grTexDownloadMipMapLevel(GR_TMU1
,
492 ti
->tm
[GR_TMU1
]->startAddr
,
493 FX_valueToLod(FX_lodToValue(lodlevel
)),
494 FX_largeLodLog2(ti
->info
),
495 FX_aspectRatioLog2(ti
->info
),
497 GR_MIPMAPLEVELMASK_EVEN
,
498 ti
->mipmapLevel
[level
].data
);
501 FX_grTexDownloadMipMapLevel(GR_TMU0
,
502 ti
->tm
[GR_TMU0
]->startAddr
,
503 FX_valueToLod(FX_lodToValue(lodlevel
)),
504 FX_largeLodLog2(ti
->info
),
505 FX_aspectRatioLog2(ti
->info
),
507 GR_MIPMAPLEVELMASK_BOTH
,
508 ti
->mipmapLevel
[level
].data
);
510 FX_grTexDownloadMipMapLevel(GR_TMU1
,
511 ti
->tm
[GR_TMU1
]->startAddr
,
512 FX_valueToLod(FX_lodToValue(lodlevel
)),
513 FX_largeLodLog2(ti
->info
),
514 FX_aspectRatioLog2(ti
->info
),
516 GR_MIPMAPLEVELMASK_BOTH
,
517 ti
->mipmapLevel
[level
].data
);
521 fprintf(stderr
,"fx Driver: internal error in fxTMReloadMipMapLevel() -> wrong tmu (%d)\n",tmu
);
527 void fxTMReloadSubMipMapLevel(fxMesaContext fxMesa
,
528 struct gl_texture_object
*tObj
,
529 GLint level
, GLint yoffset
, GLint height
)
531 tfxTexInfo
*ti
=fxTMGetTexInfo(tObj
);
533 unsigned short *data
;
537 fprintf(stderr
,"fx Driver: internal error in fxTMReloadSubMipMapLevel() -> not validated\n");
542 tmu
=(int)ti
->whichTMU
;
543 fxTMMoveInTM(fxMesa
, tObj
, tmu
);
545 fxTexGetInfo(ti
->mipmapLevel
[0].width
, ti
->mipmapLevel
[0].height
,
546 &lodlevel
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
548 if((ti
->info
.format
==GR_TEXFMT_INTENSITY_8
) ||
549 (ti
->info
.format
==GR_TEXFMT_P_8
) ||
550 (ti
->info
.format
==GR_TEXFMT_ALPHA_8
))
551 data
=ti
->mipmapLevel
[level
].data
+((yoffset
*ti
->mipmapLevel
[level
].width
)>>1);
553 data
=ti
->mipmapLevel
[level
].data
+yoffset
*ti
->mipmapLevel
[level
].width
;
558 FX_grTexDownloadMipMapLevelPartial(tmu
,
559 ti
->tm
[tmu
]->startAddr
,
560 FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
561 FX_largeLodLog2(ti
->info
),
562 FX_aspectRatioLog2(ti
->info
),
564 GR_MIPMAPLEVELMASK_BOTH
,
566 yoffset
,yoffset
+height
-1);
569 FX_grTexDownloadMipMapLevelPartial(GR_TMU0
,
570 ti
->tm
[FX_TMU0
]->startAddr
,
571 FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
572 FX_largeLodLog2(ti
->info
),
573 FX_aspectRatioLog2(ti
->info
),
575 GR_MIPMAPLEVELMASK_ODD
,
577 yoffset
,yoffset
+height
-1);
579 FX_grTexDownloadMipMapLevelPartial(GR_TMU1
,
580 ti
->tm
[FX_TMU1
]->startAddr
,
581 FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
582 FX_largeLodLog2(ti
->info
),
583 FX_aspectRatioLog2(ti
->info
),
585 GR_MIPMAPLEVELMASK_EVEN
,
587 yoffset
,yoffset
+height
-1);
590 FX_grTexDownloadMipMapLevelPartial(GR_TMU0
,
591 ti
->tm
[FX_TMU0
]->startAddr
,
592 FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
593 FX_largeLodLog2(ti
->info
),
594 FX_aspectRatioLog2(ti
->info
),
596 GR_MIPMAPLEVELMASK_BOTH
,
598 yoffset
,yoffset
+height
-1);
600 FX_grTexDownloadMipMapLevelPartial(GR_TMU1
,
601 ti
->tm
[FX_TMU1
]->startAddr
,
602 FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
603 FX_largeLodLog2(ti
->info
),
604 FX_aspectRatioLog2(ti
->info
),
606 GR_MIPMAPLEVELMASK_BOTH
,
608 yoffset
,yoffset
+height
-1);
611 fprintf(stderr
,"fx Driver: internal error in fxTMReloadSubMipMapLevel() -> wrong tmu (%d)\n",tmu
);
617 void fxTMMoveOutTM(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
)
619 tfxTexInfo
*ti
=fxTMGetTexInfo(tObj
);
621 if (MESA_VERBOSE
&VERBOSE_DRIVER
) {
622 fprintf(stderr
,"fxmesa: fxTMMoveOutTM(%x (%d))\n",(GLuint
)tObj
,tObj
->Name
);
625 if (!ti
->isInTM
) return;
627 switch(ti
->whichTMU
) {
630 fxTMRemoveRange(fxMesa
, (int)ti
->whichTMU
, ti
->tm
[ti
->whichTMU
]);
634 fxTMRemoveRange(fxMesa
, FX_TMU0
, ti
->tm
[FX_TMU0
]);
635 fxTMRemoveRange(fxMesa
, FX_TMU1
, ti
->tm
[FX_TMU1
]);
638 fprintf(stderr
,"fx Driver: internal error in fxTMMoveOutTM()\n");
644 ti
->whichTMU
=FX_TMU_NONE
;
647 void fxTMFreeTexture(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
)
649 tfxTexInfo
*ti
=fxTMGetTexInfo(tObj
);
652 fxTMMoveOutTM(fxMesa
, tObj
);
654 for (i
=0; i
<MAX_TEXTURE_LEVELS
; i
++) {
655 if (ti
->mipmapLevel
[i
].data
) {
656 FREE(ti
->mipmapLevel
[i
].data
);
657 ti
->mipmapLevel
[i
].data
= NULL
;
660 switch (ti
->whichTMU
) {
663 fxTMDeleteRangeNode(fxMesa
, ti
->tm
[ti
->whichTMU
]);
667 fxTMDeleteRangeNode(fxMesa
, ti
->tm
[FX_TMU0
]);
668 fxTMDeleteRangeNode(fxMesa
, ti
->tm
[FX_TMU1
]);
673 void fxTMInit(fxMesaContext fxMesa
)
675 fxMesa
->texBindNumber
=0;
678 fxTMUInit(fxMesa
,FX_TMU0
);
680 if(fxMesa
->haveTwoTMUs
)
681 fxTMUInit(fxMesa
,FX_TMU1
);
684 void fxTMClose(fxMesaContext fxMesa
)
686 MemRange
*tmp
, *next
;
694 tmp
=fxMesa
->tmFree
[FX_TMU0
];
700 if (fxMesa
->haveTwoTMUs
) {
701 tmp
=fxMesa
->tmFree
[FX_TMU1
];
711 fxTMRestoreTextures_NoLock(fxMesaContext ctx
) {
713 struct gl_texture_object
*tObj
;
716 tObj
=ctx
->glCtx
->Shared
->TexObjectList
;
718 ti
=fxTMGetTexInfo(tObj
);
719 if (ti
&& ti
->isInTM
) {
720 for (i
=0; i
<MAX_TEXTURE_UNITS
; i
++)
721 if (ctx
->glCtx
->Texture
.Unit
[i
].Current
==tObj
) {
722 /* Force the texture onto the board, as it could be in use */
724 fxTMMoveOutTM_NoLock(ctx
, tObj
);
725 fxTMMoveInTM_NoLock(ctx
, tObj
, where
);
728 if (i
==MAX_TEXTURE_UNITS
) /* Mark the texture as off the board */
729 fxTMMoveOutTM_NoLock(ctx
, tObj
);
739 * Need this to provide at least one external definition.
742 int gl_fx_dummy_function_texman(void)