Added InitPolicy

This allows finer control of the initialization/reset behaviour of
resources based on their ref type.

Currently, these policies only apply to the initialization/reseting of
VkDeviceMemory and VkImage resources.

Change-Id: Ib647cbaf99b650e8da40d07944400ace7dde504d
This commit is contained in:
Benson Joeris
2019-07-08 14:32:47 -04:00
committed by Baldur Karlsson
parent 40c56dafa3
commit 5120622dac
6 changed files with 121 additions and 61 deletions
+80 -24
View File
@@ -139,41 +139,97 @@ bool IsDirtyFrameRef(FrameRefType refType);
// init/reset requirements.
enum InitReqType
{
// Initial contents of the resource are not used, and also not modified.
// No initialization/reset is required for correct replay, but may be helpful
// to avoid user confusion when analyzing the resource.
// Corresponds to `None` ref type.
// No initialization required.
eInitReq_None,
// Initial contents of the resource are not used, but the contents are
// potentially modified during the frame.
// No initialization/reset is required for correct replay, but may be helpful
// to avoid user confusion when analyzing the resource.
// Corresponds to `PartialWrite` and `CompleteWrite` ref types.
// Initialize the resource by clearing.
eInitReq_Clear,
// Initial contents of the resource are read, but not overwritten;
// the resource needs to be initialized before the first replay, but need not
// be reset before subsequent replays.
// Corresponds to `Read` ref type.
eInitReq_InitOnce,
// Initialize the resource by copying initial data.
eInitReq_Copy,
};
// Initial contents of the resource are read, and later overwritten;
// the resource needs to be reset before each replay.
// Corresponds to `ReadBeforeWrite` ref type.
eInitReq_Reset,
enum InitPolicy
{
// Completely disable optimizations--copy initial data into every resource
// before every replay.
eInitPolicy_NoOpt,
// CopyAll--conservative policy which ensures each subresource begins each
// replay with the correct initial data.
//
// Initialization policy:
// Copy initial data into each subresource
//
// Reset policy:
// Copy initial data into each subresource which is written
eInitPolicy_CopyAll,
// ClearUnread--avoid copying initial data which is never read by the replay
// commands. A user inspecting a resource before it is written may observe
// cleared data, rather than the actual initial data.
//
// Initialization policy:
// Copy initial data into each subresource that is read.
// Clear each subresource that is not read.
//
// Reset policy:
// Copy initial data into each subresource where the initial data is read
// and then overwritten.
// Clear each subresource which is written, but whose initial data is not read.
eInitPolicy_ClearUnread,
// Fastest--Initialize/reset as little as possible for correct replay.
// A user inspecting a resource before it is written may observe the data
// from a future write (from the previous replay).
//
// Initialization policy:
// Copy initial data into each subresource that is read.
// Clear each subresource that is not read.
//
// Reset policy:
// Copy initial data into each subresource where the initial data is read
// and then overwritten.
eInitPolicy_Fastest,
};
// Return the initialization/reset requirements for a FrameRefType
inline InitReqType InitReq(FrameRefType refType)
inline InitReqType InitReq(FrameRefType refType, InitPolicy policy, bool initialized)
{
switch(refType)
#define COPY_ONCE (initialized ? eInitReq_None : eInitReq_Copy)
#define CLEAR_ONCE (initialized ? eInitReq_None : eInitReq_Clear)
switch(policy)
{
case eFrameRef_None: return eInitReq_None;
case eFrameRef_Read: return eInitReq_InitOnce;
case eFrameRef_ReadBeforeWrite: return eInitReq_Reset;
default: return eInitReq_Clear;
case eInitPolicy_NoOpt: return eInitReq_Copy;
case eInitPolicy_CopyAll:
switch(refType)
{
case eFrameRef_None: return COPY_ONCE;
case eFrameRef_Read: return COPY_ONCE;
default: return eInitReq_Copy;
}
case eInitPolicy_ClearUnread:
switch(refType)
{
case eFrameRef_None: return CLEAR_ONCE;
case eFrameRef_Read: return COPY_ONCE;
case eFrameRef_ReadBeforeWrite: return eInitReq_Copy;
case eFrameRef_WriteBeforeRead: return eInitReq_Copy;
default: return eInitReq_Clear;
}
case eInitPolicy_Fastest:
switch(refType)
{
case eFrameRef_None: return CLEAR_ONCE;
case eFrameRef_Read: return COPY_ONCE;
case eFrameRef_ReadBeforeWrite: return eInitReq_Copy;
case eFrameRef_WriteBeforeRead: return COPY_ONCE;
default: return CLEAR_ONCE;
}
default: RDCERR("Unknown initialization policy (%d).", policy); return eInitReq_Copy;
}
#undef COPY_ONCE
#undef CLEAR_ONCE
}
// handle marking a resource referenced for read or write and storing RAW access etc.
+1 -1
View File
@@ -900,7 +900,7 @@ private:
const char *pMessage, void *pUserData);
void AddFrameTerminator(uint64_t queueMarkerTag);
std::vector<VkImageMemoryBarrier> ImageInitializationBarriers(ResourceId id, WrappedVkRes *live,
bool initialized,
InitPolicy policy, bool initialized,
const ImgRefs *imgRefs) const;
void SubmitExtQBarriers(const std::map<uint32_t, std::vector<VkImageMemoryBarrier>> &extQBarriers);
+31 -27
View File
@@ -1314,7 +1314,7 @@ void WrappedVulkan::Create_InitialState(ResourceId id, WrappedVkRes *live, bool
}
std::vector<VkImageMemoryBarrier> WrappedVulkan::ImageInitializationBarriers(
ResourceId id, WrappedVkRes *live, bool initialized, const ImgRefs *imgRefs) const
ResourceId id, WrappedVkRes *live, InitPolicy policy, bool initialized, const ImgRefs *imgRefs) const
{
std::vector<VkImageMemoryBarrier> barriers;
@@ -1346,10 +1346,11 @@ std::vector<VkImageMemoryBarrier> WrappedVulkan::ImageInitializationBarriers(
}
else
{
auto initReqs = imgRefs->SubresourceRangeInitReqs(barrier.subresourceRange);
auto initReqs =
imgRefs->SubresourceRangeInitReqs(barrier.subresourceRange, policy, initialized);
for(auto initIt = initReqs.begin(); initIt != initReqs.end(); ++initIt)
{
if(initIt->second == eInitReq_Reset || initIt->second == eInitReq_Clear)
if(initIt->second != eInitReq_None)
{
barrier.subresourceRange = initIt->first;
barriers.push_back(barrier);
@@ -1478,6 +1479,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
ResourceId orig = GetResourceManager()->GetOriginalID(id);
ImgRefs *imgRefs = NULL;
bool initialized = false;
InitPolicy policy = GetResourceManager()->GetInitPolicy();
if(GetResourceManager()->OptimizeInitialState())
{
imgRefs = GetResourceManager()->FindImgRefs(orig);
@@ -1934,8 +1936,8 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
}
}
std::vector<VkImageMemoryBarrier> barriers =
ImageInitializationBarriers(id, live, initialized, imgRefs);
std::vector<VkImageMemoryBarrier> barriers = ImageInitializationBarriers(
id, live, GetResourceManager()->GetInitPolicy(), initialized, imgRefs);
DoPipelineBarrier(cmd, (uint32_t)barriers.size(), barriers.data());
std::map<uint32_t, std::vector<VkImageMemoryBarrier> > extQBarriers = GetExtQBarriers(barriers);
@@ -1951,19 +1953,20 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
std::vector<VkBufferImageCopy> copyRegions;
std::vector<VkImageSubresourceRange> clearRegions;
#define INIT_REGION() \
if(!initialized) \
{ \
copyRegions.push_back(region); \
} \
else \
{ \
InitReqType initReq = imgRefs->SubresourceInitReq( \
imgRefs->AspectIndex((VkImageAspectFlagBits)region.imageSubresource.aspectMask), m, a); \
if(initReq == eInitReq_Reset) \
copyRegions.push_back(region); \
else if(initReq == eInitReq_Clear) \
clearRegions.push_back(ImageRange(region.imageSubresource)); \
#define INIT_REGION() \
if(!initialized) \
{ \
copyRegions.push_back(region); \
} \
else \
{ \
InitReqType initReq = imgRefs->SubresourceInitReq( \
imgRefs->AspectIndex((VkImageAspectFlagBits)region.imageSubresource.aspectMask), m, a, \
policy, initialized); \
if(initReq == eInitReq_Copy) \
copyRegions.push_back(region); \
else if(initReq == eInitReq_Clear) \
clearRegions.push_back(ImageRange(region.imageSubresource)); \
}
// copy each slice/mip individually
@@ -2100,22 +2103,23 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
{
// No information about the memory usage in the frame.
// Pessimistically assume the entire memory needs to be reset.
resetReq.update(0, initial.mem.size, eInitReq_Reset,
[](InitReqType x, InitReqType y) -> InitReqType { return std::max(x, y); });
resetReq.update(0, initial.mem.size, eInitReq_Copy,
[](InitReqType x, InitReqType y) -> InitReqType { return RDCMAX(x, y); });
}
else
{
bool initialized = memRefs->initializedLiveRes == live;
memRefs->initializedLiveRes = live;
InitPolicy policy = GetResourceManager()->GetInitPolicy();
for(auto it = memRefs->rangeRefs.begin(); it != memRefs->rangeRefs.end(); it++)
{
InitReqType t = InitReq(it->value());
if(t == eInitReq_Reset || (t == eInitReq_InitOnce && !initialized))
resetReq.update(it->start(), it->finish(), eInitReq_Reset,
[](InitReqType x, InitReqType y) -> InitReqType { return std::max(x, y); });
else if(t == eInitReq_Clear || (t == eInitReq_None && !initialized))
InitReqType t = InitReq(it->value(), policy, initialized);
if(t == eInitReq_Copy)
resetReq.update(it->start(), it->finish(), eInitReq_Copy,
[](InitReqType x, InitReqType y) -> InitReqType { return RDCMAX(x, y); });
else if(t == eInitReq_Clear)
resetReq.update(it->start(), it->finish(), eInitReq_Clear,
[](InitReqType x, InitReqType y) -> InitReqType { return std::max(x, y); });
[](InitReqType x, InitReqType y) -> InitReqType { return RDCMAX(x, y); });
}
}
@@ -2158,7 +2162,7 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten
ObjDisp(cmd)->CmdFillBuffer(Unwrap(cmd), Unwrap(dstBuf), it->start(), size, 0);
fillCount++;
break;
case eInitReq_Reset: regions.push_back({it->start(), it->start(), size}); break;
case eInitReq_Copy: regions.push_back({it->start(), it->start(), size}); break;
default: break;
}
}
+2
View File
@@ -441,6 +441,7 @@ public:
ImgRefs *FindImgRefs(ResourceId img);
inline bool OptimizeInitialState() { return m_OptimizeInitialState; }
inline InitPolicy GetInitPolicy() { return m_InitPolicy; }
private:
bool ResourceTypeRelease(WrappedVkRes *res);
@@ -457,4 +458,5 @@ private:
std::map<ResourceId, MemRefs> m_MemFrameRefs;
std::map<ResourceId, ImgRefs> m_ImgFrameRefs;
bool m_OptimizeInitialState = false;
InitPolicy m_InitPolicy = eInitPolicy_CopyAll;
};
+3 -2
View File
@@ -2964,7 +2964,7 @@ int ImgRefs::SubresourceIndex(int aspectIndex, int level, int layer) const
}
std::vector<rdcpair<VkImageSubresourceRange, InitReqType> > ImgRefs::SubresourceRangeInitReqs(
VkImageSubresourceRange range) const
VkImageSubresourceRange range, InitPolicy policy, bool initialized) const
{
VkImageSubresourceRange out(range);
std::vector<rdcpair<VkImageSubresourceRange, InitReqType> > res;
@@ -3004,7 +3004,8 @@ std::vector<rdcpair<VkImageSubresourceRange, InitReqType> > ImgRefs::Subresource
for(int layer = range.baseArrayLayer; layer < splitLayerCount; ++layer)
{
out.baseArrayLayer = layer;
res.push_back(make_rdcpair(out, SubresourceInitReq(aspectIndex, level, layer)));
res.push_back(
make_rdcpair(out, SubresourceInitReq(aspectIndex, level, layer, policy, initialized)));
}
}
}
+4 -7
View File
@@ -1136,16 +1136,13 @@ struct ImgRefs
{
return rangeRefs[SubresourceIndex(aspectIndex, level, layer)];
}
inline InitReqType SubresourceInitReq(int aspectIndex, int level, int layer) const
inline InitReqType SubresourceInitReq(int aspectIndex, int level, int layer, InitPolicy policy,
bool initialized) const
{
return InitReq(SubresourceRef(aspectIndex, level, layer));
}
inline InitReqType SubresourceInitReq(int aspectIndex, int level, int layer, bool initialized) const
{
return InitReq(SubresourceRef(aspectIndex, level, layer));
return InitReq(SubresourceRef(aspectIndex, level, layer), policy, initialized);
}
std::vector<rdcpair<VkImageSubresourceRange, InitReqType> > SubresourceRangeInitReqs(
VkImageSubresourceRange range) const;
VkImageSubresourceRange range, InitPolicy policy, bool initialized) const;
void Split(bool splitAspects, bool splitLevels, bool splitLayers);
template <typename Compose>
FrameRefType Update(ImageRange range, FrameRefType refType, Compose comp);