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