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