From 2df0c31d13372bc29d488cf7e80d4adb9cf28b46 Mon Sep 17 00:00:00 2001 From: degasus Date: Fri, 21 Dec 2012 21:04:53 +0100 Subject: [PATCH 1/3] add invalid flag for BPStructs (fix issue 5790) this flag will be set on loading a state and checked before every rendering. --- Source/Core/VideoCommon/Src/BPStructs.cpp | 75 +++++++++++-------- Source/Core/VideoCommon/Src/BPStructs.h | 1 + Source/Core/VideoCommon/Src/MainBase.cpp | 2 +- .../VideoCommon/Src/VertexManagerBase.cpp | 4 + 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index 179196e412..1e13a36f96 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -34,9 +34,10 @@ using namespace BPFunctions; -u32 mapTexAddress; -bool mapTexFound; -int numWrites; +static u32 mapTexAddress; +static bool mapTexFound; +static int numWrites; +static bool s_invalid; extern volatile bool g_bSkipCurrentFrame; @@ -56,6 +57,7 @@ void BPInit() mapTexAddress = 0; numWrites = 0; mapTexFound = false; + s_invalid = false; } void RenderToXFB(const BPCmd &bp, const EFBRectangle &rc, float yScale, float xfbLines, u32 xfbAddr, const u32 dstWidth, const u32 dstHeight, float gamma) @@ -81,6 +83,9 @@ void BPWritten(const BPCmd& bp) just stuff geometry in them and don't put state changes there ---------------------------------------------------------------------------------------------------------------- */ + + // check for invalid state, else unneeded configuration are built + BPReload(); // Debugging only, this lets you skip a bp update //static int times = 0; @@ -680,32 +685,42 @@ void BPWritten(const BPCmd& bp) // Called when loading a saved state. void BPReload() { - // restore anything that goes straight to the renderer. - // let's not risk actually replaying any writes. - // note that PixelShaderManager is already covered since it has its own DoState. - SetGenerationMode(); - SetScissor(); - SetLineWidth(); - SetDepthMode(); - SetLogicOpMode(); - SetDitherMode(); - SetBlendMode(); - SetColorMask(); - OnPixelFormatChange(); - { - BPCmd bp = {BPMEM_TX_SETMODE0, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_TX_SETMODE0])}; - SetTextureMode(bp); - } - { - BPCmd bp = {BPMEM_TX_SETMODE0_4, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_TX_SETMODE0_4])}; - SetTextureMode(bp); - } - { - BPCmd bp = {BPMEM_FIELDMASK, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_FIELDMASK])}; - SetInterlacingMode(bp); - } - { - BPCmd bp = {BPMEM_FIELDMODE, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_FIELDMODE])}; - SetInterlacingMode(bp); + if(s_invalid) { + s_invalid = false; + + // restore anything that goes straight to the renderer. + // let's not risk actually replaying any writes. + // note that PixelShaderManager is already covered since it has its own DoState. + SetGenerationMode(); + SetScissor(); + SetLineWidth(); + SetDepthMode(); + SetLogicOpMode(); + SetDitherMode(); + SetBlendMode(); + SetColorMask(); + OnPixelFormatChange(); + { + BPCmd bp = {BPMEM_TX_SETMODE0, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_TX_SETMODE0])}; + SetTextureMode(bp); + } + { + BPCmd bp = {BPMEM_TX_SETMODE0_4, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_TX_SETMODE0_4])}; + SetTextureMode(bp); + } + { + BPCmd bp = {BPMEM_FIELDMASK, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_FIELDMASK])}; + SetInterlacingMode(bp); + } + { + BPCmd bp = {BPMEM_FIELDMODE, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_FIELDMODE])}; + SetInterlacingMode(bp); + } } } + +void BPInvalidate() +{ + s_invalid = true; +} + diff --git a/Source/Core/VideoCommon/Src/BPStructs.h b/Source/Core/VideoCommon/Src/BPStructs.h index 38b3d3a3d4..1c1bc23e06 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.h +++ b/Source/Core/VideoCommon/Src/BPStructs.h @@ -23,5 +23,6 @@ void BPInit(); void LoadBPReg(u32 value0); void BPReload(); +void BPInvalidate(); #endif // _BPSTRUCTS_H_ diff --git a/Source/Core/VideoCommon/Src/MainBase.cpp b/Source/Core/VideoCommon/Src/MainBase.cpp index cb6dc7ae5b..b5e72b1d8d 100644 --- a/Source/Core/VideoCommon/Src/MainBase.cpp +++ b/Source/Core/VideoCommon/Src/MainBase.cpp @@ -198,7 +198,7 @@ void VideoBackendHardware::DoState(PointerWrap& p) // Refresh state. if (p.GetMode() == PointerWrap::MODE_READ) { - BPReload(); + BPInvalidate(); RecomputeCachedArraybases(); // Clear all caches that touch RAM diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp index 4118e3dcbd..23f355fe3b 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp @@ -9,6 +9,7 @@ #include "NativeVertexFormat.h" #include "TextureCacheBase.h" #include "RenderBase.h" +#include "BPStructs.h" #include "VertexManagerBase.h" #include "VideoConfig.h" @@ -159,6 +160,9 @@ void VertexManager::AddVertices(int primitive, int numVertices) void VertexManager::Flush() { + // loading a state will invalidate BP, so check for it + BPReload(); + g_vertex_manager->vFlush(); } From ffddfd8662bda4fedcfcc8cad73f02bd7a522925 Mon Sep 17 00:00:00 2001 From: degasus Date: Sat, 22 Dec 2012 17:30:13 +0100 Subject: [PATCH 2/3] do only invalid hashes instead of all textures on loading this is a hack, but only the gpu thread is allowed to call ogl commands suggestion: create an unused texture cache, so we can move all textures there --- Source/Core/VideoCommon/Src/MainBase.cpp | 2 +- Source/Core/VideoCommon/Src/TextureCacheBase.cpp | 12 ++++++++++++ Source/Core/VideoCommon/Src/TextureCacheBase.h | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/Core/VideoCommon/Src/MainBase.cpp b/Source/Core/VideoCommon/Src/MainBase.cpp index b5e72b1d8d..6e0fb530db 100644 --- a/Source/Core/VideoCommon/Src/MainBase.cpp +++ b/Source/Core/VideoCommon/Src/MainBase.cpp @@ -203,7 +203,7 @@ void VideoBackendHardware::DoState(PointerWrap& p) // Clear all caches that touch RAM // (? these don't appear to touch any emulation state that gets saved. moved to on load only.) - TextureCache::Invalidate(); + TextureCache::InvalidateHashes(); VertexLoaderManager::MarkAllDirty(); } } diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index 7c47c35bb6..2bcaead19c 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -72,6 +72,18 @@ void TextureCache::Invalidate() textures.clear(); } +// this function is dirty hack to work around a OGL bug. +// it is only used on loading states. It will work for normal textures, +// but for efb2ram, it wouldn't be checked. So there may be glitches on loading +void TextureCache::InvalidateHashes() +{ + TexCache::iterator + iter = textures.begin(), + tcend = textures.end(); + for (; iter != tcend; ++iter) + iter->second->hash = TEXHASH_INVALID; +} + TextureCache::~TextureCache() { Invalidate(); diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.h b/Source/Core/VideoCommon/Src/TextureCacheBase.h index 4ef3b8a985..4d7124f215 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.h +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h @@ -106,6 +106,7 @@ public: static void Cleanup(); static void Invalidate(); + static void InvalidateHashes(); static void InvalidateRange(u32 start_address, u32 size); static void MakeRangeDynamic(u32 start_address, u32 size); static void ClearRenderTargets(); // currently only used by OGL From bd0abb3d2fe5047554bb6b87fa8e3f6aa3f42e0b Mon Sep 17 00:00:00 2001 From: degasus Date: Sun, 23 Dec 2012 13:32:23 +0100 Subject: [PATCH 3/3] revert last commit, add CheckInvalidState to VideoBackend --- Source/Core/Common/Src/VideoBackendBase.h | 8 +++ Source/Core/VideoCommon/Src/BPStructs.cpp | 68 ++++++++----------- Source/Core/VideoCommon/Src/BPStructs.h | 1 - Source/Core/VideoCommon/Src/MainBase.cpp | 14 +++- .../Core/VideoCommon/Src/TextureCacheBase.cpp | 12 ---- .../Core/VideoCommon/Src/TextureCacheBase.h | 1 - .../VideoCommon/Src/VertexManagerBase.cpp | 2 +- .../Plugin_VideoSoftware/Src/SWmain.cpp | 5 ++ .../Plugin_VideoSoftware/Src/VideoBackend.h | 3 + 9 files changed, 57 insertions(+), 57 deletions(-) diff --git a/Source/Core/Common/Src/VideoBackendBase.h b/Source/Core/Common/Src/VideoBackendBase.h index d09288ebc7..311fa66104 100644 --- a/Source/Core/Common/Src/VideoBackendBase.h +++ b/Source/Core/Common/Src/VideoBackendBase.h @@ -137,6 +137,8 @@ public: // the implementation needs not do synchronization logic, because calls to it are surrounded by PauseAndLock now virtual void DoState(PointerWrap &p) = 0; + + virtual void CheckInvalidState() = 0; }; extern std::vector g_available_video_backends; @@ -176,9 +178,15 @@ class VideoBackendHardware : public VideoBackend void PauseAndLock(bool doLock, bool unpauseOnUnlock=true); void DoState(PointerWrap &p); + + bool m_invalid; + +public: + void CheckInvalidState(); protected: void InitializeShared(); + void InvalidState(); }; #endif diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index 1e13a36f96..0bde9cc613 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -37,7 +37,6 @@ using namespace BPFunctions; static u32 mapTexAddress; static bool mapTexFound; static int numWrites; -static bool s_invalid; extern volatile bool g_bSkipCurrentFrame; @@ -57,7 +56,6 @@ void BPInit() mapTexAddress = 0; numWrites = 0; mapTexFound = false; - s_invalid = false; } void RenderToXFB(const BPCmd &bp, const EFBRectangle &rc, float yScale, float xfbLines, u32 xfbAddr, const u32 dstWidth, const u32 dstHeight, float gamma) @@ -85,7 +83,7 @@ void BPWritten(const BPCmd& bp) */ // check for invalid state, else unneeded configuration are built - BPReload(); + g_video_backend->CheckInvalidState(); // Debugging only, this lets you skip a bp update //static int times = 0; @@ -685,42 +683,32 @@ void BPWritten(const BPCmd& bp) // Called when loading a saved state. void BPReload() { - if(s_invalid) { - s_invalid = false; - - // restore anything that goes straight to the renderer. - // let's not risk actually replaying any writes. - // note that PixelShaderManager is already covered since it has its own DoState. - SetGenerationMode(); - SetScissor(); - SetLineWidth(); - SetDepthMode(); - SetLogicOpMode(); - SetDitherMode(); - SetBlendMode(); - SetColorMask(); - OnPixelFormatChange(); - { - BPCmd bp = {BPMEM_TX_SETMODE0, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_TX_SETMODE0])}; - SetTextureMode(bp); - } - { - BPCmd bp = {BPMEM_TX_SETMODE0_4, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_TX_SETMODE0_4])}; - SetTextureMode(bp); - } - { - BPCmd bp = {BPMEM_FIELDMASK, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_FIELDMASK])}; - SetInterlacingMode(bp); - } - { - BPCmd bp = {BPMEM_FIELDMODE, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_FIELDMODE])}; - SetInterlacingMode(bp); - } + // restore anything that goes straight to the renderer. + // let's not risk actually replaying any writes. + // note that PixelShaderManager is already covered since it has its own DoState. + SetGenerationMode(); + SetScissor(); + SetLineWidth(); + SetDepthMode(); + SetLogicOpMode(); + SetDitherMode(); + SetBlendMode(); + SetColorMask(); + OnPixelFormatChange(); + { + BPCmd bp = {BPMEM_TX_SETMODE0, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_TX_SETMODE0])}; + SetTextureMode(bp); + } + { + BPCmd bp = {BPMEM_TX_SETMODE0_4, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_TX_SETMODE0_4])}; + SetTextureMode(bp); + } + { + BPCmd bp = {BPMEM_FIELDMASK, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_FIELDMASK])}; + SetInterlacingMode(bp); + } + { + BPCmd bp = {BPMEM_FIELDMODE, 0xFFFFFF, static_cast(((u32*)&bpmem)[BPMEM_FIELDMODE])}; + SetInterlacingMode(bp); } } - -void BPInvalidate() -{ - s_invalid = true; -} - diff --git a/Source/Core/VideoCommon/Src/BPStructs.h b/Source/Core/VideoCommon/Src/BPStructs.h index 1c1bc23e06..38b3d3a3d4 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.h +++ b/Source/Core/VideoCommon/Src/BPStructs.h @@ -23,6 +23,5 @@ void BPInit(); void LoadBPReg(u32 value0); void BPReload(); -void BPInvalidate(); #endif // _BPSTRUCTS_H_ diff --git a/Source/Core/VideoCommon/Src/MainBase.cpp b/Source/Core/VideoCommon/Src/MainBase.cpp index 6e0fb530db..726ef71b38 100644 --- a/Source/Core/VideoCommon/Src/MainBase.cpp +++ b/Source/Core/VideoCommon/Src/MainBase.cpp @@ -180,6 +180,7 @@ void VideoBackendHardware::InitializeShared() memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs)); memset(&s_accessEFBArgs, 0, sizeof(s_accessEFBArgs)); s_AccessEFBResult = 0; + m_invalid = false; } // Run from the CPU thread @@ -198,16 +199,25 @@ void VideoBackendHardware::DoState(PointerWrap& p) // Refresh state. if (p.GetMode() == PointerWrap::MODE_READ) { - BPInvalidate(); + m_invalid = true; RecomputeCachedArraybases(); // Clear all caches that touch RAM // (? these don't appear to touch any emulation state that gets saved. moved to on load only.) - TextureCache::InvalidateHashes(); VertexLoaderManager::MarkAllDirty(); } } +void VideoBackendHardware::CheckInvalidState() { + if (m_invalid) + { + m_invalid = false; + + BPReload(); + TextureCache::Invalidate(); + } +} + void VideoBackendHardware::PauseAndLock(bool doLock, bool unpauseOnUnlock) { Fifo_PauseAndLock(doLock, unpauseOnUnlock); diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index 2bcaead19c..7c47c35bb6 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -72,18 +72,6 @@ void TextureCache::Invalidate() textures.clear(); } -// this function is dirty hack to work around a OGL bug. -// it is only used on loading states. It will work for normal textures, -// but for efb2ram, it wouldn't be checked. So there may be glitches on loading -void TextureCache::InvalidateHashes() -{ - TexCache::iterator - iter = textures.begin(), - tcend = textures.end(); - for (; iter != tcend; ++iter) - iter->second->hash = TEXHASH_INVALID; -} - TextureCache::~TextureCache() { Invalidate(); diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.h b/Source/Core/VideoCommon/Src/TextureCacheBase.h index 4d7124f215..4ef3b8a985 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.h +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.h @@ -106,7 +106,6 @@ public: static void Cleanup(); static void Invalidate(); - static void InvalidateHashes(); static void InvalidateRange(u32 start_address, u32 size); static void MakeRangeDynamic(u32 start_address, u32 size); static void ClearRenderTargets(); // currently only used by OGL diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp index 23f355fe3b..5be72e4fcf 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp @@ -161,7 +161,7 @@ void VertexManager::AddVertices(int primitive, int numVertices) void VertexManager::Flush() { // loading a state will invalidate BP, so check for it - BPReload(); + g_video_backend->CheckInvalidState(); g_vertex_manager->vFlush(); } diff --git a/Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp b/Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp index 3c6fdcca38..cbd7ccbceb 100644 --- a/Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp +++ b/Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp @@ -95,6 +95,11 @@ void VideoSoftware::DoState(PointerWrap&) // NYI } +void VideoSoftware::CheckInvalidState() +{ + // there is no state to invalidate +} + void VideoSoftware::PauseAndLock(bool doLock, bool unpauseOnUnlock) { if (doLock) diff --git a/Source/Plugins/Plugin_VideoSoftware/Src/VideoBackend.h b/Source/Plugins/Plugin_VideoSoftware/Src/VideoBackend.h index c0309c95c1..3e1490031f 100644 --- a/Source/Plugins/Plugin_VideoSoftware/Src/VideoBackend.h +++ b/Source/Plugins/Plugin_VideoSoftware/Src/VideoBackend.h @@ -50,6 +50,9 @@ class VideoSoftware : public VideoBackend void PauseAndLock(bool doLock, bool unpauseOnUnlock=true); void DoState(PointerWrap &p); + +public: + void CheckInvalidState(); }; }