5ee145e3cbf0d9232b3d67d80a3c48639b2a773e
1 /* -*- mode: C; tab-width:8; -*-
3 fxtexman.c - 3Dfx VooDoo texture memory functions
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * See the file fxapi.c for more informations about authors
33 static tfxTMFreeNode
*fxTMNewTMFreeNode(FxU32 start
, FxU32 end
)
37 if(!(tmn
=malloc(sizeof(tfxTMFreeNode
)))) {
38 fprintf(stderr
,"fx Driver: out of memory !\n");
44 tmn
->startAddress
=start
;
50 static void fxTMUInit(fxMesaContext fxMesa
, int tmu
)
52 tfxTMFreeNode
*tmn
,*tmntmp
;
53 FxU32 start
,end
,blockstart
,blockend
;
55 start
=grTexMinAddress(tmu
);
56 end
=grTexMaxAddress(tmu
);
59 fprintf(stderr
,"%s configuration:",(tmu
==FX_TMU0
) ? "TMU0" : "TMU1");
60 fprintf(stderr
," Lower texture memory address (%u)\n",(unsigned int)start
);
61 fprintf(stderr
," Higher texture memory address (%u)\n",(unsigned int)end
);
62 fprintf(stderr
," Splitting Texture memory in 2Mb blocks:\n");
65 fxMesa
->freeTexMem
[tmu
]=end
-start
;
66 fxMesa
->tmFree
[tmu
]=NULL
;
67 fxMesa
->tmAlloc
[tmu
]=NULL
;
70 while(blockstart
<=end
) {
71 if(blockstart
+0x1fffff>end
)
74 blockend
=blockstart
+0x1fffff;
77 fprintf(stderr
," %07u-%07u\n",(unsigned int)blockstart
,(unsigned int)blockend
);
79 tmn
=fxTMNewTMFreeNode(blockstart
,blockend
);
81 if(fxMesa
->tmFree
[tmu
]) {
82 for(tmntmp
=fxMesa
->tmFree
[tmu
];tmntmp
->next
!=NULL
;tmntmp
=tmntmp
->next
){};
85 fxMesa
->tmFree
[tmu
]=tmn
;
87 blockstart
+=0x1fffff+1;
91 void fxTMInit(fxMesaContext fxMesa
)
93 fxTMUInit(fxMesa
,FX_TMU0
);
95 if(fxMesa
->haveTwoTMUs
)
96 fxTMUInit(fxMesa
,FX_TMU1
);
98 fxMesa
->texBindNumber
=0;
101 static struct gl_texture_object
*fxTMFindOldestTMBlock(fxMesaContext fxMesa
,
102 tfxTMAllocNode
*tmalloc
,
103 GLuint texbindnumber
)
105 GLuint age
,oldestage
,lasttimeused
;
106 struct gl_texture_object
*oldesttexobj
;
109 oldesttexobj
=tmalloc
->tObj
;
113 lasttimeused
=((tfxTexInfo
*)(tmalloc
->tObj
->DriverData
))->tmi
.lastTimeUsed
;
115 if(lasttimeused
>texbindnumber
)
116 age
=texbindnumber
+(UINT_MAX
-lasttimeused
+1); /* TO DO: check */
118 age
=texbindnumber
-lasttimeused
;
122 oldesttexobj
=tmalloc
->tObj
;
125 tmalloc
=tmalloc
->next
;
131 static GLboolean
fxTMFreeOldTMBlock(fxMesaContext fxMesa
, GLint tmu
)
133 struct gl_texture_object
*oldesttexobj
;
135 if(!fxMesa
->tmAlloc
[tmu
])
138 oldesttexobj
=fxTMFindOldestTMBlock(fxMesa
,fxMesa
->tmAlloc
[tmu
],fxMesa
->texBindNumber
);
140 fxTMMoveOutTM(fxMesa
,oldesttexobj
);
145 static tfxTMFreeNode
*fxTMExtractTMFreeBlock(tfxTMFreeNode
*tmfree
, int texmemsize
,
146 GLboolean
*success
, FxU32
*startadr
)
150 /* TO DO: cut recursion */
157 blocksize
=(int)tmfree
->endAddress
-(int)tmfree
->startAddress
+1;
159 if(blocksize
==texmemsize
) {
160 tfxTMFreeNode
*nexttmfree
;
163 *startadr
=tmfree
->startAddress
;
165 nexttmfree
=tmfree
->next
;
171 if(blocksize
>texmemsize
) {
173 *startadr
=tmfree
->startAddress
;
175 tmfree
->startAddress
+=texmemsize
;
180 tmfree
->next
=fxTMExtractTMFreeBlock(tmfree
->next
,texmemsize
,success
,startadr
);
185 static tfxTMAllocNode
*fxTMGetTMBlock(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
,
186 GLint tmu
, int texmemsize
)
188 tfxTMFreeNode
*newtmfree
;
189 tfxTMAllocNode
*newtmalloc
;
193 for(;;) { /* TO DO: improve performaces */
194 newtmfree
=fxTMExtractTMFreeBlock(fxMesa
->tmFree
[tmu
],texmemsize
,&success
,&startadr
);
197 fxMesa
->tmFree
[tmu
]=newtmfree
;
199 fxMesa
->freeTexMem
[tmu
]-=texmemsize
;
201 if(!(newtmalloc
=malloc(sizeof(tfxTMAllocNode
)))) {
202 fprintf(stderr
,"fx Driver: out of memory !\n");
207 newtmalloc
->next
=fxMesa
->tmAlloc
[tmu
];
208 newtmalloc
->startAddress
=startadr
;
209 newtmalloc
->endAddress
=startadr
+texmemsize
-1;
210 newtmalloc
->tObj
=tObj
;
212 fxMesa
->tmAlloc
[tmu
]=newtmalloc
;
217 if(!fxTMFreeOldTMBlock(fxMesa
,tmu
)) {
218 fprintf(stderr
,"fx Driver: internal error in fxTMGetTMBlock()\n");
219 fprintf(stderr
," TMU: %d Size: %d\n",tmu
,texmemsize
);
227 void fxTMMoveInTM(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
, GLint where
)
229 tfxTexInfo
*ti
=(tfxTexInfo
*)tObj
->DriverData
;
233 if (MESA_VERBOSE
&VERBOSE_DRIVER
) {
234 fprintf(stderr
,"fxmesa: fxTMMoveInTM(%d)\n",tObj
->Name
);
237 fxMesa
->stats
.reqTexUpload
++;
240 fprintf(stderr
,"fx Driver: internal error in fxTMMoveInTM() -> not validated\n");
248 if (MESA_VERBOSE
&(VERBOSE_DRIVER
|VERBOSE_TEXTURE
)) {
249 fprintf(stderr
,"fxmesa: downloading %x (%d) in texture memory in %d\n",(GLuint
)tObj
,tObj
->Name
,where
);
252 ti
->tmi
.whichTMU
=(FxU32
)where
;
257 texmemsize
=(int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH
,&(ti
->info
));
258 ti
->tmi
.tm
[where
]=fxTMGetTMBlock(fxMesa
,tObj
,where
,texmemsize
);
259 fxMesa
->stats
.memTexUpload
+=texmemsize
;
261 for(i
=FX_largeLodValue(ti
->info
),l
=ti
->minLevel
;i
<=FX_smallLodValue(ti
->info
);i
++,l
++)
262 grTexDownloadMipMapLevel(where
,
263 ti
->tmi
.tm
[where
]->startAddress
,FX_valueToLod(i
),
264 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
265 ti
->info
.format
,GR_MIPMAPLEVELMASK_BOTH
,
266 ti
->tmi
.mipmapLevel
[l
].data
);
268 case FX_TMU_SPLIT
: /* TO DO: alternate even/odd TMU0/TMU1 */
269 texmemsize
=(int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD
,&(ti
->info
));
270 ti
->tmi
.tm
[FX_TMU0
]=fxTMGetTMBlock(fxMesa
,tObj
,FX_TMU0
,texmemsize
);
271 fxMesa
->stats
.memTexUpload
+=texmemsize
;
273 texmemsize
=(int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN
,&(ti
->info
));
274 ti
->tmi
.tm
[FX_TMU1
]=fxTMGetTMBlock(fxMesa
,tObj
,FX_TMU1
,texmemsize
);
275 fxMesa
->stats
.memTexUpload
+=texmemsize
;
277 for(i
=FX_largeLodValue(ti
->info
),l
=ti
->minLevel
;i
<=FX_smallLodValue(ti
->info
);i
++,l
++) {
278 grTexDownloadMipMapLevel(GR_TMU0
,ti
->tmi
.tm
[FX_TMU0
]->startAddress
,FX_valueToLod(i
),
279 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
280 ti
->info
.format
,GR_MIPMAPLEVELMASK_ODD
,
281 ti
->tmi
.mipmapLevel
[l
].data
);
283 grTexDownloadMipMapLevel(GR_TMU1
,ti
->tmi
.tm
[FX_TMU1
]->startAddress
,FX_valueToLod(i
),
284 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
285 ti
->info
.format
,GR_MIPMAPLEVELMASK_EVEN
,
286 ti
->tmi
.mipmapLevel
[l
].data
);
290 fprintf(stderr
,"fx Driver: internal error in fxTMMoveInTM() -> wrong tmu (%d)\n",where
);
295 fxMesa
->stats
.texUpload
++;
297 ti
->tmi
.isInTM
=GL_TRUE
;
300 void fxTMReloadMipMapLevel(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
, GLint level
)
302 tfxTexInfo
*ti
=(tfxTexInfo
*)tObj
->DriverData
;
307 fprintf(stderr
,"fx Driver: internal error in fxTMReloadMipMapLevel() -> not validated\n");
312 tmu
=(int)ti
->tmi
.whichTMU
;
313 fxTMMoveInTM(fxMesa
,tObj
,tmu
);
315 fxTexGetInfo(ti
->tmi
.mipmapLevel
[0].width
,ti
->tmi
.mipmapLevel
[0].height
,
316 &lodlevel
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
);
321 grTexDownloadMipMapLevel(tmu
,
322 ti
->tmi
.tm
[tmu
]->startAddress
,FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
323 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
324 ti
->info
.format
,GR_MIPMAPLEVELMASK_BOTH
,
325 ti
->tmi
.mipmapLevel
[level
].data
);
327 case FX_TMU_SPLIT
: /* TO DO: alternate even/odd TMU0/TMU1 */
328 grTexDownloadMipMapLevel(GR_TMU0
,
329 ti
->tmi
.tm
[GR_TMU0
]->startAddress
,FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
330 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
331 ti
->info
.format
,GR_MIPMAPLEVELMASK_ODD
,
332 ti
->tmi
.mipmapLevel
[level
].data
);
334 grTexDownloadMipMapLevel(GR_TMU1
,
335 ti
->tmi
.tm
[GR_TMU1
]->startAddress
,FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
336 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
337 ti
->info
.format
,GR_MIPMAPLEVELMASK_EVEN
,
338 ti
->tmi
.mipmapLevel
[level
].data
);
341 fprintf(stderr
,"fx Driver: internal error in fxTMReloadMipMapLevel() -> wrong tmu (%d)\n",tmu
);
347 void fxTMReloadSubMipMapLevel(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
,
348 GLint level
, GLint yoffset
, GLint height
)
350 tfxTexInfo
*ti
=(tfxTexInfo
*)tObj
->DriverData
;
352 unsigned short *data
;
356 fprintf(stderr
,"fx Driver: internal error in fxTMReloadSubMipMapLevel() -> not validated\n");
361 tmu
=(int)ti
->tmi
.whichTMU
;
362 fxTMMoveInTM(fxMesa
,tObj
,tmu
);
364 fxTexGetInfo(ti
->tmi
.mipmapLevel
[0].width
,ti
->tmi
.mipmapLevel
[0].height
,
365 &lodlevel
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
,NULL
);
367 if((ti
->info
.format
==GR_TEXFMT_INTENSITY_8
) ||
368 (ti
->info
.format
==GR_TEXFMT_P_8
) ||
369 (ti
->info
.format
==GR_TEXFMT_ALPHA_8
))
370 data
=ti
->tmi
.mipmapLevel
[level
].data
+((yoffset
*ti
->tmi
.mipmapLevel
[level
].width
)>>1);
372 data
=ti
->tmi
.mipmapLevel
[level
].data
+yoffset
*ti
->tmi
.mipmapLevel
[level
].width
;
377 grTexDownloadMipMapLevelPartial(tmu
,
378 ti
->tmi
.tm
[tmu
]->startAddress
,FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
379 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
380 ti
->info
.format
,GR_MIPMAPLEVELMASK_BOTH
,
382 yoffset
,yoffset
+height
-1);
384 case FX_TMU_SPLIT
: /* TO DO: alternate even/odd TMU0/TMU1 */
385 grTexDownloadMipMapLevelPartial(GR_TMU0
,
386 ti
->tmi
.tm
[FX_TMU0
]->startAddress
,FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
387 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
388 ti
->info
.format
,GR_MIPMAPLEVELMASK_ODD
,
390 yoffset
,yoffset
+height
-1);
392 grTexDownloadMipMapLevelPartial(GR_TMU1
,
393 ti
->tmi
.tm
[FX_TMU1
]->startAddress
,FX_valueToLod(FX_lodToValue(lodlevel
)+level
),
394 FX_largeLodLog2(ti
->info
),FX_aspectRatioLog2(ti
->info
),
395 ti
->info
.format
,GR_MIPMAPLEVELMASK_EVEN
,
397 yoffset
,yoffset
+height
-1);
400 fprintf(stderr
,"fx Driver: internal error in fxTMReloadSubMipMapLevel() -> wrong tmu (%d)\n",tmu
);
406 static tfxTMAllocNode
*fxTMFreeTMAllocBlock(tfxTMAllocNode
*tmalloc
,
407 tfxTMAllocNode
*tmunalloc
)
412 if(tmalloc
==tmunalloc
) {
413 tfxTMAllocNode
*newtmalloc
;
415 newtmalloc
=tmalloc
->next
;
421 tmalloc
->next
=fxTMFreeTMAllocBlock(tmalloc
->next
,tmunalloc
);
426 static tfxTMFreeNode
*fxTMAddTMFree(tfxTMFreeNode
*tmfree
, FxU32 startadr
, FxU32 endadr
)
429 return fxTMNewTMFreeNode(startadr
,endadr
);
431 if((endadr
+1==tmfree
->startAddress
) && (tmfree
->startAddress
& 0x1fffff)) {
432 tmfree
->startAddress
=startadr
;
437 if((startadr
-1==tmfree
->endAddress
) && (startadr
& 0x1fffff)) {
438 tmfree
->endAddress
=endadr
;
440 if((tmfree
->next
&& (endadr
+1==tmfree
->next
->startAddress
) &&
441 (tmfree
->next
->startAddress
& 0x1fffff))) {
442 tfxTMFreeNode
*nexttmfree
;
444 tmfree
->endAddress
=tmfree
->next
->endAddress
;
446 nexttmfree
=tmfree
->next
->next
;
449 tmfree
->next
=nexttmfree
;
456 if(startadr
<tmfree
->startAddress
) {
457 tfxTMFreeNode
*newtmfree
;
459 newtmfree
=fxTMNewTMFreeNode(startadr
,endadr
);
460 newtmfree
->next
=tmfree
;
465 tmfree
->next
=fxTMAddTMFree(tmfree
->next
,startadr
,endadr
);
470 static void fxTMFreeTMBlock(fxMesaContext fxMesa
, GLint tmu
, tfxTMAllocNode
*tmalloc
)
472 FxU32 startadr
,endadr
;
474 startadr
=tmalloc
->startAddress
;
475 endadr
=tmalloc
->endAddress
;
477 fxMesa
->tmAlloc
[tmu
]=fxTMFreeTMAllocBlock(fxMesa
->tmAlloc
[tmu
],tmalloc
);
479 fxMesa
->tmFree
[tmu
]=fxTMAddTMFree(fxMesa
->tmFree
[tmu
],startadr
,endadr
);
481 fxMesa
->freeTexMem
[tmu
]+=endadr
-startadr
+1;
484 void fxTMMoveOutTM(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
)
486 tfxTexInfo
*ti
=(tfxTexInfo
*)tObj
->DriverData
;
488 if (MESA_VERBOSE
&VERBOSE_DRIVER
) {
489 fprintf(stderr
,"fxmesa: fxTMMoveOutTM(%x (%d))\n",(GLuint
)tObj
,tObj
->Name
);
495 switch(ti
->tmi
.whichTMU
) {
498 fxTMFreeTMBlock(fxMesa
,(int)ti
->tmi
.whichTMU
,ti
->tmi
.tm
[ti
->tmi
.whichTMU
]);
501 fxTMFreeTMBlock(fxMesa
,FX_TMU0
,ti
->tmi
.tm
[FX_TMU0
]);
502 fxTMFreeTMBlock(fxMesa
,FX_TMU1
,ti
->tmi
.tm
[FX_TMU1
]);
505 fprintf(stderr
,"fx Driver: internal error in fxTMMoveOutTM()\n");
510 ti
->tmi
.whichTMU
=FX_TMU_NONE
;
511 ti
->tmi
.isInTM
=GL_FALSE
;
514 void fxTMFreeTexture(fxMesaContext fxMesa
, struct gl_texture_object
*tObj
)
516 tfxTexInfo
*ti
=(tfxTexInfo
*)tObj
->DriverData
;
519 fxTMMoveOutTM(fxMesa
,tObj
);
521 for(i
=0;i
<MAX_TEXTURE_LEVELS
;i
++) {
522 if(ti
->tmi
.mipmapLevel
[i
].used
&&
523 ti
->tmi
.mipmapLevel
[i
].translated
)
524 free(ti
->tmi
.mipmapLevel
[i
].data
);
526 (void)ti
->tmi
.mipmapLevel
[i
].data
;
530 void fxTMFreeAllFreeNode(tfxTMFreeNode
*fn
)
536 fxTMFreeAllFreeNode(fn
->next
);
541 void fxTMFreeAllAllocNode(tfxTMAllocNode
*an
)
547 fxTMFreeAllAllocNode(an
->next
);
552 void fxTMClose(fxMesaContext fxMesa
)
554 fxTMFreeAllFreeNode(fxMesa
->tmFree
[FX_TMU0
]);
555 fxTMFreeAllAllocNode(fxMesa
->tmAlloc
[FX_TMU0
]);
556 fxMesa
->tmFree
[FX_TMU0
] = NULL
;
557 fxMesa
->tmAlloc
[FX_TMU0
] = NULL
;
558 if(fxMesa
->haveTwoTMUs
) {
559 fxTMFreeAllFreeNode(fxMesa
->tmFree
[FX_TMU1
]);
560 fxTMFreeAllAllocNode(fxMesa
->tmAlloc
[FX_TMU1
]);
561 fxMesa
->tmFree
[FX_TMU1
] = NULL
;
562 fxMesa
->tmAlloc
[FX_TMU1
] = NULL
;
571 * Need this to provide at least one external definition.
574 int gl_fx_dummy_function_texman(void)