diff --git a/renderdoc/driver/vulkan/CMakeLists.txt b/renderdoc/driver/vulkan/CMakeLists.txt index 138fb9d59..00c01d529 100644 --- a/renderdoc/driver/vulkan/CMakeLists.txt +++ b/renderdoc/driver/vulkan/CMakeLists.txt @@ -22,6 +22,7 @@ set(sources vk_dispatchtables.h vk_dispatch_defs.h vk_hookset_defs.h + vk_image_states.cpp vk_info.cpp vk_info.h vk_initstate.cpp diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj index 078b7f00e..d09ab8a5e 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj @@ -108,6 +108,7 @@ true + diff --git a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters index 20a2021d6..0850c0f75 100644 --- a/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters +++ b/renderdoc/driver/vulkan/renderdoc_vulkan.vcxproj.filters @@ -145,6 +145,9 @@ Replay + + Util + diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 625bba39b..1b18324b2 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -488,6 +488,122 @@ void WrappedVulkan::SubmitAndFlushExtQueue(uint32_t queueFamilyIdx) const ObjDisp(q)->QueueWaitIdle(Unwrap(q)); } +void WrappedVulkan::SubmitAndFlushImageStateBarriers(ImageBarrierSequence &barriers) +{ + if(barriers.empty()) + return; + + VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, NULL, + VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT}; + VkFence queueFamilyFences[ImageBarrierSequence::MAX_QUEUE_FAMILY_COUNT] = { + VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE}; + rdcarray submittedFences; + rdcarray batch; + VkResult vkr; + for(uint32_t batchIndex = 0; batchIndex < ImageBarrierSequence::MAX_BATCH_COUNT; ++batchIndex) + { + for(uint32_t queueFamilyIndex = 0; + queueFamilyIndex < ImageBarrierSequence::MAX_QUEUE_FAMILY_COUNT; ++queueFamilyIndex) + { + barriers.ExtractUnwrappedBatch(batchIndex, queueFamilyIndex, batch); + if(batch.empty()) + continue; + + VkCommandBuffer cmd = GetExtQueueCmd(queueFamilyIndex); + VkQueue queue = m_ExternalQueues[queueFamilyIndex].queue; + + VkCommandBuffer unwrappedCmd = Unwrap(cmd); + + VkSubmitInfo submitInfo = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, + NULL, + 0, + NULL, + NULL, // wait semaphores + 1, + &unwrappedCmd, // command buffers + 0, + NULL, // signal semaphores + }; + +#if ENABLED(SINGLE_FLUSH_VALIDATE) + for(auto it = queueBatch.begin(); it != queueBatch.end(); ++it) + { + vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + DoPipelineBarrier(cmd, 1, it); + vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + vkr = ObjDisp(queue)->QueueSubmit(Unwrap(queue), 1, &submitInfo, VK_NULL_HANDLE); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + vkr = ObjDisp(queue)->QueueWaitIdle(Unwrap(queue)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } +#else + vkr = ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &beginInfo); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + DoPipelineBarrier(cmd, (uint32_t)batch.size(), batch.data()); + + vkr = ObjDisp(cmd)->EndCommandBuffer(Unwrap(cmd)); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + + VkFence &fence = queueFamilyFences[queueFamilyIndex]; + if(fence == VK_NULL_HANDLE) + { + VkFenceCreateInfo fenceInfo = { + /* sType = */ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + /* pNext = */ NULL, + /* flags = */ 0, + }; + vkr = ObjDisp(m_Device)->CreateFence(Unwrap(m_Device), &fenceInfo, NULL, &fence); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + } + + vkr = ObjDisp(queue)->QueueSubmit(Unwrap(queue), 1, &submitInfo, fence); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + submittedFences.push_back(fence); +#endif + batch.clear(); + } + if(!submittedFences.empty()) + { + vkr = ObjDisp(m_Device)->WaitForFences(Unwrap(m_Device), (uint32_t)submittedFences.size(), + submittedFences.data(), VK_TRUE, 1000000000); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + vkr = ObjDisp(m_Device)->ResetFences(Unwrap(m_Device), (uint32_t)submittedFences.size(), + submittedFences.data()); + RDCASSERTEQUAL(vkr, VK_SUCCESS); + submittedFences.clear(); + } + } + for(uint32_t queueFamilyIndex = 0; + queueFamilyIndex < ImageBarrierSequence::MAX_QUEUE_FAMILY_COUNT; ++queueFamilyIndex) + { + if(queueFamilyFences[queueFamilyIndex] != VK_NULL_HANDLE) + ObjDisp(m_Device)->DestroyFence(Unwrap(m_Device), queueFamilyFences[queueFamilyIndex], NULL); + } +} + +void WrappedVulkan::InlineSetupImageBarriers(VkCommandBuffer cmd, ImageBarrierSequence &barriers) +{ + rdcarray batch; + barriers.ExtractLastUnwrappedBatchForQueue(m_QueueFamilyIdx, batch); + if(!batch.empty()) + DoPipelineBarrier(cmd, (uint32_t)batch.size(), batch.data()); +} + +void WrappedVulkan::InlineCleanupImageBarriers(VkCommandBuffer cmd, ImageBarrierSequence &barriers) +{ + rdcarray batch; + barriers.ExtractFirstUnwrappedBatchForQueue(m_QueueFamilyIdx, batch); + if(!batch.empty()) + DoPipelineBarrier(cmd, (uint32_t)batch.size(), batch.data()); +} + uint32_t WrappedVulkan::HandlePreCallback(VkCommandBuffer commandBuffer, DrawFlags type, uint32_t multiDrawOffset) { diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 004704330..6f894c889 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -435,6 +435,10 @@ private: VkCommandBuffer GetExtQueueCmd(uint32_t queueFamilyIdx) const; void SubmitAndFlushExtQueue(uint32_t queueFamilyIdx) const; + void SubmitAndFlushImageStateBarriers(ImageBarrierSequence &barriers); + void InlineSetupImageBarriers(VkCommandBuffer cmd, ImageBarrierSequence &batches); + void InlineCleanupImageBarriers(VkCommandBuffer cmd, ImageBarrierSequence &batches); + struct QueueRemap { uint32_t family; diff --git a/renderdoc/driver/vulkan/vk_image_states.cpp b/renderdoc/driver/vulkan/vk_image_states.cpp new file mode 100644 index 000000000..7b85d02cf --- /dev/null +++ b/renderdoc/driver/vulkan/vk_image_states.cpp @@ -0,0 +1,134 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "vk_resources.h" + +template +void BarrierSequence::AddWrapped(uint32_t batchIndex, uint32_t queueFamilyIndex, + const Barrier &barrier) +{ + RDCASSERT(batchIndex < MAX_BATCH_COUNT); + RDCASSERT(queueFamilyIndex < MAX_QUEUE_FAMILY_COUNT); + batches[batchIndex][queueFamilyIndex].push_back(barrier); + ++barrierCount; +} +template void BarrierSequence::AddWrapped(uint32_t batchIndex, + uint32_t queueFamilyIndex, + const VkImageMemoryBarrier &barrier); + +template +void BarrierSequence::Merge(const BarrierSequence &other) +{ + for(uint32_t batchIndex = 0; batchIndex < MAX_BATCH_COUNT; ++batchIndex) + { + rdcarray *batch = batches[batchIndex]; + const rdcarray *otherBatch = other.batches[batchIndex]; + for(uint32_t queueFamilyIndex = 0; queueFamilyIndex < MAX_QUEUE_FAMILY_COUNT; ++queueFamilyIndex) + { + rdcarray &barriers = batch[queueFamilyIndex]; + const rdcarray &otherBarriers = otherBatch[queueFamilyIndex]; + barriers.insert(barriers.size(), otherBarriers.begin(), otherBarriers.size()); + barrierCount += otherBarriers.size(); + } + } +} +template void BarrierSequence::Merge( + const BarrierSequence &other); + +template +bool BarrierSequence::IsBatchEmpty(uint32_t batchIndex) const +{ + if(batchIndex > MAX_BATCH_COUNT) + return true; + for(uint32_t queueFamilyIndex = 0; queueFamilyIndex < MAX_QUEUE_FAMILY_COUNT; ++queueFamilyIndex) + { + if(!batches[batchIndex][queueFamilyIndex].empty()) + return false; + } + return true; +} +template bool BarrierSequence::IsBatchEmpty(uint32_t batchIndex) const; + +template <> +void BarrierSequence::UnwrapBarriers(rdcarray &barriers) +{ + for(auto it = barriers.begin(); it != barriers.end(); ++it) + { + it->image = ::Unwrap(it->image); + } +} + +template +void BarrierSequence::ExtractUnwrappedBatch(uint32_t batchIndex, uint32_t queueFamilyIndex, + rdcarray &result) +{ + if(batchIndex >= MAX_BATCH_COUNT || queueFamilyIndex >= MAX_QUEUE_FAMILY_COUNT) + return; + rdcarray &batch = batches[batchIndex][queueFamilyIndex]; + batch.swap(result); + batch.clear(); + barrierCount -= result.size(); + UnwrapBarriers(result); +} +template void BarrierSequence::ExtractUnwrappedBatch( + uint32_t batchIndex, uint32_t queueFamilyIndex, rdcarray &result); + +template +void BarrierSequence::ExtractFirstUnwrappedBatchForQueue(uint32_t queueFamilyIndex, + rdcarray &result) +{ + for(uint32_t batchIndex = 0; batchIndex < MAX_BATCH_COUNT; ++batchIndex) + { + if(!IsBatchEmpty(batchIndex)) + { + batches[batchIndex][queueFamilyIndex].swap(result); + batches[batchIndex][queueFamilyIndex].clear(); + barrierCount -= result.size(); + UnwrapBarriers(result); + return; + } + } +} +template void BarrierSequence::ExtractFirstUnwrappedBatchForQueue( + uint32_t queueFamilyIndex, rdcarray &result); + +template +void BarrierSequence::ExtractLastUnwrappedBatchForQueue(uint32_t queueFamilyIndex, + rdcarray &result) +{ + for(uint32_t batchIndex = MAX_BATCH_COUNT; batchIndex > 0;) + { + --batchIndex; + if(!IsBatchEmpty(batchIndex)) + { + batches[batchIndex][queueFamilyIndex].swap(result); + batches[batchIndex][queueFamilyIndex].clear(); + barrierCount -= result.size(); + UnwrapBarriers(result); + return; + } + } +} +template void BarrierSequence::ExtractLastUnwrappedBatchForQueue( + uint32_t queueFamilyIndex, rdcarray &result); diff --git a/renderdoc/driver/vulkan/vk_resources.h b/renderdoc/driver/vulkan/vk_resources.h index 665026142..e7d5d9b8f 100644 --- a/renderdoc/driver/vulkan/vk_resources.h +++ b/renderdoc/driver/vulkan/vk_resources.h @@ -1260,6 +1260,30 @@ struct ImageSubresourceRange } }; +template +struct BarrierSequence +{ + static const uint32_t MAX_BATCH_COUNT = 4; + static const uint32_t MAX_QUEUE_FAMILY_COUNT = 3; + + // batches[batchIndex][queueFamilyIndex] = array of barriers to submit to queueFamilyIndex as part + // of batchIndex + rdcarray batches[MAX_BATCH_COUNT][MAX_QUEUE_FAMILY_COUNT]; + size_t barrierCount = 0; + void AddWrapped(uint32_t batchIndex, uint32_t queueFamilyIndex, const Barrier &barrier); + void Merge(const BarrierSequence &other); + bool IsBatchEmpty(uint32_t batchIndex) const; + void ExtractUnwrappedBatch(uint32_t batchIndex, uint32_t queueFamilyIndex, + rdcarray &result); + void ExtractFirstUnwrappedBatchForQueue(uint32_t queueFamilyIndex, rdcarray &result); + void ExtractLastUnwrappedBatchForQueue(uint32_t queueFamilyIndex, rdcarray &result); + inline bool empty() const { return barrierCount == 0; } + inline size_t size() const { return barrierCount; } + static void UnwrapBarriers(rdcarray &barriers); +}; + +using ImageBarrierSequence = BarrierSequence; + struct ImgRefs { rdcarray rangeRefs;