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