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