VideoSoftware: Added Real XFB support.

Massivly increases the accuracy of VideoSoftware, if it's going to be slow, it
might as well be accurate.

 * Fixes flickering issues in games which double render to get Hardware AA, like the Peach's Castle tech demo.
 * Rouge Squadren 2's Cantina Intro doesn't flicker anymore, but it duplicates the top half of the screen onto the bottom.
 * Any games which need RealXFB support should now work in Video Software
This commit is contained in:
Scott Mansell
2013-08-20 23:51:39 +12:00
parent fa8a4cdbb5
commit d52e241cdf
6 changed files with 250 additions and 47 deletions

View File

@ -9,7 +9,7 @@
#include "VideoConfigDialog.h"
#endif // HAVE_WX
#include "Atomic.h"
#include "SWCommandProcessor.h"
#include "OpcodeDecoder.h"
#include "SWVideoConfig.h"
@ -29,10 +29,22 @@
#include "OpcodeDecoder.h"
#include "SWVertexLoader.h"
#include "SWStatistics.h"
#include "HW/VideoInterface.h"
#include "HW/Memmap.h"
#include "OnScreenDisplay.h"
#define VSYNC_ENABLED 0
static volatile u32 s_swapRequested = false;
static volatile struct
{
u32 xfbAddr;
FieldType field;
u32 fbWidth;
u32 fbHeight;
} s_beginFieldArgs;
namespace SW
{
@ -191,12 +203,51 @@ void VideoSoftware::Video_Prepare()
// Run from the CPU thread (from VideoInterface.cpp)
void VideoSoftware::Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight)
{
{
s_beginFieldArgs.xfbAddr = xfbAddr;
s_beginFieldArgs.field = field;
s_beginFieldArgs.fbWidth = fbWidth;
s_beginFieldArgs.fbHeight = fbHeight;
}
// Run from the CPU thread (from VideoInterface.cpp)
void VideoSoftware::Video_EndField()
{
// Techincally the XFB is continually rendered out scanline by scanline between
// BeginField and EndFeild, We could possibly get away with copying out the whole thing
// at BeginField for less lag, but for the safest emulation we run it here.
if (g_bSkipCurrentFrame || s_beginFieldArgs.xfbAddr == 0 ) {
swstats.frameCount++;
swstats.ResetFrame();
Core::Callback_VideoCopiedToXFB(false);
return;
}
if (!g_SWVideoConfig.bHwRasterizer) {
// Force Progressive
u32 xfbAddr = VideoInterface::GetXFBAddressTop();
// All drivers make an assumption that the two fields are interleaved in the framebuffer
// Give a warning if this isn't true.
if (xfbAddr + 1280 != VideoInterface::GetXFBAddressBottom()) {
WARN_LOG(VIDEO, "Feilds are not interleaved in XFB as expected.");
}
EfbInterface::yuv422_packed *xfb = (EfbInterface::yuv422_packed *) Memory::GetPointer(xfbAddr);
SWRenderer::UpdateColorTexture(xfb);
}
// Idealy we would just move all the opengl contex stuff to the CPU thread, but this gets
// messy when the Hardware Rasterizer is enabled.
// And Neobrain loves his Hardware Rasterizer
// If we are runing dual core, Signal the GPU thread about the new colour texture.
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread)
Common::AtomicStoreRelease(s_swapRequested, true);
else
SWRenderer::Swap(s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight);
}
u32 VideoSoftware::Video_AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
@ -242,6 +293,16 @@ bool VideoSoftware::Video_Screenshot(const char *_szFilename)
return false;
}
// Run from the graphics thread
static void VideoFifo_CheckSwapRequest()
{
if (Common::AtomicLoadAcquire(s_swapRequested))
{
SWRenderer::Swap(s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight);
Common::AtomicStoreRelease(s_swapRequested, false);
}
}
// -------------------------------
// Enter and exit the video loop
// -------------------------------
@ -252,6 +313,7 @@ void VideoSoftware::Video_EnterLoop()
while (fifoStateRun)
{
VideoFifo_CheckSwapRequest();
g_video_backend->PeekMessages();
if (!SWCommandProcessor::RunBuffer())
@ -262,11 +324,12 @@ void VideoSoftware::Video_EnterLoop()
while (!emuRunningState && fifoStateRun)
{
g_video_backend->PeekMessages();
VideoFifo_CheckSwapRequest();
m_csSWVidOccupied.unlock();
Common::SleepCurrentThread(1);
m_csSWVidOccupied.lock();
}
}
}
}
void VideoSoftware::Video_ExitLoop()