292f9317 |
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 | |