diff --git a/Source/Core/Common/Src/PluginVideo.cpp b/Source/Core/Common/Src/PluginVideo.cpp index 6f2b740f7b..a17823d718 100644 --- a/Source/Core/Common/Src/PluginVideo.cpp +++ b/Source/Core/Common/Src/PluginVideo.cpp @@ -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 (LoadSymbol("Video_SendFifoData")); - Video_UpdateXFB = reinterpret_cast - (LoadSymbol("Video_UpdateXFB")); + Video_BeginField = reinterpret_cast + (LoadSymbol("Video_BeginField")); Video_Screenshot = reinterpret_cast (LoadSymbol("Video_Screenshot")); Video_EnterLoop = reinterpret_cast @@ -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) && diff --git a/Source/Core/Common/Src/PluginVideo.h b/Source/Core/Common/Src/PluginVideo.h index 76472ac81d..ac3335abdf 100644 --- a/Source/Core/Common/Src/PluginVideo.h +++ b/Source/Core/Common/Src/PluginVideo.h @@ -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; diff --git a/Source/Core/Common/Src/Thread.h b/Source/Core/Common/Src/Thread.h index 76e51f83c1..55c2e62a2d 100644 --- a/Source/Core/Common/Src/Thread.h +++ b/Source/Core/Common/Src/Thread.h @@ -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 diff --git a/Source/Core/Core/Src/HW/VideoInterface.cpp b/Source/Core/Core/Src/HW/VideoInterface.cpp index 3a58eec06c..e950413c4a 100644 --- a/Source/Core/Core/Src/HW/VideoInterface.cpp +++ b/Source/Core/Core/Src/HW/VideoInterface.cpp @@ -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 diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 0d5b263c46..065ce4c2a4 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -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) { diff --git a/Source/Core/VideoCommon/Src/Fifo.h b/Source/Core/VideoCommon/Src/Fifo.h index b71e3155d6..ad4a45bce9 100644 --- a/Source/Core/VideoCommon/Src/Fifo.h +++ b/Source/Core/VideoCommon/Src/Fifo.h @@ -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 diff --git a/Source/PluginSpecs/pluginspecs_video.h b/Source/PluginSpecs/pluginspecs_video.h index 780d4e7915..b928c1c032 100644 --- a/Source/PluginSpecs/pluginspecs_video.h +++ b/Source/PluginSpecs/pluginspecs_video.h @@ -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 diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index 9f2b49f3e7..624d75b246 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -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); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp index f7670b00cc..3619a90272 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.cpp @@ -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 diff --git a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h index 02f38d63f0..99850d82d8 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/FramebufferManager.h @@ -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; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 0d0f7270a5..4cd91d33c1 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -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 -{ - u32 xfbAddr; - u32 width; - u32 height; - s32 yOffset; -} tUpdateXFBArgs; - -void Renderer::RenderToXFB(u32 xfbAddr, u32 dstWidth, u32 dstHeight, const TRectangle& sourceRc) +void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, 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; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.h b/Source/Plugins/Plugin_VideoOGL/Src/Render.h index e0c04759e4..c55f5cc285 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.h @@ -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); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index 436a57e81e..e1d86562b6 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -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; } }