Path: blob/master/libmupen64plus/mupen64plus-video-rice/src/FrameBuffer.cpp
2 views
/*1Copyright (C) 2005 Rice196423This program is free software; you can redistribute it and/or4modify it under the terms of the GNU General Public License5as published by the Free Software Foundation; either version 26of the License, or (at your option) any later version.78This program is distributed in the hope that it will be useful,9but WITHOUT ANY WARRANTY; without even the implied warranty of10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11GNU General Public License for more details.1213You should have received a copy of the GNU General Public License14along with this program; if not, write to the Free Software15Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.1617*/1819// ===========================================================================2021#include <vector>2223#include "ConvertImage.h"24#include "DeviceBuilder.h"25#include "FrameBuffer.h"26#include "UcodeDefs.h"27#include "RSP_Parser.h"28#include "Render.h"2930extern TMEMLoadMapInfo g_tmemLoadAddrMap[0x200]; // Totally 4KB TMEM;3132// 0 keeps the most recent CI info33// 1 keeps the frame buffer CI info which is being displayed now34// 2 keeps the older frame buffer CI info. This can be used if we are using triple buffer35/* Overview of framebuffer implementation361) Check if backbuffer has changed, via different detection techniques372) If changed, we copy the GFX card's backbuffer to main RAM383) This is slow due to the reading process, not the writing39*/4041RecentCIInfo g_RecentCIInfo[5];42RecentCIInfo *g_uRecentCIInfoPtrs[5] =43{44&g_RecentCIInfo[0],45&g_RecentCIInfo[1],46&g_RecentCIInfo[2],47&g_RecentCIInfo[3],48&g_RecentCIInfo[4],49};5051int numOfRecentCIInfos = 5;5253RecentViOriginInfo g_RecentVIOriginInfo[5];54uint32 dwBackBufferSavedAtFrame=0;5556RenderTextureInfo gRenderTextureInfos[20];57int numOfTxtBufInfos = sizeof(gRenderTextureInfos)/sizeof(RenderTextureInfo);58RenderTextureInfo *g_pRenderTextureInfo = NULL;5960FrameBufferManager* g_pFrameBufferManager = NULL;6162bool LastCIIsNewCI=false;6364FrameBufferManager::FrameBufferManager() :65m_isRenderingToTexture(false),66m_curRenderTextureIndex(-1),67m_lastTextureBufferIndex(-1)68{69}7071FrameBufferManager::~FrameBufferManager()72{73}7475void FrameBufferManager::CloseUp()76{77for( int i=0; i<numOfTxtBufInfos; i++ )78{79SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture);80}81}8283void FrameBufferManager::Initialize()84{85m_isRenderingToTexture = false;86m_lastTextureBufferIndex = -1;87m_curRenderTextureIndex = -1;8889status.bCIBufferIsRendered = false;90status.bN64IsDrawingTextureBuffer = false;91status.bHandleN64RenderTexture = false;92status.bN64FrameBufferIsUsed = false;9394memset(&gRenderTextureInfos[0], 0, sizeof(RenderTextureInfo)*numOfTxtBufInfos);95}96// ===========================================================================9798uint16 ConvertRGBATo555(uint8 r, uint8 g, uint8 b, uint8 a)99{100uint8 ar = a>=0x20?1:0;101return ((r>>3)<<RGBA5551_RedShift) | ((g>>3)<<RGBA5551_GreenShift) | ((b>>3)<<RGBA5551_BlueShift) | ar;//(a>>7);102}103104uint16 ConvertRGBATo555(uint32 color32)105{106return (uint16)((((color32>>19)&0x1F)<<RGBA5551_RedShift) | (((color32>>11)&0x1F)<<RGBA5551_GreenShift) | (((color32>>3)&0x1F)<<RGBA5551_BlueShift) | ((color32>>31)));;107}108109void FrameBufferManager::UpdateRecentCIAddr(SetImgInfo &ciinfo)110{111if( ciinfo.dwAddr == g_uRecentCIInfoPtrs[0]->dwAddr )112return;113114RecentCIInfo *temp;115116int i;117for( i=1; i<numOfRecentCIInfos; i++ )118{119if( ciinfo.dwAddr == g_uRecentCIInfoPtrs[i]->dwAddr )120{121temp = g_uRecentCIInfoPtrs[i];122123for( int j=i; j>0; j-- )124{125g_uRecentCIInfoPtrs[j] = g_uRecentCIInfoPtrs[j-1];126}127break;128}129}130131if( i >= numOfRecentCIInfos )132{133temp = g_uRecentCIInfoPtrs[4];134g_uRecentCIInfoPtrs[4] = g_uRecentCIInfoPtrs[3];135g_uRecentCIInfoPtrs[3] = g_uRecentCIInfoPtrs[2];136g_uRecentCIInfoPtrs[2] = g_uRecentCIInfoPtrs[1];137g_uRecentCIInfoPtrs[1] = g_uRecentCIInfoPtrs[0];138temp->dwCopiedAtFrame = 0;139temp->bCopied = false;140}141142g_uRecentCIInfoPtrs[0] = temp;143144// Fix me here for Mario Tennis145temp->dwLastWidth = windowSetting.uViWidth;146temp->dwLastHeight = windowSetting.uViHeight;147148temp->dwFormat = ciinfo.dwFormat;149temp->dwAddr = ciinfo.dwAddr;150temp->dwSize = ciinfo.dwSize;151temp->dwWidth = ciinfo.dwWidth;152temp->dwHeight = gRDP.scissor.bottom;153temp->dwMemSize = (temp->dwWidth*temp->dwHeight/2)<<temp->dwSize;154temp->bCopied = false;155temp->lastUsedFrame = status.gDlistCount;156temp->lastSetAtUcode = status.gUcodeCount;157}158159160/************************************************************************/161/* Mark the ciinfo entry that the ciinfo is used by VI origin register */162/* in another word, this is a real frame buffer, not a fake frame buffer*/163/* Fake frame buffers are never really used by VI origin */164/************************************************************************/165void FrameBufferManager::SetAddrBeDisplayed(uint32 addr)166{167uint32 viwidth = *g_GraphicsInfo.VI_WIDTH_REG;168addr &= (g_dwRamSize-1);169170int i;171for( i=0; i<numOfRecentCIInfos; i++ )172{173if( g_uRecentCIInfoPtrs[i]->dwAddr+2*viwidth == addr )174{175g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame = status.gDlistCount;176}177else if( addr >= g_uRecentCIInfoPtrs[i]->dwAddr && addr < g_uRecentCIInfoPtrs[i]->dwAddr+0x1000 )178{179g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame = status.gDlistCount;180}181}182183for( i=0; i<numOfRecentCIInfos; i++ )184{185if( g_RecentVIOriginInfo[i].addr == addr )186{187g_RecentVIOriginInfo[i].FrameCount = status.gDlistCount;188return;189}190}191192for( i=0; i<numOfRecentCIInfos; i++ )193{194if( g_RecentVIOriginInfo[i].addr == 0 )195{196// Never used197g_RecentVIOriginInfo[i].addr = addr;198g_RecentVIOriginInfo[i].FrameCount = status.gDlistCount;199return;200}201}202203int index=0;204uint32 minFrameCount = 0xffffffff;205206for( i=0; i<numOfRecentCIInfos; i++ )207{208if( g_RecentVIOriginInfo[i].FrameCount < minFrameCount )209{210index = i;211minFrameCount = g_RecentVIOriginInfo[i].FrameCount;212}213}214215g_RecentVIOriginInfo[index].addr = addr;216g_RecentVIOriginInfo[index].FrameCount = status.gDlistCount;217}218219bool FrameBufferManager::HasAddrBeenDisplayed(uint32 addr, uint32 width)220{221addr &= (g_dwRamSize-1);222223int i;224for( i=0; i<numOfRecentCIInfos; i++ )225{226if( g_uRecentCIInfoPtrs[i]->dwAddr == 0 )227continue;228229if( g_uRecentCIInfoPtrs[i]->dwAddr == addr )230{231if( status.gDlistCount-g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame < 20 )232//if( g_uRecentCIInfoPtrs[i]->bUsedByVIAtFrame != 0 )233{234return true;235}236else237{238TXTRBUF_DUMP(TRACE0("This is a new buffer address, the addr is never a displayed buffer"););239return false;240}241}242}243244for( i=0; i<numOfRecentCIInfos; i++ )245{246if( g_RecentVIOriginInfo[i].addr != 0 )247{248if( g_RecentVIOriginInfo[i].addr > addr &&249(g_RecentVIOriginInfo[i].addr - addr)%width == 0 &&250(g_RecentVIOriginInfo[i].addr - addr)/width <= 4)251{252if( status.gDlistCount-g_RecentVIOriginInfo[i].FrameCount < 20 )253//if( g_RecentVIOriginInfo[i].FrameCount != 0 )254{255return true;256}257else258{259TXTRBUF_DUMP(DebuggerAppendMsg("This is a new buffer address, the addr is never a displayed buffer"););260return false;261}262}263}264}265266if( status.gDlistCount > 20 )267return false;268else269{270TXTRBUF_DUMP({DebuggerAppendMsg("This is a new buffer address, the addr is never a displayed buffer");});271return true;272}273}274275int FrameBufferManager::FindRecentCIInfoIndex(uint32 addr)276{277for( int i=0; i<numOfRecentCIInfos; i++ )278{279if( g_uRecentCIInfoPtrs[i]->dwAddr <= addr && addr < g_uRecentCIInfoPtrs[i]->dwAddr+g_uRecentCIInfoPtrs[i]->dwMemSize )280{281return i;282}283}284return -1;285}286287bool FrameBufferManager::IsDIaRenderTexture()288{289// Knowing g_CI and g_ZI290291//if( g_CI.dwWidth )292293bool foundSetScissor=false;294bool foundFillRect=false;295bool foundSetFillColor=false;296bool foundSetCImg=false;297uint32 newFillColor = 0;298299uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction300301for( int i=0; i<10; i++ )302{303uint32 w0 = *(uint32 *)(g_pRDRAMu8 + dwPC + i*8);304uint32 w1 = *(uint32 *)(g_pRDRAMu8 + dwPC + 4 + i*8);305306if( (w0>>24) == RDP_SETSCISSOR )307{308foundSetScissor = true;309continue;310}311312if( (w0>>24) == RDP_SETFILLCOLOR )313{314foundSetFillColor = true;315newFillColor = w1;316continue;317}318319if( (w0>>24) == RDP_FILLRECT )320{321uint32 x0 = ((w1>>12)&0xFFF)/4;322uint32 y0 = ((w1>>0 )&0xFFF)/4;323uint32 x1 = ((w0>>12)&0xFFF)/4;324325if( x0 == 0 && y0 == 0 )326{327if( x1 == g_CI.dwWidth )328{329foundFillRect = true;330continue;331}332333if(x1 == (unsigned int)(g_CI.dwWidth-1))334{335foundFillRect = true;336continue;337}338}339}340341if( (w0>>24) == RDP_TEXRECT )342{343break;344}345346if( (w0>>24) == RDP_SETCIMG )347{348foundSetCImg = true;349break;350}351}352353/*354bool foundSetScissor=false;355bool foundFillRect=false;356bool foundSetFillColor=false;357bool foundSetCImg=false;358bool foundTxtRect=false;359int ucodeLength=10;360uint32 newFillColor;361*/362363if( foundFillRect )364{365if( foundSetFillColor )366{367if( newFillColor != 0xFFFCFFFC )368return true; // this is a render_texture369else370return false;371}372373if( gRDP.fillColor != 0x00FFFFF7 )374return true; // this is a render_texture375else376return false; // this is a normal ZImg377}378else if( foundSetFillColor && newFillColor == 0xFFFCFFFC && foundSetCImg )379{380return false;381}382else383{384return true;385}386387388if( !foundSetCImg )389return true;390391if( foundSetScissor )392return true;393}394395int FrameBufferManager::CheckAddrInBackBuffers(uint32 addr, uint32 memsize, bool copyToRDRAM)396{397int r = FindRecentCIInfoIndex(addr);398399if( r >= 0 )400{401// Also check if the address is overwritten by a recent render_texture402//int t = CheckAddrInRenderTextures(addr,false);403int t =-1;404for( int i=0; i<numOfTxtBufInfos; i++ )405{406uint32 bufHeight = gRenderTextureInfos[i].knownHeight ? gRenderTextureInfos[i].N64Height : gRenderTextureInfos[i].maxUsedHeight;407uint32 bufMemSize = gRenderTextureInfos[i].CI_Info.dwSize*gRenderTextureInfos[i].N64Width*bufHeight;408if( addr >=gRenderTextureInfos[i].CI_Info.dwAddr && addr < gRenderTextureInfos[i].CI_Info.dwAddr+bufMemSize)409{410if( g_uRecentCIInfoPtrs[r]->lastSetAtUcode < gRenderTextureInfos[i].updateAtUcodeCount )411{412t = i;413break;414}415}416}417418if( t >= 0 )419return -1;420}421422if( r >= 0 && status.gDlistCount - g_uRecentCIInfoPtrs[r]->lastUsedFrame <= 3 && g_uRecentCIInfoPtrs[r]->bCopied == false )423{424DEBUGGER_IF_DUMP((logTextureBuffer&&r==1),TRACE2("Hit current front buffer at %08X, size=0x%X", addr, memsize));425DEBUGGER_IF_DUMP((logTextureBuffer&&r==0),TRACE2("Hit current back buffer at %08X, size=0x%X", addr, memsize));426DEBUGGER_IF_DUMP((logTextureBuffer&&r>1),TRACE2("Hit old back buffer at %08X, size=0x%X", addr, memsize));427428SaveBackBuffer(r, NULL, true);429}430431return r;432}433434435uint8 CIFindIndex(uint16 val)436{437for( int i=0; i<=0xFF; i++ )438{439if( val == g_wRDPTlut[i] )440{441return (uint8)i;442}443}444return 0;445}446447448void TexRectToFrameBuffer_8b(uint32 dwXL, uint32 dwYL, uint32 dwXH, uint32 dwYH, float t0u0, float t0v0, float t0u1, float t0v1, uint32 dwTile)449{450// Copy the framebuffer texture into the N64 framebuffer memory451// Used in Yoshi452453/*454uint32 maxW = g_pRenderTextureInfo->CI_Info.dwWidth;455uint32 maxH = maxW*3/4;456if( status.dwTvSystem == TV_SYSTEM_PAL )457{458maxH = maxW*9/11;459}460*/461462uint32 maxW = g_pRenderTextureInfo->N64Width;463uint32 maxH = g_pRenderTextureInfo->N64Height;464465uint32 maxOff = maxW*maxH;466467TMEMLoadMapInfo &info = g_tmemLoadAddrMap[gRDP.tiles[dwTile].dwTMem];468uint32 dwWidth = dwXH-dwXL;469uint32 dwHeight = dwYH-dwYL;470471float xScale = (t0u1-t0u0)/dwWidth;472float yScale = (t0v1-t0v0)/dwHeight;473474uint8* dwSrc = g_pRDRAMu8 + info.dwLoadAddress;475uint8* dwDst = g_pRDRAMu8 + g_pRenderTextureInfo->CI_Info.dwAddr;476477uint32 dwSrcPitch = gRDP.tiles[dwTile].dwPitch;478uint32 dwDstPitch = g_pRenderTextureInfo->CI_Info.dwWidth;479480uint32 dwSrcOffX = gRDP.tiles[dwTile].hilite_sl;481uint32 dwSrcOffY = gRDP.tiles[dwTile].hilite_tl;482483uint32 dwLeft = dwXL;484uint32 dwTop = dwYL;485486dwWidth = min(dwWidth, maxW-dwLeft);487dwHeight = min(dwHeight, maxH-dwTop);488489if( maxH <= dwTop )490return;491492for (uint32 y = 0; y < dwHeight; y++)493{494uint32 dwByteOffset = (uint32)(((y*yScale+dwSrcOffY) * dwSrcPitch) + dwSrcOffX);495496for (uint32 x = 0; x < dwWidth; x++)497{498if( (((y+dwTop)*dwDstPitch+x+dwLeft)^0x3) > maxOff )499{500#ifdef DEBUGGER501TRACE0("Warning: Offset exceeds limit");502#endif503continue;504}505dwDst[((y+dwTop)*dwDstPitch+x+dwLeft)^0x3] = dwSrc[(uint32)(dwByteOffset+x*xScale) ^ 0x3];506}507}508509TXTRBUF_DUMP(DebuggerAppendMsg("TexRect To FrameBuffer: X0=%d, Y0=%d, X1=%d, Y1=%d,\n\t\tfS0=%f, fT0=%f, fS1=%f, fT1=%f ",510dwXL, dwYL, dwXH, dwYH, t0v0, t0v0, t0u1, t0v1););511}512513void TexRectToN64FrameBuffer_16b(uint32 x0, uint32 y0, uint32 width, uint32 height, uint32 dwTile)514{515// Copy the framebuffer texture into the N64 RDRAM framebuffer memory structure516517DrawInfo srcInfo;518if( g_textures[dwTile].m_pCTexture->StartUpdate(&srcInfo) == false )519{520DebuggerAppendMsg("Fail to lock texture:TexRectToN64FrameBuffer_16b" );521return;522}523524uint32 n64CIaddr = g_CI.dwAddr;525uint32 n64CIwidth = g_CI.dwWidth;526527for (uint32 y = 0; y < height; y++)528{529uint32* pSrc = (uint32*)((uint8*)srcInfo.lpSurface + y * srcInfo.lPitch);530uint16* pN64Buffer = (uint16*)(g_pRDRAMu8+(n64CIaddr&(g_dwRamSize-1)))+(y+y0)*n64CIwidth;531532for (uint32 x = 0; x < width; x++)533{534pN64Buffer[x+x0] = ConvertRGBATo555(pSrc[x]);535}536}537538g_textures[dwTile].m_pCTexture->EndUpdate(&srcInfo);539}540541#define FAST_CRC_CHECKING_INC_X 13542#define FAST_CRC_CHECKING_INC_Y 11543#define FAST_CRC_MIN_Y_INC 2544#define FAST_CRC_MIN_X_INC 2545#define FAST_CRC_MAX_X_INC 7546#define FAST_CRC_MAX_Y_INC 3547extern uint32 dwAsmHeight;548extern uint32 dwAsmPitch;549extern uint32 dwAsmdwBytesPerLine;550extern uint32 dwAsmCRC;551extern uint8* pAsmStart;552553uint32 CalculateRDRAMCRC(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes )554{555dwAsmCRC = 0;556dwAsmdwBytesPerLine = ((width<<size)+1)/2;557558if( currentRomOptions.bFastTexCRC && !options.bLoadHiResTextures && (height>=32 || (dwAsmdwBytesPerLine>>2)>=16))559{560uint32 realWidthInDWORD = dwAsmdwBytesPerLine>>2;561uint32 xinc = realWidthInDWORD / FAST_CRC_CHECKING_INC_X;562if( xinc < FAST_CRC_MIN_X_INC )563{564xinc = min(FAST_CRC_MIN_X_INC, width);565}566if( xinc > FAST_CRC_MAX_X_INC )567{568xinc = FAST_CRC_MAX_X_INC;569}570571uint32 yinc = height / FAST_CRC_CHECKING_INC_Y;572if( yinc < FAST_CRC_MIN_Y_INC )573{574yinc = min(FAST_CRC_MIN_Y_INC, height);575}576if( yinc > FAST_CRC_MAX_Y_INC )577{578yinc = FAST_CRC_MAX_Y_INC;579}580581uint32 pitch = pitchInBytes>>2;582register uint32 *pStart = (uint32*)(pPhysicalAddress);583pStart += (top * pitch) + (((left<<size)+1)>>3);584585// The original assembly code had a bug in it (it incremented pStart by 'pitch' in bytes, not in dwords)586// This C code implements the same algorithm as the ASM but without the bug587uint32 y = 0;588while (y < height)589{590uint32 x = 0;591while (x < realWidthInDWORD)592{593dwAsmCRC = (dwAsmCRC << 4) + ((dwAsmCRC >> 28) & 15);594dwAsmCRC += pStart[x];595x += xinc;596dwAsmCRC += x;597}598dwAsmCRC ^= y;599y += yinc;600pStart += pitch;601}602}603else604{605try606{607dwAsmdwBytesPerLine = ((width<<size)+1)/2;608609pAsmStart = (uint8*)(pPhysicalAddress);610pAsmStart += (top * pitchInBytes) + (((left<<size)+1)>>1);611612dwAsmHeight = height - 1;613dwAsmPitch = pitchInBytes;614615#if defined(NO_ASM)616uint32 pitch = pitchInBytes>>2;617uint32* pStart = (uint32*)pPhysicalAddress;618pStart += (top * pitch) + (((left<<size)+1)>>3);619620int y = dwAsmHeight;621622while(y >= 0)623{624uint32 esi = 0;625int x = dwAsmdwBytesPerLine - 4;626while(x >= 0)627{628esi = *(uint32*)(pAsmStart + x);629esi ^= x;630631dwAsmCRC = (dwAsmCRC << 4) + ((dwAsmCRC >> 28) & 15);632dwAsmCRC += esi;633x-=4;634}635esi ^= y;636dwAsmCRC += esi;637pAsmStart += dwAsmPitch;638y--;639}640641#elif !defined(__GNUC__) // !defined(NO_ASM)642__asm643{644push eax645push ebx646push ecx647push edx648push esi649650mov ecx, pAsmStart; // = pStart651mov edx, 0 // The CRC652mov eax, dwAsmHeight // = y653l2: mov ebx, dwAsmdwBytesPerLine // = x654sub ebx, 4655l1: mov esi, [ecx+ebx]656xor esi, ebx657rol edx, 4658add edx, esi659sub ebx, 4660jge l1661xor esi, eax662add edx, esi663add ecx, dwAsmPitch664dec eax665jge l2666667mov dwAsmCRC, edx668669pop esi670pop edx671pop ecx672pop ebx673pop eax674}675#elif defined(__x86_64__) // defined(__GNUC__) && !defined(NO_ASM)676asm volatile(" xorl %k2, %k2 \n"677" movslq %k4, %q4 \n"678"0: \n"679" movslq %3, %%rbx \n"680" sub $4, %%rbx \n"681"1: \n"682" movl (%0,%%rbx,1), %%eax \n"683" xorl %%ebx, %%eax \n"684" roll $4, %k2 \n"685" addl %%eax, %k2 \n"686" sub $4, %%rbx \n"687" jge 1b \n"688" xorl %k1, %%eax \n"689" addl %%eax, %k2 \n"690" add %q4, %0 \n"691" decl %k1 \n"692" jge 0b \n"693: "+r"(pAsmStart), "+r"(dwAsmHeight), "=&r"(dwAsmCRC)694: "m"(dwAsmdwBytesPerLine), "r"(dwAsmPitch)695: "%rbx", "%rax", "memory", "cc"696);697#elif !defined(__PIC__) // !defined(__x86_64__) && defined(__GNUC__) && !defined(NO_ASM)698asm volatile("pusha \n"699"mov %[pAsmStart], %%ecx \n" // = pStart700"mov $0, %%edx \n" // The CRC701"mov %[dwAsmHeight], %%eax \n" // = y702"0: \n" //l2:703"mov %[dwAsmdwBytesPerLine], %%ebx \n" // = x704"sub $4, %%ebx \n"705"1: \n" //l1:706"mov (%%ecx,%%ebx), %%esi \n"707"xor %%ebx, %%esi \n"708"rol $4, %%edx \n"709"add %%esi, %%edx \n"710"sub $4, %%ebx \n"711"jge 1b \n" //jge l1712"xor %%eax, %%esi \n"713"add %%esi, %%edx \n"714"add %[dwAsmPitch], %%ecx \n"715"dec %%eax \n"716"jge 0b \n" //jge l2717718"mov %%edx, %[dwAsmCRC] \n"719"popa \n"720: [pAsmStart]"+m"(pAsmStart), [dwAsmHeight]"+m"(dwAsmHeight), [dwAsmCRC]"=m"(dwAsmCRC)721: [dwAsmdwBytesPerLine]"m"(dwAsmdwBytesPerLine), [dwAsmPitch]"m"(dwAsmPitch)722: "memory", "cc"723);724#else // defined(__PIC__) && !defined(__x86_64__) && defined(__GNUC__) && !defined(NO_ASM)725unsigned int saveEBX;726unsigned int saveEAX;727unsigned int saveECX;728unsigned int saveEDX;729unsigned int saveESI;730unsigned int asmdwBytesPerLine = dwAsmdwBytesPerLine;731unsigned int asmPitch = dwAsmPitch;732unsigned int asmHeight = dwAsmHeight;733unsigned int asmCRC;734asm volatile("mov %%ebx, %2 \n"735"mov %%eax, %5 \n"736"mov %%ecx, %7 \n"737"mov %%edx, %8 \n"738"mov %%esi, %9 \n"739"mov %0, %%ecx \n" // = pStart740"mov $0, %%edx \n" // The CRC741"mov %1, %%eax \n" // = y742"0: \n" //l2:743"mov %3, %%ebx \n" // = x744"sub $4, %%ebx \n"745"1: \n" //l1:746"mov (%%ecx,%%ebx), %%esi \n"747"xor %%ebx, %%esi \n"748"rol $4, %%edx \n"749"add %%esi, %%edx \n"750"sub $4, %%ebx \n"751"jge 1b \n" //jge l1752"xor %%eax, %%esi \n"753"add %%esi, %%edx \n"754"add %4, %%ecx \n"755"dec %%eax \n"756"jge 0b \n" //jge l2757758"mov %2, %%ebx \n"759"mov %%edx, %6 \n"760"mov %5, %%eax \n"761"mov %7, %%ecx \n"762"mov %8, %%edx \n"763"mov %9, %%esi \n"764:765: "m"(pAsmStart), "m"(asmHeight), "m"(saveEBX), "m"(asmdwBytesPerLine), "m"(asmPitch), "m"(saveEAX),766"m"(asmCRC), "m"(saveECX), "m"(saveEDX), "m"(saveESI)767: "memory", "cc"768);769dwAsmCRC = asmCRC;770#endif771}772catch(...)773{774TRACE0("Exception in texture CRC calculation");775}776}777return dwAsmCRC;778}779unsigned char CalculateMaxCI(void *pPhysicalAddress, uint32 left, uint32 top, uint32 width, uint32 height, uint32 size, uint32 pitchInBytes )780{781uint32 x, y;782unsigned char *buf;783unsigned char val = 0;784785if( TXT_SIZE_8b == size )786{787for( y = 0; y<height; y++ )788{789buf = (unsigned char*)pPhysicalAddress + left + pitchInBytes * (y+top);790for( x=0; x<width; x++ )791{792if( buf[x] > val ) val = buf[x];793if( val == 0xFF )794return 0xFF;795}796}797}798else799{800unsigned char val1,val2;801left >>= 1;802width >>= 1;803for( y = 0; y<height; y++ )804{805buf = (unsigned char*)pPhysicalAddress + left + pitchInBytes * (y+top);806for( x=0; x<width; x++ )807{808val1 = buf[x]>>4;809val2 = buf[x]&0xF;810if( val1 > val ) val = val1;811if( val2 > val ) val = val2;812if( val == 0xF )813return 0xF;814}815}816}817818return val;819}820821bool FrameBufferManager::FrameBufferInRDRAMCheckCRC()822{823RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]);824uint8 *pFrameBufferBase = (uint8*)(g_pRDRAMu8+p.dwAddr);825uint32 pitch = (p.dwWidth << p.dwSize ) >> 1;826uint32 crc = CalculateRDRAMCRC(pFrameBufferBase, 0, 0, p.dwWidth, p.dwHeight, p.dwSize, pitch);827if( crc != p.dwCRC )828{829p.dwCRC = crc;830TRACE0("Frame Buffer CRC mismitch, it is modified by CPU");831return false;832}833else834{835return true;836}837}838839extern std::vector<uint32> frameWriteRecord;840void FrameBufferManager::FrameBufferWriteByCPU(uint32 addr, uint32 size)841{842if( !frameBufferOptions.bProcessCPUWrite ) return;843//WARNING(TRACE2("Frame Buffer Write, addr=%08X, CI Addr=%08X", addr, g_CI.dwAddr));844status.frameWriteByCPU = TRUE;845frameWriteRecord.push_back(addr&(g_dwRamSize-1));846}847848extern RECT frameWriteByCPURect;849extern std::vector<RECT> frameWriteByCPURects;850extern RECT frameWriteByCPURectArray[20][20];851extern bool frameWriteByCPURectFlag[20][20];852#define FRAMEBUFFER_IN_BLOCK853bool FrameBufferManager::ProcessFrameWriteRecord()854{855int size = frameWriteRecord.size();856if( size == 0 ) return false;857858int index = FindRecentCIInfoIndex(frameWriteRecord[0]);859if( index == -1 )860{861LOG_TEXTURE(TRACE1("Frame Buffer Write to non-record addr = %08X", frameWriteRecord[0]));862frameWriteRecord.clear();863return false;864}865else866{867uint32 base = g_uRecentCIInfoPtrs[index]->dwAddr;868uint32 uwidth = g_uRecentCIInfoPtrs[index]->dwWidth;869uint32 uheight = g_uRecentCIInfoPtrs[index]->dwHeight;870uint32 upitch = uwidth<<1;871872frameWriteByCPURect.left=uwidth-1;873frameWriteByCPURect.top = uheight-1;874875frameWriteByCPURect.right=0;876frameWriteByCPURect.bottom = 0;877878int x, y, off;879880for( int i=0; i<size; i++ )881{882off = frameWriteRecord[i]-base;883if( off < (int)g_uRecentCIInfoPtrs[index]->dwMemSize )884{885y = off/upitch;886x = (off - y*upitch)>>1;887888#ifdef FRAMEBUFFER_IN_BLOCK889int xidx=x/32;890int yidx=y/24;891892RECT &rect = frameWriteByCPURectArray[xidx][yidx];893894if( !frameWriteByCPURectFlag[xidx][yidx] )895{896rect.left=rect.right=x;897rect.top=rect.bottom=y;898frameWriteByCPURectFlag[xidx][yidx]=true;899}900else901{902if( x < rect.left ) rect.left = x;903if( x > rect.right ) rect.right = x;904if( y < rect.top ) rect.top = y;905if( y > rect.bottom ) rect.bottom = y;906}907#else908if( x < frameWriteByCPURect.left ) frameWriteByCPURect.left = x;909if( x > frameWriteByCPURect.right ) frameWriteByCPURect.right = x;910if( y < frameWriteByCPURect.top ) frameWriteByCPURect.top = y;911if( y > frameWriteByCPURect.bottom ) frameWriteByCPURect.bottom = y;912#endif913}914}915916frameWriteRecord.clear();917LOG_TEXTURE(TRACE4("Frame Buffer Write: Left=%d, Top=%d, Right=%d, Bottom=%d", frameWriteByCPURect.left,918frameWriteByCPURect.top, frameWriteByCPURect.right, frameWriteByCPURect.bottom));919return true;920}921}922923void FrameBufferManager::FrameBufferReadByCPU( uint32 addr )924{925///return; // it does not work very well anyway926927928if( !frameBufferOptions.bProcessCPURead ) return;929930addr &= (g_dwRamSize-1);931int index = FindRecentCIInfoIndex(addr);932if( index == -1 )933{934// Check if this is the depth buffer935uint32 size = 2*g_RecentCIInfo[0].dwWidth*g_RecentCIInfo[0].dwHeight;936addr &= 0x3FFFFFFF;937938if( addr >= g_ZI.dwAddr && addr < g_ZI.dwAddr + size )939{940TXTRBUF_OR_CI_DUMP(TRACE1("Depth Buffer read, reported by emulator, addr=%08X", addr));941}942else943{944return;945}946}947948if( status.gDlistCount - g_uRecentCIInfoPtrs[index]->lastUsedFrame > 3 )949{950// Ok, we don't have this frame anymore951return;952}953954//TXTRBUF_OR_CI_DUMP(TRACE1("FB Read By CPU at %08X", addr));955if( g_uRecentCIInfoPtrs[index]->bCopied ) return;956//if( addr != g_uRecentCIInfoPtrs[index]->dwAddr ) return;957958TXTRBUF_OR_CI_DUMP(TRACE1("Frame Buffer read, reported by emulator, addr=%08X", addr));959uint32 size = 0x1000 - addr%0x1000;960CheckAddrInBackBuffers(addr, size, true);961962DEBUGGER_IF_DUMP(pauseAtNext,{TRACE0("Frame Buffer read");});963DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE,964{DebuggerAppendMsg("Paused after setting Frame Buffer read:\n Cur CI Addr: 0x%08x, Fmt: %s Size: %s Width: %d",965g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth);});966}967968969970extern RECT frameWriteByCPURect;971extern std::vector<RECT> frameWriteByCPURects;972extern RECT frameWriteByCPURectArray[20][20];973extern bool frameWriteByCPURectFlag[20][20];974#define FRAMEBUFFER_IN_BLOCK975976void FrameBufferManager::UpdateFrameBufferBeforeUpdateFrame()977{978if( (frameBufferOptions.bProcessCPUWrite && status.frameWriteByCPU ) ||979(frameBufferOptions.bLoadBackBufFromRDRAM && !FrameBufferInRDRAMCheckCRC() ) )980// Checks if frame buffer has been modified by CPU981// Only happens to Dr. Mario982{983if( frameBufferOptions.bProcessCPUWrite )984{985if( ProcessFrameWriteRecord() )986{987#ifdef FRAMEBUFFER_IN_BLOCK988int i,j;989for( i=0; i<20; i++)990{991for( j=0; j<20; j++ )992{993if( frameWriteByCPURectFlag[i][j] )994{995CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURectArray[i][j].left, frameWriteByCPURectArray[i][j].top,996frameWriteByCPURectArray[i][j].right-frameWriteByCPURectArray[i][j].left+1, frameWriteByCPURectArray[i][j].bottom-frameWriteByCPURectArray[i][j].top+1);997}998}999}1000for( i=0; i<20; i++)1001{1002for( j=0; j<20; j++ )1003{1004if( frameWriteByCPURectFlag[i][j] )1005{1006ClearN64FrameBufferToBlack(frameWriteByCPURectArray[i][j].left, frameWriteByCPURectArray[i][j].top,1007frameWriteByCPURectArray[i][j].right-frameWriteByCPURectArray[i][j].left+1, frameWriteByCPURectArray[i][j].bottom-frameWriteByCPURectArray[i][j].top+1);1008frameWriteByCPURectFlag[i][j] = false;1009}1010}1011}1012//memset(frameWriteByCPURectArray, 0, sizeof(frameWriteByCPURectArray));1013//memset(frameWriteByCPURectFlag, 0, sizeof(frameWriteByCPURectFlag));1014#else1015CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURect.left, frameWriteByCPURect.top,1016frameWriteByCPURect.right-frameWriteByCPURect.left, frameWriteByCPURect.bottom-frameWriteByCPURect.top);1017ClearN64FrameBufferToBlack(frameWriteByCPURect.left, frameWriteByCPURect.top,1018frameWriteByCPURect.right-frameWriteByCPURect.left+1, frameWriteByCPURect.bottom-frameWriteByCPURect.top+1);10191020/*1021int size = frameWriteByCPURects.size();1022for( int i=0; i<size; i++)1023{1024CRender::GetRender()->DrawFrameBuffer(false, frameWriteByCPURects[i].left, frameWriteByCPURects[i].top,1025frameWriteByCPURects[i].right-frameWriteByCPURects[i].left, frameWriteByCPURects[i].bottom-frameWriteByCPURects[i].top);1026ClearN64FrameBufferToBlack(frameWriteByCPURects[i].left, frameWriteByCPURects[i].top,1027frameWriteByCPURects[i].right-frameWriteByCPURects[i].left+1, frameWriteByCPURects[i].bottom-frameWriteByCPURects[i].top+1);1028}1029frameWriteByCPURects.clear();1030*/1031#endif1032}1033status.frameWriteByCPU = FALSE;1034}1035else1036{1037if (CRender::IsAvailable())1038{1039RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]);1040CRender::GetRender()->DrawFrameBuffer(false, 0,0,p.dwWidth,p.dwHeight);1041ClearN64FrameBufferToBlack();1042}1043}1044}1045}10461047uint32 FrameBufferManager::ComputeCImgHeight(SetImgInfo &info, uint32 &height)1048{1049uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction10501051for( int i=0; i<10; i++ )1052{1053uint32 w0 = *(uint32 *)(g_pRDRAMu8 + dwPC + i*8);1054uint32 w1 = *(uint32 *)(g_pRDRAMu8 + dwPC + 4 + i*8);10551056if( (w0>>24) == RDP_SETSCISSOR )1057{1058height = ((w1>>0 )&0xFFF)/4;1059TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height));1060return RDP_SETSCISSOR;1061}10621063if( (w0>>24) == RDP_FILLRECT )1064{1065uint32 x0 = ((w1>>12)&0xFFF)/4;1066uint32 y0 = ((w1>>0 )&0xFFF)/4;1067uint32 x1 = ((w0>>12)&0xFFF)/4;1068uint32 y1 = ((w0>>0 )&0xFFF)/4;10691070if( x0 == 0 && y0 == 0 )1071{1072if( x1 == info.dwWidth )1073{1074height = y1;1075TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height));1076return RDP_FILLRECT;1077}10781079if(x1 == (unsigned int)(info.dwWidth-1))1080{1081height = y1+1;1082TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height));1083return RDP_FILLRECT;1084}1085}1086}10871088if( (w0>>24) == RDP_SETCIMG )1089{1090goto step2;1091}10921093if( (w0>>24) == RDP_SETCIMG )1094{1095goto step2;1096}1097}10981099if( gRDP.scissor.left == 0 && gRDP.scissor.top == 0 && (unsigned int)gRDP.scissor.right == info.dwWidth )1100{1101height = gRDP.scissor.bottom;1102TXTRBUF_DETAIL_DUMP(TRACE1("buffer height = %d", height));1103return RDP_SETSCISSOR+1;1104}11051106step2:1107TXTRBUF_DETAIL_DUMP(TRACE0("Not sure about buffer height"));11081109height = info.dwWidth*3/4;1110if( status.dwTvSystem == TV_SYSTEM_PAL )1111{1112height = info.dwWidth*9/11;1113}11141115if( gRDP.scissor.bottom < (int)height && gRDP.scissor.bottom != 0 )1116{1117height = gRDP.scissor.bottom;1118}11191120if( info.dwAddr + height*info.dwWidth*info.dwSize >= g_dwRamSize )1121{1122height = info.dwWidth*3/4;1123if( status.dwTvSystem == TV_SYSTEM_PAL )1124{1125height = info.dwWidth*9/11;1126}11271128if( gRDP.scissor.bottom < (int)height && gRDP.scissor.bottom != 0 )1129{1130height = gRDP.scissor.bottom;1131}11321133if( info.dwAddr + height*info.dwWidth*info.dwSize >= g_dwRamSize )1134{1135height = ( g_dwRamSize - info.dwAddr ) / info.dwWidth;1136}1137}11381139TXTRBUF_DETAIL_DUMP(TRACE1("render_texture height = %d", height));1140return 0;1141}11421143int FrameBufferManager::CheckRenderTexturesWithNewCI(SetImgInfo &CIinfo, uint32 height, bool byNewTxtrBuf)1144{1145int matchidx = -1;1146uint32 memsize = ((height*CIinfo.dwWidth)>>1)<<CIinfo.dwSize;11471148for( int i=0; i<numOfTxtBufInfos; i++ )1149{1150RenderTextureInfo &info = gRenderTextureInfos[i];1151if( !info.isUsed ) continue;11521153bool covered = false;11541155if( info.CI_Info.dwAddr == CIinfo.dwAddr )1156{1157if( info.CI_Info.dwSize == CIinfo.dwSize &&1158info.CI_Info.dwWidth == CIinfo.dwWidth &&1159info.CI_Info.dwFormat == CIinfo.dwFormat &&1160info.N64Height == height1161)1162{1163// This is the same texture at the same address1164if( byNewTxtrBuf )1165{1166matchidx = i;1167break;1168}1169}11701171// At the same address, but not the same size1172//SAFE_DELETE(info.psurf);1173covered = true;1174}11751176if( !covered )1177{1178uint32 memsize2 = ((info.N64Height*info.N64Width)>>1)<<info.CI_Info.dwSize;11791180if( info.CI_Info.dwAddr > CIinfo.dwAddr && info.CI_Info.dwAddr < CIinfo.dwAddr + memsize)1181covered = true;1182else if( info.CI_Info.dwAddr+memsize2 > CIinfo.dwAddr && info.CI_Info.dwAddr+memsize2 < CIinfo.dwAddr + memsize)1183covered = true;1184else if( CIinfo.dwAddr > info.CI_Info.dwAddr && CIinfo.dwAddr < info.CI_Info.dwAddr + memsize2 )1185covered = true;1186else if( CIinfo.dwAddr+ memsize > info.CI_Info.dwAddr && CIinfo.dwAddr+ memsize < info.CI_Info.dwAddr + memsize2 )1187covered = true;1188}11891190if( covered )1191{1192//SAFE_DELETE(info.psurf);1193if( info.pRenderTexture->IsBeingRendered() )1194{1195TRACE0("Error, covering a render_texture which is being rendered");1196TRACE3("New addrr=%08X, width=%d, height=%d", CIinfo.dwAddr, CIinfo.dwWidth, height );1197TRACE3("Old addrr=%08X, width=%d, height=%d", info.CI_Info.dwAddr, info.N64Width, info.N64Height );1198}1199info.isUsed = false;1200TXTRBUF_DUMP(TRACE5("Delete txtr buf %d at %08X, covered by new CI at %08X, Width=%d, Height=%d",1201i, info.CI_Info.dwAddr, CIinfo.dwAddr, CIinfo.dwWidth, height ));1202SAFE_DELETE(info.pRenderTexture);1203info.txtEntry.pTexture = NULL;1204continue;1205}1206}12071208return matchidx;1209}12101211extern RecentCIInfo *g_uRecentCIInfoPtrs[5];1212RenderTextureInfo newRenderTextureInfo;12131214int FrameBufferManager::FindASlot(void)1215{1216int idx;12171218// Find an empty slot1219bool found = false;1220for( int i=0; i<numOfTxtBufInfos; i++ )1221{1222if( !gRenderTextureInfos[i].isUsed && gRenderTextureInfos[i].updateAtFrame < status.gDlistCount )1223{1224found = true;1225idx = i;1226break;1227}1228}12291230// If cannot find an empty slot, find the oldest slot and reuse the slot1231if( !found )1232{1233uint32 oldestCount=0xFFFFFFFF;1234uint32 oldestIdx = 0;1235for( int i=0; i<numOfTxtBufInfos; i++ )1236{1237if( gRenderTextureInfos[i].updateAtUcodeCount < oldestCount )1238{1239oldestCount = gRenderTextureInfos[i].updateAtUcodeCount;1240oldestIdx = i;1241}1242}12431244idx = oldestIdx;1245}12461247DEBUGGER_IF_DUMP((logTextureBuffer && gRenderTextureInfos[idx].pRenderTexture ),TRACE2("Delete txtr buf %d at %08X, to reuse it.", idx, gRenderTextureInfos[idx].CI_Info.dwAddr ));1248SAFE_DELETE(gRenderTextureInfos[idx].pRenderTexture) ;12491250return idx;1251}125212531254void FrameBufferManager::SetRenderTexture(void)1255{1256memcpy(&(newRenderTextureInfo.CI_Info), &g_CI, sizeof(SetImgInfo));12571258newRenderTextureInfo.N64Width = newRenderTextureInfo.CI_Info.dwWidth;1259newRenderTextureInfo.knownHeight = ComputeCImgHeight(g_CI, newRenderTextureInfo.N64Height);12601261status.bHandleN64RenderTexture = true;1262newRenderTextureInfo.maxUsedHeight = 0;12631264if( defaultRomOptions.bInN64Resolution )1265{1266newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width;1267newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height;1268}1269else if( defaultRomOptions.bDoubleSizeForSmallTxtrBuf && newRenderTextureInfo.N64Width<=128 && newRenderTextureInfo.N64Height<=128)1270{1271newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width*2;1272newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height*2;1273}1274else1275{1276newRenderTextureInfo.bufferWidth = newRenderTextureInfo.N64Width;1277newRenderTextureInfo.bufferHeight = newRenderTextureInfo.N64Height;1278}12791280newRenderTextureInfo.scaleX = newRenderTextureInfo.bufferWidth / float(newRenderTextureInfo.N64Width);1281newRenderTextureInfo.scaleY = newRenderTextureInfo.bufferHeight / float(newRenderTextureInfo.N64Height);12821283status.bFrameBufferIsDrawn = false;1284status.bFrameBufferDrawnByTriangles = false;12851286newRenderTextureInfo.updateAtFrame = status.gDlistCount;1287newRenderTextureInfo.updateAtUcodeCount = status.gUcodeCount;12881289// Delay activation of the render_texture until the 1st rendering12901291TXTRBUF_DUMP(TRACE1("Set render_texture: addr=%08X", g_CI.dwAddr));1292DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE,1293{DebuggerAppendMsg("Paused after setting render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d",1294g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth, g_pRenderTextureInfo->N64Height);});1295}12961297int FrameBufferManager::SetBackBufferAsRenderTexture(SetImgInfo &CIinfo, int ciInfoIdx)1298{1299// MUDLORD:1300// OK, heres the drill!1301//1302// We set the graphics card's back buffer's contents as a render_texure1303// This is done due to how the current framebuffer implementation detects1304// changes to the backbuffer memory pointer and then we do a texture1305// copy. This might be slow since it doesnt use hardware auxillary buffers13061307RenderTextureInfo tempRenderTextureInfo;13081309memcpy(&(tempRenderTextureInfo.CI_Info), &CIinfo, sizeof(SetImgInfo));13101311tempRenderTextureInfo.N64Width = g_uRecentCIInfoPtrs[ciInfoIdx]->dwLastWidth;1312tempRenderTextureInfo.N64Height = g_uRecentCIInfoPtrs[ciInfoIdx]->dwLastHeight;1313tempRenderTextureInfo.knownHeight = true;1314tempRenderTextureInfo.maxUsedHeight = 0;13151316tempRenderTextureInfo.bufferWidth = windowSetting.uDisplayWidth;1317tempRenderTextureInfo.bufferHeight = windowSetting.uDisplayHeight;13181319tempRenderTextureInfo.scaleX = tempRenderTextureInfo.bufferWidth / float(tempRenderTextureInfo.N64Width);1320tempRenderTextureInfo.scaleY = tempRenderTextureInfo.bufferHeight / float(tempRenderTextureInfo.N64Height);13211322status.bFrameBufferIsDrawn = false;1323status.bFrameBufferDrawnByTriangles = false;13241325tempRenderTextureInfo.updateAtFrame = status.gDlistCount;1326tempRenderTextureInfo.updateAtUcodeCount = status.gUcodeCount;13271328// Checking against previous render_texture infos1329//uint32 memsize = ((tempRenderTextureInfo.N64Height*tempRenderTextureInfo.N64Width)>>1)<<tempRenderTextureInfo.CI_Info.dwSize;1330int matchidx = CheckRenderTexturesWithNewCI(CIinfo,tempRenderTextureInfo.N64Height,false);1331int idxToUse = (matchidx >= 0) ? matchidx : FindASlot();13321333if( gRenderTextureInfos[idxToUse].pRenderTexture == NULL || matchidx < 0 )1334{1335gRenderTextureInfos[idxToUse].pRenderTexture =1336new COGLRenderTexture(tempRenderTextureInfo.bufferWidth, tempRenderTextureInfo.bufferHeight, &gRenderTextureInfos[idxToUse], AS_BACK_BUFFER_SAVE);1337}13381339// Need to set all variables for gRenderTextureInfos[idxToUse]1340CRenderTexture *pRenderTexture = gRenderTextureInfos[idxToUse].pRenderTexture;1341memcpy(&gRenderTextureInfos[idxToUse], &tempRenderTextureInfo, sizeof(RenderTextureInfo) );1342gRenderTextureInfos[idxToUse].pRenderTexture = pRenderTexture;1343gRenderTextureInfos[idxToUse].isUsed = true;1344gRenderTextureInfos[idxToUse].txtEntry.pTexture = pRenderTexture->m_pTexture;1345gRenderTextureInfos[idxToUse].txtEntry.txtrBufIdx = idxToUse+1;13461347TXTRBUF_DUMP(TRACE2("Set back buf as render_texture %d, addr=%08X", idxToUse, CIinfo.dwAddr));1348DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE,1349{DebuggerAppendMsg("Paused after setting render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d",1350CIinfo.dwAddr, pszImgFormat[CIinfo.dwFormat], pszImgSize[CIinfo.dwSize], CIinfo.dwWidth, g_pRenderTextureInfo->N64Height);});13511352return idxToUse;1353}13541355void FrameBufferManager::CloseRenderTexture(bool toSave)1356{1357if( m_curRenderTextureIndex < 0 )1358return;13591360status.bHandleN64RenderTexture = false;1361if( status.bDirectWriteIntoRDRAM )1362{1363// TODO: Implement1364}1365else1366{1367RestoreNormalBackBuffer();1368if( !toSave || !status.bFrameBufferIsDrawn || !status.bFrameBufferDrawnByTriangles )1369{1370TXTRBUF_DUMP(TRACE0("Closing render_texture without save"););1371SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture);1372gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false;1373TXTRBUF_DUMP(TRACE1("Delete render_texture %d",m_curRenderTextureIndex););1374}1375else1376{1377TXTRBUF_DUMP(TRACE1("Closing render_texture %d", m_curRenderTextureIndex););1378StoreRenderTextureToRDRAM();13791380if( frameBufferOptions.bRenderTextureWriteBack )1381{1382SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture);1383gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false;1384TXTRBUF_DUMP(TRACE1("Delete render_texture %d after writing back to RDRAM",m_curRenderTextureIndex););1385}1386else1387{1388g_pRenderTextureInfo->crcInRDRAM = ComputeRenderTextureCRCInRDRAM(m_curRenderTextureIndex);1389g_pRenderTextureInfo->crcCheckedAtFrame = status.gDlistCount;1390}1391}1392}13931394SetScreenMult(windowSetting.uDisplayWidth/windowSetting.fViWidth, windowSetting.uDisplayHeight/windowSetting.fViHeight);1395CRender::g_pRender->UpdateClipRectangle();1396CRender::g_pRender->ApplyScissorWithClipRatio();13971398DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE,1399{1400DebuggerAppendMsg("Paused after saving render_texture %d:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d", m_curRenderTextureIndex,1401g_pRenderTextureInfo->CI_Info.dwAddr, pszImgFormat[g_pRenderTextureInfo->CI_Info.dwFormat], pszImgSize[g_pRenderTextureInfo->CI_Info.dwSize], g_pRenderTextureInfo->CI_Info.dwWidth);1402});1403}14041405void FrameBufferManager::ClearN64FrameBufferToBlack(uint32 left, uint32 top, uint32 width, uint32 height)1406{1407RecentCIInfo &p = *(g_uRecentCIInfoPtrs[0]);1408uint16 *frameBufferBase = (uint16*)(g_pRDRAMu8+p.dwAddr);1409uint32 pitch = p.dwWidth;14101411if( width == 0 || height == 0 )1412{1413uint32 len = p.dwHeight*p.dwWidth*p.dwSize;1414if( p.dwSize == TXT_SIZE_4b ) len = (p.dwHeight*p.dwWidth)>>1;1415memset(frameBufferBase, 0, len);1416}1417else1418{1419for( uint32 y=0; y<height; y++)1420{1421for( uint32 x=0; x<width; x++ )1422{1423*(frameBufferBase+(y+top)*pitch+x+left) = 0;1424}1425}1426}1427}14281429uint8 RevTlutTable[0x10000];1430bool RevTlutTableNeedUpdate = false;1431void InitTlutReverseLookup(void)1432{1433if( RevTlutTableNeedUpdate )1434{1435memset(RevTlutTable, 0, 0x10000);1436for( int i=0; i<=0xFF; i++ )1437{1438RevTlutTable[g_wRDPTlut[i]] = uint8(i);1439}14401441RevTlutTableNeedUpdate = false;1442}1443}144414451446// Copies backbuffer to N64 framebuffer by notification by emu core1447// **buggy**1448void FrameBufferManager::CopyBackToFrameBufferIfReadByCPU(uint32 addr)1449{1450int i = FindRecentCIInfoIndex(addr);1451if( i != -1 )1452{1453//if( i == 0 ) CGraphicsContext::Get()->UpdateFrame();1454RecentCIInfo *info = g_uRecentCIInfoPtrs[i];1455StoreBackBufferToRDRAM( info->dwAddr, info->dwFormat, info->dwSize, info->dwWidth, info->dwHeight,1456windowSetting.uDisplayWidth, windowSetting.uDisplayHeight, addr, 0x1000-addr%0x1000);1457TRACE1("Copy back for CI Addr=%08X", info->dwAddr);1458}1459}14601461// We do these checks to see if a render_texture operation is occurring...1462void FrameBufferManager::CheckRenderTextureCRCInRDRAM(void)1463{1464for( int i=0; i<numOfTxtBufInfos; i++ )1465{1466if( !gRenderTextureInfos[i].isUsed )1467continue;14681469if( gRenderTextureInfos[i].pRenderTexture->IsBeingRendered() )1470continue;14711472if( gRenderTextureInfos[i].crcCheckedAtFrame < status.gDlistCount )1473{1474uint32 crc = ComputeRenderTextureCRCInRDRAM(i);1475if( gRenderTextureInfos[i].crcInRDRAM != crc )1476{1477// RDRAM has been modified by CPU core1478TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, CRC in RDRAM changed", i, gRenderTextureInfos[i].CI_Info.dwAddr ));1479SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture);1480gRenderTextureInfos[i].isUsed = false;1481continue;1482}1483else1484{1485gRenderTextureInfos[i].crcCheckedAtFrame = status.gDlistCount;1486}1487}1488}1489}14901491// Check render_texture memory addresses1492int FrameBufferManager::CheckAddrInRenderTextures(uint32 addr, bool checkcrc)1493{1494for( int i=0; i<numOfTxtBufInfos; i++ )1495{1496if( !gRenderTextureInfos[i].isUsed )1497continue;14981499if( gRenderTextureInfos[i].pRenderTexture->IsBeingRendered() )1500continue;15011502uint32 bufHeight = gRenderTextureInfos[i].knownHeight ? gRenderTextureInfos[i].N64Height : gRenderTextureInfos[i].maxUsedHeight;1503uint32 bufMemSize = gRenderTextureInfos[i].CI_Info.dwSize*gRenderTextureInfos[i].N64Width*bufHeight;1504if( addr >=gRenderTextureInfos[i].CI_Info.dwAddr && addr < gRenderTextureInfos[i].CI_Info.dwAddr+bufMemSize)1505{1506if(checkcrc)1507{1508// Check the CRC in RDRAM1509if( gRenderTextureInfos[i].crcCheckedAtFrame < status.gDlistCount )1510{1511uint32 crc = ComputeRenderTextureCRCInRDRAM(i);1512if( gRenderTextureInfos[i].crcInRDRAM != crc )1513{1514// RDRAM has been modified by CPU core1515TRACE3("Buf %d CRC in RDRAM changed from %08X to %08X", i, gRenderTextureInfos[i].crcInRDRAM, crc );1516TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, crcInRDRAM failed.", i, gRenderTextureInfos[i].CI_Info.dwAddr ));1517SAFE_DELETE(gRenderTextureInfos[i].pRenderTexture);1518gRenderTextureInfos[i].isUsed = false;1519continue;1520}1521else1522{1523gRenderTextureInfos[i].crcCheckedAtFrame = status.gDlistCount;1524}1525}1526}15271528TXTRBUF_DUMP(TRACE2("Loading texture addr = %08X from txtr buf %d", addr, i));1529return i;1530}1531}15321533return -1;1534}15351536// Load texture from render_texture buffer1537void FrameBufferManager::LoadTextureFromRenderTexture(TxtrCacheEntry* pEntry, int infoIdx)1538{1539if( infoIdx < 0 || infoIdx >= numOfTxtBufInfos )1540{1541infoIdx = CheckAddrInRenderTextures(pEntry->ti.Address);1542}15431544if( infoIdx >= 0 && gRenderTextureInfos[infoIdx].isUsed && gRenderTextureInfos[infoIdx].pRenderTexture )1545{1546TXTRBUF_DUMP(TRACE1("Loading from render_texture %d", infoIdx));1547gRenderTextureInfos[infoIdx].pRenderTexture->LoadTexture(pEntry);1548}1549}15501551void FrameBufferManager::RestoreNormalBackBuffer()1552{1553if( m_curRenderTextureIndex >= 0 && m_curRenderTextureIndex < numOfTxtBufInfos )1554{1555if( gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture )1556gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture->SetAsRenderTarget(false);1557m_isRenderingToTexture = false;1558m_lastTextureBufferIndex = m_curRenderTextureIndex;1559}15601561if( !status.bFrameBufferIsDrawn || !status.bFrameBufferDrawnByTriangles )1562{1563gRenderTextureInfos[m_curRenderTextureIndex].isUsed = false;1564TXTRBUF_DUMP(TRACE2("Delete txtr buf %d at %08X, it is never rendered", m_curRenderTextureIndex, gRenderTextureInfos[m_curRenderTextureIndex].CI_Info.dwAddr ));1565SAFE_DELETE(gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture);1566}1567}15681569uint32 FrameBufferManager::ComputeRenderTextureCRCInRDRAM(int infoIdx)1570{1571if( infoIdx >= numOfTxtBufInfos || infoIdx < 0 || !gRenderTextureInfos[infoIdx].isUsed )1572return 0;15731574RenderTextureInfo &info = gRenderTextureInfos[infoIdx];1575uint32 height = info.knownHeight ? info.N64Height : info.maxUsedHeight;1576uint8 *pAddr = (uint8*)(g_pRDRAMu8+info.CI_Info.dwAddr);1577uint32 pitch = (info.N64Width << info.CI_Info.dwSize ) >> 1;15781579return CalculateRDRAMCRC(pAddr, 0, 0, info.N64Width, height, info.CI_Info.dwSize, pitch);1580}15811582// Activates texture buffer for drawing1583void FrameBufferManager::ActiveTextureBuffer(void)1584{1585status.bCIBufferIsRendered = true;15861587if( status.bHandleN64RenderTexture )1588{1589// Checking against previous render_texture infos1590int matchidx = -1;15911592//uint32 memsize = ((newRenderTextureInfo.N64Height*newRenderTextureInfo.N64Width)>>1)<<newRenderTextureInfo.CI_Info.dwSize;15931594matchidx = CheckRenderTexturesWithNewCI(g_CI,newRenderTextureInfo.N64Height,true);15951596int idxToUse=-1;1597if( matchidx >= 0 )1598{1599// Reuse the matched slot1600idxToUse = matchidx;1601}1602else1603{1604idxToUse = FindASlot();1605}16061607if( gRenderTextureInfos[idxToUse].pRenderTexture == NULL || matchidx < 0 )1608{1609int w = newRenderTextureInfo.bufferWidth;1610if( newRenderTextureInfo.knownHeight == RDP_SETSCISSOR && newRenderTextureInfo.CI_Info.dwAddr == g_ZI.dwAddr )1611{1612w = gRDP.scissor.right;1613}16141615gRenderTextureInfos[idxToUse].pRenderTexture =1616new COGLRenderTexture(w, newRenderTextureInfo.bufferHeight, &gRenderTextureInfos[idxToUse], AS_RENDER_TARGET);1617}16181619// Need to set all variables for gRenderTextureInfos[idxToUse]1620CRenderTexture *pRenderTexture = gRenderTextureInfos[idxToUse].pRenderTexture;1621memcpy(&gRenderTextureInfos[idxToUse], &newRenderTextureInfo, sizeof(RenderTextureInfo) );1622gRenderTextureInfos[idxToUse].pRenderTexture = pRenderTexture;1623gRenderTextureInfos[idxToUse].isUsed = true;1624gRenderTextureInfos[idxToUse].txtEntry.pTexture = pRenderTexture->m_pTexture;1625gRenderTextureInfos[idxToUse].txtEntry.txtrBufIdx = idxToUse+1;16261627g_pRenderTextureInfo = &gRenderTextureInfos[idxToUse];16281629// Active the render_texture1630if( m_curRenderTextureIndex >= 0 && gRenderTextureInfos[m_curRenderTextureIndex].isUsed && gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture )1631{1632gRenderTextureInfos[m_curRenderTextureIndex].pRenderTexture->SetAsRenderTarget(false);1633m_isRenderingToTexture = false;1634}16351636if( gRenderTextureInfos[idxToUse].pRenderTexture->SetAsRenderTarget(true) )1637{1638m_isRenderingToTexture = true;16391640//Clear(CLEAR_COLOR_AND_DEPTH_BUFFER,0x80808080,1.0f);1641if( frameBufferOptions.bFillRectNextTextureBuffer )1642CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,gRDP.fillColor,1.0f);1643else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && g_pRenderTextureInfo->N64Width > 64 && g_pRenderTextureInfo->N64Width < 300 )1644{1645CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,0,1.0f);1646}1647else if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS && g_pRenderTextureInfo->N64Width < 64 && g_pRenderTextureInfo->N64Width > 32 )1648{1649CGraphicsContext::g_pGraphicsContext->Clear(CLEAR_COLOR_BUFFER,0,1.0f);1650}16511652m_curRenderTextureIndex = idxToUse;16531654status.bDirectWriteIntoRDRAM = false;16551656//SetScreenMult(1, 1);1657SetScreenMult(gRenderTextureInfos[m_curRenderTextureIndex].scaleX, gRenderTextureInfos[m_curRenderTextureIndex].scaleY);1658CRender::g_pRender->UpdateClipRectangle();16591660// If needed, draw RDRAM into the render_texture1661//if( frameBufferOptions.bLoadRDRAMIntoRenderTexture )1662//{1663// CRender::GetRender()->LoadTxtrBufFromRDRAM();1664//}1665}1666else1667{1668if( CDeviceBuilder::m_deviceGeneralType == DIRECTX_DEVICE )1669{1670TRACE1("Error to set Render Target: %d", idxToUse);1671TRACE1("Addr = %08X", gRenderTextureInfos[idxToUse].CI_Info.dwAddr);1672TRACE2("Width = %d, Height=%d", gRenderTextureInfos[idxToUse].N64Width, gRenderTextureInfos[idxToUse].N64Height);1673}1674}167516761677TXTRBUF_DUMP(TRACE2("Rendering to render_texture %d, addr=%08X", idxToUse, g_CI.dwAddr));1678DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_RENDER_TEXTURE,1679{DebuggerAppendMsg("Paused after activating render_texture:\nAddr: 0x%08x, Fmt: %s Size: %s Width: %d, Height:%d",1680g_CI.dwAddr, pszImgFormat[g_CI.dwFormat], pszImgSize[g_CI.dwSize], g_CI.dwWidth, g_pRenderTextureInfo->N64Height);});1681}1682else1683{1684UpdateRecentCIAddr(g_CI);1685CheckRenderTexturesWithNewCI(g_CI,gRDP.scissor.bottom,false);1686}1687}16881689#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;}16901691// Sets CI address for framebuffer copies1692void FrameBufferManager::Set_CI_addr(SetImgInfo &newCI)1693{1694bool wasDrawingTextureBuffer = status.bN64IsDrawingTextureBuffer;1695status.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)) );1696status.bN64FrameBufferIsUsed = status.bN64IsDrawingTextureBuffer;16971698if( !wasDrawingTextureBuffer && g_CI.dwAddr == g_ZI.dwAddr && status.bCIBufferIsRendered )1699{1700TXTRBUF_DUMP(TRACE0("ZI is rendered"));17011702if( options.enableHackForGames != HACK_FOR_CONKER && g_uRecentCIInfoPtrs[0]->bCopied == false )1703{1704// Conker is not actually using a backbuffer1705g_pFrameBufferManager->UpdateRecentCIAddr(g_CI);1706if( status.leftRendered != -1 && status.topRendered != -1 && status.rightRendered != -1 && status.bottomRendered != -1 )1707{1708RECT rect={status.leftRendered,status.topRendered,status.rightRendered,status.bottomRendered};1709g_pFrameBufferManager->SaveBackBuffer(0,&rect);1710}1711else1712{1713g_pFrameBufferManager->SaveBackBuffer(0,NULL);1714}1715}1716}17171718frameBufferOptions.bFillRectNextTextureBuffer = false;1719if( g_CI.dwAddr == newCI.dwAddr && status.bHandleN64RenderTexture && (g_CI.dwFormat != newCI.dwFormat || g_CI.dwSize != newCI.dwSize || g_CI.dwWidth != newCI.dwWidth ) )1720{1721// Mario Tennis player shadow1722g_pFrameBufferManager->CloseRenderTexture(true);1723if( options.enableHackForGames == HACK_FOR_MARIO_TENNIS )1724frameBufferOptions.bFillRectNextTextureBuffer = true; // Hack for Mario Tennis1725}17261727SAVE_CI;17281729if( g_CI.dwAddr == g_ZI.dwAddr && !status.bN64IsDrawingTextureBuffer )1730{1731if( g_pFrameBufferManager->IsDIaRenderTexture() )1732{1733status.bN64IsDrawingTextureBuffer = true;1734status.bN64FrameBufferIsUsed = status.bN64IsDrawingTextureBuffer;1735}1736}17371738status.bCIBufferIsRendered = false;1739status.leftRendered = status.topRendered = status.rightRendered = status.bottomRendered = -1;17401741if( currentRomOptions.screenUpdateSetting==SCREEN_UPDATE_AT_CI_CHANGE && !status.bN64IsDrawingTextureBuffer )1742{1743if( status.curRenderBuffer == 0 )1744{1745status.curRenderBuffer = g_CI.dwAddr;1746}1747else if( status.curRenderBuffer != g_CI.dwAddr )1748{1749status.curDisplayBuffer = status.curRenderBuffer;1750CGraphicsContext::Get()->UpdateFrame();1751status.curRenderBuffer = g_CI.dwAddr;1752DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Screen Update because CI change to %08X, Display Buf=%08X", status.curRenderBuffer, status.curDisplayBuffer);});1753}1754}17551756if( frameBufferOptions.bAtEachFrameUpdate && !status.bHandleN64RenderTexture )1757{1758if( status.curRenderBuffer != g_CI.dwAddr )1759{1760if( status.gDlistCount%(currentRomOptions.N64FrameBufferWriteBackControl+1) == 0 )1761{1762g_pFrameBufferManager->StoreBackBufferToRDRAM(status.curRenderBuffer,1763newCI.dwFormat, newCI.dwSize, windowSetting.uViWidth, windowSetting.uViHeight,1764windowSetting.uDisplayWidth, windowSetting.uDisplayHeight);1765}1766}17671768//status.curDisplayBuffer = status.curRenderBuffer;1769status.curRenderBuffer = g_CI.dwAddr;1770}177117721773switch( currentRomOptions.N64RenderToTextureEmuType )1774{1775case TXT_BUF_NONE:1776if( status.bHandleN64RenderTexture )1777g_pFrameBufferManager->CloseRenderTexture(false);1778status.bHandleN64RenderTexture = false; // Don't handle N64 render_texture stuffs1779if( !status.bN64IsDrawingTextureBuffer )1780g_pFrameBufferManager->UpdateRecentCIAddr(g_CI);1781break;1782default:1783if( status.bHandleN64RenderTexture )1784{1785#ifdef DEBUGGER1786if( pauseAtNext && eventToPause == NEXT_RENDER_TEXTURE )1787{1788pauseAtNext = TRUE;1789eventToPause = NEXT_RENDER_TEXTURE;1790}1791#endif1792g_pFrameBufferManager->CloseRenderTexture(true);1793}17941795status.bHandleN64RenderTexture = status.bN64IsDrawingTextureBuffer;1796if( status.bHandleN64RenderTexture )1797{1798if( options.enableHackForGames != HACK_FOR_BANJO_TOOIE )1799{1800g_pFrameBufferManager->SetRenderTexture();1801}1802}1803else1804{1805#ifdef DEBUGGER1806if( g_CI.dwWidth == 512 && pauseAtNext && (eventToPause==NEXT_OBJ_BG || eventToPause==NEXT_SET_CIMG) )1807{1808DebuggerAppendMsg("Warning SetCImg: new Addr=0x%08X, fmt:%s size=%sb, Width=%d\n",1809g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth);1810}1811#endif1812//g_pFrameBufferManager->UpdateRecentCIAddr(g_CI); // Delay this until the CI buffer is actally drawn1813}1814break;1815}18161817TXTRBUF_DUMP(TRACE4("SetCImg : Addr=0x%08X, Fmt:%s-%sb, Width=%d\n",1818g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth));18191820DEBUGGER_PAUSE_AND_DUMP_NO_UPDATE(NEXT_SET_CIMG,1821{1822DebuggerAppendMsg("Pause after SetCImg: Addr=0x%08X, Fmt:%s-%sb, Width=%d\n",1823g_CI.dwAddr, pszImgFormat[newCI.dwFormat], pszImgSize[newCI.dwSize], newCI.dwWidth);1824}1825);1826}182718281829void FrameBufferManager::StoreRenderTextureToRDRAM(int infoIdx)1830{1831if( !frameBufferOptions.bRenderTextureWriteBack )1832return;18331834if( infoIdx < 0 )1835infoIdx = m_lastTextureBufferIndex;18361837if( !gRenderTextureInfos[infoIdx].pRenderTexture )1838return;18391840if( gRenderTextureInfos[infoIdx].pRenderTexture->IsBeingRendered() )1841{1842TXTRBUF_DUMP(TRACE1("Cannot SaveTextureBuffer %d, it is being rendered", infoIdx));1843return;1844}18451846gRenderTextureInfos[infoIdx].pRenderTexture->StoreToRDRAM(infoIdx);1847}184818491850//does FB copy to N64 RDAM structure1851void 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)1852{1853uint32 startline=0;18541855if( startaddr == 0xFFFFFFFF )1856startaddr = addr;18571858startline = (startaddr-addr)/siz/pitch;1859if( startline >= height )1860{1861//TRACE0("Warning: check me");1862startline = height;1863}18641865uint32 endline = height;1866if( memsize != 0xFFFFFFFF )1867{1868endline = (startaddr+memsize-addr)/siz;1869if( endline % pitch == 0 )1870endline /= pitch;1871else1872endline = endline/pitch+1;1873}1874if( endline > height )1875{1876endline = height;1877}18781879if( memsize != 0xFFFFFFFF )1880{1881TXTRBUF_DUMP(DebuggerAppendMsg("Start at: 0x%X, from line %d to %d", startaddr-addr, startline, endline););1882}18831884int indexes[600];1885{1886float sx;1887int sx0;1888float ratio = bufWidth/(float)width;1889for( uint32 j=0; j<width; j++ )1890{1891sx = j*ratio;1892sx0 = int(sx+0.5);1893indexes[j] = 4*sx0;1894}1895}18961897if( siz == TXT_SIZE_16b )1898{1899uint16 *frameBufferBase = (uint16*)(g_pRDRAMu8+addr);19001901if( bufFmt==TEXTURE_FMT_A8R8G8B8 )1902{1903int sy0;1904float ratio = bufHeight/(float)height;19051906for( uint32 i=startline; i<endline; i++ )1907{1908sy0 = int(i*ratio+0.5);19091910uint16 *pD = frameBufferBase + i * pitch;1911uint8 *pS0 = (uint8 *)buffer + sy0 * bufPitch;19121913for( uint32 j=0; j<width; j++ )1914{1915// Point1916uint8 r = pS0[indexes[j]+2];1917uint8 g = pS0[indexes[j]+1];1918uint8 b = pS0[indexes[j]+0];1919uint8 a = pS0[indexes[j]+3];19201921// Liner1922*(pD+(j^1)) = ConvertRGBATo555( r, g, b, a);1923}1924}1925}1926else1927{1928TRACE1("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);1929}1930}1931else if( siz == TXT_SIZE_8b && fmt == TXT_FMT_CI )1932{1933uint8 *frameBufferBase = (uint8*)(g_pRDRAMu8+addr);19341935if( bufFmt==TEXTURE_FMT_A8R8G8B8 )1936{1937uint16 tempword;1938InitTlutReverseLookup();19391940for( uint32 i=startline; i<endline; i++ )1941{1942uint8 *pD = frameBufferBase + i * width;1943uint8 *pS = (uint8 *)buffer + i*bufHeight/height * bufPitch;1944for( uint32 j=0; j<width; j++ )1945{1946int pos = 4*(j*bufWidth/width);1947tempword = ConvertRGBATo555((pS[pos+2]), // Red1948(pS[pos+1]), // Green1949(pS[pos+0]), // Blue1950(pS[pos+3])); // Alpha19511952//*pD = CIFindIndex(tempword);1953*(pD+(j^3)) = RevTlutTable[tempword];1954}1955}1956}1957else1958{1959TRACE1("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);1960}1961DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram", pszImgSize[siz]);});1962}1963else if( siz == TXT_SIZE_8b && fmt == TXT_FMT_I )1964{1965uint8 *frameBufferBase = (uint8*)(g_pRDRAMu8+addr);19661967if( bufFmt==TEXTURE_FMT_A8R8G8B8 )1968{1969int sy0;1970float ratio = bufHeight/(float)height;19711972for( uint32 i=startline; i<endline; i++ )1973{1974sy0 = int(i*ratio+0.5);19751976uint8 *pD = frameBufferBase + i * width;1977uint8 *pS0 = (uint8 *)buffer + sy0 * bufPitch;19781979for( uint32 j=0; j<width; j++ )1980{1981// Point1982uint32 r = pS0[indexes[j]+2];1983uint32 g = pS0[indexes[j]+1];1984uint32 b = pS0[indexes[j]+0];19851986// Liner1987*(pD+(j^3)) = (uint8)((r+b+g)/3);1988}1989}1990}1991else1992{1993//DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram, not implemented", pszImgSize[siz]);1994}1995DEBUGGER_IF_DUMP(pauseAtNext,{DebuggerAppendMsg("Copy %sb FrameBuffer to Rdram", pszImgSize[siz]);});1996}1997}199819992000#ifdef DEBUGGER2001void FrameBufferManager::DisplayRenderTexture(int infoIdx)2002{2003if( infoIdx < 0 )2004infoIdx = m_lastTextureBufferIndex;20052006if( gRenderTextureInfos[infoIdx].pRenderTexture )2007{2008if( gRenderTextureInfos[infoIdx].pRenderTexture->IsBeingRendered() )2009{2010TRACE1("Render texture %d is being rendered, cannot display", infoIdx);2011}2012else2013{2014TRACE1("Texture buffer %d:", infoIdx);2015TRACE1("Addr=%08X", gRenderTextureInfos[infoIdx].CI_Info.dwAddr);2016TRACE2("Width=%d, Created Height=%d", gRenderTextureInfos[infoIdx].N64Width,gRenderTextureInfos[infoIdx].N64Height);2017TRACE2("Fmt=%d, Size=%d", gRenderTextureInfos[infoIdx].CI_Info.dwFormat,gRenderTextureInfos[infoIdx].CI_Info.dwSize);2018}2019}2020else2021{2022TRACE1("Texture buffer %d is not used", infoIdx);2023}2024}2025#endif2026202720282029// Saves backbuffer2030// this is the core to the current framebuffer code2031// We need to save backbuffer when changed by framebuffer2032// so that we can use it for framebuffer effects2033void FrameBufferManager::SaveBackBuffer(int ciInfoIdx, RECT* pSrcRect, bool forceToSaveToRDRAM)2034{2035RecentCIInfo &ciInfo = *g_uRecentCIInfoPtrs[ciInfoIdx];20362037if( ciInfoIdx == 1 ) // to save the current front buffer2038{2039CGraphicsContext::g_pGraphicsContext->UpdateFrame(true);2040}20412042if( frameBufferOptions.bWriteBackBufToRDRAM || forceToSaveToRDRAM )2043{2044uint32 width = ciInfo.dwWidth;2045uint32 height = ciInfo.dwHeight;20462047if( ciInfo.dwWidth == *g_GraphicsInfo.VI_WIDTH_REG && ciInfo.dwWidth != windowSetting.uViWidth )2048{2049width = windowSetting.uViWidth;2050height = windowSetting.uViHeight;2051}20522053StoreBackBufferToRDRAM( ciInfo.dwAddr, ciInfo.dwFormat, ciInfo.dwSize, width, height,2054windowSetting.uDisplayWidth, windowSetting.uDisplayHeight);20552056g_uRecentCIInfoPtrs[ciInfoIdx]->bCopied = true;2057if( ciInfoIdx == 1 ) // to save the current front buffer2058{2059CGraphicsContext::g_pGraphicsContext->UpdateFrame(true);2060}2061return;2062}206320642065SetImgInfo tempinfo;2066tempinfo.dwAddr = ciInfo.dwAddr;2067tempinfo.dwFormat = ciInfo.dwFormat;2068tempinfo.dwSize = ciInfo.dwSize;2069tempinfo.dwWidth = ciInfo.dwWidth;20702071int idx = SetBackBufferAsRenderTexture(tempinfo, ciInfoIdx);20722073CopyBackBufferToRenderTexture(idx, ciInfo, pSrcRect);20742075gRenderTextureInfos[idx].crcCheckedAtFrame = status.gDlistCount;2076gRenderTextureInfos[idx].crcInRDRAM = ComputeRenderTextureCRCInRDRAM(idx);20772078DEBUGGER_IF_DUMP((logTextureBuffer&&pSrcRect==NULL),TRACE1("SaveBackBuffer at 0x%08X", ciInfo.dwAddr));2079DEBUGGER_IF_DUMP((logTextureBuffer&&pSrcRect),TRACE5("SaveBackBuffer at 0x%08X, {%d,%d -%d,%d)", ciInfo.dwAddr,2080pSrcRect->left,pSrcRect->top,pSrcRect->right,pSrcRect->bottom));2081DEBUGGER_IF_DUMP(( pauseAtNext && eventToPause == NEXT_RENDER_TEXTURE),{g_pFrameBufferManager->DisplayRenderTexture(idx);});20822083g_uRecentCIInfoPtrs[ciInfoIdx]->bCopied = true;2084}2085208620872088