Add ImageState

`ImageState` tracks the state of images and their subresources.
This functionality was previously split between the `ImageLayouts` and
`ImgRefs` classes.

Change-Id: I3242417dacf73fe07765f9bcfd449599e373e10d
This commit is contained in:
Benson Joeris
2019-12-17 11:12:34 -05:00
committed by Baldur Karlsson
parent 3d90609e39
commit 96bbeea4a5
11 changed files with 2397 additions and 20 deletions
+5
View File
@@ -133,6 +133,11 @@ FrameRefType ComposeFrameRefsFirstKnown(FrameRefType first, FrameRefType second)
return second;
}
FrameRefType KeepOldFrameRef(FrameRefType first, FrameRefType second)
{
return first;
}
bool IncludesRead(FrameRefType refType)
{
switch(refType)
+5
View File
@@ -123,6 +123,8 @@ const double PERSISTENT_RESOURCE_AGE = 3000;
DECLARE_REFLECTION_ENUM(FrameRefType);
typedef FrameRefType (*FrameRefCompFunc)(FrameRefType, FrameRefType);
// Compose frame refs that occur in a known order.
// This can be thought of as a state (`first`) and a transition from that state
// (`second`), returning the new state (see the state diagram for
@@ -143,6 +145,9 @@ FrameRefType ComposeFrameRefsDisjoint(FrameRefType x, FrameRefType y);
// Returns whichever of `first` or `second` is valid.
FrameRefType ComposeFrameRefsFirstKnown(FrameRefType first, FrameRefType second);
// Dummy frame ref composition that always keeps the old ref.
FrameRefType KeepOldFrameRef(FrameRefType first, FrameRefType second);
bool IsDirtyFrameRef(FrameRefType refType);
// Captures the possible initialization/reset requirements for resources.
+1
View File
@@ -40,6 +40,7 @@ set(sources
vk_serialise.cpp
vk_stringise.cpp
vk_layer.cpp
imagestate_tests.cpp
imgrefs_tests.cpp
official/vk_layer.h
official/vk_platform.h
@@ -0,0 +1,735 @@
/******************************************************************************
* 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 "common/globalconfig.h"
#if ENABLED(ENABLE_UNIT_TESTS)
#include "3rdparty/catch/catch.hpp"
#include "vk_resources.h"
#include <stdint.h>
#include <vector>
void CheckSubresourceRanges(const ImageState &state, bool expectAspectsSplit,
bool expectLevelsSplit, bool expectLayersSplit, bool expectDepthSplit)
{
std::vector<VkImageAspectFlags> splitAspects;
if(expectAspectsSplit)
{
for(auto it = ImageAspectFlagIter::begin(state.GetImageInfo().Aspects());
it != ImageAspectFlagIter::end(); ++it)
{
splitAspects.push_back(*it);
}
}
else
{
splitAspects.push_back(state.GetImageInfo().Aspects());
}
uint32_t splitLevelCount = expectLevelsSplit ? state.GetImageInfo().levelCount : 1;
uint32_t splitLayerCount = expectLayersSplit ? state.GetImageInfo().layerCount : 1;
uint32_t splitSliceCount = expectDepthSplit ? state.GetImageInfo().extent.depth : 1;
size_t splitSize = splitAspects.size() * (size_t)splitLevelCount * (size_t)splitLayerCount *
(size_t)splitSliceCount;
CHECK(state.subresourceStates.size() == splitSize);
auto substateIt = state.subresourceStates.begin();
auto aspectIt = splitAspects.begin();
uint32_t level = 0;
uint32_t layer = 0;
uint32_t slice = 0;
uint32_t index = 0;
for(; aspectIt != splitAspects.end() && substateIt != state.subresourceStates.end();
++substateIt, ++index)
{
const ImageSubresourceRange &range = substateIt->range();
CHECK(range.aspectMask == *aspectIt);
if(expectLevelsSplit)
{
CHECK(range.baseMipLevel == level);
CHECK(range.levelCount == 1);
}
else
{
CHECK(range.baseMipLevel == 0);
CHECK(range.levelCount == (uint32_t)state.GetImageInfo().levelCount);
}
if(expectLayersSplit)
{
CHECK(range.baseArrayLayer == layer);
CHECK(range.layerCount == 1);
}
else
{
CHECK(range.baseArrayLayer == 0);
CHECK(range.layerCount == (uint32_t)state.GetImageInfo().layerCount);
}
if(expectDepthSplit)
{
CHECK(range.baseDepthSlice == slice);
CHECK(range.sliceCount == 1);
}
else
{
CHECK(range.baseDepthSlice == 0);
CHECK(range.sliceCount == (uint32_t)state.GetImageInfo().extent.depth);
}
++slice;
if(slice < splitSliceCount)
continue;
slice = 0;
++layer;
if(layer < splitLayerCount)
continue;
layer = 0;
++level;
if(level < splitLevelCount)
continue;
level = 0;
++aspectIt;
}
CHECK(index == splitSize);
}
void CheckSubresourceState(const ImageSubresourceState &substate,
const ImageSubresourceState &expected)
{
CHECK(substate.oldQueueFamilyIndex == expected.oldQueueFamilyIndex);
CHECK(substate.newQueueFamilyIndex == expected.newQueueFamilyIndex);
CHECK(substate.oldLayout == expected.oldLayout);
CHECK(substate.newLayout == expected.newLayout);
CHECK(substate.refType == expected.refType);
}
TEST_CASE("Test ImageState type", "[imagestate]")
{
ImageTransitionInfo transitionInfo(CaptureState::ActiveCapturing, 0);
VkImage image = (VkImage)123;
VkFormat format = VK_FORMAT_D16_UNORM_S8_UINT;
VkExtent3D extent = {100, 100, 13};
int levelCount = 11;
int layerCount = 17;
int sampleCount = 1;
ImageInfo imageInfo(format, extent, levelCount, layerCount, sampleCount,
VK_IMAGE_LAYOUT_UNDEFINED, VK_SHARING_MODE_EXCLUSIVE);
ImageSubresourceState initSubstate(VK_QUEUE_FAMILY_IGNORED, UNKNOWN_PREV_IMG_LAYOUT,
eFrameRef_None);
ImageSubresourceState readSubstate(initSubstate);
readSubstate.oldQueueFamilyIndex = readSubstate.newQueueFamilyIndex = 0;
readSubstate.refType = eFrameRef_Read;
SECTION("Initial state")
{
ImageState state(image, imageInfo, eFrameRef_None);
CheckSubresourceRanges(state, false, false, false, false);
CheckSubresourceState(state.subresourceStates.begin()->state(), initSubstate);
};
SECTION("Split aspects")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range = imageInfo.FullRange();
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
state.RecordUse(range, eFrameRef_Read, 0);
CheckSubresourceRanges(state, true, false, false, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
if(it->range().aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT)
CheckSubresourceState(it->state(), readSubstate);
else
CheckSubresourceState(it->state(), initSubstate);
}
};
SECTION("Split mip levels")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range = imageInfo.FullRange();
range.baseMipLevel = 1;
range.levelCount = 3;
state.RecordUse(range, eFrameRef_Read, 0);
CheckSubresourceRanges(state, false, true, false, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
if(it->range().baseMipLevel >= range.baseMipLevel &&
it->range().baseMipLevel - range.baseMipLevel < range.levelCount)
CheckSubresourceState(it->state(), readSubstate);
else
CheckSubresourceState(it->state(), initSubstate);
}
};
SECTION("Split array layers")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range = imageInfo.FullRange();
range.baseArrayLayer = 3;
range.layerCount = 5;
state.RecordUse(range, eFrameRef_Read, 0);
CheckSubresourceRanges(state, false, false, true, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
if(it->range().baseArrayLayer >= range.baseArrayLayer &&
it->range().baseArrayLayer - range.baseArrayLayer < range.layerCount)
CheckSubresourceState(it->state(), readSubstate);
else
CheckSubresourceState(it->state(), initSubstate);
}
};
SECTION("Split depth slices")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range = imageInfo.FullRange();
range.baseDepthSlice = 1;
range.sliceCount = 1;
state.RecordUse(range, eFrameRef_Read, 0);
CheckSubresourceRanges(state, false, false, false, true);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
if(it->range().baseDepthSlice >= range.baseDepthSlice &&
it->range().baseDepthSlice - range.baseDepthSlice < range.sliceCount)
CheckSubresourceState(it->state(), readSubstate);
else
CheckSubresourceState(it->state(), initSubstate);
}
};
SECTION("Split aspect to depth")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange aspectRange(imageInfo.FullRange());
aspectRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
state.RecordUse(aspectRange, eFrameRef_Read, 0);
CheckSubresourceRanges(state, true, false, false, false);
ImageSubresourceRange levelRange(imageInfo.FullRange());
levelRange.baseMipLevel = 0;
levelRange.levelCount = 1;
state.RecordUse(levelRange, eFrameRef_PartialWrite, 1);
CheckSubresourceRanges(state, true, true, false, false);
ImageSubresourceRange layerRange(imageInfo.FullRange());
layerRange.baseArrayLayer = 0;
layerRange.layerCount = 1;
state.RecordUse(layerRange, eFrameRef_Read, 2);
CheckSubresourceRanges(state, true, true, true, false);
ImageSubresourceRange sliceRange(imageInfo.FullRange());
sliceRange.baseDepthSlice = 0;
sliceRange.sliceCount = 1;
state.RecordUse(sliceRange, eFrameRef_CompleteWrite, 3);
CheckSubresourceRanges(state, true, true, true, true);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
ImageSubresourceState substate(initSubstate);
if(it->range().aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT)
{
substate.refType = ComposeFrameRefs(substate.refType, eFrameRef_Read);
substate.newQueueFamilyIndex = 0;
if(substate.oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex;
}
if(levelRange.baseMipLevel <= it->range().baseMipLevel &&
it->range().baseMipLevel - levelRange.baseMipLevel < levelRange.levelCount)
{
substate.refType = ComposeFrameRefs(substate.refType, eFrameRef_PartialWrite);
substate.newQueueFamilyIndex = 1;
if(substate.oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex;
}
if(layerRange.baseArrayLayer <= it->range().baseArrayLayer &&
it->range().baseArrayLayer - layerRange.baseArrayLayer < layerRange.layerCount)
{
substate.refType = ComposeFrameRefs(substate.refType, eFrameRef_Read);
substate.newQueueFamilyIndex = 2;
if(substate.oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex;
}
if(sliceRange.baseDepthSlice <= it->range().baseDepthSlice &&
it->range().baseDepthSlice - sliceRange.baseDepthSlice < sliceRange.sliceCount)
{
substate.refType = ComposeFrameRefs(substate.refType, eFrameRef_CompleteWrite);
substate.newQueueFamilyIndex = 3;
if(substate.oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex;
}
CheckSubresourceState(it->state(), substate);
}
};
SECTION("Split depth to aspect")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange sliceRange(imageInfo.FullRange());
sliceRange.baseDepthSlice = 0;
sliceRange.sliceCount = 1;
state.RecordUse(sliceRange, eFrameRef_CompleteWrite, 3);
CheckSubresourceRanges(state, false, false, false, true);
ImageSubresourceRange layerRange(imageInfo.FullRange());
layerRange.baseArrayLayer = 0;
layerRange.layerCount = 1;
state.RecordUse(layerRange, eFrameRef_Read, 2);
CheckSubresourceRanges(state, false, false, true, true);
ImageSubresourceRange levelRange(imageInfo.FullRange());
levelRange.baseMipLevel = 0;
levelRange.levelCount = 1;
state.RecordUse(levelRange, eFrameRef_PartialWrite, 1);
CheckSubresourceRanges(state, false, true, true, true);
ImageSubresourceRange aspectRange(imageInfo.FullRange());
aspectRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
state.RecordUse(aspectRange, eFrameRef_Read, 0);
CheckSubresourceRanges(state, true, true, true, true);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
ImageSubresourceState substate(initSubstate);
if(sliceRange.baseDepthSlice <= it->range().baseDepthSlice &&
it->range().baseDepthSlice - sliceRange.baseDepthSlice < sliceRange.sliceCount)
{
substate.refType = ComposeFrameRefs(substate.refType, eFrameRef_CompleteWrite);
substate.newQueueFamilyIndex = 3;
if(substate.oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex;
}
if(layerRange.baseArrayLayer <= it->range().baseArrayLayer &&
it->range().baseArrayLayer - layerRange.baseArrayLayer < layerRange.layerCount)
{
substate.refType = ComposeFrameRefs(substate.refType, eFrameRef_Read);
substate.newQueueFamilyIndex = 2;
if(substate.oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex;
}
if(levelRange.baseMipLevel <= it->range().baseMipLevel &&
it->range().baseMipLevel - levelRange.baseMipLevel < levelRange.levelCount)
{
substate.refType = ComposeFrameRefs(substate.refType, eFrameRef_PartialWrite);
substate.newQueueFamilyIndex = 1;
if(substate.oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex;
}
if(it->range().aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT)
{
substate.refType = ComposeFrameRefs(substate.refType, eFrameRef_Read);
substate.newQueueFamilyIndex = 0;
if(substate.oldQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex;
}
CheckSubresourceState(it->state(), substate);
}
};
SECTION("Single barrier")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range(imageInfo.FullRange());
range.baseArrayLayer = 1;
range.layerCount = 1;
VkImageMemoryBarrier barrier = {
/* sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
/* pNext = */ NULL,
/* srcAccessMask = */ 0,
/* dstAccessMask = */ 0,
/* oldLayout = */ VK_IMAGE_LAYOUT_UNDEFINED,
/* newLayout = */ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
/* srcQueueFamilyIndex = */ 0,
/* dstQueueFamilyIndex = */ 0,
/* image = */ image,
/* subresourceRange = */ range,
};
state.RecordBarrier(barrier, 0, transitionInfo);
CheckSubresourceRanges(state, false, false, true, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
ImageSubresourceState substate(initSubstate);
if(range.baseArrayLayer <= it->range().baseArrayLayer &&
it->range().baseArrayLayer - range.baseArrayLayer < range.layerCount)
{
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex = 0;
substate.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
substate.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
CheckSubresourceState(it->state(), substate);
}
};
SECTION("Layout barriers")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range(imageInfo.FullRange());
range.baseArrayLayer = 0;
range.layerCount = 1;
VkImageMemoryBarrier barrier = {
/* sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
/* pNext = */ NULL,
/* srcAccessMask = */ 0,
/* dstAccessMask = */ 0,
/* oldLayout = */ VK_IMAGE_LAYOUT_UNDEFINED,
/* newLayout = */ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
/* srcQueueFamilyIndex = */ 0,
/* dstQueueFamilyIndex = */ 0,
/* image = */ image,
/* subresourceRange = */ range,
};
state.RecordBarrier(barrier, 0, transitionInfo);
CheckSubresourceRanges(state, false, false, true, false);
barrier.subresourceRange.baseArrayLayer = 1;
state.RecordBarrier(barrier, 0, transitionInfo);
CheckSubresourceRanges(state, false, false, true, false);
barrier.subresourceRange.baseArrayLayer = range.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = range.layerCount = 2;
barrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
state.RecordBarrier(barrier, 0, transitionInfo);
CheckSubresourceRanges(state, false, false, true, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
ImageSubresourceState substate(initSubstate);
if(range.baseArrayLayer <= it->range().baseArrayLayer &&
it->range().baseArrayLayer - range.baseArrayLayer < range.layerCount)
{
substate.oldQueueFamilyIndex = substate.newQueueFamilyIndex = 0;
substate.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
substate.newLayout = VK_IMAGE_LAYOUT_GENERAL;
}
CheckSubresourceState(it->state(), substate);
}
};
SECTION("Unmatched queue family acquire")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range(imageInfo.FullRange());
range.baseArrayLayer = 1;
range.layerCount = 2;
VkImageMemoryBarrier barrier = {
/* sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
/* pNext = */ NULL,
/* srcAccessMask = */ 0,
/* dstAccessMask = */ 0,
/* oldLayout = */ VK_IMAGE_LAYOUT_GENERAL,
/* newLayout = */ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
/* srcQueueFamilyIndex = */ 0,
/* dstQueueFamilyIndex = */ 1,
/* image = */ image,
/* subresourceRange = */ range,
};
state.RecordBarrier(barrier, 1, transitionInfo);
CheckSubresourceRanges(state, false, false, true, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
ImageSubresourceState substate(initSubstate);
if(range.baseArrayLayer <= it->range().baseArrayLayer &&
it->range().baseArrayLayer - range.baseArrayLayer < range.layerCount)
{
substate.oldQueueFamilyIndex = 0;
substate.newQueueFamilyIndex = 1;
substate.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
substate.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
CheckSubresourceState(it->state(), substate);
}
REQUIRE(state.oldQueueFamilyTransfers.size() == 1);
CHECK(state.oldQueueFamilyTransfers[0].oldLayout == VK_IMAGE_LAYOUT_GENERAL);
CHECK(state.oldQueueFamilyTransfers[0].newLayout ==
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
CHECK(state.oldQueueFamilyTransfers[0].srcQueueFamilyIndex == 0);
CHECK(state.oldQueueFamilyTransfers[0].dstQueueFamilyIndex == 1);
CHECK(state.newQueueFamilyTransfers.size() == 0);
};
SECTION("Unmatched queue family release")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range(imageInfo.FullRange());
range.baseArrayLayer = 1;
range.layerCount = 2;
VkImageMemoryBarrier barrier = {
/* sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
/* pNext = */ NULL,
/* srcAccessMask = */ 0,
/* dstAccessMask = */ 0,
/* oldLayout = */ VK_IMAGE_LAYOUT_GENERAL,
/* newLayout = */ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
/* srcQueueFamilyIndex = */ 0,
/* dstQueueFamilyIndex = */ 1,
/* image = */ image,
/* subresourceRange = */ range,
};
state.RecordBarrier(barrier, 0, transitionInfo);
CheckSubresourceRanges(state, false, false, false, false);
CheckSubresourceState(state.subresourceStates.begin()->state(), initSubstate);
REQUIRE(state.newQueueFamilyTransfers.size() == 1);
CHECK(state.newQueueFamilyTransfers[0].oldLayout == VK_IMAGE_LAYOUT_GENERAL);
CHECK(state.newQueueFamilyTransfers[0].newLayout ==
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
CHECK(state.newQueueFamilyTransfers[0].srcQueueFamilyIndex == 0);
CHECK(state.newQueueFamilyTransfers[0].dstQueueFamilyIndex == 1);
CHECK(state.oldQueueFamilyTransfers.size() == 0);
};
SECTION("Matched queue family transfer")
{
ImageState state(image, imageInfo, eFrameRef_None);
ImageSubresourceRange range(imageInfo.FullRange());
range.baseArrayLayer = 1;
range.layerCount = 2;
VkImageMemoryBarrier barrier = {
/* sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
/* pNext = */ NULL,
/* srcAccessMask = */ 0,
/* dstAccessMask = */ 0,
/* oldLayout = */ VK_IMAGE_LAYOUT_GENERAL,
/* newLayout = */ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
/* srcQueueFamilyIndex = */ 0,
/* dstQueueFamilyIndex = */ 1,
/* image = */ image,
/* subresourceRange = */ range,
};
state.RecordBarrier(barrier, 0, transitionInfo);
CheckSubresourceRanges(state, false, false, false, false);
state.RecordBarrier(barrier, 1, transitionInfo);
CheckSubresourceRanges(state, false, false, true, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
ImageSubresourceState substate(initSubstate);
if(range.baseArrayLayer <= it->range().baseArrayLayer &&
it->range().baseArrayLayer - range.baseArrayLayer < range.layerCount)
{
substate.oldQueueFamilyIndex = 0;
substate.newQueueFamilyIndex = 1;
substate.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
substate.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
CheckSubresourceState(it->state(), substate);
}
CHECK(state.oldQueueFamilyTransfers.size() == 0);
CHECK(state.newQueueFamilyTransfers.size() == 0);
};
SECTION("Unsplit aspects")
{
ImageState state(image, imageInfo, eFrameRef_None);
// read subresource, triggering a split in every dimension except depth
ImageSubresourceRange range0 = imageInfo.FullRange();
range0.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
range0.baseMipLevel = 1;
range0.levelCount = imageInfo.levelCount - 1;
range0.baseArrayLayer = 1;
range0.layerCount = imageInfo.layerCount - 1;
range0.baseDepthSlice = 0;
range0.sliceCount = imageInfo.extent.depth;
state.RecordUse(range0, eFrameRef_Read, 0);
// read all aspects
ImageSubresourceRange range1 = range0;
range1.aspectMask = imageInfo.Aspects();
state.RecordUse(range1, eFrameRef_Read, 0);
state.subresourceStates.Unsplit();
CheckSubresourceRanges(state, false, true, true, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
if(it->range().baseMipLevel > 0 && it->range().baseArrayLayer > 0)
CheckSubresourceState(it->state(), readSubstate);
else
CheckSubresourceState(it->state(), initSubstate);
}
};
SECTION("Unsplit mip levels")
{
ImageState state(image, imageInfo, eFrameRef_None);
// read subresource, triggering a split in every dimension except aspect
ImageSubresourceRange range0 = imageInfo.FullRange();
range0.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
range0.baseMipLevel = 1;
range0.levelCount = imageInfo.levelCount - 1;
range0.baseArrayLayer = 1;
range0.layerCount = imageInfo.layerCount - 1;
range0.baseDepthSlice = 1;
range0.sliceCount = imageInfo.extent.depth - 1;
state.RecordUse(range0, eFrameRef_Read, 0);
// read all mip levels
ImageSubresourceRange range1 = range0;
range1.baseMipLevel = 0;
range1.levelCount = imageInfo.levelCount;
state.RecordUse(range1, eFrameRef_Read, 0);
state.subresourceStates.Unsplit();
CheckSubresourceRanges(state, false, false, true, true);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
if(it->range().baseArrayLayer > 0 && it->range().baseDepthSlice > 0)
CheckSubresourceState(it->state(), readSubstate);
else
CheckSubresourceState(it->state(), initSubstate);
}
};
SECTION("Unsplit array layers")
{
ImageState state(image, imageInfo, eFrameRef_None);
// read subresource, triggering a split in every dimension except mip levels
ImageSubresourceRange range0 = imageInfo.FullRange();
range0.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
range0.baseMipLevel = 0;
range0.levelCount = imageInfo.levelCount;
range0.baseArrayLayer = 1;
range0.layerCount = imageInfo.layerCount - 1;
range0.baseDepthSlice = 1;
range0.sliceCount = imageInfo.extent.depth - 1;
state.RecordUse(range0, eFrameRef_Read, 0);
// read all array layers
ImageSubresourceRange range1 = range0;
range1.baseArrayLayer = 0;
range1.layerCount = imageInfo.layerCount;
state.RecordUse(range1, eFrameRef_Read, 0);
state.subresourceStates.Unsplit();
CheckSubresourceRanges(state, true, false, false, true);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
if(it->range().aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT && it->range().baseDepthSlice > 0)
CheckSubresourceState(it->state(), readSubstate);
else
CheckSubresourceState(it->state(), initSubstate);
}
};
SECTION("Unsplit depth slices")
{
ImageState state(image, imageInfo, eFrameRef_None);
// read subresource, triggering a split in every dimension except array layers
ImageSubresourceRange range0 = imageInfo.FullRange();
range0.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
range0.baseMipLevel = 1;
range0.levelCount = imageInfo.levelCount - 1;
range0.baseArrayLayer = 0;
range0.layerCount = imageInfo.layerCount;
range0.baseDepthSlice = 1;
range0.sliceCount = imageInfo.extent.depth - 1;
state.RecordUse(range0, eFrameRef_Read, 0);
// read all depth slices
ImageSubresourceRange range1 = range0;
range1.baseDepthSlice = 0;
range1.sliceCount = imageInfo.extent.depth;
state.RecordUse(range1, eFrameRef_Read, 0);
state.subresourceStates.Unsplit();
CheckSubresourceRanges(state, true, true, false, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
if(it->range().aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT && it->range().baseMipLevel > 0)
CheckSubresourceState(it->state(), readSubstate);
else
CheckSubresourceState(it->state(), initSubstate);
}
};
SECTION("Unsplit all")
{
ImageState state(image, imageInfo, eFrameRef_None);
// read subresource, triggering a split in every dimension
ImageSubresourceRange range0 = imageInfo.FullRange();
range0.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
range0.baseMipLevel = 1;
range0.levelCount = imageInfo.levelCount - 1;
range0.baseArrayLayer = 1;
range0.layerCount = imageInfo.layerCount - 1;
range0.baseDepthSlice = 1;
range0.sliceCount = imageInfo.extent.depth - 1;
state.RecordUse(range0, eFrameRef_Read, 0);
// read all subresources
ImageSubresourceRange range1 = imageInfo.FullRange();
state.RecordUse(range1, eFrameRef_Read, 0);
state.subresourceStates.Unsplit();
CheckSubresourceRanges(state, false, false, false, false);
for(auto it = state.subresourceStates.begin(); it != state.subresourceStates.end(); ++it)
{
CheckSubresourceState(it->state(), readSubstate);
}
};
};
#endif // ENABLED(ENABLE_UNIT_TESTS)
@@ -100,6 +100,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="imagestate_tests.cpp" />
<ClCompile Include="imgrefs_tests.cpp" />
<ClCompile Include="precompiled.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
@@ -145,6 +145,9 @@
<ClCompile Include="vk_pixelhistory.cpp">
<Filter>Replay</Filter>
</ClCompile>
<ClCompile Include="imagestate_tests.cpp">
<Filter>Util</Filter>
</ClCompile>
<ClCompile Include="vk_image_states.cpp">
<Filter>Util</Filter>
</ClCompile>
+7
View File
@@ -370,6 +370,13 @@ VkAccessFlags MakeAccessMask(VkImageLayout layout)
return VkAccessFlags(0);
}
void SanitiseReplayImageLayout(VkImageLayout &layout)
{
// we don't replay with present layouts since we don't create actual swapchains. So change any
// present layouts to general layouts
if(layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR || layout == VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR)
layout = VK_IMAGE_LAYOUT_GENERAL;
}
void SanitiseOldImageLayout(VkImageLayout &layout)
{
+1
View File
@@ -91,6 +91,7 @@ VkAccessFlags MakeAccessMask(VkImageLayout layout);
void SanitiseOldImageLayout(VkImageLayout &layout);
void SanitiseNewImageLayout(VkImageLayout &layout);
void SanitiseReplayImageLayout(VkImageLayout &layout);
void CombineDepthStencilLayouts(rdcarray<VkImageMemoryBarrier> &barriers);
File diff suppressed because it is too large Load Diff
-12
View File
@@ -3207,18 +3207,6 @@ VkImageAspectFlags FormatImageAspects(VkFormat fmt)
return VK_IMAGE_ASPECT_COLOR_BIT;
}
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);
}
int ImgRefs::GetAspectCount() const
{
int aspectCount = 0;
+338 -8
View File
@@ -925,6 +925,14 @@ struct ImageInfo
}
VkImageAspectFlags Aspects() const { return FormatImageAspects(format); }
ImageSubresourceRange FullRange() const;
inline bool operator==(const ImageInfo &other) const
{
return layerCount == other.layerCount && levelCount == other.levelCount &&
sampleCount == other.sampleCount && extent.width == other.extent.width &&
extent.height == other.extent.height && extent.depth == other.extent.depth &&
imageType == other.imageType && format == other.format &&
initialLayout == other.initialLayout && sharingMode == other.sharingMode;
}
};
DECLARE_REFLECTION_STRUCT(ImageInfo);
@@ -1146,9 +1154,9 @@ bool IntervalsOverlap(uint32_t base1, uint32_t count1, uint32_t base2, uint32_t
bool IntervalContainedIn(uint32_t base1, uint32_t count1, uint32_t base2, uint32_t count2);
bool ValidateLevelRange(uint32_t &baseMipLevel, uint32_t &levelCount, uint32_t imageLevelCount);
bool ValidateLayerRange(uint32_t &baseArrayLayer, uint32_t &layerCount, uint32_t imageLayerCount);
bool ValidateSliceRange(uint32_t &baseSlice, uint32_t &sliceCount, uint32_t imageSliceCount);
bool SanitiseLevelRange(uint32_t &baseMipLevel, uint32_t &levelCount, uint32_t imageLevelCount);
bool SanitiseLayerRange(uint32_t &baseArrayLayer, uint32_t &layerCount, uint32_t imageLayerCount);
bool SanitiseSliceRange(uint32_t &baseSlice, uint32_t &sliceCount, uint32_t imageSliceCount);
struct ImageSubresourceRange
{
@@ -1242,7 +1250,7 @@ struct ImageSubresourceRange
{
return other.ContainedIn(*this);
}
void Validate(const ImageInfo &info)
void Sanitise(const ImageInfo &info)
{
if(aspectMask & ~info.Aspects())
{
@@ -1250,16 +1258,230 @@ struct ImageSubresourceRange
{
RDCERR("Invalid aspect mask (%s) in image with aspects (%s)", ToStr(aspectMask).c_str(),
ToStr(info.Aspects()).c_str());
RDCDUMP();
}
aspectMask &= ~info.Aspects();
}
ValidateLevelRange(baseMipLevel, levelCount, info.levelCount);
ValidateLayerRange(baseArrayLayer, layerCount, info.layerCount);
ValidateSliceRange(baseDepthSlice, sliceCount, info.extent.depth);
SanitiseLevelRange(baseMipLevel, levelCount, info.levelCount);
SanitiseLayerRange(baseArrayLayer, layerCount, info.layerCount);
SanitiseSliceRange(baseDepthSlice, sliceCount, info.extent.depth);
}
};
struct ImageSubresourceState
{
uint32_t oldQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
uint32_t newQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
VkImageLayout oldLayout = UNKNOWN_PREV_IMG_LAYOUT;
VkImageLayout newLayout = UNKNOWN_PREV_IMG_LAYOUT;
FrameRefType refType = eFrameRef_None;
inline ImageSubresourceState() {}
inline ImageSubresourceState(const VkImageMemoryBarrier &barrier)
: oldQueueFamilyIndex(barrier.srcQueueFamilyIndex),
newQueueFamilyIndex(barrier.dstQueueFamilyIndex),
oldLayout(barrier.oldLayout),
newLayout(barrier.newLayout)
{
}
inline ImageSubresourceState(uint32_t queueFamilyIndex, VkImageLayout layout,
FrameRefType refType = eFrameRef_None)
: oldQueueFamilyIndex(queueFamilyIndex),
newQueueFamilyIndex(queueFamilyIndex),
oldLayout(layout),
newLayout(layout),
refType(refType)
{
}
inline bool operator==(const ImageSubresourceState &other) const
{
return oldQueueFamilyIndex == other.oldQueueFamilyIndex &&
newQueueFamilyIndex == other.newQueueFamilyIndex && oldLayout == other.oldLayout &&
newLayout == other.newLayout && refType == other.refType;
}
inline bool operator!=(const ImageSubresourceState &other) const { return !(*this == other); }
void Update(const ImageSubresourceState &other, FrameRefCompFunc compose);
bool Update(const ImageSubresourceState &other, ImageSubresourceState &result,
FrameRefCompFunc compose) const;
};
class ImageSubresourceMap
{
friend class SubresourceRangeIterator;
ImageInfo m_imageInfo;
// The states of the subresources, without explicit ranges.
// The ranges associated with each state are determined by the index in
// `m_values` and the `*Split` flags in `m_flags`.
rdcarray<ImageSubresourceState> m_values;
// All aspects of the image. This is computed from `m_imageInfo.format`
VkImageAspectFlags m_aspectMask = 0u;
// The bit count of `m_aspectMask`
uint16_t m_aspectCount = 0;
enum class FlagBits : uint16_t
{
AreAspectsSplit = 0x1,
AreLevelsSplit = 0x2,
AreLayersSplit = 0x4,
IsDepthSplit = 0x8,
IsUninitialized = 0x8000,
};
uint16_t m_flags = 0;
inline static bool AreAspectsSplit(uint16_t flags)
{
return (flags & (uint16_t)FlagBits::AreAspectsSplit) != 0;
}
inline static bool AreLevelsSplit(uint16_t flags)
{
return (flags & (uint16_t)FlagBits::AreLevelsSplit) != 0;
}
inline static bool AreLayersSplit(uint16_t flags)
{
return (flags & (uint16_t)FlagBits::AreLayersSplit) != 0;
}
inline static bool IsDepthSplit(uint16_t flags)
{
return (flags & (uint16_t)FlagBits::IsDepthSplit) != 0;
}
inline bool AreAspectsSplit() const { return AreAspectsSplit(m_flags); }
inline bool AreLevelsSplit() const { return AreLevelsSplit(m_flags); }
inline bool AreLayersSplit() const { return AreLayersSplit(m_flags); }
inline bool IsDepthSplit() const { return IsDepthSplit(m_flags); }
void Split(bool splitAspects, bool splitLevels, bool splitLayers, bool splitDepth);
void Unsplit(bool unsplitAspects, bool unsplitLevels, bool unsplitLayers, bool unsplitDepth);
size_t SubresourceIndex(uint32_t aspectIndex, uint32_t level, uint32_t layer, uint32_t z) const;
public:
inline const ImageInfo &GetImageInfo() const { return m_imageInfo; }
inline ImageSubresourceMap() {}
inline ImageSubresourceMap(const ImageInfo &imageInfo, FrameRefType refType)
: m_imageInfo(imageInfo), m_aspectMask(FormatImageAspects(imageInfo.format))
{
for(auto it = ImageAspectFlagIter::begin(m_aspectMask); it != ImageAspectFlagIter::end(); ++it)
++m_aspectCount;
m_values.push_back(
ImageSubresourceState(VK_QUEUE_FAMILY_IGNORED, UNKNOWN_PREV_IMG_LAYOUT, refType));
}
inline ImageSubresourceState &SubresourceValue(uint32_t aspectIndex, uint32_t level,
uint32_t layer, uint32_t slice)
{
return m_values[SubresourceIndex(aspectIndex, level, layer, slice)];
}
inline const ImageSubresourceState &SubresourceValue(uint32_t aspectIndex, uint32_t level,
uint32_t layer, uint32_t slice) const
{
return m_values[SubresourceIndex(aspectIndex, level, layer, slice)];
}
inline void Split(const ImageSubresourceRange &range)
{
Split(range.aspectMask != m_aspectMask,
range.baseMipLevel != 0u || range.levelCount < (uint32_t)GetImageInfo().levelCount,
range.baseArrayLayer != 0u || range.layerCount < (uint32_t)GetImageInfo().layerCount,
range.baseDepthSlice != 0u || range.sliceCount < GetImageInfo().extent.depth);
}
void Unsplit();
inline void Clear()
{
m_values.clear();
m_values.resize(1);
m_flags = 0;
}
FrameRefType Merge(const ImageSubresourceMap &other, FrameRefCompFunc compose);
template <typename Map, typename Pair>
class SubresourceRangeIterTemplate
{
public:
inline bool operator==(const SubresourceRangeIterTemplate &other)
{
bool isValid = IsValid();
bool otherIsValid = other.IsValid();
return (!isValid && !otherIsValid) ||
(isValid && otherIsValid &&
(m_aspectIndex == other.m_aspectIndex || !m_map->AreAspectsSplit()) &&
(m_level == other.m_level || !m_map->AreLevelsSplit()) &&
(m_layer == other.m_layer || !m_map->AreLayersSplit()) &&
(m_slice == other.m_slice || !m_map->IsDepthSplit()));
}
inline bool operator!=(const SubresourceRangeIterTemplate &other) { return !(*this == other); }
SubresourceRangeIterTemplate &operator++();
Pair *operator->();
Pair &operator*();
friend class ImageSubresourceMap;
protected:
Map *m_map = NULL;
uint16_t m_splitFlags = 0u;
ImageSubresourceRange m_range = {};
uint32_t m_aspectIndex = 0u;
uint32_t m_level = 0u;
uint32_t m_layer = 0u;
uint32_t m_slice = 0u;
Pair m_value;
SubresourceRangeIterTemplate() {}
SubresourceRangeIterTemplate(Map &map, const ImageSubresourceRange &range);
inline bool IsValid() const
{
return m_map && m_aspectIndex < m_map->m_aspectCount &&
m_level < m_range.baseMipLevel + m_range.levelCount &&
m_layer < m_range.baseArrayLayer + m_range.layerCount &&
m_slice < m_range.baseDepthSlice + m_range.sliceCount;
}
void FixSubRange();
};
template <typename State>
class SubresourcePairRefTemplate
{
public:
inline const ImageSubresourceRange &range() const { return m_range; }
inline State &state() { return *m_state; }
inline const State &state() const { return *m_state; }
SubresourcePairRefTemplate &operator=(const SubresourcePairRefTemplate &other) = delete;
protected:
template <typename Map, typename Pair>
friend class SubresourceRangeIterTemplate;
ImageSubresourceRange m_range;
State *m_state;
};
class SubresourcePairRef : public SubresourcePairRefTemplate<ImageSubresourceState>
{
public:
inline SubresourcePairRef &SetState(const ImageSubresourceState &state)
{
*m_state = state;
return *this;
}
};
using ConstSubresourcePairRef = SubresourcePairRefTemplate<const ImageSubresourceState>;
using SubresourceRangeIter = SubresourceRangeIterTemplate<ImageSubresourceMap, SubresourcePairRef>;
using SubresourceRangeConstIter =
SubresourceRangeIterTemplate<const ImageSubresourceMap, ConstSubresourcePairRef>;
inline SubresourceRangeIter RangeBegin(const ImageSubresourceRange &range)
{
return SubresourceRangeIter(*this, range);
}
inline SubresourceRangeConstIter RangeBegin(const ImageSubresourceRange &range) const
{
return SubresourceRangeConstIter(*this, range);
}
inline SubresourceRangeIter begin() { return RangeBegin(GetImageInfo().FullRange()); }
inline SubresourceRangeConstIter begin() const { return RangeBegin(GetImageInfo().FullRange()); }
inline SubresourceRangeIter end() { return SubresourceRangeIter(); }
inline SubresourceRangeConstIter end() const { return SubresourceRangeConstIter(); }
inline size_t size() const { return m_values.size(); }
};
template <typename Barrier>
struct BarrierSequence
{
@@ -1284,6 +1506,114 @@ struct BarrierSequence
using ImageBarrierSequence = BarrierSequence<VkImageMemoryBarrier>;
struct ImageTransitionInfo
{
CaptureState capState;
uint32_t defaultQueueFamilyIndex;
inline ImageTransitionInfo(CaptureState capState, uint32_t defaultQueueFamilyIndex)
: capState(capState), defaultQueueFamilyIndex(defaultQueueFamilyIndex)
{
}
inline FrameRefCompFunc GetFrameRefCompFunc()
{
if(IsCaptureMode(capState))
return ComposeFrameRefs;
else
return KeepOldFrameRef;
}
inline FrameRefType GetDefaultRefType()
{
if(IsCaptureMode(capState))
return eFrameRef_None;
else
return eFrameRef_Unknown;
}
};
struct ImageState
{
ImageSubresourceMap subresourceStates;
rdcarray<VkImageMemoryBarrier> oldQueueFamilyTransfers;
rdcarray<VkImageMemoryBarrier> newQueueFamilyTransfers;
bool isMemoryBound = false;
ResourceId boundMemory = ResourceId();
VkDeviceSize boundMemoryOffset = 0ull;
VkDeviceSize boundMemorySize = 0ull;
FrameRefType maxRefType = eFrameRef_None;
VkImage wrappedHandle = VK_NULL_HANDLE;
inline const ImageInfo &GetImageInfo() const { return subresourceStates.GetImageInfo(); }
inline ImageState() {}
inline ImageState(VkImage wrappedHandle, const ImageInfo &imageInfo, FrameRefType refType)
: wrappedHandle(wrappedHandle), subresourceStates(imageInfo, refType), maxRefType(refType)
{
}
ImageState InitialState() const;
void InitialState(ImageState &result) const;
ImageState CommandBufferInitialState() const;
ImageState UniformState(const ImageSubresourceState &sub) const;
ImageState ContentInitializationState(InitPolicy policy, bool initialized,
uint32_t queueFamilyIndex, VkImageLayout copyLayout,
VkImageLayout clearLayout) const;
void RemoveQueueFamilyTransfer(VkImageMemoryBarrier *it);
void Update(ImageSubresourceRange range, const ImageSubresourceState &dst,
FrameRefCompFunc compose);
void Merge(const ImageState &other, ImageTransitionInfo info);
void MergeCaptureBeginState(const ImageState &initialState);
static void Merge(std::map<ResourceId, ImageState> &states,
const std::map<ResourceId, ImageState> &dstStates, ImageTransitionInfo info);
void DiscardContents(const ImageSubresourceRange &range);
inline void DiscardContents() { DiscardContents(GetImageInfo().FullRange()); }
inline void RecordUse(const ImageSubresourceRange &range, FrameRefType refType,
uint32_t queueFamilyIndex)
{
Update(range, ImageSubresourceState(queueFamilyIndex, UNKNOWN_PREV_IMG_LAYOUT, refType),
ComposeFrameRefs);
}
void RecordQueueFamilyRelease(const VkImageMemoryBarrier &barrier);
void RecordQueueFamilyAcquire(const VkImageMemoryBarrier &barrier);
void RecordBarrier(VkImageMemoryBarrier barrier, uint32_t queueFamilyIndex,
ImageTransitionInfo info);
bool CloseTransfers(uint32_t batchIndex, VkAccessFlags dstAccessMask,
ImageBarrierSequence &barriers, ImageTransitionInfo info);
bool RestoreTransfers(uint32_t batchIndex, const rdcarray<VkImageMemoryBarrier> &transfers,
VkAccessFlags srcAccessMask, ImageBarrierSequence &barriers,
ImageTransitionInfo info);
void ResetToOldState(ImageBarrierSequence &barriers, ImageTransitionInfo info);
void Transition(const ImageState &dstState, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, ImageBarrierSequence &barriers,
ImageTransitionInfo info);
void Transition(uint32_t queueFamilyIndex, VkImageLayout layout, VkAccessFlags srcAccessMask,
VkAccessFlags dstAccessMask, ImageBarrierSequence &barriers,
ImageTransitionInfo info);
// Transitions the image state to `dstState` (via `preBarriers`) and back to the current state
// (via `postBarriers`).
// It is not always possible to return exactly to the current state, e.g. if the image is
// VK_IMAGE_LAYOUT_PREINITIALIZED, it will be returned to VK_IMAGE_LAYOUT_GENERAL instead.
void TempTransition(const ImageState &dstState, VkAccessFlags preSrcAccessMask,
VkAccessFlags preDstAccessMask, VkAccessFlags postSrcAccessmask,
VkAccessFlags postDstAccessMask, ImageBarrierSequence &setupBarriers,
ImageBarrierSequence &cleanupBarriers, ImageTransitionInfo info) const;
void TempTransition(uint32_t queueFamilyIndex, VkImageLayout layout, VkAccessFlags accessMask,
ImageBarrierSequence &setupBarriers, ImageBarrierSequence &cleanupBarriers,
ImageTransitionInfo info) const;
void InlineTransition(VkCommandBuffer cmd, uint32_t queueFamilyIndex, const ImageState &dstState,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
ImageTransitionInfo info);
void InlineTransition(VkCommandBuffer cmd, uint32_t queueFamilyIndex, VkImageLayout layout,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
ImageTransitionInfo info);
InitReqType MaxInitReq(const ImageSubresourceRange &range, InitPolicy policy,
bool initialized) const;
VkImageLayout GetImageLayout(VkImageAspectFlagBits aspect, uint32_t mipLevel,
uint32_t arrayLayer) const;
void BeginCapture();
};
struct ImgRefs
{
rdcarray<FrameRefType> rangeRefs;