mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-22 05:40:01 -06:00
1) XFB in DC proposal. This impact video plugin interface. WARNING: XFB_Draw is not CPU->VI dependent anymore. It's up to GP now. Except for some 2D homebrews which never use GPfifo&CP but direcly XFB. Well, in other words: emulated VSync is uncorrelated with CPU timings now. Tell me if it's too much hacky.
2) DC/GPfifo work: GP quicker to react. PeekMessages at a more steady rate. 3) Fix XFB address to avoid crash like with Animal Crossing gc. TODO: VI regs need proper typedef and logic. 4) Few misc. changes on the fly. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2001 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -7,7 +7,7 @@
|
|||||||
namespace Common {
|
namespace Common {
|
||||||
typedef void (__cdecl* TVideo_Prepare)();
|
typedef void (__cdecl* TVideo_Prepare)();
|
||||||
typedef void (__cdecl* TVideo_SendFifoData)(u8*,u32);
|
typedef void (__cdecl* TVideo_SendFifoData)(u8*,u32);
|
||||||
typedef void (__cdecl* TVideo_UpdateXFB)(u8*, u32, u32, s32);
|
typedef void (__cdecl* TVideo_UpdateXFB)(u8*, u32, u32, s32, BOOL);
|
||||||
typedef bool (__cdecl* TVideo_Screenshot)(const char* filename);
|
typedef bool (__cdecl* TVideo_Screenshot)(const char* filename);
|
||||||
typedef void (__cdecl* TVideo_EnterLoop)();
|
typedef void (__cdecl* TVideo_EnterLoop)();
|
||||||
typedef void (__cdecl* TVideo_AddMessage)(const char* pstr, unsigned int milliseconds);
|
typedef void (__cdecl* TVideo_AddMessage)(const char* pstr, unsigned int milliseconds);
|
||||||
|
@ -426,8 +426,8 @@ THREAD_RETURN EmuThread(void *pArg)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cpuThread = new Common::Thread(CpuThread, pArg);
|
|
||||||
Plugins.GetVideo()->Video_Prepare(); //wglMakeCurrent
|
Plugins.GetVideo()->Video_Prepare(); //wglMakeCurrent
|
||||||
|
cpuThread = new Common::Thread(CpuThread, pArg);
|
||||||
Common::SetCurrentThreadName("Video thread");
|
Common::SetCurrentThreadName("Video thread");
|
||||||
Plugins.GetVideo()->Video_EnterLoop();
|
Plugins.GetVideo()->Video_EnterLoop();
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,13 @@ u16 m_tokenReg;
|
|||||||
|
|
||||||
SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread
|
SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread
|
||||||
static u32 fake_GPWatchdogLastToken = 0;
|
static u32 fake_GPWatchdogLastToken = 0;
|
||||||
|
static BOOL fake_CommandProcessorNotUsed = TRUE; // This is used by VI when homebrews use directly XFB without FIFO and CP
|
||||||
|
|
||||||
|
// hack: This is used by VI when homebrews use directly XFB without FIFO and CP
|
||||||
|
BOOL IsCommandProcessorNotUsed()
|
||||||
|
{
|
||||||
|
return fake_CommandProcessorNotUsed;
|
||||||
|
}
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
@ -221,7 +228,7 @@ void Init()
|
|||||||
fifo.CPReadIdle = 1;
|
fifo.CPReadIdle = 1;
|
||||||
|
|
||||||
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
|
et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper);
|
||||||
|
fake_CommandProcessorNotUsed = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
@ -411,6 +418,7 @@ void Write16(const u16 _Value, const u32 _Address)
|
|||||||
|
|
||||||
case CTRL_REGISTER:
|
case CTRL_REGISTER:
|
||||||
{
|
{
|
||||||
|
fake_CommandProcessorNotUsed = FALSE;
|
||||||
UCPCtrlReg tmpCtrl(_Value);
|
UCPCtrlReg tmpCtrl(_Value);
|
||||||
|
|
||||||
Common::SyncInterlockedExchange((LONG*)&fifo.bFF_GPReadEnable, tmpCtrl.GPReadEnable);
|
Common::SyncInterlockedExchange((LONG*)&fifo.bFF_GPReadEnable, tmpCtrl.GPReadEnable);
|
||||||
|
@ -79,6 +79,9 @@ bool AllowIdleSkipping();
|
|||||||
void IncrementGPWDToken();
|
void IncrementGPWDToken();
|
||||||
void WaitForFrameFinish();
|
void WaitForFrameFinish();
|
||||||
|
|
||||||
|
// hack: This is used by VI when homebrews use directly XFB without FIFO and CP
|
||||||
|
BOOL IsCommandProcessorNotUsed();
|
||||||
|
|
||||||
} // end of namespace CommandProcessor
|
} // end of namespace CommandProcessor
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -810,7 +810,8 @@ u8 *GetPointer(const u32 _Address)
|
|||||||
_dbg_assert_msg_(MEMMAP, 0, "Memory", "GetPointer from IO Bridge doesnt work");
|
_dbg_assert_msg_(MEMMAP, 0, "Memory", "GetPointer from IO Bridge doesnt work");
|
||||||
return NULL;
|
return NULL;
|
||||||
default:
|
default:
|
||||||
PanicAlert("Tried to get pointer for unknown address %08x", _Address);
|
if (!PanicYesNo("Tried to get pointer for unknown address %08x\n Continue?", _Address))
|
||||||
|
Crash();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
|
|
||||||
|
#include "../Core.h" // <- for Core::GetStartupParameter().bUseDualCore
|
||||||
|
#include "CommandProcessor.h" // <- for homebrew's XFB draw hack
|
||||||
#include "PeripheralInterface.h"
|
#include "PeripheralInterface.h"
|
||||||
#include "VideoInterface.h"
|
#include "VideoInterface.h"
|
||||||
#include "Memmap.h"
|
#include "Memmap.h"
|
||||||
@ -513,30 +515,45 @@ void Update()
|
|||||||
u8* xfbPtr = 0;
|
u8* xfbPtr = 0;
|
||||||
int yOffset = 0;
|
int yOffset = 0;
|
||||||
|
|
||||||
if (NextXFBRender == 1)
|
// (mb2) hack: We request XFB updates from CPUthread (here) only when homebrews use directly XFB without FIFO and CP
|
||||||
|
if (CommandProcessor::IsCommandProcessorNotUsed())
|
||||||
{
|
{
|
||||||
NextXFBRender = LinesPerField;
|
if (NextXFBRender == 1)
|
||||||
u32 addr = (VideoInterface::m_FrameBufferTop.Hex & 0xFFFFFFF);
|
{
|
||||||
if (VideoInterface::m_FrameBufferTop.Hex & 0x10000000)
|
NextXFBRender = LinesPerField;
|
||||||
addr = addr << 5;
|
// TODO: proper VI regs typedef and logic for XFB to work.
|
||||||
xfbPtr = Memory::GetPointer(addr);
|
// eg. Animal Crossing gc have smth in TFBL.XOF bitfield.
|
||||||
}
|
// "XOF - Horizontal Offset of the left-most pixel within the first word of the fetched picture."
|
||||||
else
|
u32 addr = (m_FrameBufferTop.Hex & 0x00FFFFFF);
|
||||||
{
|
if (m_FrameBufferTop.Hex & 0x10000000)
|
||||||
NextXFBRender = 1;
|
addr = addr << 5;
|
||||||
u32 addr = (VideoInterface::m_FrameBufferBottom.Hex & 0xFFFFFFF);
|
xfbPtr = Memory::GetPointer(addr);
|
||||||
// check the top buffer address not the bottom
|
_dbg_assert_msg_(VIDEOINTERFACE, xfbPtr, "Bad top XFB address");
|
||||||
if (VideoInterface::m_FrameBufferTop.Hex & 0x10000000)
|
}
|
||||||
addr = addr << 5;
|
else
|
||||||
xfbPtr = Memory::GetPointer(addr);
|
{
|
||||||
yOffset = -1;
|
NextXFBRender = 1;
|
||||||
}
|
// TODO: proper VI regs typedef and logic for XFB to work.
|
||||||
Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo();
|
u32 addr = (m_FrameBufferBottom.Hex & 0x00FFFFFF);
|
||||||
if (xfbPtr && video->IsValid())
|
// check the top buffer address not the bottom <- (mb2) why not on the bottom one?
|
||||||
{
|
if (m_FrameBufferTop.Hex & 0x10000000)
|
||||||
int fbWidth = m_VIHorizontalStepping.FieldSteps * 16;
|
addr = addr << 5;
|
||||||
int fbHeight = (m_VIHorizontalStepping.FbSteps / m_VIHorizontalStepping.FieldSteps) * m_VIVerticalTimingRegister.ACV;
|
xfbPtr = Memory::GetPointer(addr);
|
||||||
video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset);
|
_dbg_assert_msg_(VIDEOINTERFACE, xfbPtr, "Bad bottom XFB address");
|
||||||
|
yOffset = -1;
|
||||||
|
}
|
||||||
|
Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo();
|
||||||
|
if (xfbPtr && video->IsValid())
|
||||||
|
{
|
||||||
|
int fbWidth = m_VIHorizontalStepping.FieldSteps * 16;
|
||||||
|
int fbHeight = (m_VIHorizontalStepping.FbSteps / m_VIHorizontalStepping.FieldSteps) * m_VIVerticalTimingRegister.ACV;
|
||||||
|
if (Core::GetStartupParameter().bUseDualCore)
|
||||||
|
// scheduled on EmuThread in DC mode
|
||||||
|
video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, TRUE);
|
||||||
|
else
|
||||||
|
// otherwise do it now from here (CPUthread)
|
||||||
|
video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,12 @@
|
|||||||
|
|
||||||
extern u8* g_pVideoData;
|
extern u8* g_pVideoData;
|
||||||
|
|
||||||
bool fifoStateRun = true;
|
// TODO (mb2): move/rm this global
|
||||||
|
volatile BOOL g_XFBUpdateRequested = FALSE;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
static bool fifoStateRun = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
static u8 *videoBuffer;
|
static u8 *videoBuffer;
|
||||||
@ -43,18 +48,25 @@ void Fifo_DoState(PointerWrap &p)
|
|||||||
void Fifo_Init()
|
void Fifo_Init()
|
||||||
{
|
{
|
||||||
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
|
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
|
||||||
|
#ifndef _WIN32
|
||||||
fifoStateRun = true;
|
fifoStateRun = true;
|
||||||
|
#endif
|
||||||
|
g_XFBUpdateRequested = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fifo_Shutdown()
|
void Fifo_Shutdown()
|
||||||
{
|
{
|
||||||
FreeMemoryPages(videoBuffer, FIFO_SIZE);
|
FreeMemoryPages(videoBuffer, FIFO_SIZE);
|
||||||
|
#ifndef _WIN32
|
||||||
fifoStateRun = false;
|
fifoStateRun = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fifo_Stop()
|
void Fifo_Stop()
|
||||||
{
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
fifoStateRun = false;
|
fifoStateRun = false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* FAKE_GetFifoStartPtr()
|
u8* FAKE_GetFifoStartPtr()
|
||||||
@ -97,20 +109,26 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
while (fifoStateRun)
|
while (fifoStateRun)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (_fifo.CPReadWriteDistance < _fifo.CPLoWatermark)
|
if (_fifo.CPReadWriteDistance == 0)
|
||||||
Common::SleepCurrentThread(1);
|
Common::SleepCurrentThread(1);
|
||||||
//etc...
|
//etc...
|
||||||
|
|
||||||
|
if (g_XFBUpdateRequested)
|
||||||
|
{
|
||||||
|
Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
|
||||||
|
g_XFBUpdateRequested = FALSE;
|
||||||
|
video_initialize.pCopiedToXFB();
|
||||||
|
}
|
||||||
// check if we are able to run this buffer
|
// check if we are able to run this buffer
|
||||||
if ((_fifo.bFF_GPReadEnable) && _fifo.CPReadWriteDistance && !(_fifo.bFF_BPEnable && _fifo.bFF_Breakpoint))
|
if ((_fifo.bFF_GPReadEnable) && _fifo.CPReadWriteDistance && !(_fifo.bFF_BPEnable && _fifo.bFF_Breakpoint))
|
||||||
{
|
{
|
||||||
Common::SyncInterlockedExchange((LONG*)&_fifo.CPReadIdle, 0);
|
Common::SyncInterlockedExchange((LONG*)&_fifo.CPReadIdle, 0);
|
||||||
//video_initialize.pLog("RUN...........................",FALSE);
|
//video_initialize.pLog("RUN...........................",FALSE);
|
||||||
int peek_counter = 0;
|
int peek_counter = 0;
|
||||||
while (_fifo.bFF_GPReadEnable && (_fifo.CPReadWriteDistance > 0))
|
while (_fifo.bFF_GPReadEnable && _fifo.CPReadWriteDistance)
|
||||||
{
|
{
|
||||||
peek_counter++;
|
peek_counter++;
|
||||||
if (peek_counter == 50) {
|
if (peek_counter == 1000) {
|
||||||
video_initialize.pPeekMessages();
|
video_initialize.pPeekMessages();
|
||||||
peek_counter = 0;
|
peek_counter = 0;
|
||||||
}
|
}
|
||||||
@ -146,6 +164,8 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||||||
#else
|
#else
|
||||||
// sending the whole CPReadWriteDistance
|
// sending the whole CPReadWriteDistance
|
||||||
distToSend = _fifo.CPReadWriteDistance;
|
distToSend = _fifo.CPReadWriteDistance;
|
||||||
|
// send 1024B chunk max lenght to have better control over PeekMessages' period
|
||||||
|
distToSend = distToSend > 1024 ? 1024 : distToSend;
|
||||||
if ( (distToSend+readPtr) >= _fifo.CPEnd) // TODO: better?
|
if ( (distToSend+readPtr) >= _fifo.CPEnd) // TODO: better?
|
||||||
{
|
{
|
||||||
distToSend =_fifo.CPEnd - readPtr;
|
distToSend =_fifo.CPEnd - readPtr;
|
||||||
|
@ -69,19 +69,21 @@ void _SetCol565(u16 val)
|
|||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
inline u32 _Read24(u32 iAddress)
|
inline u32 _Read24(u32 iAddress)
|
||||||
{
|
{
|
||||||
u32 col = Memory_Read_U8(iAddress) << RSHIFT; //should just get a pointer to main memory instead of going thru slow memhandler
|
// u32 col = Memory_Read_U8(iAddress) << RSHIFT; //should just get a pointer to main memory instead of going thru slow memhandler
|
||||||
col |= Memory_Read_U8(iAddress+1) << GSHIFT; //we can guarantee that it is reading from main memory
|
// col |= Memory_Read_U8(iAddress+1) << GSHIFT; //we can guarantee that it is reading from main memory
|
||||||
col |= Memory_Read_U8(iAddress+2) << BSHIFT;
|
// col |= Memory_Read_U8(iAddress+2) << BSHIFT;
|
||||||
return col | (0xFF<<ASHIFT);
|
// return col | (0xFF<<ASHIFT);
|
||||||
|
return Memory_Read_U32_Unswapped(iAddress)|0xFF000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline u32 _Read32(u32 iAddress)
|
inline u32 _Read32(u32 iAddress)
|
||||||
{
|
{
|
||||||
u32 col = Memory_Read_U8(iAddress) << RSHIFT; //should just get a pointer to main memory instead of going thru slow memhandler
|
// u32 col = Memory_Read_U8(iAddress) << RSHIFT; //should just get a pointer to main memory instead of going thru slow memhandler
|
||||||
col |= Memory_Read_U8(iAddress+1) << GSHIFT; //we can guarantee that it is reading from main memory
|
// col |= Memory_Read_U8(iAddress+1) << GSHIFT; //we can guarantee that it is reading from main memory
|
||||||
col |= Memory_Read_U8(iAddress+2) << BSHIFT;
|
// col |= Memory_Read_U8(iAddress+2) << BSHIFT;
|
||||||
col |= Memory_Read_U8(iAddress+3) << ASHIFT;
|
// col |= Memory_Read_U8(iAddress+3) << ASHIFT;
|
||||||
return col;
|
// return col;
|
||||||
|
return Memory_Read_U32_Unswapped(iAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -43,6 +43,8 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern SVideoInitialize g_VideoInitialize;
|
extern SVideoInitialize g_VideoInitialize;
|
||||||
|
// (mb2) for XFB update hack. TODO: find a static better place
|
||||||
|
extern volatile BOOL g_XFBUpdateRequested;
|
||||||
|
|
||||||
void DebugLog(const char* _fmt, ...);
|
void DebugLog(const char* _fmt, ...);
|
||||||
|
|
||||||
@ -66,6 +68,11 @@ inline u32 Memory_Read_U32(u32 _uAddress)
|
|||||||
return Common::swap32(*(u32*)g_VideoInitialize.pGetMemoryPointer(_uAddress));
|
return Common::swap32(*(u32*)g_VideoInitialize.pGetMemoryPointer(_uAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline u32 Memory_Read_U32_Unswapped(u32 _uAddress)
|
||||||
|
{
|
||||||
|
return *(u32*)g_VideoInitialize.pGetMemoryPointer(_uAddress);
|
||||||
|
}
|
||||||
|
|
||||||
inline float Memory_Read_Float(u32 _uAddress)
|
inline float Memory_Read_Float(u32 _uAddress)
|
||||||
{
|
{
|
||||||
union {u32 i; float f;} temp;
|
union {u32 i; float f;} temp;
|
||||||
|
@ -104,7 +104,7 @@ EXPORT void CALL Video_SendFifoData(u8* _uData, u32 len);
|
|||||||
// input: pointer to the XFB, width and height of the XFB
|
// input: pointer to the XFB, width and height of the XFB
|
||||||
// output: none
|
// output: none
|
||||||
//
|
//
|
||||||
EXPORT void CALL Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset);
|
EXPORT void CALL Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, BOOL scheduling);
|
||||||
|
|
||||||
// __________________________________________________________________________________________________
|
// __________________________________________________________________________________________________
|
||||||
// Function: Video_Screenshot
|
// Function: Video_Screenshot
|
||||||
|
@ -234,7 +234,7 @@ void Video_Stop(void)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video_UpdateXFB(u8* /*_pXFB*/, u32 /*_dwWidth*/, u32 /*_dwHeight*/, s32 /*_dwYOffset*/)
|
void Video_UpdateXFB(u8* /*_pXFB*/, u32 /*_dwWidth*/, u32 /*_dwHeight*/, s32 /*_dwYOffset*/, BOOL /*scheduling*/)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
ConvertXFB(tempBuffer, _pXFB, _dwWidth, _dwHeight);
|
ConvertXFB(tempBuffer, _pXFB, _dwWidth, _dwHeight);
|
||||||
|
@ -442,7 +442,13 @@ void BPWritten(int addr, int changes, int newval)
|
|||||||
// the number of lines copied is determined by the y scale * source efb height
|
// the number of lines copied is determined by the y scale * source efb height
|
||||||
float yScale = bpmem.dispcopyyscale / 256.0f;
|
float yScale = bpmem.dispcopyyscale / 256.0f;
|
||||||
float xfbLines = bpmem.copyTexSrcWH.y + 1.0f * yScale;
|
float xfbLines = bpmem.copyTexSrcWH.y + 1.0f * yScale;
|
||||||
XFB_Write(Memory_GetPtr(bpmem.copyTexDest << 5), multirc, (bpmem.copyMipMapStrideChannels << 4), (int)xfbLines);
|
//XFB_Write(Memory_GetPtr(bpmem.copyTexDest << 5), multirc, (bpmem.copyMipMapStrideChannels << 4), (int)xfbLines);
|
||||||
|
// TODO: compact this below if everyone is happy with it
|
||||||
|
u8* pXFB = Memory_GetPtr(bpmem.copyTexDest << 5);
|
||||||
|
u32 dstWidth = (bpmem.copyMipMapStrideChannels << 4);
|
||||||
|
u32 dstHeight = (u32)xfbLines;
|
||||||
|
XFB_Write(pXFB, multirc, dstWidth, dstHeight);
|
||||||
|
XFB_Draw(pXFB, dstWidth, dstHeight, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -39,6 +39,16 @@ enum {
|
|||||||
|
|
||||||
static GLuint xfb_decoded_texture;
|
static GLuint xfb_decoded_texture;
|
||||||
static int XFBInitStatus = 0;
|
static int XFBInitStatus = 0;
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
u8* pXFB;
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
s32 yOffset;
|
||||||
|
} tUpdateXFBArgs;
|
||||||
|
|
||||||
|
void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset);
|
||||||
|
|
||||||
|
|
||||||
void XFB_Init()
|
void XFB_Init()
|
||||||
{
|
{
|
||||||
@ -108,6 +118,19 @@ void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset)
|
|||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XFB_Draw()
|
||||||
|
{
|
||||||
|
XFB_Draw(tUpdateXFBArgs.pXFB, tUpdateXFBArgs.width, tUpdateXFBArgs.height, tUpdateXFBArgs.yOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset)
|
||||||
|
{
|
||||||
|
tUpdateXFBArgs.pXFB = _pXFB;
|
||||||
|
tUpdateXFBArgs.width = _dwWidth;
|
||||||
|
tUpdateXFBArgs.height = _dwHeight;
|
||||||
|
tUpdateXFBArgs.yOffset = _dwYOffset;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static GLuint xfb_texture;
|
static GLuint xfb_texture;
|
||||||
|
@ -27,9 +27,12 @@ void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt)
|
|||||||
|
|
||||||
// draw the XFB to the screen
|
// draw the XFB to the screen
|
||||||
void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset);
|
void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset);
|
||||||
|
void XFB_Draw();
|
||||||
|
|
||||||
void XFB_Shutdown();
|
void XFB_Shutdown();
|
||||||
|
|
||||||
int XFB_isInit();
|
int XFB_isInit();
|
||||||
|
|
||||||
|
void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -360,12 +360,23 @@ unsigned int Video_Screenshot(TCHAR* _szFilename)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset)
|
|
||||||
|
void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, BOOL scheduling)
|
||||||
{
|
{
|
||||||
if(g_Config.bUseXFB)
|
if(g_Config.bUseXFB && XFB_isInit())
|
||||||
{
|
{
|
||||||
if (XFB_isInit())
|
if (scheduling) // DC mode
|
||||||
XFB_Draw(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
|
{
|
||||||
|
XFB_SetUpdateArgs(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
|
||||||
|
g_XFBUpdateRequested = TRUE;
|
||||||
|
}
|
||||||
|
else // SC mode or DC without fifo&CP
|
||||||
|
{
|
||||||
|
if (_pXFB) // from CPU
|
||||||
|
XFB_Draw(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
|
||||||
|
else // from GP
|
||||||
|
XFB_Draw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user