diff --git a/Source/gs/GSH_Vulkan/GSH_Vulkan.cpp b/Source/gs/GSH_Vulkan/GSH_Vulkan.cpp index c9a1788be8..eb9fdc962e 100644 --- a/Source/gs/GSH_Vulkan/GSH_Vulkan.cpp +++ b/Source/gs/GSH_Vulkan/GSH_Vulkan.cpp @@ -1,8 +1,9 @@ +#include "GSH_Vulkan.h" #include +#include "std_experimental_map.h" #include "../GsPixelFormats.h" #include "../../Log.h" #include "../../AppConfig.h" -#include "GSH_Vulkan.h" #include "GSH_VulkanPlatformDefs.h" #include "GSH_VulkanDrawDesktop.h" #include "GSH_VulkanDrawMobile.h" @@ -269,7 +270,12 @@ void CGSH_Vulkan::FlipImpl() } PresentBackbuffer(); - m_copiedThisFrame = false; + for(auto& xferHistoryPair : m_xferHistory) + { + xferHistoryPair.second.Advance(); + } + std::experimental::erase_if(m_xferHistory, + [](const auto& xferTrackerPair) { return xferTrackerPair.second.IsEmpty(); }); CGSHandler::FlipImpl(); } @@ -1321,8 +1327,7 @@ void CGSH_Vulkan::ProcessLocalToHostTransfer() bool readsEnabled = CAppConfig::GetInstance().GetPreferenceBoolean(PREF_CGSHANDLER_GS_RAM_READS_ENABLED); if(readsEnabled) { - //Make sure our local RAM copy is in sync with GPU - //SyncMemoryCache(); + //TODO: Handle transfers with offsets in TRXPOS. m_draw->FlushRenderPass(); @@ -1330,6 +1335,10 @@ void CGSH_Vulkan::ProcessLocalToHostTransfer() auto trxReg = make_convertible(m_nReg[GS_REG_TRXREG]); auto trxPos = make_convertible(m_nReg[GS_REG_TRXPOS]); + m_xferHistory.insert(std::make_pair(bltBuf, LOCAL_TO_HOST_XFER_HISTORY{})); + auto transfer = m_xferHistory.find(bltBuf); + transfer->second.MarkUsed(); + CGsCachedArea area; area.SetArea(bltBuf.nSrcPsm, bltBuf.GetSrcPtr(), bltBuf.GetSrcWidth(), trxReg.nRRH); @@ -1358,18 +1367,19 @@ void CGSH_Vulkan::ProcessLocalToHostTransfer() m_context->device.vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &bufferCopy); } - if(!m_copiedThisFrame) + if(!transfer->second.IsRecurring()) { - void* bufferPtr = nullptr; - auto result = m_context->device.vkMapMemory(m_context->device, dstBuffer.GetMemory(), copyBase, copySize, 0, &bufferPtr); - CHECKVULKANERROR(result); + m_frameCommandBuffer->Flush(); + m_context->device.vkQueueWaitIdle(m_context->queue); + } - memcpy(m_memoryCache + copyBase, bufferPtr, copySize); + void* bufferPtr = nullptr; + auto result = m_context->device.vkMapMemory(m_context->device, dstBuffer.GetMemory(), copyBase, copySize, 0, &bufferPtr); + CHECKVULKANERROR(result); - m_context->device.vkUnmapMemory(m_context->device, dstBuffer.GetMemory()); + memcpy(m_memoryCache + copyBase, bufferPtr, copySize); - m_copiedThisFrame = true; - } + m_context->device.vkUnmapMemory(m_context->device, dstBuffer.GetMemory()); } } diff --git a/Source/gs/GSH_Vulkan/GSH_Vulkan.h b/Source/gs/GSH_Vulkan/GSH_Vulkan.h index e086e18049..51d05ab84b 100644 --- a/Source/gs/GSH_Vulkan/GSH_Vulkan.h +++ b/Source/gs/GSH_Vulkan/GSH_Vulkan.h @@ -11,6 +11,7 @@ #include "GSH_VulkanTransferHost.h" #include "GSH_VulkanTransferLocal.h" #include +#include #include "../GSHandler.h" #include "../GsDebuggerInterface.h" #include "../GsCachedArea.h" @@ -88,6 +89,45 @@ class CGSH_Vulkan : public CGSHandler, public CGsDebuggerInterface CLUT_CACHE_SIZE = 32, }; + struct LOCAL_TO_HOST_XFER_HISTORY + { + static constexpr int MAX_FRAME_COUNT = 16; + static constexpr int RECURRING_THRESHOLD = 4; + + std::array used = {}; + int frameCount = 0; + + void Advance() + { + frameCount++; + if(frameCount == MAX_FRAME_COUNT) + { + memmove(used.data(), used.data() + 1, sizeof(bool) * MAX_FRAME_COUNT - 1); + frameCount--; + used[frameCount] = false; + } + } + + void MarkUsed() + { + used[frameCount] = true; + } + + bool IsRecurring() const + { + if(frameCount != (MAX_FRAME_COUNT - 1)) return false; + auto result = std::count_if(std::begin(used), std::end(used), [](bool used) { return used; }); + return result >= RECURRING_THRESHOLD; + } + + bool IsEmpty() const + { + if(frameCount != (MAX_FRAME_COUNT - 1)) return false; + auto result = std::count_if(std::begin(used), std::end(used), [](bool used) { return used; }); + return result == 0; + } + }; + virtual void PresentBackbuffer() = 0; std::vector GetPhysicalDevices(); @@ -186,7 +226,6 @@ class CGSH_Vulkan : public CGSHandler, public CGsDebuggerInterface GSH_Vulkan::TransferLocalPtr m_transferLocal; uint8* m_memoryCache = nullptr; - bool m_copiedThisFrame = false; //Draw context VERTEX m_vtxBuffer[3]; @@ -201,6 +240,7 @@ class CGSH_Vulkan : public CGSHandler, public CGsDebuggerInterface CLUTKEY m_clutStates[CLUT_CACHE_SIZE]; uint32 m_nextClutCacheIndex = 0; std::vector m_xferBuffer; + std::map m_xferHistory; //Optimization for Virtua Fighter 2, Sega Rally 95 float m_lastLineU = 0; diff --git a/Source/gs/GSHandler.cpp b/Source/gs/GSHandler.cpp index 7cae266dd5..cf513c0007 100644 --- a/Source/gs/GSHandler.cpp +++ b/Source/gs/GSHandler.cpp @@ -594,9 +594,8 @@ void CGSHandler::FeedImageData(const void* data, uint32 length) void CGSHandler::ReadImageData(void* data, uint32 length) { assert(m_writeBufferProcessIndex == m_writeBufferSize); - //SubmitWriteBuffer(); - //SendGSCall([this, data, length]() { ReadImageDataImpl(data, length); }, true); - ReadImageDataImpl(data, length); + SubmitWriteBuffer(); + SendGSCall([this, data, length]() { ReadImageDataImpl(data, length); }, true); } void CGSHandler::ProcessWriteBuffer(const CGsPacketMetadata* metadata)