fb868e26aeebe73b3e8521bed948b82a5f965d90
[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         LOG_TEXTURE(
869         {
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);
873         });
874     }
875     else
876     {
877         TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
878     }
879
880     dwCount++;
881 }
882
883 void CTextureManager::ConvertTexture_16(TxtrCacheEntry * pEntry, bool fromTMEM)
884 {
885     static uint32 dwCount = 0;
886     
887     ConvertFunction pF;
888
889     if( options.bUseFullTMEM && fromTMEM && status.bAllowLoadFromTMEM )
890     {
891         pF = gConvertFunctions_16_FullTMEM[ pEntry->ti.Format ][ pEntry->ti.Size ];
892     }
893     else
894     {
895         if( gRDP.otherMode.text_tlut>=2 )
896             pF = gConvertTlutFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ];
897         else
898             pF = gConvertFunctions_16[ pEntry->ti.Format ][ pEntry->ti.Size ];
899     }
900
901     if( pF )
902     {
903         pF( pEntry->pTexture, pEntry->ti );
904
905         LOG_TEXTURE(TRACE2("Decompress 16bit Texture:\n\tFormat: %s\n\tImage Size:%d\n", 
906             pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]));
907     }
908     else
909     {
910         TRACE2("ConvertTexture: Unable to decompress %s/%dbpp", pszImgFormat[pEntry->ti.Format], pnImgSize[pEntry->ti.Size]);
911     }
912
913     dwCount++;
914 }
915
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)
918 {
919     if( sizeToLoad >= sizeCreated ) return;
920
921     uint32 maskWidth = (1<<mask);
922     int size = pEntry->pTexture->GetPixelSize();
923
924 #ifdef DEBUGGER
925     // Some checks
926     if( sizeToLoad > sizeToCreate || sizeToCreate > sizeCreated )   
927         TRACE0("Something is wrong, check me here in ExpandTextureS");
928 #endif
929
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
933
934     DrawInfo di;
935     if( !(pEntry->pTexture->StartUpdate(&di)) )
936     {
937         TRACE0("Cann't update the texture");
938         return;
939     }
940
941
942     if( mask == 0 )
943     {
944         // Clamp
945         Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, 
946             flag, size);
947         pEntry->pTexture->EndUpdate(&di);
948         return;
949     }
950
951 #ifdef DEBUGGER
952     if( sizeToLoad > maskWidth )
953     {
954         TRACE0("Something is wrong, check me here in ExpandTextureS");
955         pEntry->pTexture->EndUpdate(&di);
956         return;
957     }
958     if( sizeToLoad == maskWidth && maskWidth == sizeToCreate && sizeToCreate != sizeCreated )
959     {
960         TRACE0("Something is wrong, check me here in ExpandTextureS");
961         pEntry->pTexture->EndUpdate(&di);
962         return;
963     }
964 #endif
965
966     if( sizeToLoad == maskWidth )
967     {
968         uint32 tempwidth = clamp ? sizeToCreate : sizeCreated;
969         if( mirror )
970         {
971             Mirror(di.lpSurface, sizeToLoad, mask, tempwidth,
972                 arrayWidth, otherSize, flag, size );
973         }
974         else
975         {
976             Wrap(di.lpSurface, sizeToLoad, mask, tempwidth,
977                 arrayWidth, otherSize, flag, size );
978         }
979
980         if( tempwidth < sizeCreated )
981         {
982             Clamp(di.lpSurface, tempwidth, sizeCreated, arrayWidth, otherSize, 
983                 flag, size );
984         }
985
986         pEntry->pTexture->EndUpdate(&di);
987         return;
988     }
989
990
991     if( sizeToLoad < sizeToCreate && sizeToCreate == maskWidth && maskWidth == sizeCreated )
992     {
993         // widthToLoad < widthToCreate = maskWidth
994         Wrap(di.lpSurface, sizeToLoad, mask, sizeCreated, arrayWidth, otherSize, flag, size );
995
996         pEntry->pTexture->EndUpdate(&di);
997         return;
998     }
999
1000     if( sizeToLoad == sizeToCreate && sizeToCreate < maskWidth )
1001     {
1002 #ifdef DEBUGGER
1003         if( maskWidth < sizeToCreate )  TRACE0("Incorrect condition, check me");
1004 #endif
1005         Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size );
1006
1007         pEntry->pTexture->EndUpdate(&di);
1008         return;
1009     }
1010
1011     if( sizeToLoad < sizeToCreate && sizeToCreate < maskWidth )
1012     {
1013 #ifdef DEBUGGER
1014         if( clamp ) TRACE0("Incorrect condition, check me");
1015         if( maskWidth < sizeCreated )   TRACE0("Incorrect condition, check me");
1016 #endif
1017         Clamp(di.lpSurface, sizeToLoad, sizeCreated, arrayWidth, otherSize, flag, size );
1018         pEntry->pTexture->EndUpdate(&di);
1019         return;
1020     }
1021
1022     TRACE0("Check me, should not get here");
1023     pEntry->pTexture->EndUpdate(&di);
1024 }
1025
1026 void CTextureManager::ExpandTextureS(TxtrCacheEntry * pEntry)
1027 {
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);
1032 }
1033
1034 void CTextureManager::ExpandTextureT(TxtrCacheEntry * pEntry)
1035 {
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);
1041 }
1042
1043
1044 void CTextureManager::ClampS32(uint32 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
1045 {
1046     if ((int) width <= 0 || (int) towidth < 0)
1047         return;
1048
1049     for( uint32 y = 0; y<rows; y++ )
1050     {
1051         uint32* line = array+y*arrayWidth;
1052         uint32 val = line[width-1];
1053         for( uint32 x=width; x<towidth; x++ )
1054         {
1055             line[x] = val;
1056         }
1057     }
1058 }
1059
1060 void CTextureManager::ClampS16(uint16 *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows)
1061 {
1062     if ((int) width <= 0 || (int) towidth < 0)
1063         return;
1064
1065     for( uint32 y = 0; y<rows; y++ )
1066     {
1067         uint16* line = array+y*arrayWidth;
1068         uint16 val = line[width-1];
1069         for( uint32 x=width; x<towidth; x++ )
1070         {
1071             line[x] = val;
1072         }
1073     }
1074 }
1075
1076 void CTextureManager::ClampT32(uint32 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
1077 {
1078     if ((int) height <= 0 || (int) toheight < 0)
1079         return;
1080
1081     uint32* linesrc = array+arrayWidth*(height-1);
1082     for( uint32 y = height; y<toheight; y++ )
1083     {
1084         uint32* linedst = array+arrayWidth*y;
1085         for( uint32 x=0; x<arrayWidth; x++ )
1086         {
1087             linedst[x] = linesrc[x];
1088         }
1089     }
1090 }
1091
1092 void CTextureManager::ClampT16(uint16 *array, uint32 height, uint32 toheight, uint32 arrayWidth, uint32 cols)
1093 {
1094     if ((int) height <= 0 || (int) toheight < 0)
1095         return;
1096
1097     uint16* linesrc = array+arrayWidth*(height-1);
1098     for( uint32 y = height; y<toheight; y++ )
1099     {
1100         uint16* linedst = array+arrayWidth*y;
1101         for( uint32 x=0; x<arrayWidth; x++ )
1102         {
1103             linedst[x] = linesrc[x];
1104         }
1105     }
1106 }
1107
1108 void CTextureManager::MirrorS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1109 {
1110     uint32 maskval1 = (1<<mask)-1;
1111     uint32 maskval2 = (1<<(mask+1))-1;
1112
1113     for( uint32 y = 0; y<rows; y++ )
1114     {
1115         uint32* line = array+y*arrayWidth;
1116         for( uint32 x=width; x<towidth; x++ )
1117         {
1118             line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
1119         }
1120     }
1121 }
1122
1123 void CTextureManager::MirrorS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1124 {
1125     uint32 maskval1 = (1<<mask)-1;
1126     uint32 maskval2 = (1<<(mask+1))-1;
1127
1128     for( uint32 y = 0; y<rows; y++ )
1129     {
1130         uint16* line = array+y*arrayWidth;
1131         for( uint32 x=width; x<towidth; x++ )
1132         {
1133             line[x] = (x&maskval2)<=maskval1 ? line[x&maskval1] : line[maskval2-(x&maskval2)];
1134         }
1135     }
1136 }
1137
1138 void CTextureManager::MirrorT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1139 {
1140     uint32 maskval1 = (1<<mask)-1;
1141     uint32 maskval2 = (1<<(mask+1))-1;
1142
1143     for( uint32 y = height; y<toheight; y++ )
1144     {
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++ )
1149         {
1150             linedst[x] = linesrc[x];
1151         }
1152     }
1153 }
1154
1155 void CTextureManager::MirrorT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1156 {
1157     uint32 maskval1 = (1<<mask)-1;
1158     uint32 maskval2 = (1<<(mask+1))-1;
1159
1160     for( uint32 y = height; y<toheight; y++ )
1161     {
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++ )
1166         {
1167             linedst[x] = linesrc[x];
1168         }
1169     }
1170 }
1171
1172 void CTextureManager::WrapS32(uint32 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1173 {
1174     uint32 maskval = (1<<mask)-1;
1175
1176     for( uint32 y = 0; y<rows; y++ )
1177     {
1178         uint32* line = array+y*arrayWidth;
1179         for( uint32 x=width; x<towidth; x++ )
1180         {
1181             line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
1182         }
1183     }
1184 }
1185
1186 void CTextureManager::WrapS16(uint16 *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows)
1187 {
1188     uint32 maskval = (1<<mask)-1;
1189
1190     for( uint32 y = 0; y<rows; y++ )
1191     {
1192         uint16* line = array+y*arrayWidth;
1193         for( uint32 x=width; x<towidth; x++ )
1194         {
1195             line[x] = line[(x&maskval)<width?(x&maskval):towidth-(x&maskval)];
1196         }
1197     }
1198 }
1199
1200 void CTextureManager::WrapT32(uint32 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1201 {
1202     uint32 maskval = (1<<mask)-1;
1203     for( uint32 y = height; y<toheight; y++ )
1204     {
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++ )
1208         {
1209             linedst[x] = linesrc[x];
1210         }
1211     }
1212 }
1213
1214 void CTextureManager::WrapT16(uint16 *array, uint32 height, uint32 mask, uint32 toheight, uint32 arrayWidth, uint32 cols)
1215 {
1216     uint32 maskval = (1<<mask)-1;
1217     for( uint32 y = height; y<toheight; y++ )
1218     {
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++ )
1222         {
1223             linedst[x] = linesrc[x];
1224         }
1225     }
1226 }
1227
1228 void CTextureManager::Clamp(void *array, uint32 width, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1229 {
1230     if( flag == S_FLAG )    // s
1231     {
1232         if( size == 4 ) // 32 bit
1233         {
1234             ClampS32((uint32*)array, width, towidth, arrayWidth, rows);
1235         }
1236         else    // 16 bits
1237         {
1238             ClampS16((uint16*)array, width, towidth, arrayWidth, rows);
1239         }
1240     }
1241     else    // t
1242     {
1243         if( size == 4 ) // 32 bit
1244         {
1245             ClampT32((uint32*)array, width, towidth, arrayWidth, rows);
1246         }
1247         else    // 16 bits
1248         {
1249             ClampT16((uint16*)array, width, towidth, arrayWidth, rows);
1250         }
1251     }
1252 }
1253 void CTextureManager::Wrap(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1254 {
1255     if( flag == S_FLAG )    // s
1256     {
1257         if( size == 4 ) // 32 bit
1258         {
1259             WrapS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1260         }
1261         else    // 16 bits
1262         {
1263             WrapS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1264         }
1265     }
1266     else    // t
1267     {
1268         if( size == 4 ) // 32 bit
1269         {
1270             WrapT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1271         }
1272         else    // 16 bits
1273         {
1274             WrapT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1275         }
1276     }
1277 }
1278 void CTextureManager::Mirror(void *array, uint32 width, uint32 mask, uint32 towidth, uint32 arrayWidth, uint32 rows, int flag, int size )
1279 {
1280     if( flag == S_FLAG )    // s
1281     {
1282         if( size == 4 ) // 32 bit
1283         {
1284             MirrorS32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1285         }
1286         else    // 16 bits
1287         {
1288             MirrorS16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1289         }
1290     }
1291     else    // t
1292     {
1293         if( size == 4 ) // 32 bit
1294         {
1295             MirrorT32((uint32*)array, width, mask, towidth, arrayWidth, rows);
1296         }
1297         else    // 16 bits
1298         {
1299             MirrorT16((uint16*)array, width, mask, towidth, arrayWidth, rows);
1300         }
1301     }
1302
1303 }
1304
1305
1306 #ifdef DEBUGGER
1307 TxtrCacheEntry * CTextureManager::GetCachedTexture(uint32 tex)
1308 {
1309     uint32 size = 0;
1310     for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
1311     {
1312         if( m_pCacheTxtrList[i] == NULL )
1313             continue;
1314         else
1315         {
1316             TxtrCacheEntry *pEntry;
1317
1318             for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
1319             {
1320                 if( size == tex )
1321                     return pEntry;
1322                 else
1323                     size++;
1324             }
1325         }
1326     }
1327     return NULL;
1328 }
1329 uint32 CTextureManager::GetNumOfCachedTexture()
1330 {
1331     uint32 size = 0;
1332     for( uint32 i=0; i<m_numOfCachedTxtrList; i++ )
1333     {
1334         if( m_pCacheTxtrList[i] == NULL )
1335             continue;
1336         else
1337         {
1338             TxtrCacheEntry *pEntry;
1339
1340             for (pEntry = m_pCacheTxtrList[i]; pEntry; pEntry = pEntry->pNext)
1341             {
1342                 size++;
1343             }
1344         }
1345     }
1346     TRACE1("Totally %d texture cached", size);
1347     return size;
1348 }
1349 #endif
1350
1351
1352 TxtrCacheEntry * CTextureManager::GetBlackTexture(void)
1353 {
1354     if( m_blackTextureEntry.pTexture == NULL )
1355     {
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);
1360     }
1361     return &m_blackTextureEntry;
1362 }
1363 TxtrCacheEntry * CTextureManager::GetPrimColorTexture(uint32 color)
1364 {
1365     static uint32 mcolor = 0;
1366     if( m_PrimColorTextureEntry.pTexture == NULL )
1367     {
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;
1373     }
1374     else if( mcolor != color )
1375     {
1376         updateColorTexture(m_PrimColorTextureEntry.pTexture,color);
1377         gRDP.texturesAreReloaded = true;
1378     }
1379
1380     mcolor = color;
1381     return &m_PrimColorTextureEntry;
1382 }
1383 TxtrCacheEntry * CTextureManager::GetEnvColorTexture(uint32 color)
1384 {
1385     static uint32 mcolor = 0;
1386     if( m_EnvColorTextureEntry.pTexture == NULL )
1387     {
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;
1392
1393         updateColorTexture(m_EnvColorTextureEntry.pTexture,color);
1394     }
1395     else if( mcolor != color )
1396     {
1397         updateColorTexture(m_EnvColorTextureEntry.pTexture,color);
1398         gRDP.texturesAreReloaded = true;
1399     }
1400
1401     mcolor = color;
1402     return &m_EnvColorTextureEntry;
1403 }
1404 TxtrCacheEntry * CTextureManager::GetLODFracTexture(uint8 fac)
1405 {
1406     static uint8 mfac = 0;
1407     if( m_LODFracTextureEntry.pTexture == NULL )
1408     {
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;
1413         uint32 color = fac;
1414         color |= factor << 8;
1415         color |= color << 16;
1416         updateColorTexture(m_LODFracTextureEntry.pTexture,color);
1417         gRDP.texturesAreReloaded = true;
1418     }
1419     else if( mfac != fac )
1420     {
1421         uint32 factor = fac;
1422         uint32 color = fac;
1423         color |= factor << 8;
1424         color |= color << 16;
1425         updateColorTexture(m_LODFracTextureEntry.pTexture,color);
1426         gRDP.texturesAreReloaded = true;
1427     }
1428
1429     mfac = fac;
1430     return &m_LODFracTextureEntry;
1431 }
1432
1433 TxtrCacheEntry * CTextureManager::GetPrimLODFracTexture(uint8 fac)
1434 {
1435     static uint8 mfac = 0;
1436     if( m_PrimLODFracTextureEntry.pTexture == NULL )
1437     {
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;
1442         uint32 color = fac;
1443         color |= factor << 8;
1444         color |= color << 16;
1445         updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color);
1446         gRDP.texturesAreReloaded = true;
1447     }
1448     else if( mfac != fac )
1449     {
1450         uint32 factor = fac;
1451         uint32 color = fac;
1452         color |= factor << 8;
1453         color |= color << 16;
1454         updateColorTexture(m_PrimLODFracTextureEntry.pTexture,color);
1455         gRDP.texturesAreReloaded = true;
1456     }
1457
1458     mfac = fac;
1459     return &m_PrimLODFracTextureEntry;
1460 }
1461
1462 TxtrCacheEntry * CTextureManager::GetConstantColorTexture(uint32 constant)
1463 {
1464     switch( constant )
1465     {
1466     case MUX_PRIM:
1467         return GetPrimColorTexture(gRDP.primitiveColor);
1468         break;
1469     case MUX_ENV:
1470         return GetEnvColorTexture(gRDP.envColor);
1471         break;
1472     case MUX_LODFRAC:
1473         return GetLODFracTexture((uint8)gRDP.LODFrac);
1474         break;
1475     default:    // MUX_PRIMLODFRAC
1476         return GetPrimLODFracTexture((uint8)gRDP.primLODFrac);
1477         break;
1478     }
1479 }
1480
1481 void CTextureManager::updateColorTexture(CTexture *ptexture, uint32 color)
1482 {
1483     DrawInfo di;
1484     if( !(ptexture->StartUpdate(&di)) )
1485     {
1486         TRACE0("Cann't update the texture");
1487         return;
1488     }
1489
1490     int size = ptexture->GetPixelSize();
1491     switch( size )
1492     {
1493     case 2: // 16 bits
1494         {
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++ )
1501             {
1502                 buf[i] = color16;
1503             }
1504         }
1505         break;
1506     case 4: // 32 bits
1507         {
1508             uint32 *buf = (uint32*)di.lpSurface;
1509             for( int i=0; i<16; i++ )
1510             {
1511                 buf[i] = color;
1512             }
1513         }
1514         break;
1515     }
1516
1517     ptexture->EndUpdate(&di);
1518 }
1519
1520 void ConvertTextureRGBAtoI(TxtrCacheEntry* pEntry, bool alpha)
1521 {
1522     DrawInfo srcInfo;   
1523     if( pEntry->pTexture->StartUpdate(&srcInfo) )
1524     {
1525         uint32 *buf;
1526         uint32 val;
1527         uint32 r,g,b,a,i;
1528
1529         for(int nY = 0; nY < srcInfo.dwCreatedHeight; nY++)
1530         {
1531             buf = (uint32*)((uint8*)srcInfo.lpSurface+nY*srcInfo.lPitch);
1532             for(int nX = 0; nX < srcInfo.dwCreatedWidth; nX++)
1533             {
1534                 val = buf[nX];
1535                 b = (val>>0)&0xFF;
1536                 g = (val>>8)&0xFF;
1537                 r = (val>>16)&0xFF;
1538                 i = (r+g+b)/3;
1539                 a = alpha?(val&0xFF000000):(i<<24);
1540                 buf[nX] = (a|(i<<16)|(i<<8)|i);
1541             }
1542         }
1543         pEntry->pTexture->EndUpdate(&srcInfo);
1544     }
1545 }
1546