diff options
author | jtg <jtg> | 1999-08-19 00:55:39 +0000 |
---|---|---|
committer | jtg <jtg> | 1999-08-19 00:55:39 +0000 |
commit | afb833d4e89c312460a4ab9ed6a7a8ca4ebbfe1c (patch) | |
tree | 59d65b4da12fb5379224cf5f6b808fde91523c7f /src/mesa/drivers/glide/fxtexman.c | |
parent | f2544d4920ce168bec9cd94d774b7ea5103a3d74 (diff) |
Initial revision
Diffstat (limited to 'src/mesa/drivers/glide/fxtexman.c')
-rw-r--r-- | src/mesa/drivers/glide/fxtexman.c | 579 |
1 files changed, 579 insertions, 0 deletions
diff --git a/src/mesa/drivers/glide/fxtexman.c b/src/mesa/drivers/glide/fxtexman.c new file mode 100644 index 00000000000..5ee145e3cbf --- /dev/null +++ b/src/mesa/drivers/glide/fxtexman.c @@ -0,0 +1,579 @@ +/* -*- mode: C; tab-width:8; -*- + + fxtexman.c - 3Dfx VooDoo texture memory functions +*/ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * See the file fxapi.c for more informations about authors + * + */ + +#ifdef HAVE_CONFIG_H +#include "conf.h" +#endif + +#if defined(FX) + +#include "fxdrv.h" + +static tfxTMFreeNode *fxTMNewTMFreeNode(FxU32 start, FxU32 end) +{ + tfxTMFreeNode *tmn; + + if(!(tmn=malloc(sizeof(tfxTMFreeNode)))) { + fprintf(stderr,"fx Driver: out of memory !\n"); + fxCloseHardware(); + exit(-1); + } + + tmn->next=NULL; + tmn->startAddress=start; + tmn->endAddress=end; + + return tmn; +} + +static void fxTMUInit(fxMesaContext fxMesa, int tmu) +{ + tfxTMFreeNode *tmn,*tmntmp; + FxU32 start,end,blockstart,blockend; + + start=grTexMinAddress(tmu); + end=grTexMaxAddress(tmu); + + if(fxMesa->verbose) { + fprintf(stderr,"%s configuration:",(tmu==FX_TMU0) ? "TMU0" : "TMU1"); + fprintf(stderr," Lower texture memory address (%u)\n",(unsigned int)start); + fprintf(stderr," Higher texture memory address (%u)\n",(unsigned int)end); + fprintf(stderr," Splitting Texture memory in 2Mb blocks:\n"); + } + + fxMesa->freeTexMem[tmu]=end-start; + fxMesa->tmFree[tmu]=NULL; + fxMesa->tmAlloc[tmu]=NULL; + + blockstart=start; + while(blockstart<=end) { + if(blockstart+0x1fffff>end) + blockend=end; + else + blockend=blockstart+0x1fffff; + + if(fxMesa->verbose) + fprintf(stderr," %07u-%07u\n",(unsigned int)blockstart,(unsigned int)blockend); + + tmn=fxTMNewTMFreeNode(blockstart,blockend); + + if(fxMesa->tmFree[tmu]) { + for(tmntmp=fxMesa->tmFree[tmu];tmntmp->next!=NULL;tmntmp=tmntmp->next){}; + tmntmp->next=tmn; + } else + fxMesa->tmFree[tmu]=tmn; + + blockstart+=0x1fffff+1; + } +} + +void fxTMInit(fxMesaContext fxMesa) +{ + fxTMUInit(fxMesa,FX_TMU0); + + if(fxMesa->haveTwoTMUs) + fxTMUInit(fxMesa,FX_TMU1); + + fxMesa->texBindNumber=0; +} + +static struct gl_texture_object *fxTMFindOldestTMBlock(fxMesaContext fxMesa, + tfxTMAllocNode *tmalloc, + GLuint texbindnumber) +{ + GLuint age,oldestage,lasttimeused; + struct gl_texture_object *oldesttexobj; + + (void)fxMesa; + oldesttexobj=tmalloc->tObj; + oldestage=0; + + while(tmalloc) { + lasttimeused=((tfxTexInfo *)(tmalloc->tObj->DriverData))->tmi.lastTimeUsed; + + if(lasttimeused>texbindnumber) + age=texbindnumber+(UINT_MAX-lasttimeused+1); /* TO DO: check */ + else + age=texbindnumber-lasttimeused; + + if(age>=oldestage) { + oldestage=age; + oldesttexobj=tmalloc->tObj; + } + + tmalloc=tmalloc->next; + } + + return oldesttexobj; +} + +static GLboolean fxTMFreeOldTMBlock(fxMesaContext fxMesa, GLint tmu) +{ + struct gl_texture_object *oldesttexobj; + + if(!fxMesa->tmAlloc[tmu]) + return GL_FALSE; + + oldesttexobj=fxTMFindOldestTMBlock(fxMesa,fxMesa->tmAlloc[tmu],fxMesa->texBindNumber); + + fxTMMoveOutTM(fxMesa,oldesttexobj); + + return GL_TRUE; +} + +static tfxTMFreeNode *fxTMExtractTMFreeBlock(tfxTMFreeNode *tmfree, int texmemsize, + GLboolean *success, FxU32 *startadr) +{ + int blocksize; + + /* TO DO: cut recursion */ + + if(!tmfree) { + *success=GL_FALSE; + return NULL; + } + + blocksize=(int)tmfree->endAddress-(int)tmfree->startAddress+1; + + if(blocksize==texmemsize) { + tfxTMFreeNode *nexttmfree; + + *success=GL_TRUE; + *startadr=tmfree->startAddress; + + nexttmfree=tmfree->next; + free(tmfree); + + return nexttmfree; + } + + if(blocksize>texmemsize) { + *success=GL_TRUE; + *startadr=tmfree->startAddress; + + tmfree->startAddress+=texmemsize; + + return tmfree; + } + + tmfree->next=fxTMExtractTMFreeBlock(tmfree->next,texmemsize,success,startadr); + + return tmfree; +} + +static tfxTMAllocNode *fxTMGetTMBlock(fxMesaContext fxMesa, struct gl_texture_object *tObj, + GLint tmu, int texmemsize) +{ + tfxTMFreeNode *newtmfree; + tfxTMAllocNode *newtmalloc; + GLboolean success; + FxU32 startadr; + + for(;;) { /* TO DO: improve performaces */ + newtmfree=fxTMExtractTMFreeBlock(fxMesa->tmFree[tmu],texmemsize,&success,&startadr); + + if(success) { + fxMesa->tmFree[tmu]=newtmfree; + + fxMesa->freeTexMem[tmu]-=texmemsize; + + if(!(newtmalloc=malloc(sizeof(tfxTMAllocNode)))) { + fprintf(stderr,"fx Driver: out of memory !\n"); + fxCloseHardware(); + exit(-1); + } + + newtmalloc->next=fxMesa->tmAlloc[tmu]; + newtmalloc->startAddress=startadr; + newtmalloc->endAddress=startadr+texmemsize-1; + newtmalloc->tObj=tObj; + + fxMesa->tmAlloc[tmu]=newtmalloc; + + return newtmalloc; + } + + if(!fxTMFreeOldTMBlock(fxMesa,tmu)) { + fprintf(stderr,"fx Driver: internal error in fxTMGetTMBlock()\n"); + fprintf(stderr," TMU: %d Size: %d\n",tmu,texmemsize); + + fxCloseHardware(); + exit(-1); + } + } +} + +void fxTMMoveInTM(fxMesaContext fxMesa, struct gl_texture_object *tObj, GLint where) +{ + tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData; + int i,l; + int texmemsize; + + if (MESA_VERBOSE&VERBOSE_DRIVER) { + fprintf(stderr,"fxmesa: fxTMMoveInTM(%d)\n",tObj->Name); + } + + fxMesa->stats.reqTexUpload++; + + if(!ti->validated) { + fprintf(stderr,"fx Driver: internal error in fxTMMoveInTM() -> not validated\n"); + fxCloseHardware(); + exit(-1); + } + + if(ti->tmi.isInTM) + return; + + if (MESA_VERBOSE&(VERBOSE_DRIVER|VERBOSE_TEXTURE)) { + fprintf(stderr,"fxmesa: downloading %x (%d) in texture memory in %d\n",(GLuint)tObj,tObj->Name,where); + } + + ti->tmi.whichTMU=(FxU32)where; + + switch(where) { + case FX_TMU0: + case FX_TMU1: + texmemsize=(int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_BOTH,&(ti->info)); + ti->tmi.tm[where]=fxTMGetTMBlock(fxMesa,tObj,where,texmemsize); + fxMesa->stats.memTexUpload+=texmemsize; + + for(i=FX_largeLodValue(ti->info),l=ti->minLevel;i<=FX_smallLodValue(ti->info);i++,l++) + grTexDownloadMipMapLevel(where, + ti->tmi.tm[where]->startAddress,FX_valueToLod(i), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_BOTH, + ti->tmi.mipmapLevel[l].data); + break; + case FX_TMU_SPLIT: /* TO DO: alternate even/odd TMU0/TMU1 */ + texmemsize=(int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_ODD,&(ti->info)); + ti->tmi.tm[FX_TMU0]=fxTMGetTMBlock(fxMesa,tObj,FX_TMU0,texmemsize); + fxMesa->stats.memTexUpload+=texmemsize; + + texmemsize=(int)grTexTextureMemRequired(GR_MIPMAPLEVELMASK_EVEN,&(ti->info)); + ti->tmi.tm[FX_TMU1]=fxTMGetTMBlock(fxMesa,tObj,FX_TMU1,texmemsize); + fxMesa->stats.memTexUpload+=texmemsize; + + for(i=FX_largeLodValue(ti->info),l=ti->minLevel;i<=FX_smallLodValue(ti->info);i++,l++) { + grTexDownloadMipMapLevel(GR_TMU0,ti->tmi.tm[FX_TMU0]->startAddress,FX_valueToLod(i), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_ODD, + ti->tmi.mipmapLevel[l].data); + + grTexDownloadMipMapLevel(GR_TMU1,ti->tmi.tm[FX_TMU1]->startAddress,FX_valueToLod(i), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_EVEN, + ti->tmi.mipmapLevel[l].data); + } + break; + default: + fprintf(stderr,"fx Driver: internal error in fxTMMoveInTM() -> wrong tmu (%d)\n",where); + fxCloseHardware(); + exit(-1); + } + + fxMesa->stats.texUpload++; + + ti->tmi.isInTM=GL_TRUE; +} + +void fxTMReloadMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj, GLint level) +{ + tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData; + GrLOD_t lodlevel; + GLint tmu; + + if(!ti->validated) { + fprintf(stderr,"fx Driver: internal error in fxTMReloadMipMapLevel() -> not validated\n"); + fxCloseHardware(); + exit(-1); + } + + tmu=(int)ti->tmi.whichTMU; + fxTMMoveInTM(fxMesa,tObj,tmu); + + fxTexGetInfo(ti->tmi.mipmapLevel[0].width,ti->tmi.mipmapLevel[0].height, + &lodlevel,NULL,NULL,NULL,NULL,NULL,NULL,NULL); + + switch(tmu) { + case FX_TMU0: + case FX_TMU1: + grTexDownloadMipMapLevel(tmu, + ti->tmi.tm[tmu]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_BOTH, + ti->tmi.mipmapLevel[level].data); + break; + case FX_TMU_SPLIT: /* TO DO: alternate even/odd TMU0/TMU1 */ + grTexDownloadMipMapLevel(GR_TMU0, + ti->tmi.tm[GR_TMU0]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_ODD, + ti->tmi.mipmapLevel[level].data); + + grTexDownloadMipMapLevel(GR_TMU1, + ti->tmi.tm[GR_TMU1]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_EVEN, + ti->tmi.mipmapLevel[level].data); + break; + default: + fprintf(stderr,"fx Driver: internal error in fxTMReloadMipMapLevel() -> wrong tmu (%d)\n",tmu); + fxCloseHardware(); + exit(-1); + } +} + +void fxTMReloadSubMipMapLevel(fxMesaContext fxMesa, struct gl_texture_object *tObj, + GLint level, GLint yoffset, GLint height) +{ + tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData; + GrLOD_t lodlevel; + unsigned short *data; + GLint tmu; + + if(!ti->validated) { + fprintf(stderr,"fx Driver: internal error in fxTMReloadSubMipMapLevel() -> not validated\n"); + fxCloseHardware(); + exit(-1); + } + + tmu=(int)ti->tmi.whichTMU; + fxTMMoveInTM(fxMesa,tObj,tmu); + + fxTexGetInfo(ti->tmi.mipmapLevel[0].width,ti->tmi.mipmapLevel[0].height, + &lodlevel,NULL,NULL,NULL,NULL,NULL,NULL,NULL); + + if((ti->info.format==GR_TEXFMT_INTENSITY_8) || + (ti->info.format==GR_TEXFMT_P_8) || + (ti->info.format==GR_TEXFMT_ALPHA_8)) + data=ti->tmi.mipmapLevel[level].data+((yoffset*ti->tmi.mipmapLevel[level].width)>>1); + else + data=ti->tmi.mipmapLevel[level].data+yoffset*ti->tmi.mipmapLevel[level].width; + + switch(tmu) { + case FX_TMU0: + case FX_TMU1: + grTexDownloadMipMapLevelPartial(tmu, + ti->tmi.tm[tmu]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_BOTH, + data, + yoffset,yoffset+height-1); + break; + case FX_TMU_SPLIT: /* TO DO: alternate even/odd TMU0/TMU1 */ + grTexDownloadMipMapLevelPartial(GR_TMU0, + ti->tmi.tm[FX_TMU0]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_ODD, + data, + yoffset,yoffset+height-1); + + grTexDownloadMipMapLevelPartial(GR_TMU1, + ti->tmi.tm[FX_TMU1]->startAddress,FX_valueToLod(FX_lodToValue(lodlevel)+level), + FX_largeLodLog2(ti->info),FX_aspectRatioLog2(ti->info), + ti->info.format,GR_MIPMAPLEVELMASK_EVEN, + data, + yoffset,yoffset+height-1); + break; + default: + fprintf(stderr,"fx Driver: internal error in fxTMReloadSubMipMapLevel() -> wrong tmu (%d)\n",tmu); + fxCloseHardware(); + exit(-1); + } +} + +static tfxTMAllocNode *fxTMFreeTMAllocBlock(tfxTMAllocNode *tmalloc, + tfxTMAllocNode *tmunalloc) +{ + if(!tmalloc) + return NULL; + + if(tmalloc==tmunalloc) { + tfxTMAllocNode *newtmalloc; + + newtmalloc=tmalloc->next; + free(tmalloc); + + return newtmalloc; + } + + tmalloc->next=fxTMFreeTMAllocBlock(tmalloc->next,tmunalloc); + + return tmalloc; +} + +static tfxTMFreeNode *fxTMAddTMFree(tfxTMFreeNode *tmfree, FxU32 startadr, FxU32 endadr) +{ + if(!tmfree) + return fxTMNewTMFreeNode(startadr,endadr); + + if((endadr+1==tmfree->startAddress) && (tmfree->startAddress & 0x1fffff)) { + tmfree->startAddress=startadr; + + return tmfree; + } + + if((startadr-1==tmfree->endAddress) && (startadr & 0x1fffff)) { + tmfree->endAddress=endadr; + + if((tmfree->next && (endadr+1==tmfree->next->startAddress) && + (tmfree->next->startAddress & 0x1fffff))) { + tfxTMFreeNode *nexttmfree; + + tmfree->endAddress=tmfree->next->endAddress; + + nexttmfree=tmfree->next->next; + free(tmfree->next); + + tmfree->next=nexttmfree; + } + + + return tmfree; + } + + if(startadr<tmfree->startAddress) { + tfxTMFreeNode *newtmfree; + + newtmfree=fxTMNewTMFreeNode(startadr,endadr); + newtmfree->next=tmfree; + + return newtmfree; + } + + tmfree->next=fxTMAddTMFree(tmfree->next,startadr,endadr); + + return tmfree; +} + +static void fxTMFreeTMBlock(fxMesaContext fxMesa, GLint tmu, tfxTMAllocNode *tmalloc) +{ + FxU32 startadr,endadr; + + startadr=tmalloc->startAddress; + endadr=tmalloc->endAddress; + + fxMesa->tmAlloc[tmu]=fxTMFreeTMAllocBlock(fxMesa->tmAlloc[tmu],tmalloc); + + fxMesa->tmFree[tmu]=fxTMAddTMFree(fxMesa->tmFree[tmu],startadr,endadr); + + fxMesa->freeTexMem[tmu]+=endadr-startadr+1; +} + +void fxTMMoveOutTM(fxMesaContext fxMesa, struct gl_texture_object *tObj) +{ + tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData; + + if (MESA_VERBOSE&VERBOSE_DRIVER) { + fprintf(stderr,"fxmesa: fxTMMoveOutTM(%x (%d))\n",(GLuint)tObj,tObj->Name); + } + + if(!ti->tmi.isInTM) + return; + + switch(ti->tmi.whichTMU) { + case FX_TMU0: + case FX_TMU1: + fxTMFreeTMBlock(fxMesa,(int)ti->tmi.whichTMU,ti->tmi.tm[ti->tmi.whichTMU]); + break; + case FX_TMU_SPLIT: + fxTMFreeTMBlock(fxMesa,FX_TMU0,ti->tmi.tm[FX_TMU0]); + fxTMFreeTMBlock(fxMesa,FX_TMU1,ti->tmi.tm[FX_TMU1]); + break; + default: + fprintf(stderr,"fx Driver: internal error in fxTMMoveOutTM()\n"); + fxCloseHardware(); + exit(-1); + } + + ti->tmi.whichTMU=FX_TMU_NONE; + ti->tmi.isInTM=GL_FALSE; +} + +void fxTMFreeTexture(fxMesaContext fxMesa, struct gl_texture_object *tObj) +{ + tfxTexInfo *ti=(tfxTexInfo *)tObj->DriverData; + int i; + + fxTMMoveOutTM(fxMesa,tObj); + + for(i=0;i<MAX_TEXTURE_LEVELS;i++) { + if(ti->tmi.mipmapLevel[i].used && + ti->tmi.mipmapLevel[i].translated) + free(ti->tmi.mipmapLevel[i].data); + + (void)ti->tmi.mipmapLevel[i].data; + } +} + +void fxTMFreeAllFreeNode(tfxTMFreeNode *fn) +{ + if(!fn) + return; + + if(fn->next) + fxTMFreeAllFreeNode(fn->next); + + free(fn); +} + +void fxTMFreeAllAllocNode(tfxTMAllocNode *an) +{ + if(!an) + return; + + if(an->next) + fxTMFreeAllAllocNode(an->next); + + free(an); +} + +void fxTMClose(fxMesaContext fxMesa) +{ + fxTMFreeAllFreeNode(fxMesa->tmFree[FX_TMU0]); + fxTMFreeAllAllocNode(fxMesa->tmAlloc[FX_TMU0]); + fxMesa->tmFree[FX_TMU0] = NULL; + fxMesa->tmAlloc[FX_TMU0] = NULL; + if(fxMesa->haveTwoTMUs) { + fxTMFreeAllFreeNode(fxMesa->tmFree[FX_TMU1]); + fxTMFreeAllAllocNode(fxMesa->tmAlloc[FX_TMU1]); + fxMesa->tmFree[FX_TMU1] = NULL; + fxMesa->tmAlloc[FX_TMU1] = NULL; + } +} + + +#else + + +/* + * Need this to provide at least one external definition. + */ + +int gl_fx_dummy_function_texman(void) +{ + return 0; +} + +#endif /* FX */ |