Files
renderdoc/renderdoc/driver/vulkan/vk_image_states.cpp
T
baldurk 49788f34a1 Add const overload of subresource state lookup by aspect
* We also rename these functions to be distinct, since it's too easy for an
  aspect bit to be automatically cast to an aspect index.
2020-07-16 20:45:20 +01:00

1495 lines
52 KiB
C++

/******************************************************************************
* 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"
ImageSubresourceRange ImageInfo::FullRange() const
{
return ImageSubresourceRange(
/* aspectMask = */ Aspects(),
/* baseMipLevel = */ 0u,
/* levelCount = */ (uint32_t)levelCount,
/* baseArrayLayer = */ 0u,
/* layerCount = */ (uint32_t)layerCount,
/* baseDepthSlice = */ 0u,
/* sliceCount = */ extent.depth);
}
void ImageSubresourceState::Update(const ImageSubresourceState &other, FrameRefCompFunc compose)
{
if(oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
oldQueueFamilyIndex = other.oldQueueFamilyIndex;
if(other.newQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED)
newQueueFamilyIndex = other.newQueueFamilyIndex;
if(oldLayout == UNKNOWN_PREV_IMG_LAYOUT)
oldLayout = other.oldLayout;
if(other.newLayout != UNKNOWN_PREV_IMG_LAYOUT)
newLayout = other.newLayout;
refType = compose(refType, other.refType);
}
bool ImageSubresourceState::Update(const ImageSubresourceState &other,
ImageSubresourceState &result, FrameRefCompFunc compose) const
{
result = *this;
result.Update(other, compose);
return result != *this;
}
template <typename Map, typename Pair>
typename ImageSubresourceMap::SubresourceRangeIterTemplate<Map, Pair>
&ImageSubresourceMap::SubresourceRangeIterTemplate<Map, Pair>::operator++()
{
if(!IsValid())
return *this;
FixSubRange();
++m_slice;
if(IsDepthSplit(m_splitFlags) && m_slice < m_range.baseDepthSlice + m_range.sliceCount)
{
m_value.m_range.baseDepthSlice = m_slice;
return *this;
}
m_value.m_range.baseDepthSlice = m_slice = m_range.baseDepthSlice;
++m_layer;
if(AreLayersSplit(m_splitFlags) && m_layer < m_range.baseArrayLayer + m_range.layerCount)
{
m_value.m_range.baseArrayLayer = m_layer;
return *this;
}
m_value.m_range.baseArrayLayer = m_layer = m_range.baseArrayLayer;
++m_level;
if(AreLevelsSplit(m_splitFlags) && m_level < m_range.baseMipLevel + m_range.levelCount)
{
m_value.m_range.baseMipLevel = m_level;
return *this;
}
m_value.m_range.baseMipLevel = m_level = m_range.baseMipLevel;
if(AreAspectsSplit(m_splitFlags))
{
auto aspectIt = ImageAspectFlagIter(m_map->GetImageInfo().Aspects(),
(VkImageAspectFlagBits)m_value.m_range.aspectMask);
while(true)
{
++m_aspectIndex;
++aspectIt;
if(aspectIt == ImageAspectFlagIter::end())
{
break;
}
else if(m_range.aspectMask & *aspectIt)
{
m_value.m_range.aspectMask = *aspectIt;
return *this;
}
}
}
// iterator is at the end.
// make `m_aspectIndex` out of range to mark this.
m_aspectIndex = m_map->m_aspectCount;
return *this;
}
template
typename ImageSubresourceMap::SubresourceRangeIterTemplate<ImageSubresourceMap,
ImageSubresourceMap::SubresourcePairRef>
&ImageSubresourceMap::SubresourceRangeIterTemplate<
ImageSubresourceMap, ImageSubresourceMap::SubresourcePairRef>::operator++();
template typename ImageSubresourceMap::SubresourceRangeIterTemplate<
const ImageSubresourceMap, ImageSubresourceMap::ConstSubresourcePairRef>
&ImageSubresourceMap::SubresourceRangeIterTemplate<
const ImageSubresourceMap, ImageSubresourceMap::ConstSubresourcePairRef>::operator++();
void ImageSubresourceMap::Split(bool splitAspects, bool splitLevels, bool splitLayers, bool splitDepth)
{
uint16_t newFlags = m_flags;
if(splitAspects)
newFlags |= (uint16_t)FlagBits::AreAspectsSplit;
else
splitAspects = AreAspectsSplit();
if(splitLevels)
newFlags |= (uint16_t)FlagBits::AreLevelsSplit;
else
splitLevels = AreLevelsSplit();
if(splitLayers)
newFlags |= (uint16_t)FlagBits::AreLayersSplit;
else
splitLayers = AreLayersSplit();
if(splitDepth)
newFlags |= (uint16_t)FlagBits::IsDepthSplit;
else
splitDepth = IsDepthSplit();
if(newFlags == m_flags)
// not splitting anything new
return;
uint32_t oldSplitAspectCount = AreAspectsSplit() ? m_aspectCount : 1;
uint32_t newSplitAspectCount = splitAspects ? m_aspectCount : oldSplitAspectCount;
uint32_t oldSplitLevelCount = AreLevelsSplit() ? GetImageInfo().levelCount : 1;
uint32_t newSplitLevelCount = splitLevels ? GetImageInfo().levelCount : oldSplitLevelCount;
uint32_t oldSplitLayerCount = AreLayersSplit() ? GetImageInfo().layerCount : 1;
uint32_t newSplitLayerCount = splitLayers ? GetImageInfo().layerCount : oldSplitLayerCount;
uint32_t oldSplitSliceCount = IsDepthSplit() ? GetImageInfo().extent.depth : 1;
uint32_t newSplitSliceCount = splitDepth ? GetImageInfo().extent.depth : oldSplitSliceCount;
uint32_t oldSize = (uint32_t)m_values.size();
RDCASSERT(oldSize > 0);
uint32_t newSize =
newSplitAspectCount * newSplitLevelCount * newSplitLayerCount * newSplitSliceCount;
RDCASSERT(newSize > oldSize);
m_values.resize(newSize);
uint32_t newAspectIndex = newSplitAspectCount - 1;
uint32_t oldAspectIndex = AreAspectsSplit() ? newAspectIndex : 0;
uint32_t newLevel = newSplitLevelCount - 1;
uint32_t oldLevel = AreLevelsSplit() ? newLevel : 0;
uint32_t newLayer = newSplitLayerCount - 1;
uint32_t oldLayer = AreLayersSplit() ? newLayer : 0;
uint32_t newSlice = newSplitSliceCount - 1;
uint32_t oldSlice = IsDepthSplit() ? newSlice : 0;
uint32_t newIndex = newSize - 1;
while(true)
{
uint32_t oldIndex =
((oldAspectIndex * oldSplitLevelCount + oldLevel) * oldSplitLayerCount + oldLayer) *
oldSplitSliceCount +
oldSlice;
m_values[newIndex] = m_values[oldIndex];
if(newIndex == 0)
{
RDCASSERT(oldIndex == 0);
break;
}
--newIndex;
if(newSlice > 0)
{
--newSlice;
oldSlice = IsDepthSplit() ? newSlice : 0;
continue;
}
newSlice = newSplitSliceCount - 1;
oldSlice = oldSplitSliceCount - 1;
if(newLayer > 0)
{
--newLayer;
oldLayer = AreLayersSplit() ? newLayer : 0;
continue;
}
newLayer = newSplitLayerCount - 1;
oldLayer = oldSplitLayerCount - 1;
if(newLevel > 0)
{
--newLevel;
oldLevel = AreLevelsSplit() ? newLevel : 0;
continue;
}
newLevel = newSplitLevelCount - 1;
oldLevel = oldSplitLevelCount - 1;
if(newAspectIndex > 0)
{
--newAspectIndex;
oldAspectIndex = AreAspectsSplit() ? newAspectIndex : 0;
continue;
}
RDCERR("Too many subresources in ImageSubresourceMap::Split");
break;
}
m_flags = newFlags;
}
void ImageSubresourceMap::Unsplit(bool unsplitAspects, bool unsplitLevels, bool unsplitLayers,
bool unsplitDepth)
{
uint16_t newFlags = m_flags;
if(unsplitAspects)
newFlags &= ~(uint16_t)FlagBits::AreAspectsSplit;
if(unsplitLevels)
newFlags &= ~(uint16_t)FlagBits::AreLevelsSplit;
if(unsplitLayers)
newFlags &= ~(uint16_t)FlagBits::AreLayersSplit;
if(unsplitDepth)
newFlags &= ~(uint16_t)FlagBits::IsDepthSplit;
if(newFlags == m_flags)
// not splitting anything new
return;
uint32_t oldSplitAspectCount = AreAspectsSplit() ? m_aspectCount : 1;
uint32_t newSplitAspectCount = unsplitAspects ? 1 : oldSplitAspectCount;
uint32_t oldSplitLevelCount = AreLevelsSplit() ? GetImageInfo().levelCount : 1;
uint32_t newSplitLevelCount = unsplitLevels ? 1 : oldSplitLevelCount;
uint32_t oldSplitLayerCount = AreLayersSplit() ? GetImageInfo().layerCount : 1;
uint32_t newSplitLayerCount = unsplitLayers ? 1 : oldSplitLayerCount;
uint32_t oldSplitSliceCount = IsDepthSplit() ? GetImageInfo().extent.depth : 1;
uint32_t newSplitSliceCount = unsplitDepth ? 1 : oldSplitSliceCount;
uint32_t oldSize = (uint32_t)m_values.size();
RDCASSERT(oldSize > 0);
uint32_t newSize =
newSplitAspectCount * newSplitLevelCount * newSplitLayerCount * newSplitSliceCount;
RDCASSERT(newSize < oldSize);
rdcarray<ImageSubresourceState> newValues;
newValues.resize(newSize);
uint32_t aspectIndex = 0;
uint32_t level = 0;
uint32_t layer = 0;
uint32_t slice = 0;
uint32_t newIndex = 0;
while(newIndex < newValues.size())
{
uint32_t oldIndex = ((aspectIndex * oldSplitLevelCount + level) * oldSplitLayerCount + layer) *
oldSplitSliceCount +
slice;
newValues[newIndex] = m_values[oldIndex];
++newIndex;
++slice;
if(slice < newSplitSliceCount)
continue;
slice = 0;
++layer;
if(layer < newSplitLayerCount)
continue;
layer = 0;
++level;
if(level < newSplitLevelCount)
continue;
level = 0;
++aspectIndex;
}
newValues.swap(m_values);
m_flags = newFlags;
}
void ImageSubresourceMap::Unsplit()
{
if(m_values.size() == 1)
return;
uint32_t aspectCount = AreAspectsSplit() ? m_aspectCount : 1;
uint32_t aspectIndex = 0;
uint32_t levelCount = AreLevelsSplit() ? m_imageInfo.levelCount : 1;
uint32_t level = 0;
uint32_t layerCount = AreLayersSplit() ? m_imageInfo.layerCount : 1;
uint32_t layer = 0;
uint32_t sliceCount = IsDepthSplit() ? m_imageInfo.extent.depth : 1;
uint32_t slice = 0;
uint32_t index = 0;
bool canUnsplitAspects = aspectCount > 1;
bool canUnsplitLevels = levelCount > 1;
bool canUnsplitLayers = layerCount > 1;
bool canUnsplitDepth = sliceCount > 1;
RDCASSERT(aspectCount * levelCount * layerCount * sliceCount == m_values.size());
#define UNSPLIT_INDEX(ASPECT, LEVEL, LAYER, SLICE) \
((((ASPECT)*levelCount + (LEVEL)) * layerCount + (LAYER)) * sliceCount + (SLICE))
while(index < m_values.size() &&
(canUnsplitAspects || canUnsplitLevels || canUnsplitLayers || canUnsplitDepth))
{
if(canUnsplitAspects && aspectIndex > 0)
{
uint32_t index0 = UNSPLIT_INDEX(0, level, layer, slice);
if(m_values[index] != m_values[index0])
canUnsplitAspects = false;
}
if(canUnsplitLevels && level > 0)
{
uint32_t index0 = UNSPLIT_INDEX(aspectIndex, 0, layer, slice);
if(m_values[index] != m_values[index0])
canUnsplitLevels = false;
}
if(canUnsplitLayers && layer > 0)
{
uint32_t index0 = UNSPLIT_INDEX(aspectIndex, level, 0, slice);
if(m_values[index] != m_values[index0])
canUnsplitLayers = false;
}
if(canUnsplitDepth && slice > 0)
{
uint32_t index0 = UNSPLIT_INDEX(aspectIndex, level, layer, 0);
if(m_values[index] != m_values[index0])
canUnsplitDepth = false;
}
++index;
++slice;
if(slice < sliceCount)
continue;
slice = 0;
++layer;
if(layer < layerCount)
continue;
layer = 0;
++level;
if(level < levelCount)
continue;
level = 0;
++aspectIndex;
if(aspectIndex >= aspectCount)
break;
}
#undef UNSPLIT_INDEX
Unsplit(canUnsplitAspects, canUnsplitLevels, canUnsplitLayers, canUnsplitDepth);
}
inline FrameRefType ImageSubresourceMap::Merge(const ImageSubresourceMap &other,
FrameRefCompFunc compose)
{
FrameRefType maxRefType = eFrameRef_None;
bool didSplit = false;
for(auto oIt = other.begin(); oIt != other.end(); ++oIt)
{
for(auto it = RangeBegin(oIt->range()); it != end(); ++it)
{
ImageSubresourceState subState;
if(it->state().Update(oIt->state(), subState, compose))
{
if(!didSplit)
{
Split(oIt->range());
didSplit = true;
}
RDCASSERT(it->range().ContainedIn(oIt->range()));
it->SetState(subState);
maxRefType = ComposeFrameRefsDisjoint(maxRefType, subState.refType);
}
}
}
return maxRefType;
}
size_t ImageSubresourceMap::SubresourceIndex(uint32_t aspectIndex, uint32_t level, uint32_t layer,
uint32_t slice) const
{
if(!AreAspectsSplit())
aspectIndex = 0;
int splitLevelCount = 1;
if(AreLevelsSplit())
splitLevelCount = GetImageInfo().levelCount;
else
level = 0;
int splitLayerCount = 1;
if(AreLayersSplit())
splitLayerCount = GetImageInfo().layerCount;
else
layer = 0;
int splitSliceCount = 1;
if(IsDepthSplit())
splitSliceCount = GetImageInfo().extent.depth;
else
slice = 0;
return ((aspectIndex * splitLevelCount + level) * splitLayerCount + layer) * splitSliceCount +
slice;
}
void ImageSubresourceMap::ToArray(rdcarray<ImageSubresourceStateForRange> &arr)
{
arr.reserve(arr.size() + m_values.size());
for(auto src = begin(); src != end(); ++src)
{
arr.push_back(*src);
}
}
void ImageSubresourceMap::FromArray(const rdcarray<ImageSubresourceStateForRange> &arr)
{
if(arr.empty())
{
RDCERR("No values for ImageSubresourceMap");
return;
}
Split(arr.front().range);
if(m_values.size() != arr.size())
{
RDCERR("Incorrect number of values for ImageSubresourceMap");
return;
}
auto src = arr.begin();
auto dst = begin();
while(src != arr.end())
{
if(src->range != dst->range())
RDCERR("Subresource range mismatch in ImageSubresourceMap");
else
dst->SetState(src->state);
++src;
++dst;
}
}
void ImageSubresourceMap::FromImgRefs(const ImgRefs &imgRefs)
{
bool splitLayers = imgRefs.areLayersSplit;
bool splitDepth = false;
if(GetImageInfo().extent.depth > 1)
{
RDCASSERT(GetImageInfo().layerCount == 1);
splitDepth = splitLayers;
splitLayers = false;
}
Split(imgRefs.areAspectsSplit, imgRefs.areLevelsSplit, splitLayers, splitDepth);
RDCASSERT(!(AreLayersSplit() && IsDepthSplit()));
for(auto dstIt = begin(); dstIt != end(); ++dstIt)
{
int aspectIndex = imgRefs.AspectIndex((VkImageAspectFlagBits)dstIt->range().aspectMask);
int level = (int)dstIt->range().baseMipLevel;
int layer = (int)(dstIt->range().baseArrayLayer + dstIt->range().baseDepthSlice);
dstIt->state().refType = imgRefs.SubresourceRef(aspectIndex, level, layer);
}
}
bool IntervalsOverlap(uint32_t base1, uint32_t count1, uint32_t base2, uint32_t count2)
{
if((base1 + count1) < base1)
{
// integer overflow
if(count1 != VK_REMAINING_MIP_LEVELS)
RDCWARN("Integer overflow in interval: base=%u, count=%u", base1, count1);
count1 = UINT32_MAX - base1;
}
if((base2 + count2) < base2)
{
// integer overflow
if(count2 != VK_REMAINING_MIP_LEVELS)
RDCWARN("Integer overflow in interval: base=%u, count=%u", base2, count2);
count2 = UINT32_MAX - base2;
}
if(count1 == 0 || count2 == 0)
return false; // one of the intervals is empty, so no overlap
if(base1 > base2)
{
std::swap(base1, base2);
std::swap(count1, count2);
}
return base2 < base1 + count1;
}
bool IntervalContainedIn(uint32_t base1, uint32_t count1, uint32_t base2, uint32_t count2)
{
if((base1 + count1) < base1)
{
// integer overflow
if(count1 != VK_REMAINING_MIP_LEVELS)
RDCWARN("Integer overflow in interval: base=%u, count=%u", base1, count1);
count1 = UINT32_MAX - base1;
}
if((base2 + count2) < base2)
{
// integer overflow
if(count2 != VK_REMAINING_MIP_LEVELS)
RDCWARN("Integer overflow in interval: base=%u, count=%u", base2, count2);
count2 = UINT32_MAX - base2;
}
return base1 >= base2 && base1 + count1 <= base2 + count2;
}
bool SanitiseLevelRange(uint32_t &baseMipLevel, uint32_t &levelCount, uint32_t imageLevelCount)
{
bool res = true;
if(baseMipLevel > imageLevelCount)
{
RDCWARN("baseMipLevel (%u) is greater than image levelCount (%u)", baseMipLevel, imageLevelCount);
baseMipLevel = imageLevelCount;
res = false;
}
if(levelCount == VK_REMAINING_MIP_LEVELS)
{
levelCount = imageLevelCount - baseMipLevel;
}
else if(levelCount > imageLevelCount - baseMipLevel)
{
RDCWARN("baseMipLevel (%u) + levelCount (%u) is greater than the image levelCount (%u)",
baseMipLevel, levelCount, imageLevelCount);
levelCount = imageLevelCount - baseMipLevel;
res = false;
}
return res;
}
bool SanitiseLayerRange(uint32_t &baseArrayLayer, uint32_t &layerCount, uint32_t imageLayerCount)
{
bool res = true;
if(baseArrayLayer > imageLayerCount)
{
RDCWARN("baseArrayLayer (%u) is greater than image layerCount (%u)", baseArrayLayer,
imageLayerCount);
baseArrayLayer = imageLayerCount;
res = false;
}
if(layerCount == VK_REMAINING_ARRAY_LAYERS)
{
layerCount = imageLayerCount - baseArrayLayer;
}
else if(layerCount > imageLayerCount - baseArrayLayer)
{
RDCWARN("baseArrayLayer (%u) + layerCount (%u) is greater than the image layerCount (%u)",
baseArrayLayer, layerCount, imageLayerCount);
layerCount = imageLayerCount - baseArrayLayer;
res = false;
}
return res;
}
bool SanitiseSliceRange(uint32_t &baseSlice, uint32_t &sliceCount, uint32_t imageSliceCount)
{
bool res = true;
if(baseSlice > imageSliceCount)
{
RDCWARN("baseSlice (%u) is greater than image sliceCount (%u)", baseSlice, imageSliceCount);
baseSlice = imageSliceCount;
res = false;
}
if(sliceCount == VK_REMAINING_ARRAY_LAYERS)
{
sliceCount = imageSliceCount - baseSlice;
}
else if(sliceCount > imageSliceCount - baseSlice)
{
RDCWARN("baseSlice (%u) + sliceCount (%u) is greater than the image sliceCount (%u)", baseSlice,
sliceCount, imageSliceCount);
sliceCount = imageSliceCount - baseSlice;
res = false;
}
return res;
}
template <typename Map, typename Pair>
ImageSubresourceMap::SubresourceRangeIterTemplate<Map, Pair>::SubresourceRangeIterTemplate(
Map &map, const ImageSubresourceRange &range)
: m_map(&map),
m_range(range),
m_level(range.baseMipLevel),
m_layer(range.baseArrayLayer),
m_slice(range.baseDepthSlice)
{
m_range.Sanitise(m_map->GetImageInfo());
m_splitFlags = (uint16_t)ImageSubresourceMap::FlagBits::IsUninitialized;
FixSubRange();
}
template ImageSubresourceMap::SubresourceRangeIterTemplate<ImageSubresourceMap,
ImageSubresourceMap::SubresourcePairRef>::
SubresourceRangeIterTemplate(ImageSubresourceMap &map, const ImageSubresourceRange &range);
template ImageSubresourceMap::SubresourceRangeIterTemplate<
const ImageSubresourceMap, ImageSubresourceMap::ConstSubresourcePairRef>::
SubresourceRangeIterTemplate(const ImageSubresourceMap &map, const ImageSubresourceRange &range);
template <typename Map, typename Pair>
void ImageSubresourceMap::SubresourceRangeIterTemplate<Map, Pair>::FixSubRange()
{
if(m_splitFlags == m_map->m_flags)
return;
uint16_t oldFlags = m_splitFlags;
m_splitFlags = m_map->m_flags;
if(IsDepthSplit(m_splitFlags))
{
m_value.m_range.baseDepthSlice = m_slice;
m_value.m_range.sliceCount = 1u;
}
else
{
m_value.m_range.baseDepthSlice = 0u;
m_value.m_range.sliceCount = m_map->GetImageInfo().extent.depth;
}
if(AreLayersSplit(m_splitFlags))
{
m_value.m_range.baseArrayLayer = m_layer;
m_value.m_range.layerCount = 1u;
}
else
{
m_value.m_range.baseArrayLayer = 0u;
m_value.m_range.layerCount = m_map->GetImageInfo().layerCount;
}
if(AreLevelsSplit(m_splitFlags))
{
m_value.m_range.baseMipLevel = m_level;
m_value.m_range.levelCount = 1u;
}
else
{
m_value.m_range.baseMipLevel = 0u;
m_value.m_range.levelCount = m_map->GetImageInfo().levelCount;
}
if(!AreAspectsSplit(m_splitFlags))
{
m_value.m_range.aspectMask = m_map->GetImageInfo().Aspects();
}
else if(!AreAspectsSplit(oldFlags))
{
// aspects are split in the map, but are not yet split in this iterator.
// We need to find the aspectMask.
uint32_t i = 0;
for(auto it = ImageAspectFlagIter::begin(m_map->GetImageInfo().Aspects());
it != ImageAspectFlagIter::end(); ++it, ++i)
{
if(i >= m_aspectIndex && (((*it) & m_range.aspectMask) != 0))
{
m_value.m_range.aspectMask = *it;
break;
}
}
m_aspectIndex = i;
}
}
template void ImageSubresourceMap::SubresourceRangeIterTemplate<
ImageSubresourceMap, ImageSubresourceMap::SubresourcePairRef>::FixSubRange();
template void ImageSubresourceMap::SubresourceRangeIterTemplate<
const ImageSubresourceMap, ImageSubresourceMap::ConstSubresourcePairRef>::FixSubRange();
template <typename Map, typename Pair>
Pair *ImageSubresourceMap::SubresourceRangeIterTemplate<Map, Pair>::operator->()
{
FixSubRange();
m_value.m_state = &m_map->SubresourceIndexValue(m_aspectIndex, m_level, m_layer, m_slice);
return &m_value;
}
template ImageSubresourceMap::SubresourcePairRef *ImageSubresourceMap::SubresourceRangeIterTemplate<
ImageSubresourceMap, ImageSubresourceMap::SubresourcePairRef>::operator->();
template ImageSubresourceMap::ConstSubresourcePairRef *ImageSubresourceMap::SubresourceRangeIterTemplate<
const ImageSubresourceMap, ImageSubresourceMap::ConstSubresourcePairRef>::operator->();
template <typename Map, typename Pair>
Pair &ImageSubresourceMap::SubresourceRangeIterTemplate<Map, Pair>::operator*()
{
FixSubRange();
m_value.m_state = &m_map->SubresourceIndexValue(m_aspectIndex, m_level, m_layer, m_slice);
return m_value;
}
template ImageSubresourceMap::SubresourcePairRef &ImageSubresourceMap::SubresourceRangeIterTemplate<
ImageSubresourceMap, ImageSubresourceMap::SubresourcePairRef>::operator*();
template ImageSubresourceMap::ConstSubresourcePairRef &ImageSubresourceMap::SubresourceRangeIterTemplate<
const ImageSubresourceMap, ImageSubresourceMap::ConstSubresourcePairRef>::operator*();
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);
ImageState ImageState::InitialState() const
{
ImageState result(wrappedHandle, GetImageInfo(), eFrameRef_Unknown);
InitialState(result);
return result;
}
void ImageState::InitialState(ImageState &result) const
{
result.subresourceStates = subresourceStates;
for(auto it = result.subresourceStates.begin(); it != result.subresourceStates.end(); ++it)
{
ImageSubresourceState &sub = it->state();
sub.newLayout = sub.oldLayout = GetImageInfo().initialLayout;
sub.newQueueFamilyIndex = sub.oldQueueFamilyIndex;
sub.refType = eFrameRef_Unknown;
}
}
ImageState ImageState::CommandBufferInitialState() const
{
ImageSubresourceState sub;
sub.oldLayout = sub.newLayout = UNKNOWN_PREV_IMG_LAYOUT;
return UniformState(sub);
}
ImageState ImageState::UniformState(const ImageSubresourceState &sub) const
{
ImageState result(wrappedHandle, GetImageInfo(), eFrameRef_None);
result.subresourceStates.begin()->SetState(sub);
return result;
}
ImageState ImageState::ContentInitializationState(InitPolicy policy, bool initialized,
uint32_t queueFamilyIndex, VkImageLayout copyLayout,
VkImageLayout clearLayout) const
{
ImageState result = *this;
for(auto it = result.subresourceStates.begin(); it != result.subresourceStates.end(); ++it)
{
ImageSubresourceState &sub = it->state();
InitReqType initReq = InitReq(sub.refType, policy, initialized);
if(initReq == eInitReq_None)
continue;
sub.newQueueFamilyIndex = queueFamilyIndex;
if(initReq == eInitReq_Copy)
sub.newLayout = copyLayout;
else if(initReq == eInitReq_Clear)
sub.newLayout = clearLayout;
}
return result;
}
void ImageState::RemoveQueueFamilyTransfer(VkImageMemoryBarrier *it)
{
if(it < newQueueFamilyTransfers.begin() || it >= newQueueFamilyTransfers.end())
RDCERR("Attempting to remove queue family transfer at invalid address");
std::swap(*it, newQueueFamilyTransfers.back());
newQueueFamilyTransfers.erase(newQueueFamilyTransfers.size() - 1);
}
void ImageState::Update(ImageSubresourceRange range, const ImageSubresourceState &dst,
FrameRefCompFunc compose)
{
range.Sanitise(GetImageInfo());
bool didSplit = false;
for(auto it = subresourceStates.RangeBegin(range); it != subresourceStates.end(); ++it)
{
ImageSubresourceState subState;
if(it->state().Update(dst, subState, compose))
{
if(!didSplit)
{
subresourceStates.Split(range);
didSplit = true;
}
RDCASSERT(it->range().ContainedIn(range));
it->SetState(subState);
maxRefType = ComposeFrameRefsDisjoint(maxRefType, subState.refType);
}
}
}
void ImageState::Merge(const ImageState &other, ImageTransitionInfo info)
{
if(wrappedHandle == VK_NULL_HANDLE)
wrappedHandle = other.wrappedHandle;
for(auto it = other.oldQueueFamilyTransfers.begin(); it != other.oldQueueFamilyTransfers.end(); ++it)
{
RecordQueueFamilyAcquire(*it);
}
maxRefType = subresourceStates.Merge(other.subresourceStates, info.GetFrameRefCompFunc());
for(auto it = other.newQueueFamilyTransfers.begin(); it != other.newQueueFamilyTransfers.end(); ++it)
{
RecordQueueFamilyRelease(*it);
}
}
void ImageState::MergeCaptureBeginState(const ImageState &initialState)
{
oldQueueFamilyTransfers = initialState.oldQueueFamilyTransfers;
subresourceStates.Merge(initialState.subresourceStates, ComposeFrameRefsFirstKnown);
maxRefType = initialState.maxRefType;
}
void ImageState::Merge(std::map<ResourceId, ImageState> &states,
const std::map<ResourceId, ImageState> &dstStates, ImageTransitionInfo info)
{
auto it = states.begin();
auto dstIt = dstStates.begin();
while(dstIt != dstStates.end())
{
if(it == states.end() || dstIt->first < it->first)
{
it = states.insert(it, {dstIt->first, dstIt->second.InitialState()});
}
else if(it->first < dstIt->first)
{
++it;
continue;
}
it->second.Merge(dstIt->second, info);
++it;
++dstIt;
}
}
void ImageState::DiscardContents(const ImageSubresourceRange &range)
{
Update(range, ImageSubresourceState(VK_QUEUE_FAMILY_IGNORED, VK_IMAGE_LAYOUT_UNDEFINED),
KeepOldFrameRef);
}
void ImageState::RecordQueueFamilyRelease(const VkImageMemoryBarrier &barrier)
{
for(auto it = newQueueFamilyTransfers.begin(); it != newQueueFamilyTransfers.end(); ++it)
{
if(ImageSubresourceRange(barrier.subresourceRange).Overlaps(it->subresourceRange))
{
RDCWARN("Queue family release barriers overlap");
RemoveQueueFamilyTransfer(it);
--it;
}
}
newQueueFamilyTransfers.push_back(barrier);
}
void ImageState::RecordQueueFamilyAcquire(const VkImageMemoryBarrier &barrier)
{
bool foundRelease = false;
ImageSubresourceRange acquireRange(barrier.subresourceRange);
for(auto it = newQueueFamilyTransfers.begin(); it != newQueueFamilyTransfers.end(); ++it)
{
ImageSubresourceRange releaseRange(it->subresourceRange);
if(acquireRange.Overlaps(releaseRange))
{
if(acquireRange != releaseRange)
RDCWARN(
"Overlapping queue family release and acquire barriers have different "
"subresourceRange");
if(barrier.srcQueueFamilyIndex != it->srcQueueFamilyIndex ||
barrier.dstQueueFamilyIndex != it->dstQueueFamilyIndex)
RDCWARN("Queue family mismatch between release and acquire barriers");
if(barrier.oldLayout != it->oldLayout || barrier.newLayout != it->newLayout)
RDCWARN("Image layouts mismatch between release and acquire barriers");
if(foundRelease)
RDCWARN("Found multiple release barriers for acquire barrier");
RemoveQueueFamilyTransfer(it);
--it;
foundRelease = true;
}
}
if(!foundRelease)
{
oldQueueFamilyTransfers.push_back(barrier);
}
}
void ImageState::RecordBarrier(VkImageMemoryBarrier barrier, uint32_t queueFamilyIndex,
ImageTransitionInfo info)
{
if(barrier.srcQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
barrier.srcQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT ||
barrier.dstQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
barrier.dstQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT)
{
RDCERR("External/foreign queue families are not supported");
return;
}
if(GetImageInfo().sharingMode == VK_SHARING_MODE_CONCURRENT)
{
if(!(barrier.srcQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED &&
barrier.dstQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED))
{
RDCWARN("Barrier contains invalid queue families for VK_SHARING_MODE_CONCURRENT");
}
barrier.srcQueueFamilyIndex = barrier.dstQueueFamilyIndex = queueFamilyIndex;
}
else if(GetImageInfo().sharingMode == VK_SHARING_MODE_EXCLUSIVE)
{
if(barrier.srcQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED ||
barrier.dstQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
{
if(barrier.srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED ||
barrier.dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED)
{
RDCERR("Barrier contains invalid queue families for VK_SHARING_MODE_EXCLUSIVE: (%s, %s)",
ToStr(barrier.srcQueueFamilyIndex).c_str(),
ToStr(barrier.dstQueueFamilyIndex).c_str());
return;
}
barrier.srcQueueFamilyIndex = queueFamilyIndex;
barrier.dstQueueFamilyIndex = queueFamilyIndex;
}
else if(barrier.srcQueueFamilyIndex == queueFamilyIndex)
{
if(barrier.dstQueueFamilyIndex != queueFamilyIndex)
{
RecordQueueFamilyRelease(barrier);
// Skip the updates to the subresource states.
// These will be updated by the acquire.
// This allows us to restore a released-but-not-acquired state by first transitioning to the
// subresource states (which will match the srcQueueFamilyIndex/oldLayout), and then
// applying the release barrier.
return;
}
}
else if(barrier.dstQueueFamilyIndex == queueFamilyIndex)
{
RecordQueueFamilyAcquire(barrier);
}
else
{
RDCERR("Ownership transfer from queue family %u to %u submitted to queue family %u",
barrier.srcQueueFamilyIndex, barrier.dstAccessMask, queueFamilyIndex);
}
}
Update(barrier.subresourceRange, ImageSubresourceState(barrier), info.GetFrameRefCompFunc());
}
bool ImageState::CloseTransfers(uint32_t batchIndex, VkAccessFlags dstAccessMask,
ImageBarrierSequence &barriers, ImageTransitionInfo info)
{
if(newQueueFamilyTransfers.empty())
return false;
FrameRefCompFunc compose = info.GetFrameRefCompFunc();
for(auto it = newQueueFamilyTransfers.begin(); it != newQueueFamilyTransfers.end(); ++it)
{
Update(it->subresourceRange, ImageSubresourceState(it->dstQueueFamilyIndex, it->newLayout),
compose);
it->dstAccessMask = dstAccessMask;
it->image = wrappedHandle;
barriers.AddWrapped(batchIndex, it->dstQueueFamilyIndex, *it);
}
newQueueFamilyTransfers.clear();
return true;
}
bool ImageState::RestoreTransfers(uint32_t batchIndex,
const rdcarray<VkImageMemoryBarrier> &transfers,
VkAccessFlags srcAccessMask, ImageBarrierSequence &barriers,
ImageTransitionInfo info)
{
// TODO: figure out why `transfers` has duplicate entries
if(transfers.empty())
return false;
for(auto it = transfers.begin(); it != transfers.end(); ++it)
{
VkImageMemoryBarrier barrier = *it;
barrier.srcAccessMask = srcAccessMask;
barrier.image = wrappedHandle;
barriers.AddWrapped(batchIndex, barrier.srcQueueFamilyIndex, barrier);
RecordQueueFamilyRelease(barrier);
}
return true;
}
void ImageState::ResetToOldState(ImageBarrierSequence &barriers, ImageTransitionInfo info)
{
VkAccessFlags srcAccessMask = VK_ACCESS_ALL_WRITE_BITS;
VkAccessFlags dstAccessMask = VK_ACCESS_ALL_READ_BITS;
const uint32_t CLOSE_TRANSFERS_BATCH_INDEX = 0;
const uint32_t MAIN_BATCH_INDEX = 1;
const uint32_t ACQUIRE_BATCH_INDEX = 2;
const uint32_t RESTORE_TRANSFERS_BATCH_INDEX = 3;
CloseTransfers(CLOSE_TRANSFERS_BATCH_INDEX, dstAccessMask, barriers, info);
for(auto subIt = subresourceStates.begin(); subIt != subresourceStates.end(); ++subIt)
{
VkImageLayout oldLayout = subIt->state().newLayout;
if(oldLayout == UNKNOWN_PREV_IMG_LAYOUT)
oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageLayout newLayout = subIt->state().oldLayout;
subIt->state().newLayout = subIt->state().oldLayout;
if(newLayout == UNKNOWN_PREV_IMG_LAYOUT || newLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
// contents discarded, no barrier necessary
continue;
}
SanitiseReplayImageLayout(oldLayout);
SanitiseReplayImageLayout(newLayout);
if(oldLayout != VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
{
// Transitioning back to PREINITIALIZED; this is impossible, so transition to GENERAL instead.
newLayout = VK_IMAGE_LAYOUT_GENERAL;
}
uint32_t srcQueueFamilyIndex = subIt->state().newQueueFamilyIndex;
uint32_t dstQueueFamilyIndex = subIt->state().oldQueueFamilyIndex;
if(srcQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
srcQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT)
{
srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
}
if(dstQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
dstQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT)
{
dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
}
uint32_t submitQueueFamilyIndex = srcQueueFamilyIndex;
if(GetImageInfo().sharingMode == VK_SHARING_MODE_EXCLUSIVE)
{
if(srcQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
{
submitQueueFamilyIndex = dstQueueFamilyIndex;
dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
}
else if(dstQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
{
srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
}
}
else
{
if(submitQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
submitQueueFamilyIndex = dstQueueFamilyIndex;
srcQueueFamilyIndex = dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
}
if(srcQueueFamilyIndex == dstQueueFamilyIndex && oldLayout == newLayout)
{
subIt->state().newQueueFamilyIndex = subIt->state().oldQueueFamilyIndex;
continue;
}
if(submitQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
{
RDCWARN(
"ResetToOldState: barrier submitted to VK_QUEUE_FAMILY_IGNORED; defaulting to queue "
"family %u",
info.defaultQueueFamilyIndex);
submitQueueFamilyIndex = info.defaultQueueFamilyIndex;
}
subIt->state().newQueueFamilyIndex = subIt->state().oldQueueFamilyIndex;
ImageSubresourceRange subRange = subIt->range();
if(subRange.baseDepthSlice != 0)
{
// We can't issue barriers per depth slice, so skip the barriers for non-zero depth slices.
// The zero depth slice barrier will implicitly cover the non-zerp depth slices.
continue;
}
if((GetImageInfo().Aspects() & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) ==
(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) &&
!info.separateDepthStencil)
{
// This is a subresource of a depth and stencil image, and
// VK_KHR_separate_depth_stencil_layouts is not enabled, so the barrier needs to include both
// depth and stencil aspects. We skip the stencil-only aspect and expand the barrier for the
// depth-only aspect to include both depth and stencil aspects.
if(subRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)
continue;
if(subRange.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT)
subRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
VkImageMemoryBarrier barrier = {
/* sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
/* pNext = */ NULL,
/* srcAccessMask = */ srcAccessMask,
/* dstAccessMask = */ dstAccessMask,
/* oldLayout = */ oldLayout,
/* newLayout = */ newLayout,
/* srcQueueFamilyIndex = */ srcQueueFamilyIndex,
/* dstQueueFamilyIndex = */ dstQueueFamilyIndex,
/* image = */ wrappedHandle,
/* subresourceRange = */ subRange,
};
barriers.AddWrapped(MAIN_BATCH_INDEX, submitQueueFamilyIndex, barrier);
// acquire the subresource in the dstQueueFamily, if necessary
if(barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex)
{
barriers.AddWrapped(ACQUIRE_BATCH_INDEX, barrier.dstQueueFamilyIndex, barrier);
}
}
RestoreTransfers(RESTORE_TRANSFERS_BATCH_INDEX, oldQueueFamilyTransfers, srcAccessMask, barriers,
info);
}
void ImageState::Transition(const ImageState &dstState, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, ImageBarrierSequence &barriers,
ImageTransitionInfo info)
{
const uint32_t CLOSE_TRANSFERS_BATCH_INDEX = 0;
const uint32_t MAIN_BATCH_INDEX = 1;
const uint32_t ACQUIRE_BATCH_INDEX = 2;
const uint32_t RESTORE_TRANSFERS_BATCH_INDEX = 3;
CloseTransfers(CLOSE_TRANSFERS_BATCH_INDEX, dstAccessMask, barriers, info);
for(auto dstIt = dstState.subresourceStates.begin(); dstIt != dstState.subresourceStates.end();
++dstIt)
{
const ImageSubresourceRange &dstRng = dstIt->range();
const ImageSubresourceState &dstSub = dstIt->state();
for(auto it = subresourceStates.RangeBegin(dstRng); it != subresourceStates.end(); ++it)
{
ImageSubresourceState srcSub;
if(!it->state().Update(dstSub, srcSub, info.GetFrameRefCompFunc()))
// subresource state did not change, so no need for a barrier
continue;
subresourceStates.Split(dstRng);
std::swap(it->state(), srcSub);
ImageSubresourceRange srcRng = it->range();
VkImageLayout oldLayout = srcSub.newLayout;
if(oldLayout == UNKNOWN_PREV_IMG_LAYOUT)
oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageLayout newLayout = dstSub.newLayout;
if(newLayout == UNKNOWN_PREV_IMG_LAYOUT || newLayout == VK_IMAGE_LAYOUT_UNDEFINED)
// ignore transitions to undefined
continue;
uint32_t srcQueueFamilyIndex = srcSub.newQueueFamilyIndex;
uint32_t dstQueueFamilyIndex = dstSub.newQueueFamilyIndex;
if(oldLayout == VK_IMAGE_LAYOUT_UNDEFINED)
// transitions from undefined discard the contents anyway, so no queue family ownership
// transfer is necessary
srcQueueFamilyIndex = dstQueueFamilyIndex;
if(newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && oldLayout != VK_IMAGE_LAYOUT_PREINITIALIZED)
{
// Transitioning to PREINITIALIZED, which is invalid. This happens when we are resetting to
// an earlier image state.
// Instead, we transition to GENERAL, and make the image owned by oldQueueFamilyIndex.
newLayout = VK_IMAGE_LAYOUT_GENERAL;
dstQueueFamilyIndex = srcSub.oldQueueFamilyIndex;
RDCASSERT(dstQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED);
}
if(IsReplayMode(info.capState))
{
// Get rid of PRESENT layouts
SanitiseReplayImageLayout(oldLayout);
SanitiseReplayImageLayout(newLayout);
}
uint32_t submitQueueFamilyIndex = (srcQueueFamilyIndex != VK_QUEUE_FAMILY_IGNORED)
? srcQueueFamilyIndex
: dstQueueFamilyIndex;
if(submitQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED ||
submitQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
submitQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT)
{
RDCERR("Ignoring state transition submitted to invalid queue family %u",
submitQueueFamilyIndex);
continue;
}
if(GetImageInfo().sharingMode == VK_SHARING_MODE_CONCURRENT)
{
srcQueueFamilyIndex = dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
}
else
{
if(srcQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
{
RDCWARN("ImageState::Transition: src queue family == VK_QUEUE_FAMILY_IGNORED.");
srcQueueFamilyIndex = dstQueueFamilyIndex;
}
if(dstQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
{
RDCWARN("ImageState::Transition: dst queue family == VK_QUEUE_FAMILY_IGNORED.");
dstQueueFamilyIndex = srcQueueFamilyIndex;
}
}
if(srcQueueFamilyIndex == dstQueueFamilyIndex && oldLayout == newLayout)
// Skip the barriers, because it would do nothing
continue;
if(srcRng.baseDepthSlice != 0 || dstRng.baseDepthSlice != 0)
{
// We can't issue barriers per depth slice, so skip the barriers for non-zero depth slices.
// The zero depth slice barrier will implicitly cover the non-zerp depth slices.
continue;
}
VkImageAspectFlags aspectMask = srcRng.aspectMask & dstRng.aspectMask;
if((GetImageInfo().Aspects() & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) ==
(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) &&
!info.separateDepthStencil)
{
// This is a subresource of a depth and stencil image, and
// VK_KHR_separate_depth_stencil_layouts is not enabled, so the barrier needs to include
// both depth and stencil aspects. We skip the stencil-only aspect and expand the barrier
// for the depth-only aspect to include both depth and stencil aspects.
if(aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT)
continue;
if(aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT)
aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
uint32_t baseMipLevel = RDCMAX(dstRng.baseMipLevel, srcRng.baseMipLevel);
uint32_t endMipLevel =
RDCMIN(dstRng.baseMipLevel + dstRng.levelCount, srcRng.baseMipLevel + srcRng.levelCount);
uint32_t baseArrayLayer = RDCMAX(dstRng.baseArrayLayer, srcRng.baseArrayLayer);
uint32_t endArrayLayer = RDCMIN(dstRng.baseArrayLayer + dstRng.layerCount,
srcRng.baseArrayLayer + srcRng.layerCount);
VkImageMemoryBarrier barrier = {
/* sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
/* pNext = */ NULL,
/* srcAccessMask = */ srcAccessMask,
/* dstAccessMask = */ dstAccessMask,
/* oldLayout = */ oldLayout,
/* newLayout = */ newLayout,
/* srcQueueFamilyIndex = */ srcQueueFamilyIndex,
/* dstQueueFamilyIndex = */ dstQueueFamilyIndex,
/* image = */ wrappedHandle,
/* subresourceRange = */
{
/* aspectMask = */ aspectMask,
/* baseMipLevel = */ baseMipLevel,
/* levelCount = */ endMipLevel - baseMipLevel,
/* baseArrayLayer = */ baseArrayLayer,
/* layerCount = */ endArrayLayer - baseArrayLayer,
},
};
barriers.AddWrapped(MAIN_BATCH_INDEX, submitQueueFamilyIndex, barrier);
// acquire the subresource in the dstQueueFamily, if necessary
if(barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex)
{
barriers.AddWrapped(ACQUIRE_BATCH_INDEX, barrier.dstQueueFamilyIndex, barrier);
}
}
}
RestoreTransfers(RESTORE_TRANSFERS_BATCH_INDEX, dstState.newQueueFamilyTransfers, srcAccessMask,
barriers, info);
}
void ImageState::Transition(uint32_t queueFamilyIndex, VkImageLayout layout,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
ImageBarrierSequence &barriers, ImageTransitionInfo info)
{
Transition(UniformState(ImageSubresourceState(queueFamilyIndex, layout)), srcAccessMask,
dstAccessMask, barriers, info);
}
void ImageState::TempTransition(const ImageState &dstState, VkAccessFlags preSrcAccessMask,
VkAccessFlags preDstAccessMask, VkAccessFlags postSrcAccessmask,
VkAccessFlags postDstAccessMask, ImageBarrierSequence &setupBarriers,
ImageBarrierSequence &cleanupBarriers, ImageTransitionInfo info) const
{
ImageState temp(*this);
temp.Transition(dstState, preSrcAccessMask, preDstAccessMask, setupBarriers, info);
temp.Transition(*this, postSrcAccessmask, postDstAccessMask, cleanupBarriers, info);
}
void ImageState::TempTransition(uint32_t queueFamilyIndex, VkImageLayout layout,
VkAccessFlags accessMask, ImageBarrierSequence &setupBarriers,
ImageBarrierSequence &cleanupBarriers, ImageTransitionInfo info) const
{
TempTransition(UniformState(ImageSubresourceState(queueFamilyIndex, layout)),
VK_ACCESS_ALL_WRITE_BITS, accessMask, accessMask, VK_ACCESS_ALL_READ_BITS,
setupBarriers, cleanupBarriers, info);
}
void ImageState::InlineTransition(VkCommandBuffer cmd, uint32_t queueFamilyIndex,
const ImageState &dstState, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, ImageTransitionInfo info)
{
ImageBarrierSequence barriers;
Transition(dstState, srcAccessMask, dstAccessMask, barriers, info);
if(barriers.empty())
return;
rdcarray<VkImageMemoryBarrier> barriersArray;
barriers.ExtractFirstUnwrappedBatchForQueue(queueFamilyIndex, barriersArray);
if(!barriersArray.empty())
DoPipelineBarrier(cmd, (uint32_t)barriersArray.size(), barriersArray.data());
if(!barriers.empty())
{
RDCERR("Could not inline all image state transition barriers");
}
}
void ImageState::InlineTransition(VkCommandBuffer cmd, uint32_t queueFamilyIndex,
VkImageLayout layout, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, ImageTransitionInfo info)
{
InlineTransition(cmd, queueFamilyIndex,
UniformState(ImageSubresourceState(queueFamilyIndex, layout)), srcAccessMask,
dstAccessMask, info);
}
InitReqType ImageState::MaxInitReq(const ImageSubresourceRange &range, InitPolicy policy,
bool initialized) const
{
FrameRefType refType = eFrameRef_None;
for(auto it = subresourceStates.RangeBegin(range); it != subresourceStates.end(); ++it)
{
refType = ComposeFrameRefsDisjoint(refType, it->state().refType);
}
return InitReq(refType, policy, initialized);
}
VkImageLayout ImageState::GetImageLayout(VkImageAspectFlagBits aspect, uint32_t mipLevel,
uint32_t arrayLayer) const
{
return subresourceStates.SubresourceAspectValue(aspect, mipLevel, arrayLayer, 0).newLayout;
}
void ImageState::BeginCapture()
{
maxRefType = eFrameRef_None;
// Forget any pending queue family release operations.
// If the matching queue family acquire operation happens during the frame,
// an implicit release operation will be put into `oldQueueFamilyTransfers`.
newQueueFamilyTransfers.clear();
// Also clear implicit queue family acquire operations because these correspond to release
// operations already submitted (and therefore not part of the capture).
oldQueueFamilyTransfers.clear();
for(auto it = subresourceStates.begin(); it != subresourceStates.end(); ++it)
{
ImageSubresourceState state = it->state();
state.oldLayout = state.newLayout;
state.oldQueueFamilyIndex = state.newQueueFamilyIndex;
state.refType = eFrameRef_None;
it->SetState(state);
}
}