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