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)
42 // Just make sure it's odd
43 if ((nCurrent % 2) == 0)
51 // nSqrtCurrent = nCurrent^0.5 + 1 (round up)
52 nSqrtCurrent = (int)sqrt((double)nCurrent) + 1;
56 // Test all odd numbers from 3..nSqrtCurrent
57 for (int i = 3; i <= nSqrtCurrent; i+=2)
59 if ((nCurrent % i) == 0)
71 // Select next odd candidate...
78 ///////////////////////////////////////////////////////////////////////
80 ///////////////////////////////////////////////////////////////////////
81 CTextureManager::CTextureManager() :
83 m_pCacheTxtrList(NULL),
84 m_numOfCachedTxtrList(809)
86 m_numOfCachedTxtrList = GetNextPrime(800);
88 m_currentTextureMemUsage = 0;
89 m_pYoungestTexture = NULL;
90 m_pOldestTexture = NULL;
92 m_pCacheTxtrList = new TxtrCacheEntry *[m_numOfCachedTxtrList];
93 SAFE_CHECK(m_pCacheTxtrList);
95 for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
96 m_pCacheTxtrList[i] = NULL;
98 memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry));
99 memset(&m_PrimColorTextureEntry, 0, sizeof(TxtrCacheEntry));
100 memset(&m_EnvColorTextureEntry, 0, sizeof(TxtrCacheEntry));
101 memset(&m_LODFracTextureEntry, 0, sizeof(TxtrCacheEntry));
102 memset(&m_PrimLODFracTextureEntry, 0, sizeof(TxtrCacheEntry));
105 CTextureManager::~CTextureManager()
109 delete []m_pCacheTxtrList;
110 m_pCacheTxtrList = NULL;
115 // Delete all textures.
117 bool CTextureManager::CleanUp()
119 RecycleAllTextures();
121 if (!g_bUseSetTextureMem)
125 TxtrCacheEntry * pVictim = m_pHead;
126 m_pHead = pVictim->pNext;
132 if( m_blackTextureEntry.pTexture ) delete m_blackTextureEntry.pTexture;
133 if( m_PrimColorTextureEntry.pTexture ) delete m_PrimColorTextureEntry.pTexture;
134 if( m_EnvColorTextureEntry.pTexture ) delete m_EnvColorTextureEntry.pTexture;
135 if( m_LODFracTextureEntry.pTexture ) delete m_LODFracTextureEntry.pTexture;
136 if( m_PrimLODFracTextureEntry.pTexture ) delete m_PrimLODFracTextureEntry.pTexture;
137 memset(&m_blackTextureEntry, 0, sizeof(TxtrCacheEntry));
138 memset(&m_PrimColorTextureEntry, 0, sizeof(TxtrCacheEntry));
139 memset(&m_EnvColorTextureEntry, 0, sizeof(TxtrCacheEntry));
140 memset(&m_LODFracTextureEntry, 0, sizeof(TxtrCacheEntry));
141 memset(&m_PrimLODFracTextureEntry, 0, sizeof(TxtrCacheEntry));
146 bool CTextureManager::TCacheEntryIsLoaded(TxtrCacheEntry *pEntry)
148 for (int i = 0; i < MAX_TEXTURES; i++)
150 if (g_textures[i].pTextureEntry == pEntry)
157 // Purge any textures whos last usage was over 5 seconds ago
158 void CTextureManager::PurgeOldTextures()
160 if (m_pCacheTxtrList == NULL)
163 if (g_bUseSetTextureMem)
166 static const uint32 dwFramesToKill = 5*30; // 5 secs at 30 fps
167 static const uint32 dwFramesToDelete = 30*30; // 30 secs at 30 fps
169 for ( uint32 i = 0; i < m_numOfCachedTxtrList; i++ )
171 TxtrCacheEntry * pEntry;
172 TxtrCacheEntry * pNext;
174 pEntry = m_pCacheTxtrList[i];
177 pNext = pEntry->pNext;
179 if ( status.gDlistCount - pEntry->FrameLastUsed > dwFramesToKill && !TCacheEntryIsLoaded(pEntry))
181 RemoveTexture(pEntry);
188 // Remove any old textures that haven't been recycled in 1 minute or so
189 // Normally these would be reused
190 TxtrCacheEntry * pPrev;
191 TxtrCacheEntry * pCurr;
192 TxtrCacheEntry * pNext;
200 pNext = pCurr->pNext;
202 if ( status.gDlistCount - pCurr->FrameLastUsed > dwFramesToDelete && !TCacheEntryIsLoaded(pCurr) )
204 if (pPrev != NULL) pPrev->pNext = pCurr->pNext;
205 else m_pHead = pCurr->pNext;
218 void CTextureManager::RecycleAllTextures()
220 if (m_pCacheTxtrList == NULL)
224 uint32 dwTotalUses = 0;
226 m_pYoungestTexture = NULL;
227 m_pOldestTexture = NULL;
229 for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
231 while (m_pCacheTxtrList[i])
233 TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i];
234 m_pCacheTxtrList[i] = pTVictim->pNext;
236 dwTotalUses += pTVictim->dwUses;
238 if (g_bUseSetTextureMem)
241 RecycleTexture(pTVictim);
246 void CTextureManager::RecheckHiresForAllTextures()
248 if (m_pCacheTxtrList == NULL)
251 for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
253 while (m_pCacheTxtrList[i])
255 TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i];
256 m_pCacheTxtrList[i] = pTVictim->pNext;
257 pTVictim->bExternalTxtrChecked = false;
264 // Add to the recycle list
265 void CTextureManager::RecycleTexture(TxtrCacheEntry *pEntry)
267 if (g_bUseSetTextureMem)
270 if( CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE )
272 // Fix me, why I can not reuse the texture in OpenGL,
273 // how can I unload texture from video card memory for OpenGL
278 if (pEntry->pTexture == NULL)
280 // No point in saving!
286 pEntry->pNext = m_pHead;
287 SAFE_DELETE(pEntry->pEnhancedTexture);
292 // Search for a texture of the specified dimensions to recycle
293 TxtrCacheEntry * CTextureManager::ReviveTexture( uint32 width, uint32 height )
295 if (g_bUseSetTextureMem)
298 TxtrCacheEntry * pPrev;
299 TxtrCacheEntry * pCurr;
306 if (pCurr->ti.WidthToCreate == width &&
307 pCurr->ti.HeightToCreate == height)
310 if (pPrev != NULL) pPrev->pNext = pCurr->pNext;
311 else m_pHead = pCurr->pNext;
317 pCurr = pCurr->pNext;
324 uint32 CTextureManager::Hash(uint32 dwValue)
326 // Divide by four, because most textures will be on a 4 byte boundry, so bottom four
328 return (dwValue>>2) % m_numOfCachedTxtrList;
331 void CTextureManager::MakeTextureYoungest(TxtrCacheEntry *pEntry)
333 if (!g_bUseSetTextureMem)
336 if (pEntry == m_pYoungestTexture)
339 // if its the oldest, then change the oldest pointer
340 if (pEntry == m_pOldestTexture)
342 m_pOldestTexture = pEntry->pNextYoungest;
345 // if its a not a new texture, close the gap in the age list
346 // where pEntry use to reside
347 if (pEntry->pNextYoungest != NULL || pEntry->pLastYoungest != NULL)
349 if (pEntry->pNextYoungest != NULL)
351 pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest;
353 if (pEntry->pLastYoungest != NULL)
355 pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest;
359 // this texture is now the youngest, so place it on the end of the list
360 if (m_pYoungestTexture != NULL)
362 m_pYoungestTexture->pNextYoungest = pEntry;
365 pEntry->pNextYoungest = NULL;
366 pEntry->pLastYoungest = m_pYoungestTexture;
367 m_pYoungestTexture = pEntry;
369 // if this is the first texture in memory then its also the oldest
370 if (m_pOldestTexture == NULL)
372 m_pOldestTexture = pEntry;
376 void CTextureManager::AddTexture(TxtrCacheEntry *pEntry)
378 uint32 dwKey = Hash(pEntry->ti.Address);
380 if (m_pCacheTxtrList == NULL)
383 //TxtrCacheEntry **p = &m_pCacheTxtrList[dwKey];
385 // Add to head (not tail, for speed - new textures are more likely to be accessed next)
386 pEntry->pNext = m_pCacheTxtrList[dwKey];
387 m_pCacheTxtrList[dwKey] = pEntry;
389 // Move the texture to the top of the age list
390 MakeTextureYoungest(pEntry);
395 TxtrCacheEntry * CTextureManager::GetTxtrCacheEntry(TxtrInfo * pti)
397 TxtrCacheEntry *pEntry;
399 if (m_pCacheTxtrList == NULL)
402 // See if it is already in the hash table
403 uint32 dwKey = Hash(pti->Address);
405 for (pEntry = m_pCacheTxtrList[dwKey]; pEntry; pEntry = pEntry->pNext)
407 if ( pEntry->ti == *pti )
409 MakeTextureYoungest(pEntry);
419 void CTextureManager::RemoveTexture(TxtrCacheEntry * pEntry)
421 TxtrCacheEntry * pPrev;
422 TxtrCacheEntry * pCurr;
424 if (m_pCacheTxtrList == NULL)
427 // See if it is already in the hash table
428 uint32 dwKey = Hash(pEntry->ti.Address);
431 pCurr = m_pCacheTxtrList[dwKey];
435 // Check that the attributes match
436 if ( pCurr->ti == pEntry->ti )
439 pPrev->pNext = pCurr->pNext;
441 m_pCacheTxtrList[dwKey] = pCurr->pNext;
443 if (g_bUseSetTextureMem)
445 // remove the texture from the age list
446 if (pEntry->pNextYoungest != NULL)
448 pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest;
450 if (pEntry->pLastYoungest != NULL)
452 pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest;
455 // decrease the mem usage counter
456 m_currentTextureMemUsage -= (pEntry->pTexture->m_dwWidth * pEntry->pTexture->m_dwHeight * 4);
462 RecycleTexture(pEntry);
469 pCurr = pCurr->pNext;
474 TxtrCacheEntry * CTextureManager::CreateNewCacheEntry(uint32 dwAddr, uint32 dwWidth, uint32 dwHeight)
476 TxtrCacheEntry * pEntry = NULL;
478 if (g_bUseSetTextureMem)
480 uint32 widthToCreate = dwWidth;
481 uint32 heightToCreate = dwHeight;
482 unsigned int freeUpSize = (widthToCreate * heightToCreate * 4) + g_amountToFree;
484 // make sure there is enough room for the new texture by deleting old textures
485 while ((m_currentTextureMemUsage + freeUpSize) > g_maxTextureMemUsage && m_pOldestTexture != NULL)
487 TxtrCacheEntry *nextYoungest = m_pOldestTexture->pNextYoungest;
489 RemoveTexture(m_pOldestTexture);
491 m_pOldestTexture = nextYoungest;
493 //printf("Freeing Texture\n");
496 m_currentTextureMemUsage += widthToCreate * heightToCreate * 4;
500 // Find a used texture
501 pEntry = ReviveTexture(dwWidth, dwHeight);
504 if (pEntry == NULL || g_bUseSetTextureMem)
506 // Couldn't find on - recreate!
507 pEntry = new TxtrCacheEntry;
510 _VIDEO_DisplayTemporaryMessage("Error to create an texture entry");
514 pEntry->pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(dwWidth, dwHeight);
515 if (pEntry->pTexture == NULL || pEntry->pTexture->GetTexture() == NULL)
517 _VIDEO_DisplayTemporaryMessage("Error to create an texture");
518 TRACE2("Warning, unable to create %d x %d texture!", dwWidth, dwHeight);
522 pEntry->pTexture->m_bScaledS = false;
523 pEntry->pTexture->m_bScaledT = false;
528 pEntry->ti.Address = dwAddr;
529 pEntry->pNext = NULL;
530 pEntry->pNextYoungest = NULL;
531 pEntry->pLastYoungest = NULL;
533 pEntry->dwTimeLastUsed = status.gRDPTime;
535 pEntry->FrameLastUsed = status.gDlistCount;
536 pEntry->FrameLastUpdated = 0;
537 pEntry->lastEntry = NULL;
538 pEntry->bExternalTxtrChecked = false;
541 // Add to the hash table
546 // If already in table, return
547 // Otherwise, create surfaces, and load texture into memory
550 uint32 dwAsmdwBytesPerLine;
555 TxtrCacheEntry *g_lastTextureEntry=NULL;
556 bool lastEntryModified = false;
559 TxtrCacheEntry * CTextureManager::GetTexture(TxtrInfo * pgti, bool fromTMEM, bool doCRCCheck, bool AutoExtendTexture)
561 TxtrCacheEntry *pEntry;
563 if( g_curRomInfo.bDisableTextureCRC )
566 gRDP.texturesAreReloaded = true;
571 pEntry = GetTxtrCacheEntry(pgti);
572 bool loadFromTextureBuffer=false;
573 int txtBufIdxToLoadFrom = -1;
574 if( (frameBufferOptions.bCheckRenderTextures&&!frameBufferOptions.bWriteBackBufToRDRAM) || (frameBufferOptions.bCheckBackBufs&&!frameBufferOptions.bWriteBackBufToRDRAM) )
576 txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address);
577 if( txtBufIdxToLoadFrom >= 0 )
579 loadFromTextureBuffer = true;
580 // Check if it is the same size,
581 RenderTextureInfo &info = gRenderTextureInfos[txtBufIdxToLoadFrom];
582 //if( info.pRenderTexture && info.CI_Info.dwAddr == pgti->Address && info.CI_Info.dwFormat == pgti->Format
583 if( info.pRenderTexture && info.CI_Info.dwFormat == pgti->Format
584 && info.CI_Info.dwSize == pgti->Size )
586 info.txtEntry.ti = *pgti;
587 return &info.txtEntry;
592 if( frameBufferOptions.bCheckBackBufs && g_pFrameBufferManager->CheckAddrInBackBuffers(pgti->Address, pgti->HeightToLoad*pgti->Pitch) >= 0 )
594 if( !frameBufferOptions.bWriteBackBufToRDRAM )
596 // Load the texture from recent back buffer
597 txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address);
598 if( txtBufIdxToLoadFrom >= 0 )
600 loadFromTextureBuffer = true;
601 // Check if it is the same size,
602 RenderTextureInfo &info = gRenderTextureInfos[txtBufIdxToLoadFrom];
603 //if( info.pRenderTexture && info.CI_Info.dwAddr == pgti->Address && info.CI_Info.dwFormat == pgti->Format
604 if( info.pRenderTexture && info.CI_Info.dwFormat == pgti->Format
605 && info.CI_Info.dwSize == pgti->Size )
607 info.txtEntry.ti = *pgti;
608 return &info.txtEntry;
614 if (pEntry && pEntry->dwTimeLastUsed == status.gRDPTime && status.gDlistCount != 0 && !status.bN64FrameBufferIsUsed ) // This is not good, Palatte may changes
616 // We've already calculated a CRC this frame!
617 dwAsmCRC = pEntry->dwCRC;
623 if( loadFromTextureBuffer )
624 dwAsmCRC = gRenderTextureInfos[txtBufIdxToLoadFrom].crcInRDRAM;
626 CalculateRDRAMCRC(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch);
631 if ( doCRCCheck && (pgti->Format == TXT_FMT_CI || (pgti->Format == TXT_FMT_RGBA && pgti->Size <= TXT_SIZE_8b )))
633 //maxCI = pgti->Size == TXT_SIZE_8b ? 255 : 15;
634 extern unsigned char CalculateMaxCI(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes );
636 if( !pEntry || pEntry->dwCRC != dwAsmCRC || pEntry->maxCI < 0 )
638 maxCI = CalculateMaxCI(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch);
642 maxCI = pEntry->maxCI;
647 uint32 dwPalSize = 16;
650 if( pgti->Size == TXT_SIZE_8b )
657 dwOffset = pgti->Palette << 4;
660 pStart = (uint8*)pgti->PalAddress+dwOffset*2;
662 //for (y = 0; y < dwPalSize*2; y+=4)
664 // dwPalCRC = (dwPalCRC + *(uint32*)&pStart[y]);
667 uint32 dwAsmCRCSave = dwAsmCRC;
668 //dwPalCRC = CalculateRDRAMCRC(pStart, 0, 0, dwPalSize, 1, TXT_SIZE_16b, dwPalSize*2);
669 dwPalCRC = CalculateRDRAMCRC(pStart, 0, 0, maxCI+1, 1, TXT_SIZE_16b, dwPalSize*2);
670 dwAsmCRC = dwAsmCRCSave;
673 if (pEntry && doCRCCheck )
675 if(pEntry->dwCRC == dwAsmCRC && pEntry->dwPalCRC == dwPalCRC &&
676 (!loadFromTextureBuffer || gRenderTextureInfos[txtBufIdxToLoadFrom].updateAtFrame < pEntry->FrameLastUsed ) )
678 // Tile is ok, return
680 pEntry->dwTimeLastUsed = status.gRDPTime;
681 pEntry->FrameLastUsed = status.gDlistCount;
682 LOG_TEXTURE(TRACE0(" Use current texture:\n"));
683 pEntry->lastEntry = g_lastTextureEntry;
684 g_lastTextureEntry = pEntry;
685 lastEntryModified = false;
687 DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) ,
688 {DebuggerAppendMsg("Load cached texture from render_texture");}
701 // We need to create a new entry, and add it
702 // to the hash table.
703 pEntry = CreateNewCacheEntry(pgti->Address, pgti->WidthToCreate, pgti->HeightToCreate);
707 g_lastTextureEntry = pEntry;
708 _VIDEO_DisplayTemporaryMessage("Fail to create new texture entry");
714 pEntry->dwCRC = dwAsmCRC;
715 pEntry->dwPalCRC = dwPalCRC;
716 pEntry->bExternalTxtrChecked = false;
717 pEntry->maxCI = maxCI;
721 if (pEntry->pTexture != NULL)
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;
736 TextureFmt dwType = pEntry->pTexture->GetSurfaceFormat();
737 SAFE_DELETE(pEntry->pEnhancedTexture);
738 pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
740 if (dwType != TEXTURE_FMT_UNKNOWN)
742 if( loadFromTextureBuffer )
744 g_pFrameBufferManager->LoadTextureFromRenderTexture(pEntry, txtBufIdxToLoadFrom);
745 DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) ,
746 {DebuggerAppendMsg("Load texture from render_texture %d", txtBufIdxToLoadFrom);}
749 extern void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha);
750 if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_I )
752 // Convert texture from RGBA to I
753 ConvertTextureRGBAtoI(pEntry,false);
755 else if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_IA )
757 // Convert texture from RGBA to IA
758 ConvertTextureRGBAtoI(pEntry,true);
763 LOG_TEXTURE(TRACE0(" Load new texture from RDRAM:\n"));
764 if (dwType == TEXTURE_FMT_A8R8G8B8)
766 ConvertTexture(pEntry, fromTMEM);
769 ConvertTexture_16(pEntry, fromTMEM);
770 pEntry->FrameLastUpdated = status.gDlistCount;
771 SAFE_DELETE(pEntry->pEnhancedTexture);
772 pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
776 pEntry->ti.WidthToLoad = pgti->WidthToLoad;
777 pEntry->ti.HeightToLoad = pgti->HeightToLoad;
779 if( AutoExtendTexture )
781 ExpandTextureS(pEntry);
782 ExpandTextureT(pEntry);
785 if( options.bDumpTexturesToFiles && !loadFromTextureBuffer )
787 DumpCachedTexture(*pEntry);
791 if( pauseAtNext && eventToPause == NEXT_NEW_TEXTURE )
793 CRender::g_pRender->SetCurrentTexture( 0, pEntry->pTexture, pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate, pEntry);
794 CRender::g_pRender->DrawTexture(0);
795 debuggerPause = true;
796 TRACE0("Pause after loading a new texture");
797 if( pEntry->ti.Format == TXT_FMT_YUV )
799 TRACE0("This is YUV texture");
801 DebuggerAppendMsg("W:%d, H:%d, RealW:%d, RealH:%d, D3DW:%d, D3DH: %d", pEntry->ti.WidthToCreate, pEntry->ti.HeightToCreate,
802 pEntry->ti.WidthToLoad, pEntry->ti.HeightToLoad, pEntry->pTexture->m_dwCreatedTextureWidth, pEntry->pTexture->m_dwCreatedTextureHeight);
803 DebuggerAppendMsg("ScaledS:%s, ScaledT:%s, CRC=%08X", pEntry->pTexture->m_bScaledS?"T":"F", pEntry->pTexture->m_bScaledT?"T":"F", pEntry->dwCRC);
805 CRender::g_pRender->SetCurrentTexture( 0, NULL, 64, 64, NULL);
812 TRACE0("Exception in texture decompression");
813 g_lastTextureEntry = NULL;
817 pEntry->lastEntry = g_lastTextureEntry;
818 g_lastTextureEntry = pEntry;
819 lastEntryModified = true;
826 const char *pszImgFormat[8] = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"};
827 uint8 pnImgSize[4] = {4, 8, 16, 32};
828 const char *textlutname[4] = {"RGB16", "I16?", "RGBA16", "IA16"};
830 extern uint16 g_wRDPTlut[];
831 extern ConvertFunction gConvertFunctions_FullTMEM[ 8 ][ 4 ];
832 extern ConvertFunction gConvertFunctions[ 8 ][ 4 ];
833 extern ConvertFunction gConvertTlutFunctions[ 8 ][ 4 ];
834 extern ConvertFunction gConvertFunctions_16[ 8 ][ 4 ];
835 extern ConvertFunction gConvertFunctions_16_FullTMEM[ 8 ][ 4 ];
836 extern ConvertFunction gConvertTlutFunctions_16[ 8 ][ 4 ];
837 void CTextureManager::ConvertTexture(TxtrCacheEntry * pEntry, bool fromTMEM)
839 static uint32 dwCount = 0;
842 if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM )
844 pF = gConvertFunctions_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ];
848 if( gRDP.tiles[7].dwFormat == TXT_FMT_YUV )
850 if( gRDP.otherMode.text_tlut>=2 )
851 pF = gConvertTlutFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ];
853 pF = gConvertFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ];
857 if( gRDP.otherMode.text_tlut>=2 )
858 pF = gConvertTlutFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ];
860 pF = gConvertFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ];
866 pF( pEntry->pTexture, pEntry->ti );
870 DebuggerAppendMsg("Decompress 32bit Texture:\n\tFormat: %s\n\tImage Size:%d\n",
871 pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
872 DebuggerAppendMsg("Palette Format: %s (%d)\n", textlutname[pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT], pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT);
877 TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
883 void CTextureManager::ConvertTexture_16(TxtrCacheEntry * pEntry, bool fromTMEM)
885 static uint32 dwCount = 0;
889 if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM )
891 pF = gConvertFunctions_16_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ];
895 if( gRDP.otherMode.text_tlut>=2 )
896 pF = gConvertTlutFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ];
898 pF = gConvertFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ];
903 pF( pEntry->pTexture, pEntry->ti );
905 LOG_TEXTURE(TRACE2("Decompress 16bit Texture:\n\tFormat: %s\n\tImage Size:%d\n",
906 pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]));
910 TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
916 void CTextureManager::ExpandTexture(TxtrCacheEntry * pEntry, uint32 sizeToLoad, uint32 sizeToCreate, uint32 sizeCreated,
917 int arrayWidth, int flag, int mask, int mirror, int clamp, uint32 otherSize)
919 if( sizeToLoad >= sizeCreated ) return;
921 uint32 maskWidth = (1<<mask);
922 int size = pEntry->pTexture->GetPixelSize();
926 if( sizeToLoad > sizeToCreate || sizeToCreate > sizeCreated )
927 TRACE0("Something is wrong, check me here in ExpandTextureS");
930 // Doing Mirror And/Or Wrap in S direction
931 // Image has been loaded with width=WidthToLoad, we need to enlarge the image
932 // to width = pEntry->ti.WidthToCreate by doing mirroring or wrapping
935 if( !(pEntry->pTexture->StartUpdate(&di)) )
937 TRACE0("Cann't update the texture");
945 Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize,
947 pEntry->pTexture->EndUpdate(&di);
952 if( sizeToLoad > maskWidth )
954 TRACE0("Something is wrong, check me here in ExpandTextureS");
955 pEntry->pTexture->EndUpdate(&di);
958 if( sizeToLoad == maskWidth && maskWidth == sizeToCreate && sizeToCreate != sizeCreated )
960 TRACE0("Something is wrong, check me here in ExpandTextureS");
961 pEntry->pTexture->EndUpdate(&di);
966 if( sizeToLoad == maskWidth )
968 uint32 tempwidth = clamp ? sizeToCreate : sizeCreated;
971 Mirror(di.lpSurface, sizeToLoad, mask, tempwidth,
972 arrayWidth, otherSize, flag, size );
976 Wrap(di.lpSurface, sizeToLoad, mask, tempwidth,
977 arrayWidth, otherSize, flag, size );
980 if( tempwidth < sizeCreated )
982 Clamp(di.lpSurface, tempwidth, sizeCreated, arrayWidth, otherSize,
986 pEntry->pTexture->EndUpdate(&di);
991 if( sizeToLoad < sizeToCreate && sizeToCreate == maskWidth && maskWidth == sizeCreated )
993 // widthToLoad < widthToCreate = maskWidth
994 Wrap(di.lpSurface, sizeToLoad, mask, sizeCreated, arrayWidth, otherSize, flag, size );
996 pEntry->pTexture->EndUpdate(&di);
1000 if( sizeToLoad == sizeToCreate && sizeToCreate < maskWidth )
1003 if( maskWidth < sizeToCreate ) TRACE0("Incorrect condition, check me");
1005 Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size );
1007 pEntry->pTexture->EndUpdate(&di);
1011 if( sizeToLoad < sizeToCreate && sizeToCreate < maskWidth )
1014 if( clamp ) TRACE0("Incorrect condition, check me");
1015 if( maskWidth < sizeCreated ) TRACE0("Incorrect condition, check me");
1017 Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size );
1018 pEntry->pTexture->EndUpdate(&di);
1022 TRACE0("Check me, should not get here");
1023 pEntry->pTexture->EndUpdate(&di);
1026 void CTextureManager::ExpandTextureS(TxtrCacheEntry * pEntry)
1028 TxtrInfo &ti = pEntry->ti;
1029 uint32 textureWidth = pEntry->pTexture->m_dwCreatedTextureWidth;
1030 ExpandTexture(pEntry, ti.WidthToLoad, ti.WidthToCreate, textureWidth,
1031 textureWidth, S_FLAG, ti.maskS, ti.mirrorS, ti.clampS, ti.HeightToLoad);
1034 void CTextureManager::ExpandTextureT(TxtrCacheEntry * pEntry)
1036 TxtrInfo &ti = pEntry->ti;
1037 uint32 textureHeight = pEntry->pTexture->m_dwCreatedTextureHeight;
1038 uint32 textureWidth = pEntry->pTexture->m_dwCreatedTextureWidth;
1039 ExpandTexture(pEntry, ti.HeightToLoad, ti.HeightToCreate, textureHeight,
1040 textureWidth, T_FLAG, ti.maskT, ti.mirrorT, ti.clampT, ti.WidthToLoad);
1044 void CTextureManager::ClampS32(uint32 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
1046 if ((int) width <= 0 || (int) towidth < 0)
1049 for( uint32 y = 0; y<rows; y++ )
1051 uint32* line = array+y*arrayWidth;
1052 uint32 val = line[width-1];
1053 for( uint32 x=width; x<towidth; x++ )
1060 void CTextureManager::ClampS16(uint16 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
1062 if ((int) width <= 0 || (int) towidth < 0)
1065 for( uint32 y = 0; y<rows; y++ )
1067 uint16* line = array+y*arrayWidth;
1068 uint16 val = line[width-1];
1069 for( uint32 x=width; x<towidth; x++ )
1076 void CTextureManager::ClampT32(uint32 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
1078 if ((int) height <= 0 || (int) toheight < 0)
1081 uint32* linesrc = array+arrayWidth*(height-1);
1082 for( uint32 y = height; y<toheight; y++ )
1084 uint32* linedst = array+arrayWidth*y;
1085 for( uint32 x=0; x<arrayWidth; x++ )
1087 linedst[x] = linesrc[x];
1092 void CTextureManager::ClampT16(uint16 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
1094 if ((int) height <= 0 || (int) toheight < 0)
1097 uint16* linesrc = array+arrayWidth*(height-1);
1098 for( uint32 y = height; y<toheight; y++ )
1100 uint16* linedst = array+arrayWidth*y;
1101 for( uint32 x=0; x<arrayWidth; x++ )
1103 linedst[x] = linesrc[x];
1108 void CTextureManager::MirrorS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1110 uint32 maskval1 = (1<<mask)-1;
1111 uint32 maskval2 = (1<<(mask+1))-1;
1113 for( uint32 y = 0; y<rows; y++ )
1115 uint32* line = array+y*arrayWidth;
1116 for( uint32 x=width; x<towidth; x++ )
1118 line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
1123 void CTextureManager::MirrorS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1125 uint32 maskval1 = (1<<mask)-1;
1126 uint32 maskval2 = (1<<(mask+1))-1;
1128 for( uint32 y = 0; y<rows; y++ )
1130 uint16* line = array+y*arrayWidth;
1131 for( uint32 x=width; x<towidth; x++ )
1133 line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
1138 void CTextureManager::MirrorT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1140 uint32 maskval1 = (1<<mask)-1;
1141 uint32 maskval2 = (1<<(mask+1))-1;
1143 for( uint32 y = height; y<toheight; y++ )
1145 uint32 srcy = (y&maskval2)<=maskval1 ? y&maskval1 : maskval2-(y&maskval2);
1146 uint32* linesrc = array+arrayWidth*srcy;
1147 uint32* linedst = array+arrayWidth*y;;
1148 for( uint32 x=0; x<arrayWidth; x++ )
1150 linedst[x] = linesrc[x];
1155 void CTextureManager::MirrorT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1157 uint32 maskval1 = (1<<mask)-1;
1158 uint32 maskval2 = (1<<(mask+1))-1;
1160 for( uint32 y = height; y<toheight; y++ )
1162 uint32 srcy = (y&maskval2)<=maskval1 ? y&maskval1 : maskval2-(y&maskval2);
1163 uint16* linesrc = array+arrayWidth*srcy;
1164 uint16* linedst = array+arrayWidth*y;;
1165 for( uint32 x=0; x<arrayWidth; x++ )
1167 linedst[x] = linesrc[x];
1172 void CTextureManager::WrapS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1174 uint32 maskval = (1<<mask)-1;
1176 for( uint32 y = 0; y<rows; y++ )
1178 uint32* line = array+y*arrayWidth;
1179 for( uint32 x=width; x<towidth; x++ )
1181 line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
1186 void CTextureManager::WrapS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1188 uint32 maskval = (1<<mask)-1;
1190 for( uint32 y = 0; y<rows; y++ )
1192 uint16* line = array+y*arrayWidth;
1193 for( uint32 x=width; x<towidth; x++ )
1195 line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
1200 void CTextureManager::WrapT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1202 uint32 maskval = (1<<mask)-1;
1203 for( uint32 y = height; y<toheight; y++ )
1205 uint32* linesrc = array+arrayWidth*(y>maskval?y&maskval:y-height);
1206 uint32* linedst = array+arrayWidth*y;;
1207 for( uint32 x=0; x<arrayWidth; x++ )
1209 linedst[x] = linesrc[x];
1214 void CTextureManager::WrapT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1216 uint32 maskval = (1<<mask)-1;
1217 for( uint32 y = height; y<toheight; y++ )
1219 uint16* linesrc = array+arrayWidth*(y>maskval?y&maskval:y-height);
1220 uint16* linedst = array+arrayWidth*y;;
1221 for( uint32 x=0; x<arrayWidth; x++ )
1223 linedst[x] = linesrc[x];
1228 void CTextureManager::Clamp(void *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1230 if( flag == S_FLAG ) // s
1232 if( size == 4 ) // 32 bit
1234 ClampS32((uint32*)array, width, towidth, arrayWidth, rows);
1238 ClampS16((uint16*)array, width, towidth, arrayWidth, rows);
1243 if( size == 4 ) // 32 bit
1245 ClampT32((uint32*)array, width, towidth, arrayWidth, rows);
1249 ClampT16((uint16*)array, width, towidth, arrayWidth, rows);
1253 void CTextureManager::Wrap(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1255 if( flag == S_FLAG ) // s
1257 if( size == 4 ) // 32 bit
1259 WrapS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1263 WrapS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1268 if( size == 4 ) // 32 bit
1270 WrapT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1274 WrapT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1278 void CTextureManager::Mirror(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1280 if( flag == S_FLAG ) // s
1282 if( size == 4 ) // 32 bit
1284 MirrorS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1288 MirrorS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1293 if( size == 4 ) // 32 bit
1295 MirrorT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1299 MirrorT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1307 TxtrCacheEntry * CTextureManager::GetCachedTexture(uint32 tex)
1310 for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
1312 if( m_pCacheTxtrList[i] == NULL )
1316 TxtrCacheEntry *pEntry;
1318 for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
1329 uint32 CTextureManager::GetNumOfCachedTexture()
1332 for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
1334 if( m_pCacheTxtrList[i] == NULL )
1338 TxtrCacheEntry *pEntry;
1340 for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
1346 TRACE1("Totally %d texture cached", size);
1352 TxtrCacheEntry * CTextureManager::GetBlackTexture(void)
1354 if( m_blackTextureEntry.pTexture == NULL )
1356 m_blackTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1357 m_blackTextureEntry.ti.WidthToCreate = 4;
1358 m_blackTextureEntry.ti.HeightToCreate = 4;
1359 updateColorTexture(m_blackTextureEntry.pTexture,0x00000000);
1361 return &m_blackTextureEntry;
1363 TxtrCacheEntry * CTextureManager::GetPrimColorTexture(uint32 color)
1365 static uint32 mcolor = 0;
1366 if( m_PrimColorTextureEntry.pTexture == NULL )
1368 m_PrimColorTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1369 m_PrimColorTextureEntry.ti.WidthToCreate = 4;
1370 m_PrimColorTextureEntry.ti.HeightToCreate = 4;
1371 updateColorTexture(m_PrimColorTextureEntry.pTexture,color);
1372 gRDP.texturesAreReloaded = true;
1374 else if( mcolor != color )
1376 updateColorTexture(m_PrimColorTextureEntry.pTexture,color);
1377 gRDP.texturesAreReloaded = true;
1381 return &m_PrimColorTextureEntry;
1383 TxtrCacheEntry * CTextureManager::GetEnvColorTexture(uint32 color)
1385 static uint32 mcolor = 0;
1386 if( m_EnvColorTextureEntry.pTexture == NULL )
1388 m_EnvColorTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1389 m_EnvColorTextureEntry.ti.WidthToCreate = 4;
1390 m_EnvColorTextureEntry.ti.HeightToCreate = 4;
1391 gRDP.texturesAreReloaded = true;
1393 updateColorTexture(m_EnvColorTextureEntry.pTexture,color);
1395 else if( mcolor != color )
1397 updateColorTexture(m_EnvColorTextureEntry.pTexture,color);
1398 gRDP.texturesAreReloaded = true;
1402 return &m_EnvColorTextureEntry;
1404 TxtrCacheEntry * CTextureManager::GetLODFracTexture(uint8 fac)
1406 static uint8 mfac = 0;
1407 if( m_LODFracTextureEntry.pTexture == NULL )
1409 m_LODFracTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1410 m_LODFracTextureEntry.ti.WidthToCreate = 4;
1411 m_LODFracTextureEntry.ti.HeightToCreate = 4;
1412 uint32 factor = fac;
1414 color |= factor << 8;
1415 color |= color << 16;
1416 updateColorTexture(m_LODFracTextureEntry.pTexture,color);
1417 gRDP.texturesAreReloaded = true;
1419 else if( mfac != fac )
1421 uint32 factor = fac;
1423 color |= factor << 8;
1424 color |= color << 16;
1425 updateColorTexture(m_LODFracTextureEntry.pTexture,color);
1426 gRDP.texturesAreReloaded = true;
1430 return &m_LODFracTextureEntry;
1433 TxtrCacheEntry * CTextureManager::GetPrimLODFracTexture(uint8 fac)
1435 static uint8 mfac = 0;
1436 if( m_PrimLODFracTextureEntry.pTexture == NULL )
1438 m_PrimLODFracTextureEntry.pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(4, 4);
1439 m_PrimLODFracTextureEntry.ti.WidthToCreate = 4;
1440 m_PrimLODFracTextureEntry.ti.HeightToCreate = 4;
1441 uint32 factor = fac;
1443 color |= factor << 8;
1444 color |= color << 16;
1445 updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color);
1446 gRDP.texturesAreReloaded = true;
1448 else if( mfac != fac )
1450 uint32 factor = fac;
1452 color |= factor << 8;
1453 color |= color << 16;
1454 updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color);
1455 gRDP.texturesAreReloaded = true;
1459 return &m_PrimLODFracTextureEntry;
1462 TxtrCacheEntry * CTextureManager::GetConstantColorTexture(uint32 constant)
1467 return GetPrimColorTexture(gRDP.primitiveColor);
1470 return GetEnvColorTexture(gRDP.envColor);
1473 return GetLODFracTexture((uint8)gRDP.LODFrac);
1475 default: // MUX_PRIMLODFRAC
1476 return GetPrimLODFracTexture((uint8)gRDP.primLODFrac);
1481 void CTextureManager::updateColorTexture(CTexture *ptexture, uint32 color)
1484 if( !(ptexture->StartUpdate(&di)) )
1486 TRACE0("Cann't update the texture");
1490 int size = ptexture->GetPixelSize();
1495 uint16 *buf = (uint16*)di.lpSurface;
1496 uint16 color16= (uint16)((color>>4)&0xF);
1497 color16 |= ((color>>12)&0xF)<<4;
1498 color16 |= ((color>>20)&0xF)<<8;
1499 color16 |= ((color>>28)&0xF)<<12;
1500 for( int i=0; i<16; i++ )
1508 uint32 *buf = (uint32*)di.lpSurface;
1509 for( int i=0; i<16; i++ )
1517 ptexture->EndUpdate(&di);
1520 void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha)
1523 if( pEntry->pTexture->StartUpdate(&srcInfo) )
1529 for(int nY = 0; nY < srcInfo.dwCreatedHeight; nY++)
1531 buf = (uint32*)((uint8*)srcInfo.lpSurface+nY*srcInfo.lPitch);
1532 for(int nX = 0; nX < srcInfo.dwCreatedWidth; nX++)
1539 a = alpha?(val&0xFF000000):(i<<24);
1540 buf[nX] = (a|(i<<16)|(i<<8)|i);
1543 pEntry->pTexture->EndUpdate(&srcInfo);