~ubuntu-branches/ubuntu/saucy/mupen64plus-video-rice/saucy

« back to all changes in this revision

Viewing changes to src/TextureManager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sven Eckelmann
  • Date: 2011-01-22 11:05:28 UTC
  • Revision ID: james.westby@ubuntu.com-20110122110528-k6z84gdespqqd9zp
Tags: upstream-1.99.4
ImportĀ upstreamĀ versionĀ 1.99.4

Show diffs side-by-side

added added

removed removed

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