From 39431bb83f5404e7be1f3ff91a31a3e18e8ceeb9 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 31 Jul 2020 17:20:25 +0100 Subject: [PATCH] Don't flush mapped memory in driver for detected coherent memory writes --- renderdoc/driver/vulkan/vk_common.h | 1 + renderdoc/driver/vulkan/vk_core.cpp | 1 + renderdoc/driver/vulkan/vk_core.h | 4 +++ renderdoc/driver/vulkan/vk_stringise.cpp | 3 ++- .../driver/vulkan/wrappers/vk_queue_funcs.cpp | 10 +++++--- .../vulkan/wrappers/vk_resource_funcs.cpp | 23 ++++++++++++++--- util/test/demos/vk/vk_misaligned_dirty.cpp | 25 +++++++++++++++++-- util/test/tests/Vulkan/VK_Misaligned_Dirty.py | 12 ++++++++- 8 files changed, 69 insertions(+), 10 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 6ffbe033a..bd875b3cd 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -617,6 +617,7 @@ enum class VulkanChunk : uint32_t vkCmdSetDepthBoundsTestEnableEXT, vkCmdSetStencilTestEnableEXT, vkCmdSetStencilOpEXT, + CoherentMapWrite, Max, }; diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 586be74b8..cc16eb472 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -2720,6 +2720,7 @@ bool WrappedVulkan::ProcessChunk(ReadSerialiser &ser, VulkanChunk chunk) case VulkanChunk::vkUnmapMemory: return Serialise_vkUnmapMemory(ser, VK_NULL_HANDLE, VK_NULL_HANDLE); case VulkanChunk::vkFlushMappedMemoryRanges: + case VulkanChunk::CoherentMapWrite: return Serialise_vkFlushMappedMemoryRanges(ser, VK_NULL_HANDLE, 0, NULL); case VulkanChunk::vkCreateCommandPool: return Serialise_vkCreateCommandPool(ser, VK_NULL_HANDLE, NULL, NULL, NULL); diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index b5b05a2d3..73e7ac5e7 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -680,6 +680,10 @@ private: // All IDs are original IDs, not live. VulkanRenderState m_RenderState; + // an internal structure used to differentiate forced vkFlushMappedMemoryRanges due to coherent + // map writes from real calls to vkFlushMappedMemoryRanges + VkBaseInStructure internalMemoryFlushMarker = {}; + bool InRerecordRange(ResourceId cmdid); bool HasRerecordCmdBuf(ResourceId cmdid); bool ShouldUpdateRenderState(ResourceId cmdid, bool forcePrimary = false); diff --git a/renderdoc/driver/vulkan/vk_stringise.cpp b/renderdoc/driver/vulkan/vk_stringise.cpp index 28903700a..3322cc613 100644 --- a/renderdoc/driver/vulkan/vk_stringise.cpp +++ b/renderdoc/driver/vulkan/vk_stringise.cpp @@ -28,7 +28,7 @@ template <> rdcstr DoStringise(const VulkanChunk &el) { - RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1152, "Chunks changed without updating names"); + RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1153, "Chunks changed without updating names"); BEGIN_ENUM_STRINGISE(VulkanChunk) { @@ -184,6 +184,7 @@ rdcstr DoStringise(const VulkanChunk &el) STRINGISE_ENUM_CLASS(vkCmdSetDepthBoundsTestEnableEXT); STRINGISE_ENUM_CLASS(vkCmdSetStencilTestEnableEXT); STRINGISE_ENUM_CLASS(vkCmdSetStencilOpEXT); + STRINGISE_ENUM_CLASS_NAMED(CoherentMapWrite, "Internal: Coherent Mapped Memory Write") STRINGISE_ENUM_CLASS_NAMED(Max, "Max Chunk"); } END_ENUM_STRINGISE() diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index 00491d973..912155a9b 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -1137,9 +1137,13 @@ VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount, { RDCLOG("Persistent map flush forced for %s (%llu -> %llu)", ToStr(record->GetResourceID()).c_str(), (uint64_t)diffStart, (uint64_t)diffEnd); - VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, NULL, - (VkDeviceMemory)(uint64_t)record->Resource, - state.mapOffset + diffStart, diffEnd - diffStart}; + VkMappedMemoryRange range = { + VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + &internalMemoryFlushMarker, + (VkDeviceMemory)(uint64_t)record->Resource, + state.mapOffset + diffStart, + diffEnd - diffStart, + }; vkFlushMappedMemoryRanges(dev, 1, &range); state.mapFlushed = false; } diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index b94274ed4..3c39531d2 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -840,8 +840,24 @@ VkResult WrappedVulkan::vkFlushMappedMemoryRanges(VkDevice device, uint32_t memR } VkResult ret; - SERIALISE_TIME_CALL( - ret = ObjDisp(device)->FlushMappedMemoryRanges(Unwrap(device), memRangeCount, unwrapped)); + bool internalFlush = false; + + // don't call the driver for a fake coherent map flush + if(memRangeCount == 1 && pMemRanges->pNext == &internalMemoryFlushMarker) + { + ret = VK_SUCCESS; + internalFlush = true; + + // for simplicity we set the pNext to NULL after we've seen our internal marker. We can safely + // modify this because it's a temporary variable in the calling stackframe + VkMappedMemoryRange *range = (VkMappedMemoryRange *)pMemRanges; + range->pNext = NULL; + } + else + { + SERIALISE_TIME_CALL( + ret = ObjDisp(device)->FlushMappedMemoryRanges(Unwrap(device), memRangeCount, unwrapped)); + } if(IsCaptureMode(m_State)) { @@ -857,7 +873,8 @@ VkResult WrappedVulkan::vkFlushMappedMemoryRanges(VkDevice device, uint32_t memR { CACHE_THREAD_SERIALISER(); - SCOPED_SERIALISE_CHUNK(VulkanChunk::vkFlushMappedMemoryRanges); + SCOPED_SERIALISE_CHUNK(internalFlush ? VulkanChunk::CoherentMapWrite + : VulkanChunk::vkFlushMappedMemoryRanges); Serialise_vkFlushMappedMemoryRanges(ser, device, 1, pMemRanges + i); m_FrameCaptureRecord->AddChunk(scope.Get()); diff --git a/util/test/demos/vk/vk_misaligned_dirty.cpp b/util/test/demos/vk/vk_misaligned_dirty.cpp index 5e6f4dd50..9c8e1b735 100644 --- a/util/test/demos/vk/vk_misaligned_dirty.cpp +++ b/util/test/demos/vk/vk_misaligned_dirty.cpp @@ -58,10 +58,11 @@ RD_TEST(VK_Misaligned_Dirty, VulkanGraphicsTest) const float val = 2.0f / 3.0f; - const DefaultA2V tri[3] = { + const DefaultA2V tri[4] = { {Vec3f(-val, -val, val), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)}, {Vec3f(0.0f, val, val), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)}, {Vec3f(val, -val, val), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)}, + {}, }; AllocatedBuffer vb(this, vkh::BufferCreateInfo(sizeof(tri), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | @@ -77,10 +78,28 @@ RD_TEST(VK_Misaligned_Dirty, VulkanGraphicsTest) copy_src.upload(tri); + float *mapped = (float *)(copy_src.map() + sizeof(DefaultA2V) * 3); + + float counter = 0; while(Running()) { + mapped[2] = counter; + counter += 1.0f; + VkCommandBuffer cmd = GetCommandBuffer(); + // create a dummy submit which uses the memory. This will serialise the whole memory contents + // (we don't create reference data until after this) + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); + vkCmdUpdateBuffer(cmd, copy_src.buffer, sizeof(Vec3f), sizeof(Vec4f), &tri[0].col); + vkEndCommandBuffer(cmd); + Submit(0, 2, {cmd}); + + mapped[2] = counter; + counter += 1.0f; + + cmd = GetCommandBuffer(); + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); VkImage swapimg = @@ -112,11 +131,13 @@ RD_TEST(VK_Misaligned_Dirty, VulkanGraphicsTest) vkEndCommandBuffer(cmd); - Submit(0, 1, {cmd}); + Submit(1, 2, {cmd}); Present(); } + copy_src.unmap(); + return 0; } }; diff --git a/util/test/tests/Vulkan/VK_Misaligned_Dirty.py b/util/test/tests/Vulkan/VK_Misaligned_Dirty.py index b2ee6136e..a3f9c445f 100644 --- a/util/test/tests/Vulkan/VK_Misaligned_Dirty.py +++ b/util/test/tests/Vulkan/VK_Misaligned_Dirty.py @@ -5,8 +5,13 @@ import rdtest class VK_Misaligned_Dirty(rdtest.TestCase): demos_test_name = 'VK_Misaligned_Dirty' + def get_capture_options(self): + opts = rdtest.TestCase.get_capture_options(self) + opts.apiValidation = True + return opts + def get_replay_options(self): - opts = rd.ReplayOptions() + opts = rdtest.TestCase.get_replay_options(self) # Set a balanced optimisation level to ensure that written ranges are cleared instead of being either restored # or ignored opts.optimisation = rd.ReplayOptimisationLevel.Balanced @@ -19,6 +24,11 @@ class VK_Misaligned_Dirty(rdtest.TestCase): self.controller.SetFrameEvent(draw.eventId, False) + self.check(len(self.controller.GetFrameInfo().debugMessages) == 0) + self.check(len(self.controller.GetDebugMessages()) == 0) + + rdtest.log.success("No debug messages found") + pipe: rd.PipeState = self.controller.GetPipelineState() postvs_data = self.get_postvs(draw, rd.MeshDataStage.VSOut, 0, draw.numIndices)