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