Some attempts to speedup Rice when using FB
[mupen64plus-pandora.git] / source / gles2rice / src / TextureManager.cpp
1 /*
2 Copyright (C) 2003 Rice1964
3
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.
8
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.
13
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.
17
18 */
19
20 #include <exception>
21 #include <cmath>
22
23 #include "ConvertImage.h"
24 #include "DeviceBuilder.h"
25 #include "FrameBuffer.h"
26 #include "RenderBase.h"
27 #include "TextureManager.h"
28
29 CTextureManager gTextureManager;
30
31 unsigned int g_maxTextureMemUsage = (5*1024*1024);
32 unsigned int g_amountToFree = (512*1024);
33 bool g_bUseSetTextureMem = false;
34
35 // Returns the first prime greater than or equal to nFirst
36 inline int GetNextPrime(int nFirst)
37 {
38     int nCurrent;
39
40     nCurrent = nFirst;
41
42     // Just make sure it's odd
43     if ((nCurrent % 2) == 0)
44         nCurrent++;
45
46     for (;;)
47     {
48         int nSqrtCurrent;
49         BOOL bIsComposite;
50
51         // nSqrtCurrent = nCurrent^0.5 + 1 (round up)
52         nSqrtCurrent = (int)sqrt((double)nCurrent) + 1;
53
54         bIsComposite = FALSE;
55         
56         // Test all odd numbers from 3..nSqrtCurrent
57         for (int i = 3; i <= nSqrtCurrent; i+=2)
58         {
59             if ((nCurrent % i) == 0)
60             {
61                 bIsComposite = TRUE;
62                 break;
63             }
64         }
65
66         if (!bIsComposite)
67         {           
68             return nCurrent;
69         }
70
71         // Select next odd candidate...
72         nCurrent += 2;
73     }
74 }
75
76
77
78 ///////////////////////////////////////////////////////////////////////
79 //
80 ///////////////////////////////////////////////////////////////////////
81 CTextureManager::CTextureManager() :
82     m_pHead(NULL),
83     m_pCacheTxtrList(NULL),
84     m_numOfCachedTxtrList(809)
85 {
86     m_numOfCachedTxtrList = GetNextPrime(800);
87
88     m_currentTextureMemUsage    = 0;
89     m_pYoungestTexture          = NULL;
90     m_pOldestTexture            = NULL;
91
92     m_pCacheTxtrList = new TxtrCacheEntry *[m_numOfCachedTxtrList];
93     SAFE_CHECK(m_pCacheTxtrList);
94
95     for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
96         m_pCacheTxtrList[i] = NULL;
97
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));
103 }
104
105 CTextureManager::~CTextureManager()
106 {
107     CleanUp();
108
109     delete []m_pCacheTxtrList;
110     m_pCacheTxtrList = NULL;    
111 }
112
113
114 //
115 //  Delete all textures.
116 //
117 bool CTextureManager::CleanUp()
118 {
119     RecycleAllTextures();
120
121     if (!g_bUseSetTextureMem)
122     {
123         while (m_pHead)
124         {
125             TxtrCacheEntry * pVictim = m_pHead;
126             m_pHead = pVictim->pNext;
127
128             delete pVictim;
129         }
130     }
131
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));
142
143     return true;
144 }
145
146 bool CTextureManager::TCacheEntryIsLoaded(TxtrCacheEntry *pEntry)
147 {
148     for (int i = 0; i < MAX_TEXTURES; i++)
149     {
150         if (g_textures[i].pTextureEntry == pEntry)
151             return true;
152     }
153
154     return false;
155 }
156
157 // Purge any textures whos last usage was over 5 seconds ago
158 void CTextureManager::PurgeOldTextures()
159 {
160     if (m_pCacheTxtrList == NULL)
161         return;
162     
163     if (g_bUseSetTextureMem)
164         return;
165
166     static const uint32 dwFramesToKill = 5*30;          // 5 secs at 30 fps
167     static const uint32 dwFramesToDelete = 30*30;       // 30 secs at 30 fps
168     
169     for ( uint32 i = 0; i < m_numOfCachedTxtrList; i++ )
170     {
171         TxtrCacheEntry * pEntry;
172         TxtrCacheEntry * pNext;
173         
174         pEntry = m_pCacheTxtrList[i];
175         while (pEntry)
176         {
177             pNext = pEntry->pNext;
178             
179             if ( status.gDlistCount - pEntry->FrameLastUsed > dwFramesToKill && !TCacheEntryIsLoaded(pEntry))
180             {
181                 RemoveTexture(pEntry);
182             }
183             pEntry = pNext;
184         }
185     }
186     
187     
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;
193     
194     
195     pPrev = NULL;
196     pCurr = m_pHead;
197     
198     while (pCurr)
199     {
200         pNext = pCurr->pNext;
201         
202         if ( status.gDlistCount - pCurr->FrameLastUsed > dwFramesToDelete && !TCacheEntryIsLoaded(pCurr) )
203         {
204             if (pPrev != NULL) pPrev->pNext        = pCurr->pNext;
205             else               m_pHead = pCurr->pNext;
206             
207             delete pCurr;
208             pCurr = pNext;  
209         }
210         else
211         {
212             pPrev = pCurr;
213             pCurr = pNext;
214         }
215     }
216 }
217
218 void CTextureManager::RecycleAllTextures()
219 {
220     if (m_pCacheTxtrList == NULL)
221         return;
222     
223     uint32 dwCount = 0;
224     uint32 dwTotalUses = 0;
225     
226     m_pYoungestTexture          = NULL;
227     m_pOldestTexture            = NULL;
228
229     for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
230     {
231         while (m_pCacheTxtrList[i])
232         {
233             TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i];
234             m_pCacheTxtrList[i] = pTVictim->pNext;
235             
236             dwTotalUses += pTVictim->dwUses;
237             dwCount++;
238             if (g_bUseSetTextureMem)
239                 delete pTVictim;
240             else
241             RecycleTexture(pTVictim);
242         }
243     }
244 }
245
246 void CTextureManager::RecheckHiresForAllTextures()
247 {
248     if (m_pCacheTxtrList == NULL)
249         return;
250
251     for (uint32 i = 0; i < m_numOfCachedTxtrList; i++)
252     {
253         while (m_pCacheTxtrList[i])
254         {
255             TxtrCacheEntry *pTVictim = m_pCacheTxtrList[i];
256             m_pCacheTxtrList[i] = pTVictim->pNext;
257             pTVictim->bExternalTxtrChecked = false;
258
259         }
260     }
261 }
262
263
264 // Add to the recycle list
265 void CTextureManager::RecycleTexture(TxtrCacheEntry *pEntry)
266 {
267     if (g_bUseSetTextureMem)
268         return;
269
270     if( CDeviceBuilder::GetGeneralDeviceType() == OGL_DEVICE )
271     {
272         // Fix me, why I can not reuse the texture in OpenGL,
273         // how can I unload texture from video card memory for OpenGL
274         delete pEntry;
275         return;
276     }
277
278     if (pEntry->pTexture == NULL)
279     {
280         // No point in saving!
281         delete pEntry;
282     }
283     else
284     {
285         // Add to the list
286         pEntry->pNext = m_pHead;
287         SAFE_DELETE(pEntry->pEnhancedTexture);
288         m_pHead = pEntry;
289     }
290 }
291
292 // Search for a texture of the specified dimensions to recycle
293 TxtrCacheEntry * CTextureManager::ReviveTexture( uint32 width, uint32 height )
294 {
295     if (g_bUseSetTextureMem)
296         return NULL;
297
298     TxtrCacheEntry * pPrev;
299     TxtrCacheEntry * pCurr;
300     
301     pPrev = NULL;
302     pCurr = m_pHead;
303     
304     while (pCurr)
305     {
306         if (pCurr->ti.WidthToCreate == width &&
307             pCurr->ti.HeightToCreate == height)
308         {
309             // Remove from list
310             if (pPrev != NULL) pPrev->pNext        = pCurr->pNext;
311             else               m_pHead = pCurr->pNext;
312             
313             return pCurr;
314         }
315         
316         pPrev = pCurr;
317         pCurr = pCurr->pNext;
318     }
319     
320     return NULL;
321 }
322
323
324 uint32 CTextureManager::Hash(uint32 dwValue)
325 {
326     // Divide by four, because most textures will be on a 4 byte boundry, so bottom four
327     // bits are null
328     return (dwValue>>2) % m_numOfCachedTxtrList;
329 }
330
331 void CTextureManager::MakeTextureYoungest(TxtrCacheEntry *pEntry)
332 {
333     if (!g_bUseSetTextureMem)
334         return;
335
336     if (pEntry == m_pYoungestTexture)
337         return;
338
339     // if its the oldest, then change the oldest pointer
340     if (pEntry == m_pOldestTexture)
341     {
342         m_pOldestTexture = pEntry->pNextYoungest;
343     }
344
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)
348     {
349         if (pEntry->pNextYoungest != NULL)
350         {
351             pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest;
352         }
353         if (pEntry->pLastYoungest != NULL)
354         {
355             pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest;
356         }
357     }
358
359     // this texture is now the youngest, so place it on the end of the list
360     if (m_pYoungestTexture != NULL)
361     {
362         m_pYoungestTexture->pNextYoungest = pEntry;
363     }
364
365     pEntry->pNextYoungest = NULL;
366     pEntry->pLastYoungest = m_pYoungestTexture;
367     m_pYoungestTexture = pEntry;
368      
369     // if this is the first texture in memory then its also the oldest
370     if (m_pOldestTexture == NULL)
371     {
372         m_pOldestTexture = pEntry;
373     }
374 }
375
376 void CTextureManager::AddTexture(TxtrCacheEntry *pEntry)
377 {   
378     uint32 dwKey = Hash(pEntry->ti.Address);
379     
380     if (m_pCacheTxtrList == NULL)
381         return;
382     
383     //TxtrCacheEntry **p = &m_pCacheTxtrList[dwKey];
384     
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;
388
389     // Move the texture to the top of the age list
390     MakeTextureYoungest(pEntry);
391 }
392
393
394
395 TxtrCacheEntry * CTextureManager::GetTxtrCacheEntry(TxtrInfo * pti)
396 {
397     TxtrCacheEntry *pEntry;
398     
399     if (m_pCacheTxtrList == NULL)
400         return NULL;
401     
402     // See if it is already in the hash table
403     uint32 dwKey = Hash(pti->Address);
404
405     for (pEntry = m_pCacheTxtrList[dwKey]; pEntry; pEntry = pEntry->pNext)
406     {
407         if ( pEntry->ti == *pti )
408         {
409             MakeTextureYoungest(pEntry);
410             return pEntry;
411         }
412     }
413
414     return NULL;
415 }
416
417
418
419 void CTextureManager::RemoveTexture(TxtrCacheEntry * pEntry)
420 {
421     TxtrCacheEntry * pPrev;
422     TxtrCacheEntry * pCurr;
423     
424     if (m_pCacheTxtrList == NULL)
425         return;
426     
427     // See if it is already in the hash table
428     uint32 dwKey = Hash(pEntry->ti.Address);
429     
430     pPrev = NULL;
431     pCurr = m_pCacheTxtrList[dwKey];
432     
433     while (pCurr)
434     {
435         // Check that the attributes match
436         if ( pCurr->ti == pEntry->ti )
437         {
438             if (pPrev != NULL) 
439                 pPrev->pNext = pCurr->pNext;
440             else
441                m_pCacheTxtrList[dwKey] = pCurr->pNext;
442
443             if (g_bUseSetTextureMem)
444             {
445                 // remove the texture from the age list
446                 if (pEntry->pNextYoungest != NULL)
447                 {
448                     pEntry->pNextYoungest->pLastYoungest = pEntry->pLastYoungest;
449                 }
450                 if (pEntry->pLastYoungest != NULL)
451                 {
452                     pEntry->pLastYoungest->pNextYoungest = pEntry->pNextYoungest;
453                 }
454
455                 // decrease the mem usage counter
456                 m_currentTextureMemUsage -= (pEntry->pTexture->m_dwWidth * pEntry->pTexture->m_dwHeight * 4);
457             
458                 delete pEntry;
459             }
460             else
461             {
462                 RecycleTexture(pEntry);
463             }
464
465             break;
466         }
467
468         pPrev = pCurr;
469         pCurr = pCurr->pNext;
470     }
471     
472 }
473     
474 TxtrCacheEntry * CTextureManager::CreateNewCacheEntry(uint32 dwAddr, uint32 dwWidth, uint32 dwHeight)
475 {
476     TxtrCacheEntry * pEntry = NULL;
477
478     if (g_bUseSetTextureMem)
479     {
480         uint32 widthToCreate = dwWidth;
481         uint32 heightToCreate = dwHeight;
482         unsigned int freeUpSize = (widthToCreate * heightToCreate * 4) + g_amountToFree;
483
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)
486         {
487             TxtrCacheEntry *nextYoungest = m_pOldestTexture->pNextYoungest;
488
489             RemoveTexture(m_pOldestTexture);
490
491             m_pOldestTexture = nextYoungest;
492
493         //printf("Freeing Texture\n");
494         }
495
496         m_currentTextureMemUsage += widthToCreate * heightToCreate * 4;
497     }
498     else
499     {
500     // Find a used texture
501     pEntry = ReviveTexture(dwWidth, dwHeight);
502     }
503
504     if (pEntry == NULL || g_bUseSetTextureMem)
505     {
506         // Couldn't find on - recreate!
507         pEntry = new TxtrCacheEntry;
508         if (pEntry == NULL)
509         {
510             _VIDEO_DisplayTemporaryMessage("Error to create an texture entry");
511             return NULL;
512         }
513
514         pEntry->pTexture = CDeviceBuilder::GetBuilder()->CreateTexture(dwWidth, dwHeight);
515         if (pEntry->pTexture == NULL || pEntry->pTexture->GetTexture() == NULL)
516         {
517             _VIDEO_DisplayTemporaryMessage("Error to create an texture");
518             TRACE2("Warning, unable to create %d x %d texture!", dwWidth, dwHeight);
519         }
520         else
521         {
522             pEntry->pTexture->m_bScaledS = false;
523             pEntry->pTexture->m_bScaledT = false;
524         }
525     }
526     
527     // Initialize
528     pEntry->ti.Address = dwAddr;
529     pEntry->pNext = NULL;
530     pEntry->pNextYoungest = NULL;
531     pEntry->pLastYoungest = NULL;
532     pEntry->dwUses = 0;
533     pEntry->dwTimeLastUsed = status.gRDPTime;
534     pEntry->dwCRC = 0;
535     pEntry->FrameLastUsed = status.gDlistCount;
536     pEntry->FrameLastUpdated = 0;
537     pEntry->lastEntry = NULL;
538     pEntry->bExternalTxtrChecked = false;
539     pEntry->maxCI = -1;
540
541     // Add to the hash table
542     AddTexture(pEntry);
543     return pEntry;  
544 }
545
546 // If already in table, return
547 // Otherwise, create surfaces, and load texture into memory
548 uint32 dwAsmHeight;
549 uint32 dwAsmPitch;
550 uint32 dwAsmdwBytesPerLine;
551 uint32 dwAsmCRC;
552 uint32 dwAsmCRC2;
553 uint8* pAsmStart;
554
555 TxtrCacheEntry *g_lastTextureEntry=NULL;
556 bool lastEntryModified = false;
557
558
559 TxtrCacheEntry * CTextureManager::GetTexture(TxtrInfo * pgti, bool fromTMEM, bool doCRCCheck, bool AutoExtendTexture)
560 {
561     TxtrCacheEntry *pEntry;
562
563     if( g_curRomInfo.bDisableTextureCRC )
564         doCRCCheck = false;
565
566     gRDP.texturesAreReloaded = true;
567
568     dwAsmCRC = 0;
569     uint32 dwPalCRC = 0;
570
571     pEntry = GetTxtrCacheEntry(pgti);
572     bool loadFromTextureBuffer=false;
573     int txtBufIdxToLoadFrom = -1;
574     if( (frameBufferOptions.bCheckRenderTextures&&!frameBufferOptions.bWriteBackBufToRDRAM) || (frameBufferOptions.bCheckBackBufs&&!frameBufferOptions.bWriteBackBufToRDRAM) )
575     {
576         txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address);
577         if( txtBufIdxToLoadFrom >= 0 )
578         {
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 )
585             {
586                 info.txtEntry.ti = *pgti;
587                 return &info.txtEntry;
588             }
589         }
590     }
591
592     if( frameBufferOptions.bCheckBackBufs && g_pFrameBufferManager->CheckAddrInBackBuffers(pgti->Address, pgti->HeightToLoad*pgti->Pitch) >= 0 )
593     {
594         if( !frameBufferOptions.bWriteBackBufToRDRAM )
595         {
596             // Load the texture from recent back buffer
597             txtBufIdxToLoadFrom = g_pFrameBufferManager->CheckAddrInRenderTextures(pgti->Address);
598             if( txtBufIdxToLoadFrom >= 0 )
599             {
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 )
606                 {
607                     info.txtEntry.ti = *pgti;
608                     return &info.txtEntry;
609                 }
610             }
611         }
612     }
613
614     if (pEntry && pEntry->dwTimeLastUsed == status.gRDPTime && status.gDlistCount != 0 && !status.bN64FrameBufferIsUsed )       // This is not good, Palatte may changes
615     {
616         // We've already calculated a CRC this frame!
617         dwAsmCRC = pEntry->dwCRC;
618     }
619     else
620     {
621         if ( doCRCCheck )
622         {
623             if( loadFromTextureBuffer )
624                 dwAsmCRC = gRenderTextureInfos[txtBufIdxToLoadFrom].crcInRDRAM;
625             else
626                 CalculateRDRAMCRC(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch);
627         }
628     }
629
630     int maxCI = 0;
631     if ( doCRCCheck && (pgti->Format == TXT_FMT_CI || (pgti->Format == TXT_FMT_RGBA && pgti->Size <= TXT_SIZE_8b )))
632     {
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 );
635
636         if( !pEntry || pEntry->dwCRC != dwAsmCRC || pEntry->maxCI < 0 )
637         {
638             maxCI = CalculateMaxCI(pgti->pPhysicalAddress, pgti->LeftToLoad, pgti->TopToLoad, pgti->WidthToLoad, pgti->HeightToLoad, pgti->Size, pgti->Pitch);
639         }
640         else
641         {
642             maxCI = pEntry->maxCI;
643         }
644
645         //Check PAL CRC
646         uint8 * pStart;
647         uint32 dwPalSize = 16;
648         uint32 dwOffset;
649
650         if( pgti->Size == TXT_SIZE_8b )
651         {
652             dwPalSize = 256;
653             dwOffset = 0;
654         }
655         else
656         {
657             dwOffset = pgti->Palette << 4;
658         }
659
660         pStart = (uint8*)pgti->PalAddress+dwOffset*2;
661         //uint32 y;
662         //for (y = 0; y < dwPalSize*2; y+=4)
663         //{
664         //  dwPalCRC = (dwPalCRC + *(uint32*)&pStart[y]);
665         //}
666
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;
671     }
672
673     if (pEntry && doCRCCheck )
674     {
675         if(pEntry->dwCRC == dwAsmCRC && pEntry->dwPalCRC == dwPalCRC &&
676             (!loadFromTextureBuffer || gRenderTextureInfos[txtBufIdxToLoadFrom].updateAtFrame < pEntry->FrameLastUsed ) )
677         {
678             // Tile is ok, return
679             pEntry->dwUses++;
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;
686
687             DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) ,
688             {DebuggerAppendMsg("Load cached texture from render_texture");}
689             );
690
691             return pEntry;
692         }
693         else
694         {
695             //Do something
696         }
697     }
698
699     if (pEntry == NULL)
700     {
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);
704
705         if (pEntry == NULL)
706         {
707             g_lastTextureEntry = pEntry;
708             _VIDEO_DisplayTemporaryMessage("Fail to create new texture entry");
709             return NULL;
710         }
711     }
712
713     pEntry->ti = *pgti;
714     pEntry->dwCRC = dwAsmCRC;
715     pEntry->dwPalCRC = dwPalCRC;
716     pEntry->bExternalTxtrChecked = false;
717     pEntry->maxCI = maxCI;
718
719     try 
720     {
721         if (pEntry->pTexture != NULL)
722         {
723             if( pEntry->pTexture->m_dwCreatedTextureWidth < pgti->WidthToCreate )
724             {
725                 pEntry->ti.WidthToLoad = pEntry->pTexture->m_dwCreatedTextureWidth;
726                 pEntry->pTexture->m_bScaledS = false;
727                 pEntry->pTexture->m_bScaledT = false;
728             }
729             if( pEntry->pTexture->m_dwCreatedTextureHeight < pgti->HeightToCreate )
730             {
731                 pEntry->ti.HeightToLoad = pEntry->pTexture->m_dwCreatedTextureHeight;
732                 pEntry->pTexture->m_bScaledT = false;
733                 pEntry->pTexture->m_bScaledS = false;
734             }
735             
736             TextureFmt dwType = pEntry->pTexture->GetSurfaceFormat();
737             SAFE_DELETE(pEntry->pEnhancedTexture);
738             pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
739
740             if (dwType != TEXTURE_FMT_UNKNOWN)
741             {
742                 if( loadFromTextureBuffer )
743                 {
744                     g_pFrameBufferManager->LoadTextureFromRenderTexture(pEntry, txtBufIdxToLoadFrom);
745                     DEBUGGER_IF_DUMP((pauseAtNext && loadFromTextureBuffer) ,
746                     {DebuggerAppendMsg("Load texture from render_texture %d", txtBufIdxToLoadFrom);}
747                     );
748
749                     extern void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha);
750                     if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_I )
751                     {
752                         // Convert texture from RGBA to I
753                         ConvertTextureRGBAtoI(pEntry,false);
754                     }
755                     else if( g_pRenderTextureInfo->CI_Info.dwFormat == TXT_FMT_IA )
756                     {
757                         // Convert texture from RGBA to IA
758                         ConvertTextureRGBAtoI(pEntry,true);
759                     }
760                 }
761                 else
762                 {
763                     LOG_TEXTURE(TRACE0("   Load new texture from RDRAM:\n"));
764                     if (dwType == TEXTURE_FMT_A8R8G8B8)
765                     {
766                         ConvertTexture(pEntry, fromTMEM);
767                     }
768                     else
769                         ConvertTexture_16(pEntry, fromTMEM);
770                     pEntry->FrameLastUpdated = status.gDlistCount;
771                     SAFE_DELETE(pEntry->pEnhancedTexture);
772                     pEntry->dwEnhancementFlag = TEXTURE_NO_ENHANCEMENT;
773                 }
774             }
775
776             pEntry->ti.WidthToLoad = pgti->WidthToLoad;
777             pEntry->ti.HeightToLoad = pgti->HeightToLoad;
778             
779             if( AutoExtendTexture )
780             {
781                 ExpandTextureS(pEntry);
782                 ExpandTextureT(pEntry);
783             }
784
785             if( options.bDumpTexturesToFiles && !loadFromTextureBuffer )
786             {
787                 DumpCachedTexture(*pEntry);
788             }
789
790 #ifdef DEBUGGER
791             if( pauseAtNext && eventToPause == NEXT_NEW_TEXTURE )
792             {
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 )
798                 {
799                     TRACE0("This is YUV texture");
800                 }
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);
804                 DebuggerPause();
805                 CRender::g_pRender->SetCurrentTexture( 0, NULL, 64, 64, NULL);
806             }
807 #endif
808         }
809     }
810     catch (...)
811     {
812         TRACE0("Exception in texture decompression");
813         g_lastTextureEntry = NULL;
814         return NULL;
815     }
816
817     pEntry->lastEntry = g_lastTextureEntry;
818     g_lastTextureEntry = pEntry;
819     lastEntryModified = true;
820     return pEntry;
821 }
822
823
824
825
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"};
829
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)
838 {
839     static uint32 dwCount = 0;
840     
841     ConvertFunction pF;
842     if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM )
843     {
844         pF = gConvertFunctions_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ];
845     }
846     else
847     {
848         if( gRDP.tiles[7].dwFormat == TXT_FMT_YUV )
849         {
850             if( gRDP.otherMode.text_tlut>=2 )
851                 pF = gConvertTlutFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ];
852             else
853                 pF = gConvertFunctions[ TXT_FMT_YUV ][ pEntry->ti.Size ];
854         }
855         else
856         {
857             if( gRDP.otherMode.text_tlut>=2 )
858                 pF = gConvertTlutFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ];
859             else
860                 pF = gConvertFunctions[ pEntry->ti.Format ][ pEntry->ti.Size ];
861         }
862     }
863
864     if( pF )
865     {
866         pF( pEntry->pTexture, pEntry->ti );
867     
868 /*printf("Decompress 32bit Texture:\n\tFormat: %s\n\tImage Size:%d\n", 
869                 pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
870 printf("Palette Format: %s (%d)\n", textlutname[pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT], pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT);*/
871         LOG_TEXTURE(
872         {
873             DebuggerAppendMsg("Decompress 32bit Texture:\n\tFormat: %s\n\tImage Size:%d\n", 
874                 pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
875             DebuggerAppendMsg("Palette Format: %s (%d)\n", textlutname[pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT], pEntry->ti.TLutFmt>>RSP_SETOTHERMODE_SHIFT_TEXTLUT);
876         });
877     }
878     else
879     {
880 //printf("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
881         TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
882     }
883
884     dwCount++;
885 }
886
887 void CTextureManager::ConvertTexture_16(TxtrCacheEntry * pEntry, bool fromTMEM)
888 {
889     static uint32 dwCount = 0;
890     
891     ConvertFunction pF;
892
893     if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM )
894     {
895         pF = gConvertFunctions_16_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ];
896     }
897     else
898     {
899         if( gRDP.otherMode.text_tlut>=2 )
900             pF = gConvertTlutFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ];
901         else
902             pF = gConvertFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ];
903     }
904
905     if( pF )
906     {
907         pF( pEntry->pTexture, pEntry->ti );
908
909         LOG_TEXTURE(TRACE2("Decompress 16bit Texture:\n\tFormat: %s\n\tImage Size:%d\n", 
910             pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]));
911     }
912     else
913     {
914         TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
915     }
916
917     dwCount++;
918 }
919
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)
922 {
923     if( sizeToLoad >= sizeCreated ) return;
924
925     uint32 maskWidth = (1<<mask);
926     int size = pEntry->pTexture->GetPixelSize();
927
928 #ifdef DEBUGGER
929     // Some checks
930     if( sizeToLoad > sizeToCreate || sizeToCreate > sizeCreated )   
931         TRACE0("Something is wrong, check me here in ExpandTextureS");
932 #endif
933
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
937
938     DrawInfo di;
939     if( !(pEntry->pTexture->StartUpdate(&di)) )
940     {
941         TRACE0("Cann't update the texture");
942         return;
943     }
944
945
946     if( mask == 0 )
947     {
948         // Clamp
949         Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, 
950             flag, size);
951         pEntry->pTexture->EndUpdate(&di);
952         return;
953     }
954
955 #ifdef DEBUGGER
956     if( sizeToLoad > maskWidth )
957     {
958         TRACE0("Something is wrong, check me here in ExpandTextureS");
959         pEntry->pTexture->EndUpdate(&di);
960         return;
961     }
962     if( sizeToLoad == maskWidth && maskWidth == sizeToCreate && sizeToCreate != sizeCreated )
963     {
964         TRACE0("Something is wrong, check me here in ExpandTextureS");
965         pEntry->pTexture->EndUpdate(&di);
966         return;
967     }
968 #endif
969
970     if( sizeToLoad == maskWidth )
971     {
972         uint32 tempwidth = clamp ? sizeToCreate : sizeCreated;
973         if( mirror )
974         {
975             Mirror(di.lpSurface, sizeToLoad, mask, tempwidth,
976                 arrayWidth, otherSize, flag, size );
977         }
978         else
979         {
980             Wrap(di.lpSurface, sizeToLoad, mask, tempwidth,
981                 arrayWidth, otherSize, flag, size );
982         }
983
984         if( tempwidth < sizeCreated )
985         {
986             Clamp(di.lpSurface, tempwidth, sizeCreated, arrayWidth, otherSize, 
987                 flag, size );
988         }
989
990         pEntry->pTexture->EndUpdate(&di);
991         return;
992     }
993
994
995     if( sizeToLoad < sizeToCreate && sizeToCreate == maskWidth && maskWidth == sizeCreated )
996     {
997         // widthToLoad < widthToCreate = maskWidth
998         Wrap(di.lpSurface, sizeToLoad, mask, sizeCreated, arrayWidth, otherSize, flag, size );
999
1000         pEntry->pTexture->EndUpdate(&di);
1001         return;
1002     }
1003
1004     if( sizeToLoad == sizeToCreate && sizeToCreate < maskWidth )
1005     {
1006 #ifdef DEBUGGER
1007         if( maskWidth < sizeToCreate )  TRACE0("Incorrect condition, check me");
1008 #endif
1009         Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size );
1010
1011         pEntry->pTexture->EndUpdate(&di);
1012         return;
1013     }
1014
1015     if( sizeToLoad < sizeToCreate && sizeToCreate < maskWidth )
1016     {
1017 #ifdef DEBUGGER
1018         if( clamp ) TRACE0("Incorrect condition, check me");
1019         if( maskWidth < sizeCreated )   TRACE0("Incorrect condition, check me");
1020 #endif
1021         Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size );
1022         pEntry->pTexture->EndUpdate(&di);
1023         return;
1024     }
1025
1026     TRACE0("Check me, should not get here");
1027     pEntry->pTexture->EndUpdate(&di);
1028 }
1029
1030 void CTextureManager::ExpandTextureS(TxtrCacheEntry * pEntry)
1031 {
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);
1036 }
1037
1038 void CTextureManager::ExpandTextureT(TxtrCacheEntry * pEntry)
1039 {
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);
1045 }
1046
1047
1048 void CTextureManager::ClampS32(uint32 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
1049 {
1050     if ((int) width <= 0 || (int) towidth < 0)
1051         return;
1052
1053     for( uint32 y = 0; y<rows; y++ )
1054     {
1055         uint32* line = array+y*arrayWidth;
1056         uint32 val = line[width-1];
1057         for( uint32 x=width; x<towidth; x++ )
1058         {
1059             line[x] = val;
1060         }
1061     }
1062 }
1063
1064 void CTextureManager::ClampS16(uint16 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
1065 {
1066     if ((int) width <= 0 || (int) towidth < 0)
1067         return;
1068
1069     for( uint32 y = 0; y<rows; y++ )
1070     {
1071         uint16* line = array+y*arrayWidth;
1072         uint16 val = line[width-1];
1073         for( uint32 x=width; x<towidth; x++ )
1074         {
1075             line[x] = val;
1076         }
1077     }
1078 }
1079
1080 void CTextureManager::ClampT32(uint32 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
1081 {
1082     if ((int) height <= 0 || (int) toheight < 0)
1083         return;
1084
1085     uint32* linesrc = array+arrayWidth*(height-1);
1086     for( uint32 y = height; y<toheight; y++ )
1087     {
1088         uint32* linedst = array+arrayWidth*y;
1089         for( uint32 x=0; x<arrayWidth; x++ )
1090         {
1091             linedst[x] = linesrc[x];
1092         }
1093     }
1094 }
1095
1096 void CTextureManager::ClampT16(uint16 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
1097 {
1098     if ((int) height <= 0 || (int) toheight < 0)
1099         return;
1100
1101     uint16* linesrc = array+arrayWidth*(height-1);
1102     for( uint32 y = height; y<toheight; y++ )
1103     {
1104         uint16* linedst = array+arrayWidth*y;
1105         for( uint32 x=0; x<arrayWidth; x++ )
1106         {
1107             linedst[x] = linesrc[x];
1108         }
1109     }
1110 }
1111
1112 void CTextureManager::MirrorS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1113 {
1114     uint32 maskval1 = (1<<mask)-1;
1115     uint32 maskval2 = (1<<(mask+1))-1;
1116
1117     for( uint32 y = 0; y<rows; y++ )
1118     {
1119         uint32* line = array+y*arrayWidth;
1120         for( uint32 x=width; x<towidth; x++ )
1121         {
1122             line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
1123         }
1124     }
1125 }
1126
1127 void CTextureManager::MirrorS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1128 {
1129     uint32 maskval1 = (1<<mask)-1;
1130     uint32 maskval2 = (1<<(mask+1))-1;
1131
1132     for( uint32 y = 0; y<rows; y++ )
1133     {
1134         uint16* line = array+y*arrayWidth;
1135         for( uint32 x=width; x<towidth; x++ )
1136         {
1137             line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
1138         }
1139     }
1140 }
1141
1142 void CTextureManager::MirrorT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1143 {
1144     uint32 maskval1 = (1<<mask)-1;
1145     uint32 maskval2 = (1<<(mask+1))-1;
1146
1147     for( uint32 y = height; y<toheight; y++ )
1148     {
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++ )
1153         {
1154             linedst[x] = linesrc[x];
1155         }
1156     }
1157 }
1158
1159 void CTextureManager::MirrorT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1160 {
1161     uint32 maskval1 = (1<<mask)-1;
1162     uint32 maskval2 = (1<<(mask+1))-1;
1163
1164     for( uint32 y = height; y<toheight; y++ )
1165     {
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++ )
1170         {
1171             linedst[x] = linesrc[x];
1172         }
1173     }
1174 }
1175
1176 void CTextureManager::WrapS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1177 {
1178     uint32 maskval = (1<<mask)-1;
1179
1180     for( uint32 y = 0; y<rows; y++ )
1181     {
1182         uint32* line = array+y*arrayWidth;
1183         for( uint32 x=width; x<towidth; x++ )
1184         {
1185             line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
1186         }
1187     }
1188 }
1189
1190 void CTextureManager::WrapS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1191 {
1192     uint32 maskval = (1<<mask)-1;
1193
1194     for( uint32 y = 0; y<rows; y++ )
1195     {
1196         uint16* line = array+y*arrayWidth;
1197         for( uint32 x=width; x<towidth; x++ )
1198         {
1199             line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
1200         }
1201     }
1202 }
1203
1204 void CTextureManager::WrapT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1205 {
1206     uint32 maskval = (1<<mask)-1;
1207     for( uint32 y = height; y<toheight; y++ )
1208     {
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++ )
1212         {
1213             linedst[x] = linesrc[x];
1214         }
1215     }
1216 }
1217
1218 void CTextureManager::WrapT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1219 {
1220     uint32 maskval = (1<<mask)-1;
1221     for( uint32 y = height; y<toheight; y++ )
1222     {
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++ )
1226         {
1227             linedst[x] = linesrc[x];
1228         }
1229     }
1230 }
1231
1232 void CTextureManager::Clamp(void *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1233 {
1234     if( flag == S_FLAG )    // s
1235     {
1236         if( size == 4 ) // 32 bit
1237         {
1238             ClampS32((uint32*)array, width, towidth, arrayWidth, rows);
1239         }
1240         else    // 16 bits
1241         {
1242             ClampS16((uint16*)array, width, towidth, arrayWidth, rows);
1243         }
1244     }
1245     else    // t
1246     {
1247         if( size == 4 ) // 32 bit
1248         {
1249             ClampT32((uint32*)array, width, towidth, arrayWidth, rows);
1250         }
1251         else    // 16 bits
1252         {
1253             ClampT16((uint16*)array, width, towidth, arrayWidth, rows);
1254         }
1255     }
1256 }
1257 void CTextureManager::Wrap(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1258 {
1259     if( flag == S_FLAG )    // s
1260     {
1261         if( size == 4 ) // 32 bit
1262         {
1263             WrapS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1264         }
1265         else    // 16 bits
1266         {
1267             WrapS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1268         }
1269     }
1270     else    // t
1271     {
1272         if( size == 4 ) // 32 bit
1273         {
1274             WrapT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1275         }
1276         else    // 16 bits
1277         {
1278             WrapT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1279         }
1280     }
1281 }
1282 void CTextureManager::Mirror(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1283 {
1284     if( flag == S_FLAG )    // s
1285     {
1286         if( size == 4 ) // 32 bit
1287         {
1288             MirrorS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1289         }
1290         else    // 16 bits
1291         {
1292             MirrorS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1293         }
1294     }
1295     else    // t
1296     {
1297         if( size == 4 ) // 32 bit
1298         {
1299             MirrorT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1300         }
1301         else    // 16 bits
1302         {
1303             MirrorT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1304         }
1305     }
1306
1307 }
1308
1309
1310 #ifdef DEBUGGER
1311 TxtrCacheEntry * CTextureManager::GetCachedTexture(uint32 tex)
1312 {
1313     uint32 size = 0;
1314     for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
1315     {
1316         if( m_pCacheTxtrList[i] == NULL )
1317             continue;
1318         else
1319         {
1320             TxtrCacheEntry *pEntry;
1321
1322             for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
1323             {
1324                 if( size == tex )
1325                     return pEntry;
1326                 else
1327                     size++;
1328             }
1329         }
1330     }
1331     return NULL;
1332 }
1333 uint32 CTextureManager::GetNumOfCachedTexture()
1334 {
1335     uint32 size = 0;
1336     for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
1337     {
1338         if( m_pCacheTxtrList[i] == NULL )
1339             continue;
1340         else
1341         {
1342             TxtrCacheEntry *pEntry;
1343
1344             for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
1345             {
1346                 size++;
1347             }
1348         }
1349     }
1350     TRACE1("Totally %d texture cached", size);
1351     return size;
1352 }
1353 #endif
1354
1355
1356 TxtrCacheEntry * CTextureManager::GetBlackTexture(void)
1357 {
1358     if( m_blackTextureEntry.pTexture == NULL )
1359     {
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);
1364     }
1365     return &m_blackTextureEntry;
1366 }
1367 TxtrCacheEntry * CTextureManager::GetPrimColorTexture(uint32 color)
1368 {
1369     static uint32 mcolor = 0;
1370     if( m_PrimColorTextureEntry.pTexture == NULL )
1371     {
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;
1377     }
1378     else if( mcolor != color )
1379     {
1380         updateColorTexture(m_PrimColorTextureEntry.pTexture,color);
1381         gRDP.texturesAreReloaded = true;
1382     }
1383
1384     mcolor = color;
1385     return &m_PrimColorTextureEntry;
1386 }
1387 TxtrCacheEntry * CTextureManager::GetEnvColorTexture(uint32 color)
1388 {
1389     static uint32 mcolor = 0;
1390     if( m_EnvColorTextureEntry.pTexture == NULL )
1391     {
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;
1396
1397         updateColorTexture(m_EnvColorTextureEntry.pTexture,color);
1398     }
1399     else if( mcolor != color )
1400     {
1401         updateColorTexture(m_EnvColorTextureEntry.pTexture,color);
1402         gRDP.texturesAreReloaded = true;
1403     }
1404
1405     mcolor = color;
1406     return &m_EnvColorTextureEntry;
1407 }
1408 TxtrCacheEntry * CTextureManager::GetLODFracTexture(uint8 fac)
1409 {
1410     static uint8 mfac = 0;
1411     if( m_LODFracTextureEntry.pTexture == NULL )
1412     {
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;
1417         uint32 color = fac;
1418         color |= factor << 8;
1419         color |= color << 16;
1420         updateColorTexture(m_LODFracTextureEntry.pTexture,color);
1421         gRDP.texturesAreReloaded = true;
1422     }
1423     else if( mfac != fac )
1424     {
1425         uint32 factor = fac;
1426         uint32 color = fac;
1427         color |= factor << 8;
1428         color |= color << 16;
1429         updateColorTexture(m_LODFracTextureEntry.pTexture,color);
1430         gRDP.texturesAreReloaded = true;
1431     }
1432
1433     mfac = fac;
1434     return &m_LODFracTextureEntry;
1435 }
1436
1437 TxtrCacheEntry * CTextureManager::GetPrimLODFracTexture(uint8 fac)
1438 {
1439     static uint8 mfac = 0;
1440     if( m_PrimLODFracTextureEntry.pTexture == NULL )
1441     {
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;
1446         uint32 color = fac;
1447         color |= factor << 8;
1448         color |= color << 16;
1449         updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color);
1450         gRDP.texturesAreReloaded = true;
1451     }
1452     else if( mfac != fac )
1453     {
1454         uint32 factor = fac;
1455         uint32 color = fac;
1456         color |= factor << 8;
1457         color |= color << 16;
1458         updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color);
1459         gRDP.texturesAreReloaded = true;
1460     }
1461
1462     mfac = fac;
1463     return &m_PrimLODFracTextureEntry;
1464 }
1465
1466 TxtrCacheEntry * CTextureManager::GetConstantColorTexture(uint32 constant)
1467 {
1468     switch( constant )
1469     {
1470     case MUX_PRIM:
1471         return GetPrimColorTexture(gRDP.primitiveColor);
1472         break;
1473     case MUX_ENV:
1474         return GetEnvColorTexture(gRDP.envColor);
1475         break;
1476     case MUX_LODFRAC:
1477         return GetLODFracTexture((uint8)gRDP.LODFrac);
1478         break;
1479     default:    // MUX_PRIMLODFRAC
1480         return GetPrimLODFracTexture((uint8)gRDP.primLODFrac);
1481         break;
1482     }
1483 }
1484
1485 void CTextureManager::updateColorTexture(CTexture *ptexture, uint32 color)
1486 {
1487     DrawInfo di;
1488     if( !(ptexture->StartUpdate(&di)) )
1489     {
1490         TRACE0("Cann't update the texture");
1491         return;
1492     }
1493
1494     int size = ptexture->GetPixelSize();
1495     switch( size )
1496     {
1497     case 2: // 16 bits
1498         {
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++ )
1505             {
1506                 buf[i] = color16;
1507             }
1508         }
1509         break;
1510     case 4: // 32 bits
1511         {
1512             uint32 *buf = (uint32*)di.lpSurface;
1513             for( int i=0; i<16; i++ )
1514             {
1515                 buf[i] = color;
1516             }
1517         }
1518         break;
1519     }
1520
1521     ptexture->EndUpdate(&di);
1522 }
1523
1524 void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha)
1525 {
1526     DrawInfo srcInfo;   
1527     if( pEntry->pTexture->StartUpdate(&srcInfo) )
1528     {
1529         uint32 *buf;
1530         uint32 val;
1531         uint32 r,g,b,a,i;
1532
1533         for(int nY = 0; nY < srcInfo.dwCreatedHeight; nY++)
1534         {
1535             buf = (uint32*)((uint8*)srcInfo.lpSurface+nY*srcInfo.lPitch);
1536             for(int nX = 0; nX < srcInfo.dwCreatedWidth; nX++)
1537             {
1538                 val = buf[nX];
1539                 b = (val>>0)&0xFF;
1540                 g = (val>>8)&0xFF;
1541                 r = (val>>16)&0xFF;
1542                 i = (r+g+b)/3;
1543                 a = alpha?(val&0xFF000000):(i<<24);
1544                 buf[nX] = (a|(i<<16)|(i<<8)|i);
1545             }
1546         }
1547         pEntry->pTexture->EndUpdate(&srcInfo);
1548     }
1549 }
1550