2
Copyright (C) 2003 Rice1964
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version 2
7
of the License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
#include "ConvertImage.h"
24
#include "DeviceBuilder.h"
25
#include "FrameBuffer.h"
26
#include "RenderBase.h"
27
#include "TextureManager.h"
29
CTextureManager gTextureManager;
31
unsigned int g_maxTextureMemUsage = (5*1024*1024);
32
unsigned int g_amountToFree = (512*1024);
33
bool g_bUseSetTextureMem = false;
35
// Returns the first prime greater than or equal to nFirst
36
inline int GetNextPrime(int nFirst)
44
// Just make sure it's odd
45
if ((nCurrent % 2) == 0)
53
// nSqrtCurrent = nCurrent^0.5 + 1 (round up)
54
nSqrtCurrent = (int)sqrt((double)nCurrent) + 1;
59
// Test all odd numbers from 3..nSqrtCurrent
60
for (i = 3; i <= nSqrtCurrent; i+=2)
62
if ((nCurrent % i) == 0)
74
// Select next odd candidate...
82
///////////////////////////////////////////////////////////////////////
84
///////////////////////////////////////////////////////////////////////
85
CTextureManager::CTextureManager() :
87
m_pCacheTxtrList(NULL),
88
m_numOfCachedTxtrList(809)
90
m_numOfCachedTxtrList = GetNextPrime(800);
92
m_currentTextureMemUsage = 0;
93
m_pYoungestTexture = NULL;
94
m_pOldestTexture = NULL;
96
m_pCacheTxtrList = new TxtrCacheEntry *[m_numOfCachedTxtrList];
97
SAFE_CHECK(m_pCacheTxtrList);
99
for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
100
m_pCacheTxtrList[i] = NULL;
102
memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry));
103
memset(&m_PrimColorTextureEntry, 0, sizeof(TxtrCacheEntry));
104
memset(&m_EnvColorTextureEntry, 0, sizeof(TxtrCacheEntry));
105
memset(&m_LODFracTextureEntry, 0, sizeof(TxtrCacheEntry));
106
memset(&m_PrimLODFracTextureEntry, 0, sizeof(TxtrCacheEntry));
109
CTextureManager::~CTextureManager()
113
delete []m_pCacheTxtrList;
114
m_pCacheTxtrList = NULL;
119
// Delete all textures.
121
bool CTextureManager::CleanUp()
123
RecycleAllTextures();
125
if (!g_bUseSetTextureMem)
129
TxtrCacheEntry * pVictim = m_pHead;
130
m_pHead = pVictim->pNext;
136
if( m_blackTextureEntry.pTexture ) delete m_blackTextureEntry.pTexture;
137
if( m_PrimColorTextureEntry.pTexture ) delete m_PrimColorTextureEntry.pTexture;
138
if( m_EnvColorTextureEntry.pTexture ) delete m_EnvColorTextureEntry.pTexture;
139
if( m_LODFracTextureEntry.pTexture ) delete m_LODFracTextureEntry.pTexture;
140
if( m_PrimLODFracTextureEntry.pTexture ) delete m_PrimLODFracTextureEntry.pTexture;
141
memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry));
142
memset(&m_PrimColorTextureEntry, 0, sizeof(TxtrCacheEntry));
143
memset(&m_EnvColorTextureEntry, 0, sizeof(TxtrCacheEntry));
144
memset(&m_LODFracTextureEntry, 0, sizeof(TxtrCacheEntry));
145
memset(&m_PrimLODFracTextureEntry, 0, sizeof(TxtrCacheEntry));
150
bool CTextureManager::TCacheEntryIsLoaded(TxtrCacheEntry *pEntry)
152
for (int i = 0; i < MAX_TEXTURES; i++)
153
if (g_textures[i].pTextureEntry == pEntry)
159
// Purge any textures whos last usage was over 5 seconds ago
160
void CTextureManager::PurgeOldTextures()
162
if (m_pCacheTxtrList == NULL)
165
if (g_bUseSetTextureMem)
168
static const uint32 dwFramesToKill = 5*30; // 5 secs at 30 fps
169
static const uint32 dwFramesToDelete = 30*30; // 30 secs at 30 fps
171
for ( uint32 i = 0; i < m_numOfCachedTxtrList; i++ )
173
TxtrCacheEntry * pEntry;
174
TxtrCacheEntry * pNext;
176
pEntry = m_pCacheTxtrList[i];
179
pNext = pEntry->pNext;
181
if ( status.gDlistCount - pEntry->FrameLastUsed > dwFramesToKill && !TCacheEntryIsLoaded(pEntry))
183
RemoveTexture(pEntry);
190
// Remove any old textures that haven't been recycled in 1 minute or so
191
// Normally these would be reused
192
TxtrCacheEntry * pPrev;
193
TxtrCacheEntry * pCurr;
194
TxtrCacheEntry * pNext;
202
pNext = pCurr->pNext;
204
if ( status.gDlistCount - pCurr->FrameLastUsed > dwFramesToDelete && !TCacheEntryIsLoaded(pCurr) )
206
if (pPrev != NULL) pPrev->pNext = pCurr->pNext;
207
else m_pHead = pCurr->pNext;
220
void CTextureManager::RecycleAllTextures()
222
if (m_pCacheTxtrList == NULL)
226
uint32 dwTotalUses = 0;
228
m_pYoungestTexture = NULL;
229
m_pOldestTexture = NULL;
231
for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
233
while (m_pCacheTxtrList[i])
235
TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i];
236
m_pCacheTxtrList[i] = pTVictim->pNext;
238
dwTotalUses += pTVictim->dwUses;
240
if (g_bUseSetTextureMem)
243
RecycleTexture(pTVictim);
248
void CTextureManager::RecheckHiresForAllTextures()
250
if (m_pCacheTxtrList == NULL)
253
for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
255
while (m_pCacheTxtrList[i])
257
TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i];
258
m_pCacheTxtrList[i] = pTVictim->pNext;
259
pTVictim->bExternalTxtrChecked = false;
266
// Add to the recycle list
267
void CTextureManager::RecycleTexture(TxtrCacheEntry *pEntry)
269
if (g_bUseSetTextureMem)
272
if( CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE )
274
// Fix me, why I can not reuse the texture in OpenGL,
275
// how can I unload texture from video card memory for OpenGL
280
if (pEntry->pTexture == NULL)
282
// No point in saving!
288
pEntry->pNext = m_pHead;
289
SAFE_DELETE(pEntry->pEnhancedTexture);
294
// Search for a texture of the specified dimensions to recycle
295
TxtrCacheEntry * CTextureManager::ReviveTexture( uint32 width, uint32 height )
297
if (g_bUseSetTextureMem)
300
TxtrCacheEntry * pPrev;
301
TxtrCacheEntry * pCurr;
308
if (pCurr->ti.WidthToCreate == width &&
309
pCurr->ti.HeightToCreate == height)
312
if (pPrev != NULL) pPrev->pNext = pCurr->pNext;
313
else m_pHead = pCurr->pNext;
319
pCurr = pCurr->pNext;
326
uint32 CTextureManager::Hash(uint32 dwValue)
328
// Divide by four, because most textures will be on a 4 byte boundry, so bottom four
330
return (dwValue>>2) % m_numOfCachedTxtrList;
333
void CTextureManager::MakeTextureYoungest(TxtrCacheEntry *pEntry)
335
if (!g_bUseSetTextureMem)
338
if (pEntry == m_pYoungestTexture)
341
// if its the oldest, then change the oldest pointer
342
if (pEntry == m_pOldestTexture)
344
m_pOldestTexture = pEntry->pNextYoungest;
347
// if its a not a new texture, close the gap in the age list
348
// where pEntry use to reside
349
if (pEntry->pNextYoungest != NULL || pEntry->pLastYoungest != NULL)
351
if (pEntry->pNextYoungest != NULL)
353
pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest;
355
if (pEntry->pLastYoungest != NULL)
357
pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest;
361
// this texture is now the youngest, so place it on the end of the list
362
if (m_pYoungestTexture != NULL)
364
m_pYoungestTexture->pNextYoungest = pEntry;
367
pEntry->pNextYoungest = NULL;
368
pEntry->pLastYoungest = m_pYoungestTexture;
369
m_pYoungestTexture = pEntry;
371
// if this is the first texture in memory then its also the oldest
372
if (m_pOldestTexture == NULL)
374
m_pOldestTexture = pEntry;
378
void CTextureManager::AddTexture(TxtrCacheEntry *pEntry)
380
uint32 dwKey = Hash(pEntry->ti.Address);
382
if (m_pCacheTxtrList == NULL)
385
//TxtrCacheEntry **p = &m_pCacheTxtrList[dwKey];
387
// Add to head (not tail, for speed - new textures are more likely to be accessed next)
388
pEntry->pNext = m_pCacheTxtrList[dwKey];
389
m_pCacheTxtrList[dwKey] = pEntry;
391
// Move the texture to the top of the age list
392
MakeTextureYoungest(pEntry);
397
TxtrCacheEntry * CTextureManager::GetTxtrCacheEntry(TxtrInfo * pti)
399
TxtrCacheEntry *pEntry;
401
if (m_pCacheTxtrList == NULL)
404
// See if it is already in the hash table
405
uint32 dwKey = Hash(pti->Address);
407
for (pEntry = m_pCacheTxtrList[dwKey]; pEntry; pEntry = pEntry->pNext)
409
if ( pEntry->ti == *pti )
411
MakeTextureYoungest(pEntry);
421
void CTextureManager::RemoveTexture(TxtrCacheEntry * pEntry)
423
TxtrCacheEntry * pPrev;
424
TxtrCacheEntry * pCurr;
426
if (m_pCacheTxtrList == NULL)
429
// See if it is already in the hash table
430
uint32 dwKey = Hash(pEntry->ti.Address);
433
pCurr = m_pCacheTxtrList[dwKey];
437
// Check that the attributes match
438
if ( pCurr->ti == pEntry->ti )
441
pPrev->pNext = pCurr->pNext;
443
m_pCacheTxtrList[dwKey] = pCurr->pNext;
445
if (g_bUseSetTextureMem)
447
// remove the texture from the age list
448
if (pEntry->pNextYoungest != NULL)
450
pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest;
452
if (pEntry->pLastYoungest != NULL)
454
pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest;
457
// decrease the mem usage counter
458
m_currentTextureMemUsage -= (pEntry->pTexture->m_dwWidth * pEntry->pTexture->m_dwHeight * 4);
464
RecycleTexture(pEntry);
471
pCurr = pCurr->pNext;
476
TxtrCacheEntry * CTextureManager::CreateNewCacheEntry(uint32 dwAddr, uint32 dwWidth, uint32 dwHeight)
478
TxtrCacheEntry * pEntry = NULL;
480
if (g_bUseSetTextureMem)
482
uint32 widthToCreate = dwWidth;
483
uint32 heightToCreate = dwHeight;
484
unsigned int freeUpSize = (widthToCreate * heightToCreate * 4) + g_amountToFree;
486
// make sure there is enough room for the new texture by deleting old textures
487
while ((m_currentTextureMemUsage + freeUpSize) > g_maxTextureMemUsage && m_pOldestTexture != NULL)
489
TxtrCacheEntry *nextYoungest = m_pOldestTexture->pNextYoungest;
491
RemoveTexture(m_pOldestTexture);
493
m_pOldestTexture = nextYoungest;
495
//printf("Freeing Texture\n");
498
m_currentTextureMemUsage += widthToCreate * heightToCreate * 4;
502
// Find a used texture
503
pEntry = ReviveTexture(dwWidth, dwHeight);
506
if (pEntry == NULL || g_bUseSetTextureMem)
508
// Couldn't find on - recreate!
509
pEntry = new TxtrCacheEntry;
512
_VIDEO_DisplayTemporaryMessage("Error to create an texture entry");
516
pEntry->pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(dwWidth, dwHeight);
517
if (pEntry->pTexture == NULL || pEntry->pTexture->GetTexture() == NULL)
519
_VIDEO_DisplayTemporaryMessage("Error to create an texture");
520
TRACE2("Warning, unable to create %d x %d texture!", dwWidth, dwHeight);
524
pEntry->pTexture->m_bScaledS = false;
525
pEntry->pTexture->m_bScaledT = false;
530
pEntry->ti.Address = dwAddr;
531
pEntry->pNext = NULL;
532
pEntry->pNextYoungest = NULL;
533
pEntry->pLastYoungest = NULL;
535
pEntry->dwTimeLastUsed = status.gRDPTime;
537
pEntry->FrameLastUsed = status.gDlistCount;
538
pEntry->FrameLastUpdated = 0;
539
pEntry->lastEntry = NULL;
540
pEntry->bExternalTxtrChecked = false;
543
// Add to the hash table
548
// If already in table, return
549
// Otherwise, create surfaces, and load texture into memory
552
uint32 dwAsmdwBytesPerLine;
557
TxtrCacheEntry *g_lastTextureEntry=NULL;
558
bool lastEntryModified = false;
561
TxtrCacheEntry * CTextureManager::GetTexture(TxtrInfo * pgti, bool fromTMEM, bool doCRCCheck, bool AutoExtendTexture)
563
TxtrCacheEntry *pEntry;
565
if( g_curRomInfo.bDisableTextureCRC )
568
gRDP.texturesAreReloaded = true;
573
pEntry = GetTxtrCacheEntry(pgti);
574
bool loadFromTextureBuffer=false;
575
int txtBufIdxToLoadFrom = -1;
576
if( (frameBufferOptions.bCheckRenderTextures&&!frameBufferOptions.bWriteBackBufToRDRAM) || (frameBufferOptions.bCheckBackBufs&&!frameBufferOptions.bWriteBackBufToRDRAM) )
578
txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address);
579
if( txtBufIdxToLoadFrom >= 0 )
581
loadFromTextureBuffer = true;
582
// Check if it is the same size,
583
RenderTextureInfo &info = gRenderTextureInfos[txtBufIdxToLoadFrom];
584
//if( info.pRenderTexture && info.CI_Info.dwAddr == pgti->Address && info.CI_Info.dwFormat == pgti->Format
585
if( info.pRenderTexture && info.CI_Info.dwFormat == pgti->Format
586
&& info.CI_Info.dwSize == pgti->Size )
588
info.txtEntry.ti = *pgti;
589
return &info.txtEntry;
594
bool loadFromBackBuffer=false;
595
if( frameBufferOptions.bCheckBackBufs && g_pFrameBufferManager->CheckAddrInBackBuffers(pgti->Address, pgti->HeightToLoad*pgti->Pitch) >= 0 )
597
if( !frameBufferOptions.bWriteBackBufToRDRAM )
599
// Load the texture from recent back buffer
600
loadFromBackBuffer = true;
601
txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address);
602
if( txtBufIdxToLoadFrom >= 0 )
604
loadFromTextureBuffer = true;
605
// Check if it is the same size,
606
RenderTextureInfo &info = gRenderTextureInfos[txtBufIdxToLoadFrom];
607
//if( info.pRenderTexture && info.CI_Info.dwAddr == pgti->Address && info.CI_Info.dwFormat == pgti->Format
608
if( info.pRenderTexture && info.CI_Info.dwFormat == pgti->Format
609
&& info.CI_Info.dwSize == pgti->Size )
611
info.txtEntry.ti = *pgti;
612
return &info.txtEntry;
618
if (pEntry && pEntry->dwTimeLastUsed == status.gRDPTime && status.gDlistCount != 0 && !status.bN64FrameBufferIsUsed ) // This is not good, Palatte may changes
620
// We've already calculated a CRC this frame!
621
dwAsmCRC = pEntry->dwCRC;
627
if( loadFromTextureBuffer )
628
dwAsmCRC = gRenderTextureInfos[txtBufIdxToLoadFrom].crcInRDRAM;
630
CalculateRDRAMCRC(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch);
635
if ( doCRCCheck && (pgti->Format == TXT_FMT_CI || (pgti->Format == TXT_FMT_RGBA && pgti->Size <= TXT_SIZE_8b )))
637
//maxCI = pgti->Size == TXT_SIZE_8b ? 255 : 15;
638
extern unsigned char CalculateMaxCI(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes );
640
if( !pEntry || pEntry->dwCRC != dwAsmCRC || pEntry->maxCI < 0 )
642
maxCI = CalculateMaxCI(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch);
646
maxCI = pEntry->maxCI;
651
uint32 dwPalSize = 16;
654
if( pgti->Size == TXT_SIZE_8b )
661
dwOffset = pgti->Palette << 4;
664
pStart = (uint8*)pgti->PalAddress+dwOffset*2;
666
//for (y = 0; y < dwPalSize*2; y+=4)
668
// dwPalCRC = (dwPalCRC + *(uint32*)&pStart[y]);
671
uint32 dwAsmCRCSave = dwAsmCRC;
672
//dwPalCRC = CalculateRDRAMCRC(pStart, 0, 0, dwPalSize, 1, TXT_SIZE_16b, dwPalSize*2);
673
dwPalCRC = CalculateRDRAMCRC(pStart, 0, 0, maxCI+1, 1, TXT_SIZE_16b, dwPalSize*2);
674
dwAsmCRC = dwAsmCRCSave;
677
if (pEntry && doCRCCheck )
679
if(pEntry->dwCRC == dwAsmCRC && pEntry->dwPalCRC == dwPalCRC &&
680
(!loadFromTextureBuffer || gRenderTextureInfos[txtBufIdxToLoadFrom].updateAtFrame < pEntry->FrameLastUsed ) )
682
// Tile is ok, return
684
pEntry->dwTimeLastUsed = status.gRDPTime;
685
pEntry->FrameLastUsed = status.gDlistCount;
686
LOG_TEXTURE(TRACE0(" Use current texture:\n"));
687
pEntry->lastEntry = g_lastTextureEntry;
688
g_lastTextureEntry = pEntry;
689
lastEntryModified = false;
691
DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) ,
692
{DebuggerAppendMsg("Load cached texture from render_texture");}
705
// We need to create a new entry, and add it
706
// to the hash table.
707
pEntry = CreateNewCacheEntry(pgti->Address, pgti->WidthToCreate, pgti->HeightToCreate);
711
g_lastTextureEntry = pEntry;
712
_VIDEO_DisplayTemporaryMessage("Fail to create new texture entry");
718
pEntry->dwCRC = dwAsmCRC;
719
pEntry->dwPalCRC = dwPalCRC;
720
pEntry->bExternalTxtrChecked = false;
721
pEntry->maxCI = maxCI;
723
if( pEntry->pTexture->m_dwCreatedTextureWidth < pgti->WidthToCreate )
725
pEntry->ti.WidthToLoad = pEntry->pTexture->m_dwCreatedTextureWidth;
726
pEntry->pTexture->m_bScaledS = false;
727
pEntry->pTexture->m_bScaledT = false;
729
if( pEntry->pTexture->m_dwCreatedTextureHeight < pgti->HeightToCreate )
731
pEntry->ti.HeightToLoad = pEntry->pTexture->m_dwCreatedTextureHeight;
732
pEntry->pTexture->m_bScaledT = false;
733
pEntry->pTexture->m_bScaledS = false;
738
if (pEntry->pTexture != NULL)
740
TextureFmt dwType = pEntry->pTexture->GetSurfaceFormat();
741
SAFE_DELETE(pEntry->pEnhancedTexture);
742
pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
744
if (dwType != TEXTURE_FMT_UNKNOWN)
746
if( loadFromTextureBuffer )
748
g_pFrameBufferManager->LoadTextureFromRenderTexture(pEntry, txtBufIdxToLoadFrom);
749
DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) ,
750
{DebuggerAppendMsg("Load texture from render_texture %d", txtBufIdxToLoadFrom);}
753
extern void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha);
754
if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_I )
756
// Convert texture from RGBA to I
757
ConvertTextureRGBAtoI(pEntry,false);
759
else if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_IA )
761
// Convert texture from RGBA to IA
762
ConvertTextureRGBAtoI(pEntry,true);
767
LOG_TEXTURE(TRACE0(" Load new texture from RDRAM:\n"));
768
if (dwType == TEXTURE_FMT_A8R8G8B8)
770
ConvertTexture(pEntry, fromTMEM);
773
ConvertTexture_16(pEntry, fromTMEM);
774
pEntry->FrameLastUpdated = status.gDlistCount;
775
SAFE_DELETE(pEntry->pEnhancedTexture);
776
pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
780
pEntry->ti.WidthToLoad = pgti->WidthToLoad;
781
pEntry->ti.HeightToLoad = pgti->HeightToLoad;
783
if( AutoExtendTexture )
785
ExpandTextureS(pEntry);
786
ExpandTextureT(pEntry);
789
if( options.bDumpTexturesToFiles && !loadFromTextureBuffer )
791
DumpCachedTexture(*pEntry);
795
if( pauseAtNext && eventToPause == NEXT_NEW_TEXTURE )
797
CRender::g_pRender->SetCurrentTexture( 0, pEntry->pTexture, pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry);
798
CRender::g_pRender->DrawTexture(0);
799
debuggerPause = true;
800
TRACE0("Pause after loading a new texture");
801
if( pEntry->ti.Format == TXT_FMT_YUV )
803
TRACE0("This is YUV texture");
805
DebuggerAppendMsg("W:%d, H:%d, RealW:%d, RealH:%d, D3DW:%d, D3DH: %d", pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate,
806
pEntry->ti.WidthToLoad, pEntry->ti.HeightToLoad, pEntry->pTexture->m_dwCreatedTextureWidth, pEntry->pTexture->m_dwCreatedTextureHeight);
807
DebuggerAppendMsg("ScaledS:%s, ScaledT:%s, CRC=%08X", pEntry->pTexture->m_bScaledS?"T":"F", pEntry->pTexture->m_bScaledT?"T":"F", pEntry->dwCRC);
809
CRender::g_pRender->SetCurrentTexture( 0, NULL, 64, 64, NULL);
816
TRACE0("Exception in texture decompression");
817
g_lastTextureEntry = NULL;
821
pEntry->lastEntry = g_lastTextureEntry;
822
g_lastTextureEntry = pEntry;
823
lastEntryModified = true;
830
const char *pszImgFormat[8] = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"};
831
uint8 pnImgSize[4] = {4, 8, 16, 32};
832
const char *textlutname[4] = {"RGB16", "I16?", "RGBA16", "IA16"};
834
extern uint16 g_wRDPTlut[];
835
extern ConvertFunction gConvertFunctions_FullTMEM[ 8 ][ 4 ];
836
extern ConvertFunction gConvertFunctions[ 8 ][ 4 ];
837
extern ConvertFunction gConvertTlutFunctions[ 8 ][ 4 ];
838
extern ConvertFunction gConvertFunctions_16[ 8 ][ 4 ];
839
extern ConvertFunction gConvertFunctions_16_FullTMEM[ 8 ][ 4 ];
840
extern ConvertFunction gConvertTlutFunctions_16[ 8 ][ 4 ];
841
void CTextureManager::ConvertTexture(TxtrCacheEntry * pEntry, bool fromTMEM)
843
static uint32 dwCount = 0;
846
if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM )
848
pF = gConvertFunctions_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ];
852
if( gRDP.tiles[7].dwFormat == TXT_FMT_YUV )
854
if( gRDP.otherMode.text_tlut>=2 )
855
pF = gConvertTlutFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ];
857
pF = gConvertFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ];
861
if( gRDP.otherMode.text_tlut>=2 )
862
pF = gConvertTlutFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ];
864
pF = gConvertFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ];
870
pF( pEntry->pTexture, pEntry->ti );
874
DebuggerAppendMsg("Decompress 32bit Texture:\n\tFormat: %s\n\tImage Size:%d\n",
875
pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
876
DebuggerAppendMsg("Palette Format: %s (%d)\n", textlutname[pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT], pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT);
881
TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
887
void CTextureManager::ConvertTexture_16(TxtrCacheEntry * pEntry, bool fromTMEM)
889
static uint32 dwCount = 0;
893
if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM )
895
pF = gConvertFunctions_16_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ];
899
if( gRDP.otherMode.text_tlut>=2 )
900
pF = gConvertTlutFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ];
902
pF = gConvertFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ];
907
pF( pEntry->pTexture, pEntry->ti );
909
LOG_TEXTURE(TRACE2("Decompress 16bit Texture:\n\tFormat: %s\n\tImage Size:%d\n",
910
pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]));
914
TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
920
void CTextureManager::ExpandTexture(TxtrCacheEntry * pEntry, uint32 sizeToLoad, uint32 sizeToCreate, uint32 sizeCreated,
921
int arrayWidth, int flag, int mask, int mirror, int clamp, uint32 otherSize)
923
if( sizeToLoad >= sizeCreated ) return;
925
uint32 maskWidth = (1<<mask);
926
int size = pEntry->pTexture->GetPixelSize();
930
if( sizeToLoad > sizeToCreate || sizeToCreate > sizeCreated )
931
TRACE0("Something is wrong, check me here in ExpandTextureS");
934
// Doing Mirror And/Or Wrap in S direction
935
// Image has been loaded with width=WidthToLoad, we need to enlarge the image
936
// to width = pEntry->ti.WidthToCreate by doing mirroring or wrapping
939
if( !(pEntry->pTexture->StartUpdate(&di)) )
941
TRACE0("Cann't update the texture");
949
Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize,
951
pEntry->pTexture->EndUpdate(&di);
956
if( sizeToLoad > maskWidth )
958
TRACE0("Something is wrong, check me here in ExpandTextureS");
959
pEntry->pTexture->EndUpdate(&di);
962
if( sizeToLoad == maskWidth && maskWidth == sizeToCreate && sizeToCreate != sizeCreated )
964
TRACE0("Something is wrong, check me here in ExpandTextureS");
965
pEntry->pTexture->EndUpdate(&di);
970
if( sizeToLoad == maskWidth )
972
uint32 tempwidth = clamp ? sizeToCreate : sizeCreated;
975
Mirror(di.lpSurface, sizeToLoad, mask, tempwidth,
976
arrayWidth, otherSize, flag, size );
980
Wrap(di.lpSurface, sizeToLoad, mask, tempwidth,
981
arrayWidth, otherSize, flag, size );
984
if( tempwidth < sizeCreated )
986
Clamp(di.lpSurface, tempwidth, sizeCreated, arrayWidth, otherSize,
990
pEntry->pTexture->EndUpdate(&di);
995
if( sizeToLoad < sizeToCreate && sizeToCreate == maskWidth && maskWidth == sizeCreated )
997
// widthToLoad < widthToCreate = maskWidth
998
Wrap(di.lpSurface, sizeToLoad, mask, sizeCreated, arrayWidth, otherSize, flag, size );
1000
pEntry->pTexture->EndUpdate(&di);
1004
if( sizeToLoad == sizeToCreate && sizeToCreate < maskWidth )
1007
if( maskWidth < sizeToCreate ) TRACE0("Incorrect condition, check me");
1009
Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size );
1011
pEntry->pTexture->EndUpdate(&di);
1015
if( sizeToLoad < sizeToCreate && sizeToCreate < maskWidth )
1018
if( clamp ) TRACE0("Incorrect condition, check me");
1019
if( maskWidth < sizeCreated ) TRACE0("Incorrect condition, check me");
1021
Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size );
1022
pEntry->pTexture->EndUpdate(&di);
1026
TRACE0("Check me, should not get here");
1027
pEntry->pTexture->EndUpdate(&di);
1030
void CTextureManager::ExpandTextureS(TxtrCacheEntry * pEntry)
1032
TxtrInfo &ti = pEntry->ti;
1033
uint32 textureWidth = pEntry->pTexture->m_dwCreatedTextureWidth;
1034
ExpandTexture(pEntry, ti.WidthToLoad, ti.WidthToCreate, textureWidth,
1035
textureWidth, S_FLAG, ti.maskS, ti.mirrorS, ti.clampS, ti.HeightToLoad);
1038
void CTextureManager::ExpandTextureT(TxtrCacheEntry * pEntry)
1040
TxtrInfo &ti = pEntry->ti;
1041
uint32 textureHeight = pEntry->pTexture->m_dwCreatedTextureHeight;
1042
uint32 textureWidth = pEntry->pTexture->m_dwCreatedTextureWidth;
1043
ExpandTexture(pEntry, ti.HeightToLoad, ti.HeightToCreate, textureHeight,
1044
textureWidth, T_FLAG, ti.maskT, ti.mirrorT, ti.clampT, ti.WidthToLoad);
1048
void CTextureManager::ClampS32(uint32 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
1050
if ((int) width <= 0 || (int) towidth < 0)
1053
for( uint32 y = 0; y<rows; y++ )
1055
uint32* line = array+y*arrayWidth;
1056
uint32 val = line[width-1];
1057
for( uint32 x=width; x<towidth; x++ )
1064
void CTextureManager::ClampS16(uint16 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
1066
if ((int) width <= 0 || (int) towidth < 0)
1069
for( uint32 y = 0; y<rows; y++ )
1071
uint16* line = array+y*arrayWidth;
1072
uint16 val = line[width-1];
1073
for( uint32 x=width; x<towidth; x++ )
1080
void CTextureManager::ClampT32(uint32 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
1082
if ((int) height <= 0 || (int) toheight < 0)
1085
uint32* linesrc = array+arrayWidth*(height-1);
1086
for( uint32 y = height; y<toheight; y++ )
1088
uint32* linedst = array+arrayWidth*y;
1089
for( uint32 x=0; x<arrayWidth; x++ )
1091
linedst[x] = linesrc[x];
1096
void CTextureManager::ClampT16(uint16 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
1098
if ((int) height <= 0 || (int) toheight < 0)
1101
uint16* linesrc = array+arrayWidth*(height-1);
1102
for( uint32 y = height; y<toheight; y++ )
1104
uint16* linedst = array+arrayWidth*y;
1105
for( uint32 x=0; x<arrayWidth; x++ )
1107
linedst[x] = linesrc[x];
1112
void CTextureManager::MirrorS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1114
uint32 maskval1 = (1<<mask)-1;
1115
uint32 maskval2 = (1<<(mask+1))-1;
1117
for( uint32 y = 0; y<rows; y++ )
1119
uint32* line = array+y*arrayWidth;
1120
for( uint32 x=width; x<towidth; x++ )
1122
line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
1127
void CTextureManager::MirrorS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1129
uint32 maskval1 = (1<<mask)-1;
1130
uint32 maskval2 = (1<<(mask+1))-1;
1132
for( uint32 y = 0; y<rows; y++ )
1134
uint16* line = array+y*arrayWidth;
1135
for( uint32 x=width; x<towidth; x++ )
1137
line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
1142
void CTextureManager::MirrorT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1144
uint32 maskval1 = (1<<mask)-1;
1145
uint32 maskval2 = (1<<(mask+1))-1;
1147
for( uint32 y = height; y<toheight; y++ )
1149
uint32 srcy = (y&maskval2)<=maskval1 ? y&maskval1 : maskval2-(y&maskval2);
1150
uint32* linesrc = array+arrayWidth*srcy;
1151
uint32* linedst = array+arrayWidth*y;;
1152
for( uint32 x=0; x<arrayWidth; x++ )
1154
linedst[x] = linesrc[x];
1159
void CTextureManager::MirrorT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1161
uint32 maskval1 = (1<<mask)-1;
1162
uint32 maskval2 = (1<<(mask+1))-1;
1164
for( uint32 y = height; y<toheight; y++ )
1166
uint32 srcy = (y&maskval2)<=maskval1 ? y&maskval1 : maskval2-(y&maskval2);
1167
uint16* linesrc = array+arrayWidth*srcy;
1168
uint16* linedst = array+arrayWidth*y;;
1169
for( uint32 x=0; x<arrayWidth; x++ )
1171
linedst[x] = linesrc[x];
1176
void CTextureManager::WrapS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1178
uint32 maskval = (1<<mask)-1;
1180
for( uint32 y = 0; y<rows; y++ )
1182
uint32* line = array+y*arrayWidth;
1183
for( uint32 x=width; x<towidth; x++ )
1185
line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
1190
void CTextureManager::WrapS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1192
uint32 maskval = (1<<mask)-1;
1194
for( uint32 y = 0; y<rows; y++ )
1196
uint16* line = array+y*arrayWidth;
1197
for( uint32 x=width; x<towidth; x++ )
1199
line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
1204
void CTextureManager::WrapT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1206
uint32 maskval = (1<<mask)-1;
1207
for( uint32 y = height; y<toheight; y++ )
1209
uint32* linesrc = array+arrayWidth*(y>maskval?y&maskval:y-height);
1210
uint32* linedst = array+arrayWidth*y;;
1211
for( uint32 x=0; x<arrayWidth; x++ )
1213
linedst[x] = linesrc[x];
1218
void CTextureManager::WrapT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1220
uint32 maskval = (1<<mask)-1;
1221
for( uint32 y = height; y<toheight; y++ )
1223
uint16* linesrc = array+arrayWidth*(y>maskval?y&maskval:y-height);
1224
uint16* linedst = array+arrayWidth*y;;
1225
for( uint32 x=0; x<arrayWidth; x++ )
1227
linedst[x] = linesrc[x];
1232
void CTextureManager::Clamp(void *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1234
if( flag == S_FLAG ) // s
1236
if( size == 4 ) // 32 bit
1238
ClampS32((uint32*)array, width, towidth, arrayWidth, rows);
1242
ClampS16((uint16*)array, width, towidth, arrayWidth, rows);
1247
if( size == 4 ) // 32 bit
1249
ClampT32((uint32*)array, width, towidth, arrayWidth, rows);
1253
ClampT16((uint16*)array, width, towidth, arrayWidth, rows);
1257
void CTextureManager::Wrap(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1259
if( flag == S_FLAG ) // s
1261
if( size == 4 ) // 32 bit
1263
WrapS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1267
WrapS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1272
if( size == 4 ) // 32 bit
1274
WrapT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1278
WrapT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1282
void CTextureManager::Mirror(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1284
if( flag == S_FLAG ) // s
1286
if( size == 4 ) // 32 bit
1288
MirrorS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1292
MirrorS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1297
if( size == 4 ) // 32 bit
1299
MirrorT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1303
MirrorT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1311
TxtrCacheEntry * CTextureManager::GetCachedTexture(uint32 tex)
1314
for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
1316
if( m_pCacheTxtrList[i] == NULL )
1320
TxtrCacheEntry *pEntry;
1322
for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
1333
uint32 CTextureManager::GetNumOfCachedTexture()
1336
for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
1338
if( m_pCacheTxtrList[i] == NULL )
1342
TxtrCacheEntry *pEntry;
1344
for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
1350
TRACE1("Totally %d texture cached", size);
1356
TxtrCacheEntry * CTextureManager::GetBlackTexture(void)
1358
if( m_blackTextureEntry.pTexture == NULL )
1360
m_blackTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1361
m_blackTextureEntry.ti.WidthToCreate = 4;
1362
m_blackTextureEntry.ti.HeightToCreate = 4;
1363
updateColorTexture(m_blackTextureEntry.pTexture,0x00000000);
1365
return &m_blackTextureEntry;
1367
TxtrCacheEntry * CTextureManager::GetPrimColorTexture(uint32 color)
1369
static uint32 mcolor = 0;
1370
if( m_PrimColorTextureEntry.pTexture == NULL )
1372
m_PrimColorTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1373
m_PrimColorTextureEntry.ti.WidthToCreate = 4;
1374
m_PrimColorTextureEntry.ti.HeightToCreate = 4;
1375
updateColorTexture(m_PrimColorTextureEntry.pTexture,color);
1376
gRDP.texturesAreReloaded = true;
1378
else if( mcolor != color )
1380
updateColorTexture(m_PrimColorTextureEntry.pTexture,color);
1381
gRDP.texturesAreReloaded = true;
1385
return &m_PrimColorTextureEntry;
1387
TxtrCacheEntry * CTextureManager::GetEnvColorTexture(uint32 color)
1389
static uint32 mcolor = 0;
1390
if( m_EnvColorTextureEntry.pTexture == NULL )
1392
m_EnvColorTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1393
m_EnvColorTextureEntry.ti.WidthToCreate = 4;
1394
m_EnvColorTextureEntry.ti.HeightToCreate = 4;
1395
gRDP.texturesAreReloaded = true;
1397
updateColorTexture(m_EnvColorTextureEntry.pTexture,color);
1399
else if( mcolor != color )
1401
updateColorTexture(m_EnvColorTextureEntry.pTexture,color);
1402
gRDP.texturesAreReloaded = true;
1406
return &m_EnvColorTextureEntry;
1408
TxtrCacheEntry * CTextureManager::GetLODFracTexture(uint8 fac)
1410
static uint8 mfac = 0;
1411
if( m_LODFracTextureEntry.pTexture == NULL )
1413
m_LODFracTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1414
m_LODFracTextureEntry.ti.WidthToCreate = 4;
1415
m_LODFracTextureEntry.ti.HeightToCreate = 4;
1416
uint32 factor = fac;
1418
color |= factor << 8;
1419
color |= color << 16;
1420
updateColorTexture(m_LODFracTextureEntry.pTexture,color);
1421
gRDP.texturesAreReloaded = true;
1423
else if( mfac != fac )
1425
uint32 factor = fac;
1427
color |= factor << 8;
1428
color |= color << 16;
1429
updateColorTexture(m_LODFracTextureEntry.pTexture,color);
1430
gRDP.texturesAreReloaded = true;
1434
return &m_LODFracTextureEntry;
1437
TxtrCacheEntry * CTextureManager::GetPrimLODFracTexture(uint8 fac)
1439
static uint8 mfac = 0;
1440
if( m_PrimLODFracTextureEntry.pTexture == NULL )
1442
m_PrimLODFracTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1443
m_PrimLODFracTextureEntry.ti.WidthToCreate = 4;
1444
m_PrimLODFracTextureEntry.ti.HeightToCreate = 4;
1445
uint32 factor = fac;
1447
color |= factor << 8;
1448
color |= color << 16;
1449
updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color);
1450
gRDP.texturesAreReloaded = true;
1452
else if( mfac != fac )
1454
uint32 factor = fac;
1456
color |= factor << 8;
1457
color |= color << 16;
1458
updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color);
1459
gRDP.texturesAreReloaded = true;
1463
return &m_PrimLODFracTextureEntry;
1466
TxtrCacheEntry * CTextureManager::GetConstantColorTexture(uint32 constant)
1471
return GetPrimColorTexture(gRDP.primitiveColor);
1474
return GetEnvColorTexture(gRDP.envColor);
1477
return GetLODFracTexture((uint8)gRDP.LODFrac);
1479
default: // MUX_PRIMLODFRAC
1480
return GetPrimLODFracTexture((uint8)gRDP.primLODFrac);
1485
void CTextureManager::updateColorTexture(CTexture *ptexture, uint32 color)
1488
if( !(ptexture->StartUpdate(&di)) )
1490
TRACE0("Cann't update the texture");
1494
int size = ptexture->GetPixelSize();
1499
uint16 *buf = (uint16*)di.lpSurface;
1500
uint16 color16= (uint16)((color>>4)&0xF);
1501
color16 |= ((color>>12)&0xF)<<4;
1502
color16 |= ((color>>20)&0xF)<<8;
1503
color16 |= ((color>>28)&0xF)<<12;
1504
for( int i=0; i<16; i++ )
1512
uint32 *buf = (uint32*)di.lpSurface;
1513
for( int i=0; i<16; i++ )
1521
ptexture->EndUpdate(&di);
1524
void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha)
1527
if( pEntry->pTexture->StartUpdate(&srcInfo) )
1533
for(int nY = 0; nY < srcInfo.dwCreatedHeight; nY++)
1535
buf = (uint32*)((uint8*)srcInfo.lpSurface+nY*srcInfo.lPitch);
1536
for(int nX = 0; nX < srcInfo.dwCreatedWidth; nX++)
1543
a = alpha?(val&0xFF000000):(i<<24);
1544
buf[nX] = (a|(i<<16)|(i<<8)|i);
1547
pEntry->pTexture->EndUpdate(&srcInfo); }