Rice GLES2 (from mupen64plus-ae) plugin. Compile but doesn't works well on the OpenPa...
[mupen64plus-pandora.git] / source / gles2rice / src / FrameBuffer.cpp
1 /*
2 Copyright (C) 2005 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 // ===========================================================================
21
22 #include <vector>
23
24 #include "ConvertImage.h"
25 #include "DeviceBuilder.h"
26 #include "FrameBuffer.h"
27 #include "UcodeDefs.h"
28 #include "RSP_Parser.h"
29 #include "Render.h"
30
31 extern TMEMLoadMapInfo g_tmemLoadAddrMap[0x200];    // Totally 4KB TMEM;
32
33 // 0 keeps the most recent CI info
34 // 1 keeps the frame buffer CI info which is being displayed now
35 // 2 keeps the older frame buffer CI info. This can be used if we are using triple buffer
36 /* Overview of framebuffer implementation
37 1) Check if backbuffer has changed, via different detection techniques
38 2) If changed, we copy the GFX card's backbuffer to main RAM
39 3) This is slow due to the reading process, not the writing
40 */
41
42 RecentCIInfo g_RecentCIInfo[5];
43 RecentCIInfo *g_uRecentCIInfoPtrs[5] =
44 {
45     &g_RecentCIInfo[0],
46     &g_RecentCIInfo[1],
47     &g_RecentCIInfo[2],
48     &g_RecentCIInfo[3],
49     &g_RecentCIInfo[4],
50 };
51
52 int numOfRecentCIInfos = 5;
53
54 RecentViOriginInfo g_RecentVIOriginInfo[5];
55 uint32 dwBackBufferSavedAtFrame=0;
56
57 RenderTextureInfo gRenderTextureInfos[20];
58 int numOfTxtBufInfos = sizeof(gRenderTextureInfos)/sizeof(RenderTextureInfo);
59 RenderTextureInfo *g_pRenderTextureInfo = NULL;
60
61 FrameBufferManager* g_pFrameBufferManager = NULL;
62
63 bool LastCIIsNewCI=false;
64
65 FrameBufferManager::FrameBufferManager() :
66     m_isRenderingToTexture(false),
67     m_curRenderTextureIndex(-1),
68         m_lastTextureBufferIndex(-1)
69 {
70 }
71
72 FrameBufferManager::~FrameBufferManager()
73 {
74 }
75
76 void FrameBufferManager::CloseUp()
77 {
78     for( int i=0; i<numOfTxtBufInfos; i++ )
79     {
80         SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture);
81     }
82 }
83
84 void FrameBufferManager::Initialize()
85 {
86     m_isRenderingToTexture = false;
87     m_lastTextureBufferIndex = -1;
88     m_curRenderTextureIndex = -1;
89     
90     status.bCIBufferIsRendered = false;
91     status.bN64IsDrawingTextureBuffer = false;
92     status.bHandleN64RenderTexture = false;
93     status.bN64FrameBufferIsUsed = false;
94
95     memset(&gRenderTextureInfos[0], 0, sizeof(RenderTextureInfo)*numOfTxtBufInfos);
96 }
97 // ===========================================================================
98
99 uint16 ConvertRGBATo555(uint8 r, uint8 g, uint8 b, uint8 a)
100 {
101     uint8 ar = a>=0x20?1:0;
102     return ((r>>3)<<RGBA5551_RedShift) | ((g>>3)<<RGBA5551_GreenShift) | ((b>>3)<<RGBA5551_BlueShift) | ar;//(a>>7);
103 }
104
105 uint16 ConvertRGBATo555(uint32 color32)
106 {
107     return (uint16)((((color32>>19)&0x1F)<<RGBA5551_RedShift) | (((color32>>11)&0x1F)<<RGBA5551_GreenShift) | (((color32>>3)&0x1F)<<RGBA5551_BlueShift) | ((color32>>31)));;
108 }
109
110 void FrameBufferManager::UpdateRecentCIAddr(SetImgInfo &ciinfo)
111 {
112     if( ciinfo.dwAddr == g_uRecentCIInfoPtrs[0]->dwAddr )
113         return;
114
115     RecentCIInfo *temp;
116
117     int i;
118     for( i=1; i<numOfRecentCIInfos; i++ )
119     {
120         if( ciinfo.dwAddr == g_uRecentCIInfoPtrs[i]->dwAddr )
121         {
122             temp = g_uRecentCIInfoPtrs[i];
123
124             for( int j=i; j>0; j-- )
125             {
126                 g_uRecentCIInfoPtrs[j] = g_uRecentCIInfoPtrs[j-1];
127             }
128             break;
129         }
130     }
131
132     if( i >= numOfRecentCIInfos )
133     {
134         temp = g_uRecentCIInfoPtrs[4];
135         g_uRecentCIInfoPtrs[4] = g_uRecentCIInfoPtrs[3];
136         g_uRecentCIInfoPtrs[3] = g_uRecentCIInfoPtrs[2];
137         g_uRecentCIInfoPtrs[2] = g_uRecentCIInfoPtrs[1];
138         g_uRecentCIInfoPtrs[1] = g_uRecentCIInfoPtrs[0];
139         temp->dwCopiedAtFrame = 0;
140         temp->bCopied = false;
141     }
142
143     g_uRecentCIInfoPtrs[0] = temp;
144
145     // Fix me here for Mario Tennis
146     temp->dwLastWidth = windowSetting.uViWidth;
147     temp->dwLastHeight = windowSetting.uViHeight;
148
149     temp->dwFormat = ciinfo.dwFormat;
150     temp->dwAddr = ciinfo.dwAddr;
151     temp->dwSize = ciinfo.dwSize;
152     temp->dwWidth = ciinfo.dwWidth;
153     temp->dwHeight = gRDP.scissor.bottom;
154     temp->dwMemSize = (temp->dwWidth*temp->dwHeight/2)<<temp->dwSize;
155     temp->bCopied = false;
156     temp->lastUsedFrame = status.gDlistCount;
157     temp->lastSetAtUcode = status.gUcodeCount;
158 }
159
160
161 /************************************************************************/
162 /* Mark the ciinfo entry that the ciinfo is used by VI origin register  */
163 /* in another word, this is a real frame buffer, not a fake frame buffer*/
164 /* Fake frame buffers are never really used by VI origin                */
165 /************************************************************************/
166 void FrameBufferManager::SetAddrBeDisplayed(uint32 addr)
167 {
168     uint32 viwidth = *g_GraphicsInfo.VI_WIDTH_REG;
169     addr &= (g_dwRamSize-1);
170     
171     int i;
172     for( i=0; i<numOfRecentCIInfos; i++ )
173     {
174         if( g_uRecentCIInfoPtrs[i]->dwAddr+2*viwidth == addr )
175         {
176             g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame = status.gDlistCount;
177         }
178         else if( addr >= g_uRecentCIInfoPtrs[i]->dwAddr && addr < g_uRecentCIInfoPtrs[i]->dwAddr+0x1000 )
179         {
180             g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame = status.gDlistCount;
181         }
182     }
183
184     for( i=0; i<numOfRecentCIInfos; i++ )
185     {
186         if( g_RecentVIOriginInfo[i].addr == addr )
187         {
188             g_RecentVIOriginInfo[i].FrameCount = status.gDlistCount;
189             return;
190         }
191     }
192
193     for( i=0; i<numOfRecentCIInfos; i++ )
194     {
195         if( g_RecentVIOriginInfo[i].addr == 0 )
196         {
197             // Never used
198             g_RecentVIOriginInfo[i].addr = addr;
199             g_RecentVIOriginInfo[i].FrameCount = status.gDlistCount;
200             return;
201         }
202     }
203
204     int index=0;
205     uint32 minFrameCount = 0xffffffff;
206
207     for( i=0; i<numOfRecentCIInfos; i++ )
208     {
209         if( g_RecentVIOriginInfo[i].FrameCount < minFrameCount )
210         {
211             index = i;
212             minFrameCount = g_RecentVIOriginInfo[i].FrameCount;
213         }
214     }
215
216     g_RecentVIOriginInfo[index].addr = addr;
217     g_RecentVIOriginInfo[index].FrameCount = status.gDlistCount;
218 }
219
220 bool FrameBufferManager::HasAddrBeenDisplayed(uint32 addr, uint32 width)
221 {
222     addr &= (g_dwRamSize-1);
223     
224     int i;
225     for( i=0; i<numOfRecentCIInfos; i++ )
226     {
227         if( g_uRecentCIInfoPtrs[i]->dwAddr == 0 )
228             continue;
229
230         if( g_uRecentCIInfoPtrs[i]->dwAddr == addr )
231         {
232             if( status.gDlistCount-g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame < 20 )
233                 //if( g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame != 0 )
234             {
235                 return true;
236             }
237             else
238             {
239                 TXTRBUF_DUMP(TRACE0("This is a new buffer address, the addr is never a displayed buffer"););
240                 return false;
241             }
242         }
243     }
244
245     for( i=0; i<numOfRecentCIInfos; i++ )
246     {
247         if( g_RecentVIOriginInfo[i].addr != 0 )
248         {
249             if( g_RecentVIOriginInfo[i].addr > addr && 
250                 (g_RecentVIOriginInfo[i].addr - addr)%width == 0 &&
251                 (g_RecentVIOriginInfo[i].addr - addr)/width <= 4)
252             {
253                 if( status.gDlistCount-g_RecentVIOriginInfo[i].FrameCount < 20 )
254                     //if( g_RecentVIOriginInfo[i].FrameCount != 0 )
255                 {
256                     return true;
257                 }
258                 else
259                 {
260                     TXTRBUF_DUMP(DebuggerAppendMsg("This is a new buffer address, the addr is never a displayed buffer"););
261                     return false;
262                 }
263             }
264         }
265     }
266
267     if( status.gDlistCount > 20 )
268         return false;
269     else
270     {
271         TXTRBUF_DUMP({DebuggerAppendMsg("This is a new buffer address, the addr is never a displayed buffer");});
272         return true;
273     }
274 }
275
276 int FrameBufferManager::FindRecentCIInfoIndex(uint32 addr)
277 {
278     for( int i=0; i<numOfRecentCIInfos; i++ )
279     {
280         if( g_uRecentCIInfoPtrs[i]->dwAddr <= addr && addr < g_uRecentCIInfoPtrs[i]->dwAddr+g_uRecentCIInfoPtrs[i]->dwMemSize )
281         {
282             return i;
283         }
284     }
285     return -1;
286 }
287
288 bool FrameBufferManager::IsDIaRenderTexture()
289 {
290     // Knowing g_CI and g_ZI
291
292     //if( g_CI.dwWidth )
293
294     bool foundSetScissor=false;
295     bool foundFillRect=false;
296     bool foundSetFillColor=false;
297     bool foundSetCImg=false;
298     uint32 newFillColor = 0;
299
300     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;       // This points to the next instruction
301
302     for( int i=0; i<10; i++ )
303     {
304         uint32 w0 = *(uint32 *)(g_pRDRAMu8 + dwPC + i*8);
305         uint32 w1 = *(uint32 *)(g_pRDRAMu8 + dwPC + 4 + i*8);
306
307         if( (w0>>24) == RDP_SETSCISSOR )
308         {
309             foundSetScissor = true;
310             continue;
311         }
312
313         if( (w0>>24) == RDP_SETFILLCOLOR )
314         {
315             foundSetFillColor = true;
316             newFillColor = w1;
317             continue;
318         }
319
320         if( (w0>>24) == RDP_FILLRECT )
321         {
322             uint32 x0   = ((w1>>12)&0xFFF)/4;
323             uint32 y0   = ((w1>>0 )&0xFFF)/4;
324             uint32 x1   = ((w0>>12)&0xFFF)/4;
325
326             if( x0 == 0 && y0 == 0 )
327             {
328                 if( x1 == g_CI.dwWidth )
329                 {
330                     foundFillRect = true;
331                     continue;
332                 }
333
334                 if(x1 == (unsigned int)(g_CI.dwWidth-1))
335                 {
336                     foundFillRect = true;
337                     continue;
338                 }
339             }
340         }   
341
342         if( (w0>>24) == RDP_TEXRECT )
343         {
344             break;
345         }
346
347         if( (w0>>24) == RDP_SETCIMG )
348         {
349             foundSetCImg = true;
350             break;
351         }
352     }
353
354     /*
355     bool foundSetScissor=false;
356     bool foundFillRect=false;
357     bool foundSetFillColor=false;
358     bool foundSetCImg=false;
359     bool foundTxtRect=false;
360     int ucodeLength=10;
361     uint32 newFillColor;
362     */
363
364     if( foundFillRect )
365     {
366         if( foundSetFillColor )
367         {
368             if( newFillColor != 0xFFFCFFFC )
369                 return true;    // this is a render_texture
370             else
371                 return false;
372         }
373
374         if( gRDP.fillColor != 0x00FFFFF7 )
375             return true;    // this is a render_texture
376         else
377             return false;   // this is a normal ZImg
378     }
379     else if( foundSetFillColor && newFillColor == 0xFFFCFFFC && foundSetCImg )
380     {
381         return false;
382     }
383     else
384     {
385         return true;
386     }
387
388
389     if( !foundSetCImg )
390         return true;
391
392     if( foundSetScissor )
393         return true;
394 }
395
396 int FrameBufferManager::CheckAddrInBackBuffers(uint32 addr, uint32 memsize, bool copyToRDRAM)
397 {
398     int r = FindRecentCIInfoIndex(addr);
399
400     if( r >= 0 )
401     {
402         // Also check if the address is overwritten by a recent render_texture
403         //int t = CheckAddrInRenderTextures(addr,false);
404         int t =-1;
405         for( int i=0; i<numOfTxtBufInfos; i++ )
406         {
407             uint32 bufHeight = gRenderTextureInfos[i].knownHeight ? gRenderTextureInfos[i].N64Height : gRenderTextureInfos[i].maxUsedHeight;
408             uint32 bufMemSize = gRenderTextureInfos[i].CI_Info.dwSize*gRenderTextureInfos[i].N64Width*bufHeight;
409             if( addr >=gRenderTextureInfos[i].CI_Info.dwAddr && addr < gRenderTextureInfos[i].CI_Info.dwAddr+bufMemSize)
410             {
411                 if( g_uRecentCIInfoPtrs[r]->lastSetAtUcode < gRenderTextureInfos[i].updateAtUcodeCount )
412                 {
413                     t = i;
414                     break;
415                 }
416             }
417         }
418
419         if( t >= 0 )
420             return -1;
421     }
422
423     if( r >= 0 && status.gDlistCount - g_uRecentCIInfoPtrs[r]->lastUsedFrame <= 3  && g_uRecentCIInfoPtrs[r]->bCopied == false )
424     {
425         DEBUGGER_IF_DUMP((logTextureBuffer&&r==1),TRACE2("Hit current front buffer at %08X, size=0x%X", addr, memsize));
426         DEBUGGER_IF_DUMP((logTextureBuffer&&r==0),TRACE2("Hit current back buffer at %08X, size=0x%X", addr, memsize));
427         DEBUGGER_IF_DUMP((logTextureBuffer&&r>1),TRACE2("Hit old back buffer at %08X, size=0x%X", addr, memsize));
428
429         SaveBackBuffer(r, NULL, true);
430     }
431
432     return r;
433 }
434
435
436 uint8 CIFindIndex(uint16 val)
437 {
438     for( int i=0; i<=0xFF; i++ )
439     {
440         if( val == g_wRDPTlut[i] )
441         {
442             return (uint8)i;
443         }
444     }
445     return 0;
446 }
447
448
449 void TexRectToFrameBuffer_8b(uint32 dwXL, uint32 dwYL, uint32 dwXH, uint32 dwYH, float t0u0, float t0v0, float t0u1, float t0v1, uint32 dwTile)
450 {
451     // Copy the framebuffer texture into the N64 framebuffer memory
452     // Used in Yoshi
453
454     /*
455     uint32 maxW = g_pRenderTextureInfo->CI_Info.dwWidth;
456     uint32 maxH = maxW*3/4;
457     if( status.dwTvSystem == TV_SYSTEM_PAL )
458     {
459     maxH = maxW*9/11;
460     }
461     */
462
463     uint32 maxW = g_pRenderTextureInfo->N64Width;
464     uint32 maxH = g_pRenderTextureInfo->N64Height;
465
466     uint32 maxOff = maxW*maxH;
467
468     TMEMLoadMapInfo &info = g_tmemLoadAddrMap[gRDP.tiles[dwTile].dwTMem];
469     uint32 dwWidth = dwXH-dwXL;
470     uint32 dwHeight = dwYH-dwYL;
471
472     float xScale = (t0u1-t0u0)/dwWidth;
473     float yScale = (t0v1-t0v0)/dwHeight;
474
475     uint8* dwSrc = g_pRDRAMu8 + info.dwLoadAddress;
476     uint8* dwDst = g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr;
477
478     uint32 dwSrcPitch = gRDP.tiles[dwTile].dwPitch;
479     uint32 dwDstPitch = g_pRenderTextureInfo->CI_Info.dwWidth;
480
481     uint32 dwSrcOffX = gRDP.tiles[dwTile].hilite_sl;
482     uint32 dwSrcOffY = gRDP.tiles[dwTile].hilite_tl;
483
484     uint32 dwLeft = dwXL;
485     uint32 dwTop = dwYL;
486
487     dwWidth = min(dwWidth, maxW-dwLeft);
488     dwHeight = min(dwHeight, maxH-dwTop);
489     
490     if( maxH <= dwTop )
491         return;
492
493     for (uint32 y = 0; y < dwHeight; y++)
494     {
495         uint32 dwByteOffset = (uint32)(((y*yScale+dwSrcOffY) * dwSrcPitch) + dwSrcOffX);
496
497         for (uint32 x = 0; x < dwWidth; x++)
498         {
499             if( (((y+dwTop)*dwDstPitch+x+dwLeft)^0x3) > maxOff )
500             {
501 #ifdef DEBUGGER
502                 TRACE0("Warning: Offset exceeds limit");
503 #endif
504                 continue;
505             }
506             dwDst[((y+dwTop)*dwDstPitch+x+dwLeft)^0x3] = dwSrc[(uint32)(dwByteOffset+x*xScale) ^ 0x3];
507         }
508     }
509
510     TXTRBUF_DUMP(DebuggerAppendMsg("TexRect To FrameBuffer: X0=%d, Y0=%d, X1=%d, Y1=%d,\n\t\tfS0=%f, fT0=%f, fS1=%f, fT1=%f ",
511         dwXL, dwYL, dwXH, dwYH, t0v0, t0v0, t0u1, t0v1););
512 }
513
514 void TexRectToN64FrameBuffer_16b(uint32 x0, uint32 y0, uint32 width, uint32 height, uint32 dwTile)
515 {
516     // Copy the framebuffer texture into the N64 RDRAM framebuffer memory structure
517
518     DrawInfo srcInfo;   
519     if( g_textures[dwTile].m_pCTexture->StartUpdate(&srcInfo) == false )
520     {
521         DebuggerAppendMsg("Fail to lock texture:TexRectToN64FrameBuffer_16b" );
522         return;
523     }
524
525     uint32 n64CIaddr = g_CI.dwAddr;
526     uint32 n64CIwidth = g_CI.dwWidth;
527
528     for (uint32 y = 0; y < height; y++)
529     {
530         uint32* pSrc = (uint32*)((uint8*)srcInfo.lpSurface + y * srcInfo.lPitch);
531         uint16* pN64Buffer = (uint16*)(g_pRDRAMu8+(n64CIaddr&(g_dwRamSize-1)))+(y+y0)*n64CIwidth;
532
533         for (uint32 x = 0; x < width; x++)
534         {
535             pN64Buffer[x+x0] = ConvertRGBATo555(pSrc[x]);
536         }
537     }
538
539     g_textures[dwTile].m_pCTexture->EndUpdate(&srcInfo);
540 }
541
542 #define FAST_CRC_CHECKING_INC_X 13
543 #define FAST_CRC_CHECKING_INC_Y 11
544 #define FAST_CRC_MIN_Y_INC      2
545 #define FAST_CRC_MIN_X_INC      2
546 #define FAST_CRC_MAX_X_INC      7
547 #define FAST_CRC_MAX_Y_INC      3
548 extern uint32 dwAsmHeight;
549 extern uint32 dwAsmPitch;
550 extern uint32 dwAsmdwBytesPerLine;
551 extern uint32 dwAsmCRC;
552 extern uint8* pAsmStart;
553
554 uint32 CalculateRDRAMCRC(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes )
555 {
556     dwAsmCRC = 0;
557     dwAsmdwBytesPerLine = ((width<<size)+1)/2;
558
559     if( currentRomOptions.bFastTexCRC && !options.bLoadHiResTextures && (height>=32 || (dwAsmdwBytesPerLine>>2)>=16))
560     {
561         uint32 realWidthInDWORD = dwAsmdwBytesPerLine>>2;
562         uint32 xinc = realWidthInDWORD / FAST_CRC_CHECKING_INC_X;   
563         if( xinc < FAST_CRC_MIN_X_INC )
564         {
565             xinc = min(FAST_CRC_MIN_X_INC, width);
566         }
567         if( xinc > FAST_CRC_MAX_X_INC )
568         {
569             xinc = FAST_CRC_MAX_X_INC;
570         }
571
572         uint32 yinc = height / FAST_CRC_CHECKING_INC_Y; 
573         if( yinc < FAST_CRC_MIN_Y_INC ) 
574         {
575             yinc = min(FAST_CRC_MIN_Y_INC, height);
576         }
577         if( yinc > FAST_CRC_MAX_Y_INC )
578         {
579             yinc = FAST_CRC_MAX_Y_INC;
580         }
581
582         uint32 pitch = pitchInBytes>>2;
583         register uint32 *pStart = (uint32*)(pPhysicalAddress);
584         pStart += (top * pitch) + (((left<<size)+1)>>3);
585
586         // The original assembly code had a bug in it (it incremented pStart by 'pitch' in bytes, not in dwords)
587         // This C code implements the same algorithm as the ASM but without the bug
588         uint32 y = 0;
589         while (y < height)
590         {
591             uint32 x = 0;
592             while (x < realWidthInDWORD)
593             {
594                 dwAsmCRC = (dwAsmCRC << 4) + ((dwAsmCRC >> 28) & 15);
595                 dwAsmCRC += pStart[x];
596                 x += xinc;
597                 dwAsmCRC += x;
598             }
599             dwAsmCRC ^= y;
600             y += yinc;
601             pStart += pitch;
602         }
603     }
604     else
605     {
606         try
607         {
608             dwAsmdwBytesPerLine = ((width<<size)+1)/2;
609
610             pAsmStart = (uint8*)(pPhysicalAddress);
611             pAsmStart += (top * pitchInBytes) + (((left<<size)+1)>>1);
612
613             dwAsmHeight = height - 1;
614             dwAsmPitch = pitchInBytes;
615
616 #if defined(NO_ASM)
617             uint32 pitch = pitchInBytes>>2;
618             uint32* pStart = (uint32*)pPhysicalAddress;
619             pStart += (top * pitch) + (((left<<size)+1)>>3);
620
621             int y = dwAsmHeight;
622
623             while(y >= 0)
624             {
625                 uint32 esi = 0;
626                 int x = dwAsmdwBytesPerLine - 4;
627                 while(x >= 0)
628                 {
629                     esi = *(uint32*)(pAsmStart + x);
630                     esi ^= x;
631
632                     dwAsmCRC = (dwAsmCRC << 4) + ((dwAsmCRC >> 28) & 15);
633                     dwAsmCRC += esi;
634                     x-=4;
635                 }
636                 esi ^= y;
637                 dwAsmCRC += esi;
638                 pAsmStart += dwAsmPitch;
639                 y--;
640             }
641
642 #elif !defined(__GNUC__) // !defined(NO_ASM)
643             __asm 
644             {
645                 push eax
646                 push ebx
647                 push ecx
648                 push edx
649                 push esi
650
651                 mov ecx, pAsmStart;             // = pStart
652                 mov edx, 0                      // The CRC
653                 mov eax, dwAsmHeight            // = y
654 l2:             mov ebx, dwAsmdwBytesPerLine    // = x
655                 sub ebx, 4
656 l1:             mov esi, [ecx+ebx]
657                 xor esi, ebx
658                 rol edx, 4
659                 add edx, esi
660                 sub ebx, 4
661                 jge l1
662                 xor esi, eax
663                 add edx, esi
664                 add ecx, dwAsmPitch
665                 dec eax
666                 jge l2
667
668                 mov dwAsmCRC, edx
669
670                 pop esi
671                 pop edx
672                 pop ecx
673                 pop ebx
674                 pop eax
675             }
676 #elif defined(__x86_64__) // defined(__GNUC__) && !defined(NO_ASM)
677         asm volatile(" xorl          %k2,      %k2           \n"
678                      " movslq        %k4,      %q4           \n"
679                      "0:                                     \n"
680                      " movslq         %3,    %%rbx           \n"
681                      " sub            $4,    %%rbx           \n"
682                      "1:                                     \n"
683                      " movl (%0,%%rbx,1),    %%eax           \n"
684                      " xorl        %%ebx,    %%eax           \n"
685                      " roll           $4,      %k2           \n"
686                      " addl        %%eax,      %k2           \n"
687                      " sub            $4,    %%rbx           \n"
688                      " jge            1b                     \n"
689                      " xorl          %k1,    %%eax           \n"
690                      " addl        %%eax,      %k2           \n"
691                      " add           %q4,       %0           \n"
692                      " decl          %k1                     \n"
693                      " jge            0b                     \n"
694                      : "+r"(pAsmStart), "+r"(dwAsmHeight), "=&r"(dwAsmCRC)
695                      : "m"(dwAsmdwBytesPerLine), "r"(dwAsmPitch)
696                      : "%rbx", "%rax", "memory", "cc"
697                      );
698 #elif !defined(__PIC__) // !defined(__x86_64__) && defined(__GNUC__) && !defined(NO_ASM)
699            asm volatile("pusha                        \n"
700                 "mov    %[pAsmStart], %%ecx           \n" // = pStart
701                 "mov    $0, %%edx                     \n" // The CRC
702                 "mov    %[dwAsmHeight], %%eax         \n" // = y
703                 "0:                                   \n" //l2:
704                 "mov    %[dwAsmdwBytesPerLine], %%ebx \n" // = x
705                 "sub    $4, %%ebx                     \n"
706                 "1:                                   \n" //l1:
707                 "mov    (%%ecx,%%ebx), %%esi          \n"
708                 "xor %%ebx, %%esi                     \n"
709                 "rol $4, %%edx                        \n"
710                 "add %%esi, %%edx                     \n"
711                 "sub    $4, %%ebx                     \n"
712                 "jge 1b                               \n" //jge l1
713                 "xor %%eax, %%esi                     \n"
714                 "add %%esi, %%edx                     \n"
715                 "add %[dwAsmPitch], %%ecx             \n"
716                 "dec %%eax                            \n"
717                 "jge 0b                               \n" //jge l2
718                 
719                 "mov    %%edx, %[dwAsmCRC]            \n"
720                 "popa                                 \n"
721                 : [pAsmStart]"+m"(pAsmStart), [dwAsmHeight]"+m"(dwAsmHeight), [dwAsmCRC]"=m"(dwAsmCRC)
722                 : [dwAsmdwBytesPerLine]"m"(dwAsmdwBytesPerLine), [dwAsmPitch]"m"(dwAsmPitch)
723                 : "memory", "cc"
724                 );
725 #else // defined(__PIC__) && !defined(__x86_64__) && defined(__GNUC__) && !defined(NO_ASM)
726            unsigned int saveEBX;
727            unsigned int saveEAX;
728            unsigned int saveECX;
729            unsigned int saveEDX;
730            unsigned int saveESI;
731            unsigned int asmdwBytesPerLine = dwAsmdwBytesPerLine;
732            unsigned int asmPitch = dwAsmPitch;
733            unsigned int asmHeight = dwAsmHeight;
734            unsigned int asmCRC;
735            asm volatile("mov    %%ebx, %2                  \n"
736                 "mov    %%eax, %5                  \n"
737                 "mov    %%ecx, %7                  \n"
738                 "mov    %%edx, %8                  \n"
739                 "mov    %%esi, %9                  \n"
740                 "mov    %0, %%ecx                  \n" // = pStart
741                 "mov    $0, %%edx                  \n" // The CRC
742                 "mov    %1, %%eax                  \n" // = y
743                 "0:                                \n" //l2:
744                 "mov    %3, %%ebx                  \n" // = x
745                 "sub    $4, %%ebx                  \n"
746                 "1:                                \n" //l1:
747                 "mov    (%%ecx,%%ebx), %%esi       \n"
748                 "xor %%ebx, %%esi                  \n"
749                 "rol $4, %%edx                     \n"
750                 "add %%esi, %%edx                  \n"
751                 "sub    $4, %%ebx                  \n"
752                 "jge 1b                            \n" //jge l1
753                 "xor %%eax, %%esi                  \n"
754                 "add %%esi, %%edx                  \n"
755                 "add %4, %%ecx                     \n"
756                 "dec %%eax                         \n"
757                 "jge 0b                            \n" //jge l2
758                 
759                 "mov    %2, %%ebx                  \n"
760                 "mov    %%edx, %6                  \n"
761                 "mov    %5, %%eax                  \n"
762                 "mov    %7, %%ecx                  \n"
763                 "mov    %8, %%edx                  \n"
764                 "mov    %9, %%esi                  \n"
765                 :
766                 : "m"(pAsmStart), "m"(asmHeight), "m"(saveEBX), "m"(asmdwBytesPerLine), "m"(asmPitch), "m"(saveEAX), 
767                 "m"(asmCRC), "m"(saveECX), "m"(saveEDX), "m"(saveESI)
768                 : "memory", "cc"
769                 );
770            dwAsmCRC = asmCRC;
771 #endif
772         }
773         catch(...)
774         {
775             TRACE0("Exception in texture CRC calculation");
776         }
777     }
778     return dwAsmCRC;
779 }
780 unsigned char CalculateMaxCI(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes )
781 {
782     uint32 x, y;
783     unsigned char *buf;
784     unsigned char val = 0;
785
786     if( TXT_SIZE_8b == size )
787     {
788         for( y = 0; y<height; y++ )
789         {
790             buf = (unsigned char*)pPhysicalAddress + left + pitchInBytes * (y+top);
791             for( x=0; x<width; x++ )
792             {
793                 if( buf[x] > val )  val = buf[x];
794                 if( val == 0xFF )
795                     return 0xFF;
796             }
797         }
798     }
799     else
800     {
801         unsigned char val1,val2;
802         left >>= 1;
803         width >>= 1;
804         for( y = 0; y<height; y++ )
805         {
806             buf = (unsigned char*)pPhysicalAddress + left + pitchInBytes * (y+top);
807             for( x=0; x<width; x++ )
808             {
809                 val1 = buf[x]>>4;
810                 val2 = buf[x]&0xF;
811                 if( val1 > val )    val = val1;
812                 if( val2 > val )    val = val2;
813                 if( val == 0xF )
814                     return 0xF;
815             }
816         }
817     }
818
819     return val;
820 }
821
822 bool FrameBufferManager::FrameBufferInRDRAMCheckCRC()
823 {
824     RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]);
825     uint8 *pFrameBufferBase = (uint8*)(g_pRDRAMu8+p.dwAddr);
826     uint32 pitch = (p.dwWidth << p.dwSize ) >> 1;
827     uint32 crc = CalculateRDRAMCRC(pFrameBufferBase, 0, 0, p.dwWidth, p.dwHeight, p.dwSize, pitch);
828     if( crc != p.dwCRC )
829     {
830         p.dwCRC = crc;
831         TRACE0("Frame Buffer CRC mismitch, it is modified by CPU");
832         return false;
833     }
834     else
835     {
836         return true;
837     }
838 }
839
840 extern std::vector<uint32> frameWriteRecord;
841 void FrameBufferManager::FrameBufferWriteByCPU(uint32 addr, uint32 size)
842 {
843     if( !frameBufferOptions.bProcessCPUWrite )  return;
844     //WARNING(TRACE2("Frame Buffer Write, addr=%08X, CI Addr=%08X", addr, g_CI.dwAddr));
845     status.frameWriteByCPU = TRUE;
846     frameWriteRecord.push_back(addr&(g_dwRamSize-1));
847 }
848
849 extern RECT frameWriteByCPURect;
850 extern std::vector<RECT> frameWriteByCPURects;
851 extern RECT frameWriteByCPURectArray[20][20];
852 extern bool frameWriteByCPURectFlag[20][20];
853 #define FRAMEBUFFER_IN_BLOCK
854 bool FrameBufferManager::ProcessFrameWriteRecord()
855 {
856     int size = frameWriteRecord.size();
857     if( size == 0 ) return false;
858
859     int index = FindRecentCIInfoIndex(frameWriteRecord[0]);
860     if( index == -1 )
861     {
862         LOG_TEXTURE(TRACE1("Frame Buffer Write to non-record addr = %08X", frameWriteRecord[0]));
863         frameWriteRecord.clear();
864         return false;
865     }
866     else
867     {
868         uint32 base = g_uRecentCIInfoPtrs[index]->dwAddr;
869         uint32 uwidth = g_uRecentCIInfoPtrs[index]->dwWidth;
870         uint32 uheight = g_uRecentCIInfoPtrs[index]->dwHeight;
871         uint32 upitch = uwidth<<1;
872
873         frameWriteByCPURect.left=uwidth-1;
874         frameWriteByCPURect.top = uheight-1;
875
876         frameWriteByCPURect.right=0;
877         frameWriteByCPURect.bottom = 0;
878
879         int x, y, off;
880
881         for( int i=0; i<size; i++ )
882         {
883             off = frameWriteRecord[i]-base;
884             if( off < (int)g_uRecentCIInfoPtrs[index]->dwMemSize )
885             {
886                 y = off/upitch;
887                 x = (off - y*upitch)>>1;
888
889 #ifdef FRAMEBUFFER_IN_BLOCK
890                 int xidx=x/32;
891                 int yidx=y/24;
892
893                 RECT &rect = frameWriteByCPURectArray[xidx][yidx];
894
895                 if( !frameWriteByCPURectFlag[xidx][yidx] )
896                 {
897                     rect.left=rect.right=x;
898                     rect.top=rect.bottom=y;
899                     frameWriteByCPURectFlag[xidx][yidx]=true;
900                 }
901                 else
902                 {
903                     if( x < rect.left ) rect.left = x;
904                     if( x > rect.right ) rect.right = x;
905                     if( y < rect.top )  rect.top = y;
906                     if( y > rect.bottom ) rect.bottom = y;
907                 }
908 #else
909                 if( x < frameWriteByCPURect.left )  frameWriteByCPURect.left = x;
910                 if( x > frameWriteByCPURect.right ) frameWriteByCPURect.right = x;
911                 if( y < frameWriteByCPURect.top )   frameWriteByCPURect.top = y;
912                 if( y > frameWriteByCPURect.bottom ) frameWriteByCPURect.bottom = y;
913 #endif
914             }
915         }
916
917         frameWriteRecord.clear();
918         LOG_TEXTURE(TRACE4("Frame Buffer Write: Left=%d, Top=%d, Right=%d, Bottom=%d", frameWriteByCPURect.left,
919             frameWriteByCPURect.top, frameWriteByCPURect.right, frameWriteByCPURect.bottom));
920         return true;
921     }
922 }
923
924 void FrameBufferManager::FrameBufferReadByCPU( uint32 addr )
925 {
926     ///return;  // it does not work very well anyway
927
928
929     if( !frameBufferOptions.bProcessCPURead )   return;
930
931     addr &= (g_dwRamSize-1);
932     int index = FindRecentCIInfoIndex(addr);
933     if( index == -1 ) 
934     {
935         // Check if this is the depth buffer
936         uint32 size = 2*g_RecentCIInfo[0].dwWidth*g_RecentCIInfo[0].dwHeight;
937         addr &= 0x3FFFFFFF;
938
939         if( addr >= g_ZI.dwAddr && addr < g_ZI.dwAddr + size )
940         {
941             TXTRBUF_OR_CI_DUMP(TRACE1("Depth Buffer read, reported by emulator, addr=%08X", addr));
942         }
943         else
944         {
945             return;
946         }
947     }
948
949     if( status.gDlistCount - g_uRecentCIInfoPtrs[index]->lastUsedFrame > 3 )
950     {
951         // Ok, we don't have this frame anymore
952         return;
953     }
954
955     //TXTRBUF_OR_CI_DUMP(TRACE1("FB Read By CPU at %08X", addr));
956     if( g_uRecentCIInfoPtrs[index]->bCopied )   return;
957     //if( addr != g_uRecentCIInfoPtrs[index]->dwAddr )  return;
958
959     TXTRBUF_OR_CI_DUMP(TRACE1("Frame Buffer read, reported by emulator, addr=%08X", addr));
960     uint32 size = 0x1000 - addr%0x1000;
961     CheckAddrInBackBuffers(addr, size, true);
962
963     DEBUGGER_IF_DUMP(pauseAtNext,{TRACE0("Frame Buffer read");});
964     DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, 
965     {DebuggerAppendMsg("Paused after setting Frame Buffer read:\n Cur CI Addr: 0x%08x, Fmt: %s Size: %s Width: %d",
966     g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth);});
967 }
968
969
970
971 extern RECT frameWriteByCPURect;
972 extern std::vector<RECT> frameWriteByCPURects;
973 extern RECT frameWriteByCPURectArray[20][20];
974 extern bool frameWriteByCPURectFlag[20][20];
975 #define FRAMEBUFFER_IN_BLOCK
976
977 void FrameBufferManager::UpdateFrameBufferBeforeUpdateFrame()
978 {
979     if( (frameBufferOptions.bProcessCPUWrite && status.frameWriteByCPU ) ||
980         (frameBufferOptions.bLoadBackBufFromRDRAM && !FrameBufferInRDRAMCheckCRC() ) )      
981         // Checks if frame buffer has been modified by CPU
982         // Only happens to Dr. Mario
983     {
984         if( frameBufferOptions.bProcessCPUWrite )
985         {
986             if( ProcessFrameWriteRecord() )
987             {
988 #ifdef FRAMEBUFFER_IN_BLOCK
989                 int i,j;
990                 for( i=0; i<20; i++)
991                 {
992                     for( j=0; j<20; j++ )
993                     {
994                         if( frameWriteByCPURectFlag[i][j] )
995                         {
996                             CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURectArray[i][j].left, frameWriteByCPURectArray[i][j].top,
997                                 frameWriteByCPURectArray[i][j].right-frameWriteByCPURectArray[i][j].left+1, frameWriteByCPURectArray[i][j].bottom-frameWriteByCPURectArray[i][j].top+1);
998                         }
999                     }
1000                 }
1001                 for( i=0; i<20; i++)
1002                 {
1003                     for( j=0; j<20; j++ )
1004                     {
1005                         if( frameWriteByCPURectFlag[i][j] )
1006                         {
1007                             ClearN64FrameBufferToBlack(frameWriteByCPURectArray[i][j].left, frameWriteByCPURectArray[i][j].top,
1008                                 frameWriteByCPURectArray[i][j].right-frameWriteByCPURectArray[i][j].left+1, frameWriteByCPURectArray[i][j].bottom-frameWriteByCPURectArray[i][j].top+1);
1009                             frameWriteByCPURectFlag[i][j] = false;
1010                         }
1011                     }
1012                 }
1013                 //memset(frameWriteByCPURectArray, 0, sizeof(frameWriteByCPURectArray));
1014                 //memset(frameWriteByCPURectFlag, 0, sizeof(frameWriteByCPURectFlag));
1015 #else
1016                 CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURect.left, frameWriteByCPURect.top,
1017                     frameWriteByCPURect.right-frameWriteByCPURect.left, frameWriteByCPURect.bottom-frameWriteByCPURect.top);
1018                 ClearN64FrameBufferToBlack(frameWriteByCPURect.left, frameWriteByCPURect.top,
1019                     frameWriteByCPURect.right-frameWriteByCPURect.left+1, frameWriteByCPURect.bottom-frameWriteByCPURect.top+1);
1020
1021                 /*
1022                 int size = frameWriteByCPURects.size();
1023                 for( int i=0; i<size; i++)
1024                 {
1025                 CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURects[i].left, frameWriteByCPURects[i].top,
1026                 frameWriteByCPURects[i].right-frameWriteByCPURects[i].left, frameWriteByCPURects[i].bottom-frameWriteByCPURects[i].top);
1027                 ClearN64FrameBufferToBlack(frameWriteByCPURects[i].left, frameWriteByCPURects[i].top,
1028                 frameWriteByCPURects[i].right-frameWriteByCPURects[i].left+1, frameWriteByCPURects[i].bottom-frameWriteByCPURects[i].top+1);
1029                 }
1030                 frameWriteByCPURects.clear();
1031                 */
1032 #endif
1033             }
1034             status.frameWriteByCPU = FALSE;
1035         }
1036         else
1037         {
1038             if (CRender::IsAvailable())
1039             {
1040                 RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]);
1041                 CRender::GetRender()->DrawFrameBuffer(false, 0,0,p.dwWidth,p.dwHeight);
1042                 ClearN64FrameBufferToBlack();
1043             }
1044         }
1045     }
1046 }
1047
1048 uint32 FrameBufferManager::ComputeCImgHeight(SetImgInfo &info, uint32 &height)
1049 {
1050     uint32 dwPC = gDlistStack[gDlistStackPointer].pc;       // This points to the next instruction
1051
1052     for( int i=0; i<10; i++ )
1053     {
1054         uint32 w0 = *(uint32 *)(g_pRDRAMu8 + dwPC + i*8);
1055         uint32 w1 = *(uint32 *)(g_pRDRAMu8 + dwPC + 4 + i*8);
1056
1057         if( (w0>>24) == RDP_SETSCISSOR )
1058         {
1059             height   = ((w1>>0 )&0xFFF)/4;
1060             TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height));
1061             return RDP_SETSCISSOR;
1062         }
1063
1064         if( (w0>>24) == RDP_FILLRECT )
1065         {
1066             uint32 x0   = ((w1>>12)&0xFFF)/4;
1067             uint32 y0   = ((w1>>0 )&0xFFF)/4;
1068             uint32 x1   = ((w0>>12)&0xFFF)/4;
1069             uint32 y1   = ((w0>>0 )&0xFFF)/4;
1070
1071             if( x0 == 0 && y0 == 0 )
1072             {
1073                 if( x1 == info.dwWidth )
1074                 {
1075                     height = y1;
1076                     TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height));
1077                     return RDP_FILLRECT;
1078                 }
1079
1080                 if(x1 == (unsigned int)(info.dwWidth-1))
1081                 {
1082                     height = y1+1;
1083                     TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height));
1084                     return RDP_FILLRECT;
1085                 }
1086             }
1087         }   
1088
1089         if( (w0>>24) == RDP_SETCIMG )
1090         {
1091             goto step2;
1092         }
1093
1094         if( (w0>>24) == RDP_SETCIMG )
1095         {
1096             goto step2;
1097         }
1098     }
1099
1100     if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && (unsigned int)gRDP.scissor.right == info.dwWidth )
1101     {
1102         height = gRDP.scissor.bottom;
1103         TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height));
1104         return RDP_SETSCISSOR+1;
1105     }
1106
1107 step2:
1108     TXTRBUF_DETAIL_DUMP(TRACE0("Not sure about buffer height"));
1109
1110     height = info.dwWidth*3/4;
1111     if( status.dwTvSystem == TV_SYSTEM_PAL )
1112     {
1113         height = info.dwWidth*9/11;
1114     }
1115
1116     if( gRDP.scissor.bottom < (int)height && gRDP.scissor.bottom != 0 )
1117     {
1118         height = gRDP.scissor.bottom;
1119     }
1120
1121     if( info.dwAddr + height*info.dwWidth*info.dwSize >= g_dwRamSize )
1122     {
1123         height = info.dwWidth*3/4;
1124         if( status.dwTvSystem == TV_SYSTEM_PAL )
1125         {
1126             height = info.dwWidth*9/11;
1127         }
1128
1129         if( gRDP.scissor.bottom < (int)height && gRDP.scissor.bottom != 0 )
1130         {
1131             height = gRDP.scissor.bottom;
1132         }
1133
1134         if( info.dwAddr + height*info.dwWidth*info.dwSize >= g_dwRamSize )
1135         {
1136             height = ( g_dwRamSize - info.dwAddr ) / info.dwWidth;
1137         }
1138     }
1139
1140     TXTRBUF_DETAIL_DUMP(TRACE1("render_texture height = %d", height));
1141     return 0;
1142 }
1143
1144 int FrameBufferManager::CheckRenderTexturesWithNewCI(SetImgInfo &CIinfo, uint32 height, bool byNewTxtrBuf)
1145 {
1146     int matchidx = -1;
1147     uint32 memsize = ((height*CIinfo.dwWidth)>>1)<<CIinfo.dwSize;
1148
1149     for( int i=0; i<numOfTxtBufInfos; i++ )
1150     {
1151         RenderTextureInfo &info = gRenderTextureInfos[i];
1152         if( !info.isUsed )  continue;
1153
1154         bool covered = false;
1155
1156         if( info.CI_Info.dwAddr == CIinfo.dwAddr )
1157         {
1158             if( info.CI_Info.dwSize == CIinfo.dwSize &&
1159                 info.CI_Info.dwWidth == CIinfo.dwWidth &&
1160                 info.CI_Info.dwFormat == CIinfo.dwFormat &&
1161                 info.N64Height == height 
1162                 )
1163             {
1164                 // This is the same texture at the same address
1165                 if( byNewTxtrBuf )
1166                 {
1167                     matchidx = i;
1168                     break;
1169                 }
1170             }
1171
1172             // At the same address, but not the same size
1173             //SAFE_DELETE(info.psurf);
1174             covered = true;
1175         }
1176
1177         if( !covered )
1178         {
1179             uint32 memsize2 = ((info.N64Height*info.N64Width)>>1)<<info.CI_Info.dwSize;
1180
1181             if( info.CI_Info.dwAddr > CIinfo.dwAddr && info.CI_Info.dwAddr < CIinfo.dwAddr + memsize)
1182                 covered = true;
1183             else if( info.CI_Info.dwAddr+memsize2 > CIinfo.dwAddr && info.CI_Info.dwAddr+memsize2 < CIinfo.dwAddr + memsize)
1184                 covered = true;
1185             else if( CIinfo.dwAddr > info.CI_Info.dwAddr && CIinfo.dwAddr < info.CI_Info.dwAddr + memsize2 )
1186                 covered = true;
1187             else if( CIinfo.dwAddr+ memsize > info.CI_Info.dwAddr && CIinfo.dwAddr+ memsize < info.CI_Info.dwAddr + memsize2 )
1188                 covered = true;
1189         }
1190
1191         if( covered )
1192         {
1193             //SAFE_DELETE(info.psurf);
1194             if( info.pRenderTexture->IsBeingRendered() )
1195             {
1196                 TRACE0("Error, covering a render_texture which is being rendered");
1197                 TRACE3("New addrr=%08X, width=%d, height=%d", CIinfo.dwAddr, CIinfo.dwWidth, height );
1198                 TRACE3("Old addrr=%08X, width=%d, height=%d", info.CI_Info.dwAddr, info.N64Width, info.N64Height );
1199             }
1200             info.isUsed = false;
1201             TXTRBUF_DUMP(TRACE5("Delete txtr buf %d at %08X, covered by new CI at %08X, Width=%d, Height=%d", 
1202                 i, info.CI_Info.dwAddr, CIinfo.dwAddr, CIinfo.dwWidth, height ));
1203             SAFE_DELETE(info.pRenderTexture);
1204             info.txtEntry.pTexture = NULL;
1205             continue;
1206         }
1207     }
1208
1209     return matchidx;
1210 }
1211
1212 extern RecentCIInfo *g_uRecentCIInfoPtrs[5];
1213 RenderTextureInfo newRenderTextureInfo;
1214
1215 int FrameBufferManager::FindASlot(void)
1216 {
1217     int idx;
1218
1219     // Find an empty slot
1220     bool found = false;
1221     for( int i=0; i<numOfTxtBufInfos; i++ )
1222     {
1223         if( !gRenderTextureInfos[i].isUsed && gRenderTextureInfos[i].updateAtFrame < status.gDlistCount )
1224         {
1225             found = true;
1226             idx = i;
1227             break;
1228         }
1229     }
1230
1231     // If cannot find an empty slot, find the oldest slot and reuse the slot
1232     if( !found )
1233     {
1234         uint32 oldestCount=0xFFFFFFFF;
1235         uint32 oldestIdx = 0;
1236         for( int i=0; i<numOfTxtBufInfos; i++ )
1237         {
1238             if( gRenderTextureInfos[i].updateAtUcodeCount < oldestCount )
1239             {
1240                 oldestCount = gRenderTextureInfos[i].updateAtUcodeCount;
1241                 oldestIdx = i;
1242             }
1243         }
1244
1245         idx = oldestIdx;
1246     }
1247
1248     DEBUGGER_IF_DUMP((logTextureBuffer && gRenderTextureInfos[idx].pRenderTexture ),TRACE2("Delete txtr buf %d at %08X, to reuse it.", idx, gRenderTextureInfos[idx].CI_Info.dwAddr ));
1249     SAFE_DELETE(gRenderTextureInfos[idx].pRenderTexture) ;
1250
1251     return idx;
1252 }
1253
1254
1255 void FrameBufferManager::SetRenderTexture(void)
1256 {
1257     memcpy(&(newRenderTextureInfo.CI_Info), &g_CI, sizeof(SetImgInfo));
1258
1259     newRenderTextureInfo.N64Width = newRenderTextureInfo.CI_Info.dwWidth;
1260     newRenderTextureInfo.knownHeight = ComputeCImgHeight(g_CI, newRenderTextureInfo.N64Height);
1261
1262     status.bHandleN64RenderTexture = true;
1263     newRenderTextureInfo.maxUsedHeight = 0;
1264
1265     if( defaultRomOptions.bInN64Resolution )
1266     {
1267         newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width;
1268         newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height;
1269     }
1270     else if( defaultRomOptions.bDoubleSizeForSmallTxtrBuf && newRenderTextureInfo.N64Width<=128 && newRenderTextureInfo.N64Height<=128)
1271     {
1272         newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width*2;
1273         newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height*2;
1274     }
1275     else
1276     {
1277         newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width;
1278         newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height;
1279     }
1280
1281     newRenderTextureInfo.scaleX = newRenderTextureInfo.bufferWidth / float(newRenderTextureInfo.N64Width);
1282     newRenderTextureInfo.scaleY = newRenderTextureInfo.bufferHeight / float(newRenderTextureInfo.N64Height);
1283
1284     status.bFrameBufferIsDrawn = false;
1285     status.bFrameBufferDrawnByTriangles = false;
1286
1287     newRenderTextureInfo.updateAtFrame = status.gDlistCount;
1288     newRenderTextureInfo.updateAtUcodeCount = status.gUcodeCount;
1289
1290     // Delay activation of the render_texture until the 1st rendering
1291
1292     TXTRBUF_DUMP(TRACE1("Set render_texture: addr=%08X", g_CI.dwAddr));
1293     DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, 
1294     {DebuggerAppendMsg("Paused after setting render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d",
1295     g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth, g_pRenderTextureInfo->N64Height);});
1296 }
1297
1298 int FrameBufferManager::SetBackBufferAsRenderTexture(SetImgInfo &CIinfo, int ciInfoIdx)
1299 {
1300     // MUDLORD:
1301     // OK, heres the drill!
1302     //
1303     // We  set the graphics card's back buffer's contents as a render_texure
1304     // This is done due to how the current framebuffer implementation detects
1305     // changes to the backbuffer memory pointer and then we do a texture
1306     // copy. This might be slow since it doesnt use hardware auxillary buffers
1307
1308     RenderTextureInfo tempRenderTextureInfo;
1309
1310     memcpy(&(tempRenderTextureInfo.CI_Info), &CIinfo, sizeof(SetImgInfo));
1311
1312     tempRenderTextureInfo.N64Width = g_uRecentCIInfoPtrs[ciInfoIdx]->dwLastWidth;
1313     tempRenderTextureInfo.N64Height = g_uRecentCIInfoPtrs[ciInfoIdx]->dwLastHeight;
1314     tempRenderTextureInfo.knownHeight = true;
1315     tempRenderTextureInfo.maxUsedHeight = 0;
1316
1317     tempRenderTextureInfo.bufferWidth = windowSetting.uDisplayWidth;
1318     tempRenderTextureInfo.bufferHeight = windowSetting.uDisplayHeight;
1319
1320     tempRenderTextureInfo.scaleX = tempRenderTextureInfo.bufferWidth / float(tempRenderTextureInfo.N64Width);
1321     tempRenderTextureInfo.scaleY = tempRenderTextureInfo.bufferHeight / float(tempRenderTextureInfo.N64Height);
1322
1323     status.bFrameBufferIsDrawn = false;
1324     status.bFrameBufferDrawnByTriangles = false;
1325
1326     tempRenderTextureInfo.updateAtFrame = status.gDlistCount;
1327     tempRenderTextureInfo.updateAtUcodeCount = status.gUcodeCount;
1328
1329     // Checking against previous render_texture infos
1330     //uint32 memsize = ((tempRenderTextureInfo.N64Height*tempRenderTextureInfo.N64Width)>>1)<<tempRenderTextureInfo.CI_Info.dwSize;
1331     int matchidx = CheckRenderTexturesWithNewCI(CIinfo,tempRenderTextureInfo.N64Height,false);
1332     int idxToUse = (matchidx >= 0) ? matchidx : FindASlot();
1333
1334     if( gRenderTextureInfos[idxToUse].pRenderTexture == NULL || matchidx < 0 )
1335     {
1336         gRenderTextureInfos[idxToUse].pRenderTexture = 
1337         new COGLRenderTexture(tempRenderTextureInfo.bufferWidth, tempRenderTextureInfo.bufferHeight, &gRenderTextureInfos[idxToUse], AS_BACK_BUFFER_SAVE);
1338     }
1339
1340     // Need to set all variables for gRenderTextureInfos[idxToUse]
1341     CRenderTexture *pRenderTexture = gRenderTextureInfos[idxToUse].pRenderTexture;
1342     memcpy(&gRenderTextureInfos[idxToUse], &tempRenderTextureInfo, sizeof(RenderTextureInfo) );
1343     gRenderTextureInfos[idxToUse].pRenderTexture = pRenderTexture;
1344     gRenderTextureInfos[idxToUse].isUsed = true;
1345     gRenderTextureInfos[idxToUse].txtEntry.pTexture = pRenderTexture->m_pTexture;
1346     gRenderTextureInfos[idxToUse].txtEntry.txtrBufIdx = idxToUse+1;
1347
1348     TXTRBUF_DUMP(TRACE2("Set back buf as render_texture %d, addr=%08X", idxToUse, CIinfo.dwAddr));
1349     DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, 
1350     {DebuggerAppendMsg("Paused after setting render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d",
1351     CIinfo.dwAddr, pszImgFormat[CIinfo.dwFormat], pszImgSize[CIinfo.dwSize], CIinfo.dwWidth, g_pRenderTextureInfo->N64Height);});
1352
1353     return idxToUse;
1354 }
1355
1356 void FrameBufferManager::CloseRenderTexture(bool toSave)
1357 {
1358     if( m_curRenderTextureIndex < 0 )
1359         return;
1360
1361     status.bHandleN64RenderTexture = false;
1362     if( status.bDirectWriteIntoRDRAM )
1363     {
1364         // TODO: Implement
1365     }
1366     else 
1367     {
1368         RestoreNormalBackBuffer();
1369         if( !toSave || !status.bFrameBufferIsDrawn || !status.bFrameBufferDrawnByTriangles )
1370         {
1371             TXTRBUF_DUMP(TRACE0("Closing render_texture without save"););
1372             SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture);
1373             gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false;
1374             TXTRBUF_DUMP(TRACE1("Delete render_texture %d",m_curRenderTextureIndex););
1375         }
1376         else
1377         {
1378             TXTRBUF_DUMP(TRACE1("Closing render_texture %d", m_curRenderTextureIndex););
1379             StoreRenderTextureToRDRAM();
1380
1381             if( frameBufferOptions.bRenderTextureWriteBack )
1382             {
1383                 SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture);
1384                 gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false;
1385                 TXTRBUF_DUMP(TRACE1("Delete render_texture %d after writing back to RDRAM",m_curRenderTextureIndex););
1386             }
1387             else
1388             {
1389                 g_pRenderTextureInfo->crcInRDRAM = ComputeRenderTextureCRCInRDRAM(m_curRenderTextureIndex);
1390                 g_pRenderTextureInfo->crcCheckedAtFrame = status.gDlistCount;
1391             }
1392         }
1393     }
1394
1395     SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight);
1396     CRender::g_pRender->UpdateClipRectangle();
1397     CRender::g_pRender->ApplyScissorWithClipRatio();
1398
1399     DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, 
1400     {
1401         DebuggerAppendMsg("Paused after saving render_texture %d:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d", m_curRenderTextureIndex,
1402             g_pRenderTextureInfo->CI_Info.dwAddr, pszImgFormat[g_pRenderTextureInfo->CI_Info.dwFormat], pszImgSize[g_pRenderTextureInfo->CI_Info.dwSize], g_pRenderTextureInfo->CI_Info.dwWidth);
1403     });
1404 }
1405
1406 void FrameBufferManager::ClearN64FrameBufferToBlack(uint32 left, uint32 top, uint32 width, uint32 height)
1407 {
1408     RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]);
1409     uint16 *frameBufferBase = (uint16*)(g_pRDRAMu8+p.dwAddr);
1410     uint32 pitch = p.dwWidth;
1411
1412     if( width == 0 || height == 0 )
1413     {
1414         uint32 len = p.dwHeight*p.dwWidth*p.dwSize;
1415         if( p.dwSize == TXT_SIZE_4b ) len = (p.dwHeight*p.dwWidth)>>1;
1416         memset(frameBufferBase, 0, len);
1417     }
1418     else
1419     {
1420         for( uint32 y=0; y<height; y++)
1421         {
1422             for( uint32 x=0; x<width; x++ )
1423             {
1424                 *(frameBufferBase+(y+top)*pitch+x+left) = 0;
1425             }
1426         }
1427     }
1428 }
1429
1430 uint8 RevTlutTable[0x10000];
1431 bool RevTlutTableNeedUpdate = false;
1432 void InitTlutReverseLookup(void)
1433 {
1434     if( RevTlutTableNeedUpdate )
1435     {
1436         memset(RevTlutTable, 0, 0x10000);
1437         for( int i=0; i<=0xFF; i++ )
1438         {
1439             RevTlutTable[g_wRDPTlut[i]] = uint8(i);
1440         }
1441
1442         RevTlutTableNeedUpdate = false;
1443     }
1444 }
1445
1446
1447 // Copies backbuffer to N64 framebuffer by notification by emu core
1448 // **buggy**
1449 void FrameBufferManager::CopyBackToFrameBufferIfReadByCPU(uint32 addr)
1450 {
1451     int i = FindRecentCIInfoIndex(addr);
1452     if( i != -1 )
1453     {
1454         //if( i == 0 ) CGraphicsContext::Get()->UpdateFrame();
1455         RecentCIInfo *info = g_uRecentCIInfoPtrs[i];
1456         StoreBackBufferToRDRAM( info->dwAddr, info->dwFormat, info->dwSize, info->dwWidth, info->dwHeight, 
1457             windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, addr, 0x1000-addr%0x1000);
1458         TRACE1("Copy back for CI Addr=%08X", info->dwAddr);
1459     }
1460 }
1461
1462 // We do these checks to see if a render_texture operation is occurring...
1463 void FrameBufferManager::CheckRenderTextureCRCInRDRAM(void)
1464 {
1465     for( int i=0; i<numOfTxtBufInfos; i++ )
1466     {
1467         if( !gRenderTextureInfos[i].isUsed )    
1468             continue;
1469
1470         if( gRenderTextureInfos[i].pRenderTexture->IsBeingRendered() )
1471             continue;
1472
1473         if( gRenderTextureInfos[i].crcCheckedAtFrame < status.gDlistCount )
1474         {
1475             uint32 crc = ComputeRenderTextureCRCInRDRAM(i);
1476             if( gRenderTextureInfos[i].crcInRDRAM != crc )
1477             {
1478                 // RDRAM has been modified by CPU core
1479                 TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, CRC in RDRAM changed", i, gRenderTextureInfos[i].CI_Info.dwAddr ));
1480                 SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture);
1481                 gRenderTextureInfos[i].isUsed = false;
1482                 continue;
1483             }
1484             else
1485             {
1486                 gRenderTextureInfos[i].crcCheckedAtFrame = status.gDlistCount;
1487             }
1488         }
1489     }
1490 }
1491
1492 // Check render_texture memory addresses
1493 int FrameBufferManager::CheckAddrInRenderTextures(uint32 addr, bool checkcrc)
1494 {
1495     for( int i=0; i<numOfTxtBufInfos; i++ )
1496     {
1497         if( !gRenderTextureInfos[i].isUsed )    
1498             continue;
1499
1500         if( gRenderTextureInfos[i].pRenderTexture->IsBeingRendered() )
1501             continue;
1502
1503         uint32 bufHeight = gRenderTextureInfos[i].knownHeight ? gRenderTextureInfos[i].N64Height : gRenderTextureInfos[i].maxUsedHeight;
1504         uint32 bufMemSize = gRenderTextureInfos[i].CI_Info.dwSize*gRenderTextureInfos[i].N64Width*bufHeight;
1505         if( addr >=gRenderTextureInfos[i].CI_Info.dwAddr && addr < gRenderTextureInfos[i].CI_Info.dwAddr+bufMemSize)
1506         {
1507             if(checkcrc)
1508             {
1509                 // Check the CRC in RDRAM
1510                 if( gRenderTextureInfos[i].crcCheckedAtFrame < status.gDlistCount )
1511                 {
1512                     uint32 crc = ComputeRenderTextureCRCInRDRAM(i);
1513                     if( gRenderTextureInfos[i].crcInRDRAM != crc )
1514                     {
1515                         // RDRAM has been modified by CPU core
1516                         TRACE3("Buf %d CRC in RDRAM changed from %08X to %08X", i, gRenderTextureInfos[i].crcInRDRAM, crc );
1517                         TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, crcInRDRAM failed.", i, gRenderTextureInfos[i].CI_Info.dwAddr ));
1518                         SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture);
1519                         gRenderTextureInfos[i].isUsed = false;
1520                         continue;
1521                     }
1522                     else
1523                     {
1524                         gRenderTextureInfos[i].crcCheckedAtFrame = status.gDlistCount;
1525                     }
1526                 }
1527             }
1528
1529             TXTRBUF_DUMP(TRACE2("Loading texture addr = %08X from txtr buf %d", addr, i));
1530             return i;
1531         }
1532     }
1533
1534     return -1;
1535 }
1536
1537 // Load texture from render_texture buffer
1538 void FrameBufferManager::LoadTextureFromRenderTexture(TxtrCacheEntry* pEntry, int infoIdx)
1539 {
1540     if( infoIdx < 0 || infoIdx >= numOfTxtBufInfos )
1541     {
1542         infoIdx = CheckAddrInRenderTextures(pEntry->ti.Address);
1543     }
1544
1545     if( infoIdx >= 0 && gRenderTextureInfos[infoIdx].isUsed && gRenderTextureInfos[infoIdx].pRenderTexture )
1546     {
1547         TXTRBUF_DUMP(TRACE1("Loading from render_texture %d", infoIdx));
1548         gRenderTextureInfos[infoIdx].pRenderTexture->LoadTexture(pEntry);
1549     }
1550 }
1551
1552 void FrameBufferManager::RestoreNormalBackBuffer()
1553 {
1554     if( m_curRenderTextureIndex >= 0 && m_curRenderTextureIndex < numOfTxtBufInfos )
1555     {
1556         if( gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture )
1557             gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture->SetAsRenderTarget(false);
1558         m_isRenderingToTexture = false;
1559         m_lastTextureBufferIndex = m_curRenderTextureIndex;
1560     }
1561
1562     if( !status.bFrameBufferIsDrawn || !status.bFrameBufferDrawnByTriangles )
1563     {
1564         gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false;
1565         TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, it is never rendered", m_curRenderTextureIndex, gRenderTextureInfos[m_curRenderTextureIndex].CI_Info.dwAddr ));
1566         SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture);
1567     }
1568 }
1569
1570 uint32 FrameBufferManager::ComputeRenderTextureCRCInRDRAM(int infoIdx)
1571 {
1572     if( infoIdx >= numOfTxtBufInfos || infoIdx < 0 || !gRenderTextureInfos[infoIdx].isUsed )
1573         return 0;
1574
1575     RenderTextureInfo &info = gRenderTextureInfos[infoIdx];
1576     uint32 height = info.knownHeight ? info.N64Height : info.maxUsedHeight;
1577     uint8 *pAddr = (uint8*)(g_pRDRAMu8+info.CI_Info.dwAddr);
1578     uint32 pitch = (info.N64Width << info.CI_Info.dwSize ) >> 1;
1579
1580     return CalculateRDRAMCRC(pAddr, 0, 0, info.N64Width, height, info.CI_Info.dwSize, pitch);
1581 }
1582
1583 // Activates texture buffer for drawing
1584 void FrameBufferManager::ActiveTextureBuffer(void)
1585 {
1586     status.bCIBufferIsRendered = true;
1587
1588     if( status.bHandleN64RenderTexture )
1589     {
1590         // Checking against previous render_texture infos
1591         int matchidx = -1;
1592
1593         //uint32 memsize = ((newRenderTextureInfo.N64Height*newRenderTextureInfo.N64Width)>>1)<<newRenderTextureInfo.CI_Info.dwSize;
1594
1595         matchidx = CheckRenderTexturesWithNewCI(g_CI,newRenderTextureInfo.N64Height,true);
1596
1597         int idxToUse=-1;
1598         if( matchidx >= 0 )
1599         {
1600             // Reuse the matched slot
1601             idxToUse = matchidx;
1602         }
1603         else
1604         {
1605             idxToUse = FindASlot();
1606         }
1607
1608         if( gRenderTextureInfos[idxToUse].pRenderTexture == NULL || matchidx < 0 )
1609         {
1610             int w = newRenderTextureInfo.bufferWidth;
1611             if( newRenderTextureInfo.knownHeight == RDP_SETSCISSOR && newRenderTextureInfo.CI_Info.dwAddr == g_ZI.dwAddr )
1612             {
1613                 w = gRDP.scissor.right;
1614             }
1615
1616             gRenderTextureInfos[idxToUse].pRenderTexture = 
1617                 new COGLRenderTexture(w, newRenderTextureInfo.bufferHeight, &gRenderTextureInfos[idxToUse], AS_RENDER_TARGET);
1618         }
1619
1620         // Need to set all variables for gRenderTextureInfos[idxToUse]
1621         CRenderTexture *pRenderTexture = gRenderTextureInfos[idxToUse].pRenderTexture;
1622         memcpy(&gRenderTextureInfos[idxToUse], &newRenderTextureInfo, sizeof(RenderTextureInfo) );
1623         gRenderTextureInfos[idxToUse].pRenderTexture = pRenderTexture;
1624         gRenderTextureInfos[idxToUse].isUsed = true;
1625         gRenderTextureInfos[idxToUse].txtEntry.pTexture = pRenderTexture->m_pTexture;
1626         gRenderTextureInfos[idxToUse].txtEntry.txtrBufIdx = idxToUse+1;
1627
1628         g_pRenderTextureInfo = &gRenderTextureInfos[idxToUse];
1629
1630         // Active the render_texture
1631         if( m_curRenderTextureIndex >= 0 && gRenderTextureInfos[m_curRenderTextureIndex].isUsed && gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture )
1632         {
1633             gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture->SetAsRenderTarget(false);
1634             m_isRenderingToTexture = false;
1635         }
1636
1637         if( gRenderTextureInfos[idxToUse].pRenderTexture->SetAsRenderTarget(true) )
1638         {
1639             m_isRenderingToTexture = true;
1640
1641             //Clear(CLEAR_COLOR_AND_DEPTH_BUFFER,0x80808080,1.0f);
1642             if( frameBufferOptions.bFillRectNextTextureBuffer )
1643                 CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,gRDP.fillColor,1.0f);
1644             else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && g_pRenderTextureInfo->N64Width > 64 && g_pRenderTextureInfo->N64Width < 300 )
1645             {
1646                 CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,0,1.0f);
1647             }
1648             else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && g_pRenderTextureInfo->N64Width < 64 && g_pRenderTextureInfo->N64Width > 32 )
1649             {
1650                 CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,0,1.0f);
1651             }
1652
1653             m_curRenderTextureIndex = idxToUse;
1654
1655             status.bDirectWriteIntoRDRAM = false;
1656
1657             //SetScreenMult(1, 1);
1658             SetScreenMult(gRenderTextureInfos[m_curRenderTextureIndex].scaleX, gRenderTextureInfos[m_curRenderTextureIndex].scaleY);
1659             CRender::g_pRender->UpdateClipRectangle();
1660
1661             // If needed, draw RDRAM into the render_texture
1662             //if( frameBufferOptions.bLoadRDRAMIntoRenderTexture )
1663             //{
1664             //  CRender::GetRender()->LoadTxtrBufFromRDRAM();
1665             //}
1666         }
1667         else
1668         {
1669             if( CDeviceBuilder::m_deviceGeneralType == DIRECTX_DEVICE )
1670             {
1671                 TRACE1("Error to set Render Target: %d", idxToUse);
1672                 TRACE1("Addr = %08X", gRenderTextureInfos[idxToUse].CI_Info.dwAddr);
1673                 TRACE2("Width = %d, Height=%d", gRenderTextureInfos[idxToUse].N64Width, gRenderTextureInfos[idxToUse].N64Height);
1674             }
1675         }   
1676
1677
1678         TXTRBUF_DUMP(TRACE2("Rendering to render_texture %d, addr=%08X", idxToUse, g_CI.dwAddr));
1679         DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE, 
1680         {DebuggerAppendMsg("Paused after activating render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d",
1681         g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth, g_pRenderTextureInfo->N64Height);});
1682     }
1683     else
1684     {
1685         UpdateRecentCIAddr(g_CI);
1686         CheckRenderTexturesWithNewCI(g_CI,gRDP.scissor.bottom,false);
1687     }
1688 }
1689
1690 #define SAVE_CI {g_CI.dwAddr = newCI.dwAddr;g_CI.dwFormat = newCI.dwFormat;g_CI.dwSize = newCI.dwSize;g_CI.dwWidth = newCI.dwWidth;g_CI.bpl=newCI.bpl;}
1691
1692 // Sets CI address for framebuffer copies
1693 void FrameBufferManager::Set_CI_addr(SetImgInfo &newCI)
1694 {
1695     bool wasDrawingTextureBuffer = status.bN64IsDrawingTextureBuffer;
1696     status.bN64IsDrawingTextureBuffer = ( newCI.dwSize != TXT_SIZE_16b || newCI.dwFormat != TXT_FMT_RGBA || newCI.dwWidth < 200 || ( newCI.dwAddr != g_ZI.dwAddr && newCI.dwWidth != 512 && !g_pFrameBufferManager->HasAddrBeenDisplayed(newCI.dwAddr, newCI.dwWidth)) );
1697     status.bN64FrameBufferIsUsed = status.bN64IsDrawingTextureBuffer;
1698
1699     if( !wasDrawingTextureBuffer && g_CI.dwAddr == g_ZI.dwAddr && status.bCIBufferIsRendered )
1700     {
1701         TXTRBUF_DUMP(TRACE0("ZI is rendered"));
1702
1703         if( options.enableHackForGames != HACK_FOR_CONKER && g_uRecentCIInfoPtrs[0]->bCopied == false )
1704         {
1705             // Conker is not actually using a backbuffer
1706             g_pFrameBufferManager->UpdateRecentCIAddr(g_CI);
1707             if( status.leftRendered != -1 && status.topRendered != -1 && status.rightRendered != -1 && status.bottomRendered != -1 )
1708             {
1709                 RECT rect={status.leftRendered,status.topRendered,status.rightRendered,status.bottomRendered};
1710                 g_pFrameBufferManager->SaveBackBuffer(0,&rect);
1711             }
1712             else
1713             {
1714                 g_pFrameBufferManager->SaveBackBuffer(0,NULL);
1715             }
1716         }
1717     }
1718
1719     frameBufferOptions.bFillRectNextTextureBuffer = false;
1720     if( g_CI.dwAddr == newCI.dwAddr && status.bHandleN64RenderTexture && (g_CI.dwFormat != newCI.dwFormat || g_CI.dwSize != newCI.dwSize || g_CI.dwWidth != newCI.dwWidth ) )
1721     {
1722         // Mario Tennis player shadow
1723         g_pFrameBufferManager->CloseRenderTexture(true);
1724         if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS )
1725             frameBufferOptions.bFillRectNextTextureBuffer = true;   // Hack for Mario Tennis
1726     }
1727
1728     SAVE_CI;
1729
1730     if( g_CI.dwAddr == g_ZI.dwAddr && !status.bN64IsDrawingTextureBuffer )
1731     {
1732         if( g_pFrameBufferManager->IsDIaRenderTexture() )
1733         {
1734             status.bN64IsDrawingTextureBuffer = true;
1735             status.bN64FrameBufferIsUsed = status.bN64IsDrawingTextureBuffer;
1736         }
1737     }
1738
1739     status.bCIBufferIsRendered = false;
1740     status.leftRendered = status.topRendered = status.rightRendered = status.bottomRendered = -1;
1741
1742     if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_CI_CHANGE && !status.bN64IsDrawingTextureBuffer )
1743     {
1744         if( status.curRenderBuffer == 0 )
1745         {
1746             status.curRenderBuffer = g_CI.dwAddr;
1747         }
1748         else if( status.curRenderBuffer != g_CI.dwAddr )
1749         {
1750             status.curDisplayBuffer = status.curRenderBuffer;
1751             CGraphicsContext::Get()->UpdateFrame();
1752             status.curRenderBuffer = g_CI.dwAddr;
1753             DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Screen Update because CI change to %08X, Display Buf=%08X", status.curRenderBuffer, status.curDisplayBuffer);});
1754         }
1755     }
1756
1757     if( frameBufferOptions.bAtEachFrameUpdate && !status.bHandleN64RenderTexture )
1758     {
1759         if( status.curRenderBuffer != g_CI.dwAddr )
1760         {
1761             if( status.gDlistCount%(currentRomOptions.N64FrameBufferWriteBackControl+1) == 0 )
1762             {
1763                 g_pFrameBufferManager->StoreBackBufferToRDRAM(status.curRenderBuffer, 
1764                     newCI.dwFormat, newCI.dwSize, windowSetting.uViWidth, windowSetting.uViHeight,
1765                     windowSetting.uDisplayWidth, windowSetting.uDisplayHeight);
1766             }
1767         }
1768
1769         //status.curDisplayBuffer = status.curRenderBuffer;
1770         status.curRenderBuffer = g_CI.dwAddr;
1771     }
1772
1773
1774     switch( currentRomOptions.N64RenderToTextureEmuType )
1775     {
1776     case TXT_BUF_NONE:
1777         if( status.bHandleN64RenderTexture )
1778             g_pFrameBufferManager->CloseRenderTexture(false);
1779         status.bHandleN64RenderTexture = false; // Don't handle N64 render_texture stuffs
1780         if( !status.bN64IsDrawingTextureBuffer )
1781             g_pFrameBufferManager->UpdateRecentCIAddr(g_CI);
1782         break;
1783     default:
1784         if( status.bHandleN64RenderTexture )
1785         {
1786 #ifdef DEBUGGER
1787             if( pauseAtNext && eventToPause == NEXT_RENDER_TEXTURE )
1788             {
1789                 pauseAtNext = TRUE;
1790                 eventToPause = NEXT_RENDER_TEXTURE;
1791             }
1792 #endif
1793             g_pFrameBufferManager->CloseRenderTexture(true);
1794         }
1795
1796         status.bHandleN64RenderTexture = status.bN64IsDrawingTextureBuffer;
1797         if( status.bHandleN64RenderTexture )
1798         {
1799             if( options.enableHackForGames != HACK_FOR_BANJO_TOOIE )
1800             {
1801                 g_pFrameBufferManager->SetRenderTexture();
1802             }
1803         }
1804         else
1805         {
1806 #ifdef DEBUGGER
1807             if( g_CI.dwWidth == 512 && pauseAtNext && (eventToPause==NEXT_OBJ_BG || eventToPause==NEXT_SET_CIMG) )
1808             {
1809                 DebuggerAppendMsg("Warning SetCImg: new Addr=0x%08X, fmt:%s size=%sb, Width=%d\n", 
1810                     g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth);
1811             }
1812 #endif
1813             //g_pFrameBufferManager->UpdateRecentCIAddr(g_CI);      // Delay this until the CI buffer is actally drawn
1814         }
1815         break;
1816     }
1817
1818     TXTRBUF_DUMP(TRACE4("SetCImg : Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", 
1819         g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth));
1820
1821     DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG, 
1822     {
1823         DebuggerAppendMsg("Pause after SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n", 
1824             g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth);
1825     }
1826     );
1827 }
1828
1829
1830 void FrameBufferManager::StoreRenderTextureToRDRAM(int infoIdx)
1831 {
1832     if( !frameBufferOptions.bRenderTextureWriteBack )
1833         return;
1834
1835     if( infoIdx < 0 )
1836         infoIdx = m_lastTextureBufferIndex;
1837
1838     if( !gRenderTextureInfos[infoIdx].pRenderTexture )
1839         return;
1840
1841     if( gRenderTextureInfos[infoIdx].pRenderTexture->IsBeingRendered() )
1842     {
1843         TXTRBUF_DUMP(TRACE1("Cannot SaveTextureBuffer %d, it is being rendered", infoIdx));
1844         return;
1845     }
1846
1847     gRenderTextureInfos[infoIdx].pRenderTexture->StoreToRDRAM(infoIdx);
1848 }
1849
1850
1851 //does FB copy to N64 RDAM structure
1852 void FrameBufferManager::CopyBufferToRDRAM(uint32 addr, uint32 fmt, uint32 siz, uint32 width, uint32 height, uint32 bufWidth, uint32 bufHeight, uint32 startaddr, uint32 memsize, uint32 pitch, TextureFmt bufFmt, void *buffer, uint32 bufPitch)
1853 {
1854     uint32 startline=0;
1855     
1856     if( startaddr == 0xFFFFFFFF )
1857         startaddr = addr;
1858
1859     startline = (startaddr-addr)/siz/pitch;
1860     if( startline >= height )
1861     {
1862         //TRACE0("Warning: check me");
1863         startline = height;
1864     }
1865
1866     uint32 endline = height;
1867     if( memsize != 0xFFFFFFFF )
1868     {
1869         endline = (startaddr+memsize-addr)/siz;
1870         if( endline % pitch == 0 )
1871             endline /= pitch;
1872         else
1873             endline = endline/pitch+1;
1874     }
1875     if( endline > height )
1876     {
1877         endline = height;
1878     }
1879
1880     if( memsize != 0xFFFFFFFF )
1881     {
1882         TXTRBUF_DUMP(DebuggerAppendMsg("Start at: 0x%X, from line %d to %d", startaddr-addr, startline, endline););
1883     }
1884
1885     int indexes[600];
1886     {
1887         float sx;
1888         int sx0;
1889         float ratio = bufWidth/(float)width;
1890         for( uint32 j=0; j<width; j++ )
1891         {
1892             sx = j*ratio;
1893             sx0 = int(sx+0.5);
1894             indexes[j] = 4*sx0;
1895         }
1896     }
1897
1898     if( siz == TXT_SIZE_16b )
1899     {
1900         uint16 *frameBufferBase = (uint16*)(g_pRDRAMu8+addr);
1901
1902         if( bufFmt==TEXTURE_FMT_A8R8G8B8 )
1903         {
1904             int  sy0;
1905             float ratio = bufHeight/(float)height;
1906
1907             for( uint32 i=startline; i<endline; i++ )
1908             {
1909                 sy0 = int(i*ratio+0.5);
1910
1911                 uint16 *pD = frameBufferBase + i * pitch;
1912                 uint8 *pS0 = (uint8 *)buffer + sy0 * bufPitch;
1913
1914                 for( uint32 j=0; j<width; j++ )
1915                 {
1916                     // Point
1917                     uint8 r = pS0[indexes[j]+2];
1918                     uint8 g = pS0[indexes[j]+1];
1919                     uint8 b = pS0[indexes[j]+0];
1920                     uint8 a = pS0[indexes[j]+3];
1921
1922                     // Liner
1923                     *(pD+(j^1)) = ConvertRGBATo555( r, g, b, a);
1924                 }
1925             }
1926         }
1927         else
1928         {
1929             TRACE1("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);
1930         }
1931     }
1932     else if( siz == TXT_SIZE_8b && fmt == TXT_FMT_CI )
1933     {
1934         uint8 *frameBufferBase = (uint8*)(g_pRDRAMu8+addr);
1935
1936         if( bufFmt==TEXTURE_FMT_A8R8G8B8 )
1937         {
1938             uint16 tempword;
1939             InitTlutReverseLookup();
1940
1941             for( uint32 i=startline; i<endline; i++ )
1942             {
1943                 uint8 *pD = frameBufferBase + i * width;
1944                 uint8 *pS = (uint8 *)buffer + i*bufHeight/height * bufPitch;
1945                 for( uint32 j=0; j<width; j++ )
1946                 {
1947                     int pos = 4*(j*bufWidth/width);
1948                     tempword = ConvertRGBATo555((pS[pos+2]),        // Red
1949                                                 (pS[pos+1]),        // Green
1950                                                 (pS[pos+0]),        // Blue
1951                                                 (pS[pos+3]));       // Alpha
1952                     
1953                     //*pD = CIFindIndex(tempword);
1954                     *(pD+(j^3)) = RevTlutTable[tempword];
1955                 }
1956             }
1957         }
1958         else
1959         {
1960             TRACE1("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);
1961         }
1962         DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram", pszImgSize[siz]);});
1963     }
1964     else if( siz == TXT_SIZE_8b && fmt == TXT_FMT_I )
1965     {
1966         uint8 *frameBufferBase = (uint8*)(g_pRDRAMu8+addr);
1967
1968         if( bufFmt==TEXTURE_FMT_A8R8G8B8 )
1969         {
1970             int sy0;
1971             float ratio = bufHeight/(float)height;
1972
1973             for( uint32 i=startline; i<endline; i++ )
1974             {
1975                 sy0 = int(i*ratio+0.5);
1976
1977                 uint8 *pD = frameBufferBase + i * width;
1978                 uint8 *pS0 = (uint8 *)buffer + sy0 * bufPitch;
1979
1980                 for( uint32 j=0; j<width; j++ )
1981                 {
1982                     // Point
1983                     uint32 r = pS0[indexes[j]+2];
1984                     uint32 g = pS0[indexes[j]+1];
1985                     uint32 b = pS0[indexes[j]+0];
1986
1987                     // Liner
1988                     *(pD+(j^3)) = (uint8)((r+b+g)/3);
1989                 }
1990             }
1991         }
1992         else
1993         {
1994             //DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);
1995         }
1996         DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram", pszImgSize[siz]);});
1997     }
1998 }
1999
2000
2001 #ifdef DEBUGGER
2002 void FrameBufferManager::DisplayRenderTexture(int infoIdx)
2003 {
2004     if( infoIdx < 0 )
2005         infoIdx = m_lastTextureBufferIndex;
2006
2007     if( gRenderTextureInfos[infoIdx].pRenderTexture )
2008     {
2009         if( gRenderTextureInfos[infoIdx].pRenderTexture->IsBeingRendered() )
2010         {
2011             TRACE1("Render texture %d is being rendered, cannot display", infoIdx);
2012         }
2013         else
2014         {
2015             TRACE1("Texture buffer %d:", infoIdx);
2016             TRACE1("Addr=%08X", gRenderTextureInfos[infoIdx].CI_Info.dwAddr);
2017             TRACE2("Width=%d, Created Height=%d", gRenderTextureInfos[infoIdx].N64Width,gRenderTextureInfos[infoIdx].N64Height);
2018             TRACE2("Fmt=%d, Size=%d", gRenderTextureInfos[infoIdx].CI_Info.dwFormat,gRenderTextureInfos[infoIdx].CI_Info.dwSize);
2019         }
2020     }
2021     else
2022     {
2023         TRACE1("Texture buffer %d is not used", infoIdx);
2024     }
2025 }
2026 #endif
2027
2028
2029
2030 // Saves backbuffer
2031 // this is the core to the current framebuffer code
2032 // We need to save backbuffer when changed by framebuffer
2033 // so that we can use it for framebuffer effects
2034 void FrameBufferManager::SaveBackBuffer(int ciInfoIdx, RECT* pSrcRect, bool forceToSaveToRDRAM)
2035 {
2036     RecentCIInfo &ciInfo = *g_uRecentCIInfoPtrs[ciInfoIdx];
2037
2038     if( ciInfoIdx == 1 )    // to save the current front buffer
2039     {
2040         CGraphicsContext::g_pGraphicsContext->UpdateFrame(true);
2041     }
2042
2043     if( frameBufferOptions.bWriteBackBufToRDRAM || forceToSaveToRDRAM )
2044     {
2045         uint32 width = ciInfo.dwWidth;
2046         uint32 height = ciInfo.dwHeight;
2047
2048         if( ciInfo.dwWidth == *g_GraphicsInfo.VI_WIDTH_REG && ciInfo.dwWidth != windowSetting.uViWidth )
2049         {
2050             width = windowSetting.uViWidth;
2051             height = windowSetting.uViHeight;
2052         }
2053
2054         StoreBackBufferToRDRAM( ciInfo.dwAddr, ciInfo.dwFormat, ciInfo.dwSize, width, height, 
2055             windowSetting.uDisplayWidth, windowSetting.uDisplayHeight);
2056
2057         g_uRecentCIInfoPtrs[ciInfoIdx]->bCopied = true;
2058         if( ciInfoIdx == 1 )    // to save the current front buffer
2059         {
2060             CGraphicsContext::g_pGraphicsContext->UpdateFrame(true);
2061         }
2062         return;
2063     }
2064
2065
2066     SetImgInfo tempinfo;
2067     tempinfo.dwAddr = ciInfo.dwAddr;
2068     tempinfo.dwFormat = ciInfo.dwFormat;
2069     tempinfo.dwSize = ciInfo.dwSize;
2070     tempinfo.dwWidth = ciInfo.dwWidth;
2071
2072     int idx = SetBackBufferAsRenderTexture(tempinfo, ciInfoIdx);
2073
2074     CopyBackBufferToRenderTexture(idx, ciInfo, pSrcRect);
2075
2076     gRenderTextureInfos[idx].crcCheckedAtFrame = status.gDlistCount;
2077     gRenderTextureInfos[idx].crcInRDRAM = ComputeRenderTextureCRCInRDRAM(idx);
2078
2079     DEBUGGER_IF_DUMP((logTextureBuffer&&pSrcRect==NULL),TRACE1("SaveBackBuffer at 0x%08X", ciInfo.dwAddr));
2080     DEBUGGER_IF_DUMP((logTextureBuffer&&pSrcRect),TRACE5("SaveBackBuffer at 0x%08X, {%d,%d -%d,%d)", ciInfo.dwAddr,
2081         pSrcRect->left,pSrcRect->top,pSrcRect->right,pSrcRect->bottom));
2082     DEBUGGER_IF_DUMP(( pauseAtNext && eventToPause == NEXT_RENDER_TEXTURE),{g_pFrameBufferManager->DisplayRenderTexture(idx);});
2083
2084     g_uRecentCIInfoPtrs[ciInfoIdx]->bCopied = true;
2085 }
2086