Switch to Video_BeginField; hopefully fix or reduce some video stability problems by using Events.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3740 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
2a236a4631
commit
dc7d9ab998
|
@ -24,7 +24,7 @@ PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo
|
|||
{
|
||||
Video_Prepare = 0;
|
||||
Video_SendFifoData = 0;
|
||||
Video_UpdateXFB = 0;
|
||||
Video_BeginField = 0;
|
||||
Video_EnterLoop = 0;
|
||||
Video_ExitLoop = 0;
|
||||
Video_Screenshot = 0;
|
||||
|
@ -35,8 +35,8 @@ PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo
|
|||
(LoadSymbol("Video_Prepare"));
|
||||
Video_SendFifoData = reinterpret_cast<TVideo_SendFifoData>
|
||||
(LoadSymbol("Video_SendFifoData"));
|
||||
Video_UpdateXFB = reinterpret_cast<TVideo_UpdateXFB>
|
||||
(LoadSymbol("Video_UpdateXFB"));
|
||||
Video_BeginField = reinterpret_cast<TVideo_BeginField>
|
||||
(LoadSymbol("Video_BeginField"));
|
||||
Video_Screenshot = reinterpret_cast<TVideo_Screenshot>
|
||||
(LoadSymbol("Video_Screenshot"));
|
||||
Video_EnterLoop = reinterpret_cast<TVideo_EnterLoop>
|
||||
|
@ -50,7 +50,7 @@ PluginVideo::PluginVideo(const char *_Filename) : CPlugin(_Filename), validVideo
|
|||
|
||||
if ((Video_Prepare != 0) &&
|
||||
(Video_SendFifoData != 0) &&
|
||||
(Video_UpdateXFB != 0) &&
|
||||
(Video_BeginField != 0) &&
|
||||
(Video_EnterLoop != 0) &&
|
||||
(Video_ExitLoop != 0) &&
|
||||
(Video_Screenshot != 0) &&
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Common {
|
|||
|
||||
typedef void (__cdecl* TVideo_Prepare)();
|
||||
typedef void (__cdecl* TVideo_SendFifoData)(u8*,u32);
|
||||
typedef void (__cdecl* TVideo_UpdateXFB)(u32, u32, u32, s32, bool);
|
||||
typedef void (__cdecl* TVideo_BeginField)(u32, FieldType, u32, u32);
|
||||
typedef bool (__cdecl* TVideo_Screenshot)(const char* filename);
|
||||
typedef void (__cdecl* TVideo_EnterLoop)();
|
||||
typedef void (__cdecl* TVideo_ExitLoop)();
|
||||
|
@ -43,7 +43,7 @@ public:
|
|||
TVideo_SendFifoData Video_SendFifoData;
|
||||
TVideo_EnterLoop Video_EnterLoop;
|
||||
TVideo_ExitLoop Video_ExitLoop;
|
||||
TVideo_UpdateXFB Video_UpdateXFB;
|
||||
TVideo_BeginField Video_BeginField;
|
||||
TVideo_AccessEFB Video_AccessEFB;
|
||||
|
||||
TVideo_AddMessage Video_AddMessage;
|
||||
|
|
|
@ -71,6 +71,18 @@
|
|||
|
||||
namespace Common
|
||||
{
|
||||
|
||||
// MemFence: Neither the compiler nor the CPU can reorder memory accesses
|
||||
// beyond this barrier.
|
||||
__forceinline void MemFence()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
MemoryBarrier();
|
||||
#else
|
||||
// TODO: UNIX experts, please implement the memory fence.
|
||||
#endif
|
||||
}
|
||||
|
||||
class CriticalSection
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -987,15 +987,7 @@ void GenerateVIInterrupt(VIInterruptType _VIInterrupt)
|
|||
}
|
||||
}
|
||||
|
||||
u8* GetXFBPointerTop()
|
||||
{
|
||||
if (m_XFBInfoTop.POFF)
|
||||
return Memory::GetPointer(m_XFBInfoTop.FBB << 5);
|
||||
else
|
||||
return Memory::GetPointer(m_XFBInfoTop.FBB);
|
||||
}
|
||||
|
||||
u32 GetXFBPointerTop_GC()
|
||||
u32 GetXFBAddressTop()
|
||||
{
|
||||
if (m_XFBInfoTop.POFF)
|
||||
return m_XFBInfoTop.FBB << 5;
|
||||
|
@ -1003,16 +995,7 @@ u32 GetXFBPointerTop_GC()
|
|||
return m_XFBInfoTop.FBB;
|
||||
}
|
||||
|
||||
u8* GetXFBPointerBottom()
|
||||
{
|
||||
// POFF for XFB bottom is connected to POFF for XFB top
|
||||
if (m_XFBInfoTop.POFF)
|
||||
return Memory::GetPointer(m_XFBInfoBottom.FBB << 5);
|
||||
else
|
||||
return Memory::GetPointer(m_XFBInfoBottom.FBB);
|
||||
}
|
||||
|
||||
u32 GetXFBPointerBottom_GC()
|
||||
u32 GetXFBAddressBottom()
|
||||
{
|
||||
// POFF for XFB bottom is connected to POFF for XFB top
|
||||
if (m_XFBInfoTop.POFF)
|
||||
|
@ -1058,6 +1041,25 @@ int getTicksPerLine() {
|
|||
}
|
||||
|
||||
|
||||
static void BeginField(u32 xfbAddr, FieldType field)
|
||||
{
|
||||
static const char* const fieldTypeNames[] = { "Progressive", "Upper", "Lower" };
|
||||
DEBUG_LOG(VIDEOINTERFACE, "(VI->BeginField): addr: %.08X | FieldSteps %u | FbSteps %u | ACV %u | Field %s",
|
||||
xfbAddr, m_HorizontalStepping.FieldSteps, m_HorizontalStepping.FbSteps, m_VerticalTimingRegister.ACV,
|
||||
fieldTypeNames[field]
|
||||
);
|
||||
|
||||
u32 fbWidth = m_HorizontalStepping.FieldSteps * 16;
|
||||
u32 fbHeight = (m_HorizontalStepping.FbSteps / m_HorizontalStepping.FieldSteps) * m_VerticalTimingRegister.ACV;
|
||||
|
||||
Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo();
|
||||
if (xfbAddr && video->IsValid())
|
||||
{
|
||||
video->Video_BeginField(xfbAddr, field, fbWidth, fbHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Purpose 1: Send VI interrupt for every screen refresh
|
||||
// Purpose 2: Execute XFB copy in homebrew games
|
||||
// Run when: This is run 7200 times per second on full speed
|
||||
|
@ -1094,57 +1096,32 @@ void Update()
|
|||
|
||||
if (m_VBeamPos == NextXFBRender)
|
||||
{
|
||||
u32 xfbAddr = 0;
|
||||
int yOffset = 0;
|
||||
|
||||
if (NextXFBRender == 1)
|
||||
{
|
||||
NextXFBRender = LinesPerField;
|
||||
// TODO: proper VI regs typedef and logic for XFB to work.
|
||||
// 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."
|
||||
xfbAddr = GetXFBPointerTop_GC();
|
||||
u32 xfbAddr = GetXFBAddressTop();
|
||||
BeginField(xfbAddr, m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_UPPER);
|
||||
}
|
||||
else
|
||||
{
|
||||
NextXFBRender = 1;
|
||||
// Previously checked m_XFBInfoTop.POFF then used m_XFBInfoBottom.FBB, try reverting if there are problems
|
||||
xfbAddr = GetXFBPointerBottom_GC();
|
||||
yOffset = -1;
|
||||
}
|
||||
|
||||
Common::PluginVideo* video = CPluginManager::GetInstance().GetVideo();
|
||||
|
||||
if (xfbAddr && video->IsValid())
|
||||
{
|
||||
int fbWidth = m_HorizontalStepping.FieldSteps * 16;
|
||||
int fbHeight = (m_HorizontalStepping.FbSteps / m_HorizontalStepping.FieldSteps) * m_VerticalTimingRegister.ACV;
|
||||
|
||||
DEBUG_LOG(VIDEOINTERFACE, "(VI->XFBUpdate): ptr: %.08X | %ix%i | xoff: %i",
|
||||
xfbAddr, fbWidth, fbHeight, m_XFBInfoTop.XOFF);
|
||||
|
||||
if (Core::GetStartupParameter().bUseDualCore)
|
||||
// scheduled on EmuThread in DC mode
|
||||
video->Video_UpdateXFB(xfbAddr, fbWidth, fbHeight, yOffset, TRUE);
|
||||
else
|
||||
// otherwise do it now from here (CPUthread)
|
||||
video->Video_UpdateXFB(xfbAddr, fbWidth, fbHeight, yOffset, FALSE);
|
||||
u32 xfbAddr = GetXFBAddressBottom();
|
||||
BeginField(xfbAddr, m_DisplayControlRegister.NIN ? FIELD_PROGRESSIVE : FIELD_LOWER);
|
||||
}
|
||||
}
|
||||
|
||||
// check INT_PRERETRACE
|
||||
if (m_InterruptRegister[0].VCT == m_VBeamPos)
|
||||
{
|
||||
m_InterruptRegister[0].IR_INT = 1;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
// INT_POSTRETRACE
|
||||
if (m_InterruptRegister[1].VCT == m_VBeamPos)
|
||||
{
|
||||
m_InterruptRegister[1].IR_INT = 1;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (m_InterruptRegister[i].VCT == m_VBeamPos)
|
||||
{
|
||||
m_InterruptRegister[i].IR_INT = 1;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
#include "Fifo.h"
|
||||
|
||||
|
||||
// TODO (mb2): move/rm this global
|
||||
volatile u32 g_XFBUpdateRequested = FALSE;
|
||||
extern u8* g_pVideoData;
|
||||
|
||||
volatile bool g_EFBAccessRequested = false;
|
||||
|
@ -63,7 +61,6 @@ void Fifo_Init()
|
|||
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
|
||||
fifo_exit_event.Init();
|
||||
fifoStateRun = false;
|
||||
g_XFBUpdateRequested = FALSE;
|
||||
}
|
||||
|
||||
void Fifo_Shutdown()
|
||||
|
@ -147,10 +144,7 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||
#endif
|
||||
|
||||
// Draw XFB if CP/GPfifo isn't used
|
||||
if (g_XFBUpdateRequested)
|
||||
{
|
||||
Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
|
||||
}
|
||||
VideoFifo_CheckSwapRequest();
|
||||
|
||||
if (g_EFBAccessRequested)
|
||||
{
|
||||
|
|
|
@ -37,4 +37,8 @@ void Fifo_ExitLoopNonBlocking();
|
|||
|
||||
void Fifo_DoState(PointerWrap &f);
|
||||
|
||||
// Implemented by the Video Plugin
|
||||
void VideoFifo_CheckSwapRequest();
|
||||
void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#ifndef _VIDEO_H_INCLUDED__
|
||||
#define _VIDEO_H_INCLUDED__
|
||||
|
||||
#include "Thread.h"
|
||||
#include "PluginSpecs.h"
|
||||
|
||||
#include "ExportProlog.h"
|
||||
|
@ -23,6 +22,13 @@ typedef void (*TUpdateInterrupts)(void);
|
|||
typedef void (*TUpdateFPSDisplay)(const char* text); // sets the window title
|
||||
typedef void (*TKeyPressed)(int keycode, bool shift, bool control); // sets the window title
|
||||
|
||||
enum FieldType
|
||||
{
|
||||
FIELD_PROGRESSIVE = 0,
|
||||
FIELD_UPPER,
|
||||
FIELD_LOWER
|
||||
};
|
||||
|
||||
enum EFBAccessType
|
||||
{
|
||||
PEEK_Z = 0,
|
||||
|
@ -110,15 +116,14 @@ EXPORT void CALL Video_Prepare(void);
|
|||
EXPORT void CALL Video_SendFifoData(u8* _uData, u32 len);
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: Video_UpdateXFB
|
||||
// TODO: This DOC IS BROKEN!
|
||||
// Purpose: This function is called when you have to flip the yuv2
|
||||
// video-buffer. You should ignore this function after you
|
||||
// got the first EFB to XFB copy.
|
||||
// input: pointer to the XFB, width and height of the XFB
|
||||
// Function: Video_BeginField
|
||||
// Purpose: When a vertical blank occurs in the VI emulator, this function tells the video plugin
|
||||
// what the parameters of the upcoming field are. The video plugin should make sure the
|
||||
// previous field is on the player's display before returning.
|
||||
// input: vi parameters of the next field
|
||||
// output: none
|
||||
//
|
||||
EXPORT void CALL Video_UpdateXFB(u32 _dwXFBAddr, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, bool scheduling);
|
||||
EXPORT void CALL Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight);
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: Video_AccessEFB
|
||||
|
|
|
@ -254,7 +254,15 @@ void Shutdown(void)
|
|||
DeInit();
|
||||
}
|
||||
|
||||
void Video_UpdateXFB(u32 /*_dwXFBAddr*/, u32 /*_dwWidth*/, u32 /*_dwHeight*/, s32 /*_dwYOffset*/, bool /*scheduling*/)
|
||||
void VideoFifo_CheckSwapRequest()
|
||||
{
|
||||
}
|
||||
|
||||
void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
}
|
||||
|
||||
void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
/*
|
||||
ConvertXFB(tempBuffer, _pXFB, _dwWidth, _dwHeight);
|
||||
|
|
|
@ -183,20 +183,20 @@ void FramebufferManager::Shutdown()
|
|||
m_virtualXFBList.clear();
|
||||
}
|
||||
|
||||
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
|
||||
void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc)
|
||||
{
|
||||
if (g_Config.bUseXFB)
|
||||
copyToRealXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
|
||||
copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
||||
else
|
||||
copyToVirtualXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
|
||||
copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
||||
}
|
||||
|
||||
const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
|
||||
const XFBSource* FramebufferManager::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
if (g_Config.bUseXFB)
|
||||
return getRealXFBSource(xfbAddr, srcWidth, srcHeight);
|
||||
return getRealXFBSource(xfbAddr, fbWidth, fbHeight);
|
||||
else
|
||||
return getVirtualXFBSource(xfbAddr, srcWidth, srcHeight);
|
||||
return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
GLuint FramebufferManager::GetEFBColorTexture(const TRectangle& sourceRc) const
|
||||
|
@ -283,7 +283,7 @@ FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height)
|
|||
return m_virtualXFBList.end();
|
||||
}
|
||||
|
||||
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
|
||||
void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc)
|
||||
{
|
||||
u8* pXFB = Memory_GetPtr(xfbAddr);
|
||||
if (!pXFB)
|
||||
|
@ -292,22 +292,22 @@ void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight,
|
|||
return;
|
||||
}
|
||||
|
||||
XFB_Write(pXFB, sourceRc, dstWidth, dstHeight);
|
||||
XFB_Write(pXFB, sourceRc, fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
|
||||
void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc)
|
||||
{
|
||||
GLuint xfbTexture;
|
||||
|
||||
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, dstWidth, dstHeight);
|
||||
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight);
|
||||
|
||||
if (it != m_virtualXFBList.end())
|
||||
{
|
||||
// Overwrite an existing Virtual XFB.
|
||||
|
||||
it->xfbAddr = xfbAddr;
|
||||
it->xfbWidth = dstWidth;
|
||||
it->xfbHeight = dstHeight;
|
||||
it->xfbWidth = fbWidth;
|
||||
it->xfbHeight = fbHeight;
|
||||
|
||||
it->xfbSource.texWidth = m_targetWidth;
|
||||
it->xfbSource.texHeight = m_targetHeight;
|
||||
|
@ -342,8 +342,8 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeig
|
|||
VirtualXFB newVirt;
|
||||
|
||||
newVirt.xfbAddr = xfbAddr;
|
||||
newVirt.xfbWidth = dstWidth;
|
||||
newVirt.xfbHeight = dstHeight;
|
||||
newVirt.xfbWidth = fbWidth;
|
||||
newVirt.xfbHeight = fbHeight;
|
||||
|
||||
newVirt.xfbSource.texture = xfbTexture;
|
||||
newVirt.xfbSource.texWidth = m_targetWidth;
|
||||
|
@ -405,15 +405,15 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeig
|
|||
}
|
||||
}
|
||||
|
||||
const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
|
||||
const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
m_realXFBSource.texWidth = XFB_WIDTH;
|
||||
m_realXFBSource.texHeight = XFB_HEIGHT;
|
||||
|
||||
m_realXFBSource.sourceRc.left = 0;
|
||||
m_realXFBSource.sourceRc.top = 0;
|
||||
m_realXFBSource.sourceRc.right = srcWidth;
|
||||
m_realXFBSource.sourceRc.bottom = srcHeight;
|
||||
m_realXFBSource.sourceRc.right = fbWidth;
|
||||
m_realXFBSource.sourceRc.bottom = fbHeight;
|
||||
|
||||
if (!m_realXFBSource.texture)
|
||||
{
|
||||
|
@ -426,12 +426,12 @@ const XFBSource* FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 srcWidth,
|
|||
}
|
||||
|
||||
// Decode YUYV data from GameCube RAM
|
||||
TextureConverter::DecodeToTexture(xfbAddr, srcWidth, srcHeight, m_realXFBSource.texture);
|
||||
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture);
|
||||
|
||||
return &m_realXFBSource;
|
||||
}
|
||||
|
||||
const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight)
|
||||
const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
if (m_virtualXFBList.size() == 0)
|
||||
{
|
||||
|
@ -439,7 +439,7 @@ const XFBSource* FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 srcWid
|
|||
return NULL;
|
||||
}
|
||||
|
||||
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, srcWidth, srcHeight);
|
||||
VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight);
|
||||
if (it == m_virtualXFBList.end())
|
||||
{
|
||||
// Virtual XFB is not in the list, so return the most recently rendered
|
||||
|
|
|
@ -97,9 +97,9 @@ public:
|
|||
|
||||
// sourceRc is in GL target coordinates, not GameCube EFB coordinates!
|
||||
// TODO: Clean that up.
|
||||
void CopyToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
|
||||
void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc);
|
||||
|
||||
const XFBSource* GetXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
|
||||
const XFBSource* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||
|
||||
// To get the EFB in texture form, these functions may have to transfer
|
||||
// the EFB to a resolved texture first.
|
||||
|
@ -124,10 +124,10 @@ private:
|
|||
|
||||
VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height);
|
||||
|
||||
void copyToRealXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
|
||||
void copyToVirtualXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
|
||||
const XFBSource* getRealXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
|
||||
const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 srcWidth, u32 srcHeight);
|
||||
void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc);
|
||||
void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc);
|
||||
const XFBSource* getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||
const XFBSource* getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight);
|
||||
|
||||
int m_targetWidth;
|
||||
int m_targetHeight;
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "Timer.h"
|
||||
#include "StringUtil.h"
|
||||
#include "FramebufferManager.h"
|
||||
#include "Fifo.h"
|
||||
|
||||
#include "main.h" // Local
|
||||
#ifdef _WIN32
|
||||
|
@ -660,39 +661,19 @@ void ComputeBackbufferRectangle(TRectangle *rc)
|
|||
rc->bottom = YOffset + ceil(FloatGLHeight);
|
||||
}
|
||||
|
||||
// TODO: Use something less ugly than an Evil Global Variable.
|
||||
// Also, protect this structure with a mutex.
|
||||
extern volatile struct // Comes from main.cpp
|
||||
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc)
|
||||
{
|
||||
u32 xfbAddr;
|
||||
u32 width;
|
||||
u32 height;
|
||||
s32 yOffset;
|
||||
} tUpdateXFBArgs;
|
||||
|
||||
void Renderer::RenderToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc)
|
||||
{
|
||||
u32 aLower = xfbAddr;
|
||||
u32 aUpper = xfbAddr + 2 * dstWidth * dstHeight;
|
||||
u32 bLower = tUpdateXFBArgs.xfbAddr;
|
||||
u32 bUpper = tUpdateXFBArgs.xfbAddr + 2 * tUpdateXFBArgs.width * tUpdateXFBArgs.height;
|
||||
|
||||
// If we're about to write into a requested XFB, make sure the previous
|
||||
// If we're about to write to a requested XFB, make sure the previous
|
||||
// contents make it to the screen first.
|
||||
if (g_XFBUpdateRequested && addrRangesOverlap(aLower, aUpper, bLower, bUpper))
|
||||
{
|
||||
Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
|
||||
}
|
||||
VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight);
|
||||
|
||||
s_framebufferManager.CopyToXFB(xfbAddr, dstWidth, dstHeight, sourceRc);
|
||||
s_framebufferManager.CopyToXFB(xfbAddr, fbWidth, fbHeight, sourceRc);
|
||||
}
|
||||
|
||||
|
||||
// This function has the final picture. We adjust the aspect ratio here.
|
||||
// yOffset is used to eliminate interlacing jitter in Real XFB mode.
|
||||
void Renderer::Swap(u32 xfbAddr, u32 srcWidth, u32 srcHeight, s32 yOffset)
|
||||
void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
const XFBSource* xfbSource = s_framebufferManager.GetXFBSource(xfbAddr, srcWidth, srcHeight);
|
||||
const XFBSource* xfbSource = s_framebufferManager.GetXFBSource(xfbAddr, fbWidth, fbHeight);
|
||||
if (!xfbSource)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Failed to get video for this frame");
|
||||
|
@ -724,6 +705,7 @@ void Renderer::Swap(u32 xfbAddr, u32 srcWidth, u32 srcHeight, s32 yOffset)
|
|||
v_max = (float)xfbSource->texHeight;
|
||||
}
|
||||
|
||||
int yOffset = (g_Config.bUseXFB && field == FIELD_LOWER) ? -1 : 0;
|
||||
v_min -= yOffset;
|
||||
v_max -= yOffset;
|
||||
|
||||
|
|
|
@ -87,10 +87,10 @@ public:
|
|||
static void FlipImageData(u8 *data, int w, int h);
|
||||
static bool SaveRenderTarget(const char *filename, int w, int h, int YOffset = 0);
|
||||
|
||||
static void RenderToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc);
|
||||
static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const TRectangle& sourceRc);
|
||||
|
||||
// Finish up the current frame, print some stats
|
||||
static void Swap(u32 xfbAddr, u32 srcWidth, u32 srcHeight, s32 yOffset);
|
||||
static void Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight);
|
||||
};
|
||||
|
||||
void ComputeBackbufferRectangle(TRectangle *rc);
|
||||
|
|
|
@ -99,6 +99,9 @@ int GLScissorX, GLScissorY, GLScissorW, GLScissorH;
|
|||
|
||||
static bool s_PluginInitialized = false;
|
||||
|
||||
static bool s_swapRequested = false;
|
||||
static Common::Event s_swapResponseEvent;
|
||||
|
||||
static volatile u32 s_AccessEFBResult = 0, s_EFBx, s_EFBy;
|
||||
static volatile EFBAccessType s_AccessEFBType;
|
||||
static Common::Event s_AccessEFBDone;
|
||||
|
@ -372,6 +375,10 @@ void Video_Prepare(void)
|
|||
VertexLoaderManager::Init();
|
||||
TextureConverter::Init();
|
||||
|
||||
s_swapRequested = false;
|
||||
s_swapResponseEvent.Init();
|
||||
s_swapResponseEvent.Set();
|
||||
|
||||
s_PluginInitialized = true;
|
||||
INFO_LOG(VIDEO, "Video plugin initialized.");
|
||||
}
|
||||
|
@ -380,6 +387,9 @@ void Shutdown(void)
|
|||
{
|
||||
s_PluginInitialized = false;
|
||||
|
||||
s_swapRequested = false;
|
||||
s_swapResponseEvent.Shutdown();
|
||||
|
||||
Fifo_Shutdown();
|
||||
PostProcessing::Shutdown();
|
||||
TextureConverter::Shutdown();
|
||||
|
@ -423,48 +433,75 @@ void Video_AddMessage(const char* pstr, u32 milliseconds)
|
|||
OSD::AddMessage(pstr, milliseconds);
|
||||
}
|
||||
|
||||
|
||||
// TODO: Protect this structure with a mutex.
|
||||
volatile struct
|
||||
static volatile struct
|
||||
{
|
||||
u32 xfbAddr;
|
||||
u32 width;
|
||||
u32 height;
|
||||
s32 yOffset;
|
||||
} tUpdateXFBArgs;
|
||||
FieldType field;
|
||||
u32 fbWidth;
|
||||
u32 fbHeight;
|
||||
} s_beginFieldArgs = { 0 };
|
||||
|
||||
// Run from the CPU thread (from VideoInterface.cpp) for certain homebrew games only
|
||||
void Video_UpdateXFB(u32 _dwXFBAddr, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, bool scheduling)
|
||||
// Run from the graphics thread (from Fifo.cpp)
|
||||
void VideoFifo_CheckSwapRequest()
|
||||
{
|
||||
if (s_swapRequested)
|
||||
{
|
||||
s_swapRequested = false;
|
||||
|
||||
Common::MemFence();
|
||||
|
||||
Renderer::Swap(s_beginFieldArgs.xfbAddr, s_beginFieldArgs.field, s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight);
|
||||
|
||||
// TODO: Find better name for this because I don't know if it means what it says.
|
||||
g_VideoInitialize.pCopiedToXFB();
|
||||
|
||||
s_swapResponseEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper)
|
||||
{
|
||||
return (
|
||||
(aLower >= bLower && aLower < bUpper) ||
|
||||
(aUpper >= bLower && aUpper < bUpper) ||
|
||||
(bLower >= aLower && bLower < aUpper) ||
|
||||
(bUpper >= aLower && bUpper < aUpper)
|
||||
);
|
||||
}
|
||||
|
||||
// Run from the graphics thread (from Fifo.cpp)
|
||||
void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
if (s_swapRequested)
|
||||
{
|
||||
u32 aLower = xfbAddr;
|
||||
u32 aUpper = xfbAddr + 2 * fbWidth * fbHeight;
|
||||
|
||||
Common::MemFence();
|
||||
|
||||
u32 bLower = s_beginFieldArgs.xfbAddr;
|
||||
u32 bUpper = s_beginFieldArgs.xfbAddr + 2 * s_beginFieldArgs.fbWidth * s_beginFieldArgs.fbHeight;
|
||||
|
||||
if (addrRangesOverlap(aLower, aUpper, bLower, bUpper))
|
||||
VideoFifo_CheckSwapRequest();
|
||||
}
|
||||
}
|
||||
|
||||
// Run from the CPU thread (from VideoInterface.cpp)
|
||||
void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
if (s_PluginInitialized)
|
||||
{
|
||||
if (scheduling) // From CPU in DC mode
|
||||
{
|
||||
tUpdateXFBArgs.xfbAddr = _dwXFBAddr;
|
||||
tUpdateXFBArgs.width = _dwWidth;
|
||||
tUpdateXFBArgs.height = _dwHeight;
|
||||
tUpdateXFBArgs.yOffset = _dwYOffset;
|
||||
s_swapResponseEvent.MsgWait();
|
||||
|
||||
g_XFBUpdateRequested = TRUE;
|
||||
}
|
||||
else // From CPU in SC mode or graphics thread in DC mode
|
||||
{
|
||||
g_XFBUpdateRequested = FALSE;
|
||||
s_beginFieldArgs.xfbAddr = xfbAddr;
|
||||
s_beginFieldArgs.field = field;
|
||||
s_beginFieldArgs.fbWidth = fbWidth;
|
||||
s_beginFieldArgs.fbHeight = fbHeight;
|
||||
|
||||
if (!_dwXFBAddr)
|
||||
{
|
||||
// From graphics thread in DC mode
|
||||
_dwXFBAddr = tUpdateXFBArgs.xfbAddr;
|
||||
_dwWidth = tUpdateXFBArgs.width;
|
||||
_dwHeight = tUpdateXFBArgs.height;
|
||||
_dwYOffset = tUpdateXFBArgs.yOffset;
|
||||
}
|
||||
Common::MemFence();
|
||||
|
||||
// TODO: Use real XFB source parameters based on VI settings
|
||||
Renderer::Swap(_dwXFBAddr, _dwWidth, _dwHeight, g_Config.bUseXFB ? _dwYOffset : 0);
|
||||
|
||||
g_VideoInitialize.pCopiedToXFB();
|
||||
}
|
||||
s_swapRequested = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue