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