mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-26 07:35:37 +00:00
Add ImageBarrierSequence
`ImageBarrierSequence` represents a sequence of batches of `VkImageMemoryBarrier`s. The intended use case is setting image state, which may involve a combination of layout transitions and queue family transfers, and may require multiple barriers executed on different queue families, in the correct order. It is moderately expensive to execute a sequence of separate queue submissions, with synchronization to prevent overlapping execution. `ImageBarrierSequence` attempts to address this in two ways: - `ImageBarrierSequence::Merge` allows separate barrier sequences (e.g. on separate images) to be merged, so that, e.g. the first batches from each of the barrier sequences are all run together. - `InlineSetupImageBarriers`/`InlineCleanupImageBarriers` allow barriers to be inlined into an existing command buffer, when possible. E.g. to read the contents of an image, the barrier sequence may simply have a layout transition to `TRANSFER_SRC_OPTIMAL` (assuming the image is already on the correct queue family), and this can be inlined into the command buffer before executing the copy, avoiding the need for an extra queue submission. Change-Id: I7f2edc650d9ff66871c9be5711789bfe33ca8c5e
This commit is contained in:
committed by
Baldur Karlsson
parent
c84fcc2aae
commit
3d90609e39
@@ -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
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vk_bindless_feedback.cpp" />
|
||||
<ClCompile Include="vk_image_states.cpp" />
|
||||
<ClCompile Include="vk_msaa_array_conv.cpp" />
|
||||
<ClCompile Include="vk_next_chains.cpp" />
|
||||
<ClCompile Include="vk_outputwindow.cpp" />
|
||||
|
||||
@@ -145,6 +145,9 @@
|
||||
<ClCompile Include="vk_pixelhistory.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vk_image_states.cpp">
|
||||
<Filter>Util</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="vk_replay.h">
|
||||
|
||||
@@ -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<VkFence> submittedFences;
|
||||
rdcarray<VkImageMemoryBarrier> 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<VkImageMemoryBarrier> 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<VkImageMemoryBarrier> 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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <typename Barrier>
|
||||
void BarrierSequence<Barrier>::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<VkImageMemoryBarrier>::AddWrapped(uint32_t batchIndex,
|
||||
uint32_t queueFamilyIndex,
|
||||
const VkImageMemoryBarrier &barrier);
|
||||
|
||||
template <typename Barrier>
|
||||
void BarrierSequence<Barrier>::Merge(const BarrierSequence<Barrier> &other)
|
||||
{
|
||||
for(uint32_t batchIndex = 0; batchIndex < MAX_BATCH_COUNT; ++batchIndex)
|
||||
{
|
||||
rdcarray<Barrier> *batch = batches[batchIndex];
|
||||
const rdcarray<Barrier> *otherBatch = other.batches[batchIndex];
|
||||
for(uint32_t queueFamilyIndex = 0; queueFamilyIndex < MAX_QUEUE_FAMILY_COUNT; ++queueFamilyIndex)
|
||||
{
|
||||
rdcarray<Barrier> &barriers = batch[queueFamilyIndex];
|
||||
const rdcarray<Barrier> &otherBarriers = otherBatch[queueFamilyIndex];
|
||||
barriers.insert(barriers.size(), otherBarriers.begin(), otherBarriers.size());
|
||||
barrierCount += otherBarriers.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
template void BarrierSequence<VkImageMemoryBarrier>::Merge(
|
||||
const BarrierSequence<VkImageMemoryBarrier> &other);
|
||||
|
||||
template <typename Barrier>
|
||||
bool BarrierSequence<Barrier>::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<VkImageMemoryBarrier>::IsBatchEmpty(uint32_t batchIndex) const;
|
||||
|
||||
template <>
|
||||
void BarrierSequence<VkImageMemoryBarrier>::UnwrapBarriers(rdcarray<VkImageMemoryBarrier> &barriers)
|
||||
{
|
||||
for(auto it = barriers.begin(); it != barriers.end(); ++it)
|
||||
{
|
||||
it->image = ::Unwrap(it->image);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Barrier>
|
||||
void BarrierSequence<Barrier>::ExtractUnwrappedBatch(uint32_t batchIndex, uint32_t queueFamilyIndex,
|
||||
rdcarray<Barrier> &result)
|
||||
{
|
||||
if(batchIndex >= MAX_BATCH_COUNT || queueFamilyIndex >= MAX_QUEUE_FAMILY_COUNT)
|
||||
return;
|
||||
rdcarray<Barrier> &batch = batches[batchIndex][queueFamilyIndex];
|
||||
batch.swap(result);
|
||||
batch.clear();
|
||||
barrierCount -= result.size();
|
||||
UnwrapBarriers(result);
|
||||
}
|
||||
template void BarrierSequence<VkImageMemoryBarrier>::ExtractUnwrappedBatch(
|
||||
uint32_t batchIndex, uint32_t queueFamilyIndex, rdcarray<VkImageMemoryBarrier> &result);
|
||||
|
||||
template <typename Barrier>
|
||||
void BarrierSequence<Barrier>::ExtractFirstUnwrappedBatchForQueue(uint32_t queueFamilyIndex,
|
||||
rdcarray<Barrier> &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<VkImageMemoryBarrier>::ExtractFirstUnwrappedBatchForQueue(
|
||||
uint32_t queueFamilyIndex, rdcarray<VkImageMemoryBarrier> &result);
|
||||
|
||||
template <typename Barrier>
|
||||
void BarrierSequence<Barrier>::ExtractLastUnwrappedBatchForQueue(uint32_t queueFamilyIndex,
|
||||
rdcarray<Barrier> &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<VkImageMemoryBarrier>::ExtractLastUnwrappedBatchForQueue(
|
||||
uint32_t queueFamilyIndex, rdcarray<VkImageMemoryBarrier> &result);
|
||||
@@ -1260,6 +1260,30 @@ struct ImageSubresourceRange
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Barrier>
|
||||
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<Barrier> 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<Barrier> &other);
|
||||
bool IsBatchEmpty(uint32_t batchIndex) const;
|
||||
void ExtractUnwrappedBatch(uint32_t batchIndex, uint32_t queueFamilyIndex,
|
||||
rdcarray<Barrier> &result);
|
||||
void ExtractFirstUnwrappedBatchForQueue(uint32_t queueFamilyIndex, rdcarray<Barrier> &result);
|
||||
void ExtractLastUnwrappedBatchForQueue(uint32_t queueFamilyIndex, rdcarray<Barrier> &result);
|
||||
inline bool empty() const { return barrierCount == 0; }
|
||||
inline size_t size() const { return barrierCount; }
|
||||
static void UnwrapBarriers(rdcarray<Barrier> &barriers);
|
||||
};
|
||||
|
||||
using ImageBarrierSequence = BarrierSequence<VkImageMemoryBarrier>;
|
||||
|
||||
struct ImgRefs
|
||||
{
|
||||
rdcarray<FrameRefType> rangeRefs;
|
||||
|
||||
Reference in New Issue
Block a user