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