For storage resources be pessimistic about their usage in the frame

* If a storage resource is only referenced in a copy as a destination and gets
  CompleteWrite state, this may be inaccurate because we no longer track
  descriptor set access to images or buffers. That means there could be an
  earlier use of the resource in a read/write fashion but on replay we would
  clear it for initial states.
* For images this is easy as we can fix this up at the end of the frame, for
  memory we need to iterate over all storage buffers and update the memrefs on
  their bindings.
This commit is contained in:
baldurk
2021-08-02 11:15:24 +01:00
parent a3d5404393
commit 2bfc3c2264
9 changed files with 93 additions and 13 deletions
+3 -3
View File
@@ -137,9 +137,9 @@ TEST_CASE("Test ImageState type", "[imagestate]")
VkImage image = (VkImage)123; VkImage image = (VkImage)123;
VkFormat format = VK_FORMAT_D16_UNORM_S8_UINT; VkFormat format = VK_FORMAT_D16_UNORM_S8_UINT;
VkExtent3D extent = {100, 100, 13}; VkExtent3D extent = {100, 100, 13};
int levelCount = 11; uint16_t levelCount = 11;
int layerCount = 17; uint32_t layerCount = 17;
int sampleCount = 1; uint16_t sampleCount = 1;
ImageInfo imageInfo(format, extent, levelCount, layerCount, sampleCount, ImageInfo imageInfo(format, extent, levelCount, layerCount, sampleCount,
VK_IMAGE_LAYOUT_UNDEFINED, VK_SHARING_MODE_EXCLUSIVE); VK_IMAGE_LAYOUT_UNDEFINED, VK_SHARING_MODE_EXCLUSIVE);
+4
View File
@@ -1160,6 +1160,8 @@ void DescriptorSetSlot::AccumulateBindRefs(DescriptorBindRefs &refs, VulkanResou
AddBindFrameRef(refs, bufView->baseResource, eFrameRef_Read); AddBindFrameRef(refs, bufView->baseResource, eFrameRef_Read);
if(bufView->baseResourceMem != ResourceId()) if(bufView->baseResourceMem != ResourceId())
AddMemFrameRef(refs, bufView->baseResourceMem, bufView->memOffset, bufView->memSize, ref); AddMemFrameRef(refs, bufView->baseResourceMem, bufView->memOffset, bufView->memSize, ref);
if(bufView->resInfo->storable)
refs.storableRefs.insert(rm->GetResourceRecord(bufView->baseResource));
} }
if(imgView) if(imgView)
{ {
@@ -1176,6 +1178,8 @@ void DescriptorSetSlot::AccumulateBindRefs(DescriptorBindRefs &refs, VulkanResou
refs.sparseRefs.insert(buffer); refs.sparseRefs.insert(buffer);
if(buffer->baseResource != ResourceId()) if(buffer->baseResource != ResourceId())
AddMemFrameRef(refs, buffer->baseResource, buffer->memOffset, buffer->memSize, ref); AddMemFrameRef(refs, buffer->baseResource, buffer->memOffset, buffer->memSize, ref);
if(buffer->storable)
refs.storableRefs.insert(buffer);
} }
} }
+12
View File
@@ -1666,7 +1666,14 @@ template <typename SerialiserType>
bool WrappedVulkan::Serialise_BeginCaptureFrame(SerialiserType &ser) bool WrappedVulkan::Serialise_BeginCaptureFrame(SerialiserType &ser)
{ {
SCOPED_LOCK(m_ImageStatesLock); SCOPED_LOCK(m_ImageStatesLock);
for(auto it = m_ImageStates.begin(); it != m_ImageStates.end(); ++it)
{
it->second.LockWrite()->FixupStorageReferences();
}
GetResourceManager()->SerialiseImageStates(ser, m_ImageStates); GetResourceManager()->SerialiseImageStates(ser, m_ImageStates);
SERIALISE_CHECK_READ_ERRORS(); SERIALISE_CHECK_READ_ERRORS();
return true; return true;
@@ -2624,6 +2631,11 @@ ReplayStatus WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t sta
ser.SkipCurrentChunk(); ser.SkipCurrentChunk();
#else #else
Serialise_BeginCaptureFrame(ser); Serialise_BeginCaptureFrame(ser);
if(IsLoading(m_State))
{
AddResourceCurChunk(m_InitParams.InstanceID);
}
#endif #endif
} }
@@ -1502,3 +1502,22 @@ void ImageState::BeginCapture()
it->SetState(state); it->SetState(state);
} }
} }
void ImageState::FixupStorageReferences()
{
if(m_Storage)
{
// storage images we don't track the reference to because they're in descriptor sets, so the
// read/write state of them is unknown. We can't allow a 'completewrite' to be used as-is
// because
// there might be a read before then which we just didn't track at the time.
maxRefType = ComposeFrameRefsUnordered(maxRefType, eFrameRef_ReadBeforeWrite);
for(auto it = subresourceStates.begin(); it != subresourceStates.end(); ++it)
{
ImageSubresourceState state = it->state();
state.refType = ComposeFrameRefsUnordered(state.refType, eFrameRef_ReadBeforeWrite);
it->SetState(state);
}
}
}
+20 -1
View File
@@ -296,7 +296,7 @@ template <typename SerialiserType>
void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser, void VulkanResourceManager::SerialiseImageStates(SerialiserType &ser,
std::map<ResourceId, LockingImageState> &states) std::map<ResourceId, LockingImageState> &states)
{ {
SERIALISE_ELEMENT_LOCAL(NumImages, (uint32_t)states.size()); SERIALISE_ELEMENT_LOCAL(NumImages, (uint32_t)states.size()).Important();
auto srcit = states.begin(); auto srcit = states.begin();
@@ -951,6 +951,25 @@ void VulkanResourceManager::MergeReferencedMemory(std::unordered_map<ResourceId,
} }
} }
void VulkanResourceManager::FixupStorageBufferMemory(
const std::unordered_set<VkResourceRecord *> &storageBuffers)
{
SCOPED_LOCK_OPTIONAL(m_Lock, m_Capturing);
for(VkResourceRecord *buf : storageBuffers)
{
ResourceId id = buf->GetResourceID();
MemRefs ref;
ref.Update(buf->memOffset, buf->memSize, eFrameRef_ReadBeforeWrite);
auto i = m_MemFrameRefs.find(id);
if(i == m_MemFrameRefs.end())
m_MemFrameRefs[id] = ref;
else
i->second.Merge(ref, ComposeFrameRefsUnordered);
}
}
void VulkanResourceManager::ClearReferencedMemory() void VulkanResourceManager::ClearReferencedMemory()
{ {
SCOPED_LOCK_OPTIONAL(m_Lock, m_Capturing); SCOPED_LOCK_OPTIONAL(m_Lock, m_Capturing);
+1
View File
@@ -422,6 +422,7 @@ public:
void RemoveDeviceMemory(ResourceId mem); void RemoveDeviceMemory(ResourceId mem);
void MergeReferencedMemory(std::unordered_map<ResourceId, MemRefs> &memRefs); void MergeReferencedMemory(std::unordered_map<ResourceId, MemRefs> &memRefs);
void FixupStorageBufferMemory(const std::unordered_set<VkResourceRecord *> &storageBuffers);
void ClearReferencedMemory(); void ClearReferencedMemory();
MemRefs *FindMemRefs(ResourceId mem); MemRefs *FindMemRefs(ResourceId mem);
ImgRefs *FindImgRefs(ResourceId img); ImgRefs *FindImgRefs(ResourceId img);
+21 -8
View File
@@ -851,9 +851,10 @@ struct ImageSubresourceRange;
struct ImageInfo struct ImageInfo
{ {
int layerCount = 0; uint32_t layerCount = 0;
int levelCount = 0; uint16_t levelCount = 0;
int sampleCount = 0; uint16_t sampleCount = 0;
bool storage = false;
VkExtent3D extent = {0, 0, 0}; VkExtent3D extent = {0, 0, 0};
VkImageType imageType = VK_IMAGE_TYPE_2D; VkImageType imageType = VK_IMAGE_TYPE_2D;
VkFormat format = VK_FORMAT_UNDEFINED; VkFormat format = VK_FORMAT_UNDEFINED;
@@ -861,8 +862,8 @@ struct ImageInfo
VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE; VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkImageAspectFlags aspects = 0; VkImageAspectFlags aspects = 0;
ImageInfo() {} ImageInfo() {}
ImageInfo(VkFormat format, VkExtent3D extent, int levelCount, int layerCount, int sampleCount, ImageInfo(VkFormat format, VkExtent3D extent, uint16_t levelCount, uint32_t layerCount,
VkImageLayout initialLayout, VkSharingMode sharingMode) uint16_t sampleCount, VkImageLayout initialLayout, VkSharingMode sharingMode)
: format(format), : format(format),
extent(extent), extent(extent),
levelCount(levelCount), levelCount(levelCount),
@@ -875,8 +876,8 @@ struct ImageInfo
} }
ImageInfo(const VkImageCreateInfo &ci) ImageInfo(const VkImageCreateInfo &ci)
: layerCount(ci.arrayLayers), : layerCount(ci.arrayLayers),
levelCount(ci.mipLevels), levelCount((uint16_t)ci.mipLevels),
sampleCount((int)ci.samples), sampleCount((uint16_t)ci.samples),
extent(ci.extent), extent(ci.extent),
imageType(ci.imageType), imageType(ci.imageType),
format(ci.format), format(ci.format),
@@ -896,6 +897,11 @@ struct ImageInfo
extent.depth = 1; extent.depth = 1;
} }
aspects = FormatImageAspects(format); aspects = FormatImageAspects(format);
if(ci.usage & VK_IMAGE_USAGE_STORAGE_BIT)
{
storage = true;
}
} }
ImageInfo(const VkSwapchainCreateInfoKHR &ci) ImageInfo(const VkSwapchainCreateInfoKHR &ci)
: layerCount(ci.imageArrayLayers), : layerCount(ci.imageArrayLayers),
@@ -972,6 +978,7 @@ struct ResourceInfo
Sparse::PageTable sparseTable; Sparse::PageTable sparseTable;
rdcarray<AspectSparseTable> altSparseAspects; rdcarray<AspectSparseTable> altSparseAspects;
VkImageAspectFlags sparseAspect; VkImageAspectFlags sparseAspect;
bool storable;
Sparse::PageTable &getSparseTableForAspect(VkImageAspectFlags aspects) Sparse::PageTable &getSparseTableForAspect(VkImageAspectFlags aspects)
{ {
@@ -1111,6 +1118,7 @@ struct DescriptorBindRefs
std::unordered_map<ResourceId, MemRefs> bindMemRefs; std::unordered_map<ResourceId, MemRefs> bindMemRefs;
rdcflatmap<ResourceId, ImageState> bindImageStates; rdcflatmap<ResourceId, ImageState> bindImageStates;
std::unordered_set<VkResourceRecord *> sparseRefs; std::unordered_set<VkResourceRecord *> sparseRefs;
std::unordered_set<VkResourceRecord *> storableRefs;
}; };
struct PipelineLayoutData struct PipelineLayoutData
@@ -1701,6 +1709,7 @@ struct ImageState
rdcarray<VkImageMemoryBarrier> newQueueFamilyTransfers; rdcarray<VkImageMemoryBarrier> newQueueFamilyTransfers;
bool isMemoryBound = false; bool isMemoryBound = false;
bool m_Overlay = false; bool m_Overlay = false;
bool m_Storage = false;
ResourceId boundMemory = ResourceId(); ResourceId boundMemory = ResourceId();
VkDeviceSize boundMemoryOffset = 0ull; VkDeviceSize boundMemoryOffset = 0ull;
VkDeviceSize boundMemorySize = 0ull; VkDeviceSize boundMemorySize = 0ull;
@@ -1710,7 +1719,10 @@ struct ImageState
inline const ImageInfo &GetImageInfo() const { return subresourceStates.GetImageInfo(); } inline const ImageInfo &GetImageInfo() const { return subresourceStates.GetImageInfo(); }
inline ImageState() {} inline ImageState() {}
inline ImageState(VkImage wrappedHandle, const ImageInfo &imageInfo, FrameRefType refType) inline ImageState(VkImage wrappedHandle, const ImageInfo &imageInfo, FrameRefType refType)
: wrappedHandle(wrappedHandle), subresourceStates(imageInfo, refType), maxRefType(refType) : wrappedHandle(wrappedHandle),
subresourceStates(imageInfo, refType),
maxRefType(refType),
m_Storage(imageInfo.storage)
{ {
} }
void SetOverlay() { m_Overlay = true; } void SetOverlay() { m_Overlay = true; }
@@ -1778,6 +1790,7 @@ struct ImageState
uint32_t arrayLayer) const; uint32_t arrayLayer) const;
void BeginCapture(); void BeginCapture();
void FixupStorageReferences();
}; };
DECLARE_REFLECTION_STRUCT(ImageState); DECLARE_REFLECTION_STRUCT(ImageState);
@@ -981,6 +981,15 @@ void WrappedVulkan::CaptureQueueSubmit(VkQueue queue,
UpdateImageStates(refs.bindImageStates); UpdateImageStates(refs.bindImageStates);
GetResourceManager()->MergeReferencedMemory(refs.bindMemRefs); GetResourceManager()->MergeReferencedMemory(refs.bindMemRefs);
// for storage buffers we have to pessimise memory references because the order matters - if
// the first recorded reference is a complete write then a later readbeforewrite won't
// properly mark it as needing initial states preserved. So we do that here. Images are
// handled separately
for(auto refit = refs.storableRefs.begin(); refit != refs.storableRefs.end(); ++refit)
{
GetResourceManager()->FixupStorageBufferMemory(refs.storableRefs);
}
} }
GetResourceManager()->MarkResourceFrameReferenced(GetResID(queue), eFrameRef_Read); GetResourceManager()->MarkResourceFrameReferenced(GetResID(queue), eFrameRef_Read);
@@ -1700,6 +1700,8 @@ VkResult WrappedVulkan::vkCreateBuffer(VkDevice device, const VkBufferCreateInfo
{ {
record->resInfo = new ResourceInfo(); record->resInfo = new ResourceInfo();
record->resInfo->storable = record->storable;
// pre-populate memory requirements // pre-populate memory requirements
ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), Unwrap(*pBuffer), ObjDisp(device)->GetBufferMemoryRequirements(Unwrap(device), Unwrap(*pBuffer),
&record->resInfo->memreqs); &record->resInfo->memreqs);
@@ -2254,7 +2256,8 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo *
ResourceInfo &resInfo = *record->resInfo; ResourceInfo &resInfo = *record->resInfo;
resInfo.imageInfo = ImageInfo(*pCreateInfo); resInfo.imageInfo = ImageInfo(*pCreateInfo);
record->storable = (pCreateInfo->usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0; record->resInfo->storable = record->storable =
(pCreateInfo->usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0;
// pre-populate memory requirements // pre-populate memory requirements
ObjDisp(device)->GetImageMemoryRequirements(Unwrap(device), Unwrap(*pImage), &resInfo.memreqs); ObjDisp(device)->GetImageMemoryRequirements(Unwrap(device), Unwrap(*pImage), &resInfo.memreqs);