mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 09:30:44 +00:00
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:
committed by
Baldur Karlsson
parent
3d90609e39
commit
96bbeea4a5
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user