mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-11-04 21:13:09 +00:00
Serialise unique descriptor fetches on a per-resource basis
* ASs and samplers can only have one descriptor ever - we automatically fetch this at creation time when descriptor buffers are enabled. We also fetch all possible NULL descriptors at device creation and do not re-serialise them afterwards. * Image views may have either 1 descriptor (if layouts are ignored) or N (one per layout). Buffers have N per offset/size and optionally format. These are tracked for uniqueness in the corresponding resource record to ensure we don't serialise infinite descriptors over time. * For combined image/samplers since they are in a known format we serialise these as-if they are image view descriptors only (with some extra data that we ignore). The whole descriptor must still replay bitwise identical but we will only use the image view part of it.
This commit is contained in:
9 files changed
+598
-4
No files matched your search
@@ -5383,6 +5383,37 @@ WrappedVulkan::CommandBufferNode *WrappedVulkan::GetCommandBufferPartialSubmissi
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t WrappedVulkan::DescriptorDataSize(VkDescriptorType type)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
const VkPhysicalDeviceDescriptorBufferPropertiesEXT &descSizes = m_DescriptorBufferProperties;
|
||||
switch(type)
|
||||
{
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER: ret = descSizes.samplerDescriptorSize; break;
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
ret = descSizes.combinedImageSamplerDescriptorSize;
|
||||
break;
|
||||
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: ret = descSizes.inputAttachmentDescriptorSize; break;
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: ret = descSizes.sampledImageDescriptorSize; break;
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: ret = descSizes.storageImageDescriptorSize; break;
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
ret = descSizes.uniformTexelBufferDescriptorSize;
|
||||
break;
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||
ret = descSizes.storageTexelBufferDescriptorSize;
|
||||
break;
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: ret = descSizes.uniformBufferDescriptorSize; break;
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: ret = descSizes.storageBufferDescriptorSize; break;
|
||||
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
|
||||
ret = descSizes.accelerationStructureDescriptorSize;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool WrappedVulkan::IsPartialRenderPassActive()
|
||||
{
|
||||
for(const CommandBufferNode &cmdNode : m_Partial.partialStack)
|
||||
|
||||
@@ -447,9 +447,15 @@ private:
|
||||
VkQueueFamilyProperties queueProps[16] = {};
|
||||
};
|
||||
|
||||
VkPhysicalDeviceDescriptorBufferPropertiesEXT m_DescriptorBufferProperties;
|
||||
size_t DescriptorDataSize(VkDescriptorType type);
|
||||
|
||||
Threading::CriticalSection m_ASLookupByAddrLock;
|
||||
rdcflatmap<VkDeviceAddress, ResourceId> m_ASLookupByAddr;
|
||||
|
||||
bool m_NULLDescriptorPatternSaved = false;
|
||||
bool m_IgnoreLayoutForDescriptors = false;
|
||||
|
||||
bool m_SeparateDepthStencil = false;
|
||||
bool m_NULLDescriptorsAllowed = false;
|
||||
bool m_ExtendedDynState = false;
|
||||
|
||||
@@ -3973,6 +3973,10 @@ VkResourceRecord::~VkResourceRecord()
|
||||
if(resType == eResBuffer || resType == eResImage)
|
||||
SAFE_DELETE(resInfo);
|
||||
|
||||
// for image views with descriptors, they have a duplicated resInfo
|
||||
if(resType == eResImageView && resInfo && resInfo->parentResInfo != resInfo)
|
||||
SAFE_DELETE(resInfo);
|
||||
|
||||
if(resType == eResInstance || resType == eResDevice || resType == eResPhysicalDevice)
|
||||
SAFE_DELETE(instDevInfo);
|
||||
|
||||
|
||||
@@ -1017,15 +1017,83 @@ struct AspectSparseTable
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(AspectSparseTable);
|
||||
|
||||
struct DescriptorUniquenessKey
|
||||
{
|
||||
DescriptorUniquenessKey(VkImageLayout layout)
|
||||
: layout(layout), offset(0), size(0), fmt(VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
}
|
||||
DescriptorUniquenessKey(uint64_t offset, uint64_t size, VkFormat fmt)
|
||||
: layout(VK_IMAGE_LAYOUT_UNDEFINED), offset(offset), size(size), fmt(fmt)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const DescriptorUniquenessKey &key) const
|
||||
{
|
||||
return layout == key.layout && offset == key.offset && size == key.size && fmt == key.fmt;
|
||||
}
|
||||
|
||||
VkImageLayout layout;
|
||||
uint64_t offset, size;
|
||||
VkFormat fmt;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<DescriptorUniquenessKey>
|
||||
{
|
||||
std::size_t operator()(const DescriptorUniquenessKey &key) const
|
||||
{
|
||||
std::size_t hash = std::hash<uint32_t>()(key.layout);
|
||||
hash ^= std::hash<uint64_t>()(key.offset) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash ^= std::hash<uint64_t>()(key.size) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
hash ^= std::hash<uint32_t>()(key.fmt) + 0x9e3779b9 + (hash << 6) + (hash >> 2);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// these structs are allocated for images and buffers, then pointed to (non-owning) by views
|
||||
struct ResourceInfo
|
||||
{
|
||||
ResourceInfo() = default;
|
||||
ResourceInfo(const ResourceInfo &other)
|
||||
: banDedicated(other.banDedicated),
|
||||
sparseAspect(other.sparseAspect),
|
||||
dedicatedMemory(other.dedicatedMemory),
|
||||
memreqs(other.memreqs),
|
||||
imageInfo(other.imageInfo)
|
||||
{
|
||||
// this constructor is used to duplicate an image's resinfo in an image view when descriptor
|
||||
// buffers are in use so that each view can have its own descriptor tracking.
|
||||
|
||||
// sparse table info deliberately not copied as it is mutable, and obviously the same for the descriptors
|
||||
}
|
||||
|
||||
// commonly we expect only one aspect (COLOR is vastly likely and METADATA is rare) so have one
|
||||
// directly accessible. If we have others (like separate DEPTH and STENCIL, or anything and
|
||||
// METADATA) we put them in the array.
|
||||
Sparse::PageTable sparseTable;
|
||||
rdcarray<AspectSparseTable> altSparseAspects;
|
||||
|
||||
// for images this is a self pointer. For image views when we are using descriptor buffers we
|
||||
// can't alias the resInfo in each view's record because each view needs to track its own
|
||||
// descriptors - instead we point back to the image's resInfo here for sparse info. blech
|
||||
ResourceInfo *parentResInfo;
|
||||
|
||||
// for buffers, or for images when layouts can affect descriptors, the set of descriptors which
|
||||
// have already been serialised
|
||||
Threading::CriticalSection descriptorLock;
|
||||
std::unordered_set<DescriptorUniquenessKey> descriptors;
|
||||
|
||||
// return true if this is a new descriptor, false if we already had it
|
||||
bool AddDescriptor(DescriptorUniquenessKey key)
|
||||
{
|
||||
SCOPED_LOCK(descriptorLock);
|
||||
return descriptors.insert(key).second;
|
||||
}
|
||||
|
||||
// for external images if we query both external and non-external and the sizes are different, we
|
||||
// can't allow dedicated memory as it is required to precisely match in size.
|
||||
bool banDedicated = false;
|
||||
@@ -2329,6 +2397,8 @@ public:
|
||||
bool storable = false;
|
||||
bool dedicated = false;
|
||||
bool hasBDA = false;
|
||||
bool hasDescriptorSaved = false;
|
||||
bool hasNULLDescriptorSaved = false;
|
||||
|
||||
void MarkMemoryFrameReferenced(ResourceId mem, VkDeviceSize offset, VkDeviceSize size,
|
||||
FrameRefType refType);
|
||||
|
||||
@@ -199,6 +199,83 @@ VkCopyDescriptorSet WrappedVulkan::UnwrapInfo(const VkCopyDescriptorSet *copyDes
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <>
|
||||
VkDescriptorGetInfoEXT WrappedVulkan::UnwrapInfo(const VkDescriptorGetInfoEXT *pDescriptorInfo)
|
||||
{
|
||||
VkDescriptorGetInfoEXT ret = *pDescriptorInfo;
|
||||
|
||||
byte *memory = GetTempMemory(sizeof(VkDescriptorAddressInfoEXT) + GetNextPatchSize(ret.pNext));
|
||||
RDCCOMPILE_ASSERT(sizeof(VkDescriptorAddressInfoEXT) >= sizeof(VkDescriptorImageInfo),
|
||||
"Structure sizes mean not enough space is allocated for write data");
|
||||
|
||||
if(pDescriptorInfo->data.pUniformBuffer)
|
||||
ret.data.pUniformBuffer = (VkDescriptorAddressInfoEXT *)memory;
|
||||
|
||||
byte *nextMem = memory + sizeof(VkDescriptorBufferInfo);
|
||||
|
||||
UnwrapNextChain(m_State, "VkDescriptorGetInfoEXT", nextMem, (VkBaseInStructure *)&ret);
|
||||
|
||||
switch(ret.type)
|
||||
{
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
{
|
||||
VkSampler *samp = (VkSampler *)memory;
|
||||
if(pDescriptorInfo->data.pSampler)
|
||||
{
|
||||
*samp = Unwrap(*pDescriptorInfo->data.pSampler);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
// ignore the sampler part
|
||||
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
{
|
||||
VkDescriptorImageInfo *img = (VkDescriptorImageInfo *)ret.data.pCombinedImageSampler;
|
||||
if(pDescriptorInfo->data.pCombinedImageSampler)
|
||||
{
|
||||
img->imageView = Unwrap(pDescriptorInfo->data.pCombinedImageSampler->imageView);
|
||||
img->sampler = Unwrap(pDescriptorInfo->data.pCombinedImageSampler->sampler);
|
||||
img->imageLayout = pDescriptorInfo->data.pCombinedImageSampler->imageLayout;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
{
|
||||
// no unwrap, just copy
|
||||
VkDescriptorAddressInfoEXT *buf = (VkDescriptorAddressInfoEXT *)ret.data.pUniformBuffer;
|
||||
if(pDescriptorInfo->data.pUniformBuffer)
|
||||
*buf = *pDescriptorInfo->data.pUniformBuffer;
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
|
||||
{
|
||||
// no unwrap, just copy
|
||||
ret.data.accelerationStructure = pDescriptorInfo->data.accelerationStructure;
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
|
||||
case VK_DESCRIPTOR_TYPE_MUTABLE_EXT:
|
||||
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM:
|
||||
case VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM:
|
||||
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV:
|
||||
case VK_DESCRIPTOR_TYPE_MAX_ENUM:
|
||||
{
|
||||
RDCERR("Invalid descriptor type %s", ToStr(ret.type).c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename SerialiserType>
|
||||
bool WrappedVulkan::Serialise_vkCreateDescriptorPool(SerialiserType &ser, VkDevice device,
|
||||
const VkDescriptorPoolCreateInfo *pCreateInfo,
|
||||
@@ -1873,14 +1950,247 @@ void WrappedVulkan::vkUpdateDescriptorSetWithTemplate(
|
||||
template <typename SerialiserType>
|
||||
bool WrappedVulkan::Serialise_vkGetDescriptorEXT(SerialiserType &ser, VkDevice device,
|
||||
const VkDescriptorGetInfoEXT *pDescriptorInfo,
|
||||
size_t dataSize, void *pDescriptor)
|
||||
size_t dataSize_, void *pDescriptor)
|
||||
{
|
||||
SERIALISE_ELEMENT(device);
|
||||
SERIALISE_ELEMENT_LOCAL(DescriptorInfo, *pDescriptorInfo).Important();
|
||||
SERIALISE_ELEMENT_LOCAL(dataSize, uint64_t(dataSize_));
|
||||
SERIALISE_ELEMENT_ARRAY(pDescriptor, dataSize_);
|
||||
|
||||
SERIALISE_CHECK_READ_ERRORS();
|
||||
|
||||
if(IsReplayingAndReading())
|
||||
{
|
||||
byte *tempMem = GetTempMemory(GetNextPatchSize(&DescriptorInfo));
|
||||
VkDescriptorGetInfoEXT *unwrappedInfo = UnwrapStructAndChain(m_State, tempMem, &DescriptorInfo);
|
||||
|
||||
uint64_t curDataSize = DescriptorDataSize(DescriptorInfo.type);
|
||||
if(dataSize != curDataSize)
|
||||
{
|
||||
SET_ERROR_RESULT(
|
||||
m_FailedReplayResult, ResultCode::APIHardwareUnsupported,
|
||||
"Descriptor of type %s changed size, it was %llu bytes during capture but is %llu bytes "
|
||||
"during replay.\n"
|
||||
"\n%s",
|
||||
ToStr(DescriptorInfo.type).c_str(), dataSize, curDataSize,
|
||||
GetPhysDeviceCompatString(false, false).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bytebuf replayDescriptor;
|
||||
replayDescriptor.resize(dataSize);
|
||||
|
||||
// verify the descriptor is bitwise identical
|
||||
ObjDisp(device)->GetDescriptorEXT(Unwrap(device), unwrappedInfo, (size_t)dataSize,
|
||||
replayDescriptor.data());
|
||||
|
||||
if(memcmp(replayDescriptor.data(), pDescriptor, dataSize) != 0)
|
||||
{
|
||||
rdcstr bitDifferences;
|
||||
|
||||
uint32_t *capU32 = (uint32_t *)pDescriptor;
|
||||
uint32_t *replayU32 = (uint32_t *)replayDescriptor.data();
|
||||
|
||||
bitDifferences = "Capture:\n";
|
||||
for(uint32_t d = 0; d * 4 < dataSize; d++)
|
||||
bitDifferences += StringFormat::Fmt("%08llx ", capU32[d]);
|
||||
bitDifferences += "\n\n";
|
||||
bitDifferences += "Replay:\n";
|
||||
for(uint32_t d = 0; d * 4 < dataSize; d++)
|
||||
bitDifferences += StringFormat::Fmt("%08llx ", replayU32[d]);
|
||||
bitDifferences += "\n";
|
||||
|
||||
SET_ERROR_RESULT(m_FailedReplayResult, ResultCode::APIHardwareUnsupported,
|
||||
"Descriptor of type %s changed bit pattern.\n"
|
||||
"\n%s"
|
||||
"\n%s",
|
||||
ToStr(DescriptorInfo.type).c_str(), bitDifferences.c_str(),
|
||||
GetPhysDeviceCompatString(false, false).c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WrappedVulkan::vkGetDescriptorEXT(VkDevice device, const VkDescriptorGetInfoEXT *pDescriptorInfo,
|
||||
size_t dataSize, void *pDescriptor)
|
||||
{
|
||||
// the user *could* be querying straight into GPU upload memory which would be very bad to read
|
||||
// back from. To avoid that, we read into our temporary memory then memcpy to user memory but only
|
||||
// if we're actually going to process this.
|
||||
|
||||
// first determine where this should go, based on the 'primary' resource. For combined
|
||||
// image/samplers, we pre-populated the sampler one so we treat them as-if they're just images
|
||||
VkResourceRecord *dstRecord = NULL;
|
||||
|
||||
if(IsCaptureMode(m_State))
|
||||
{
|
||||
switch(pDescriptorInfo->type)
|
||||
{
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
{
|
||||
if(pDescriptorInfo->data.pSampler)
|
||||
{
|
||||
dstRecord = GetRecord(*pDescriptorInfo->data.pSampler);
|
||||
// don't need to worry about the race here, worst case we save an extra descriptor
|
||||
if(dstRecord->hasDescriptorSaved)
|
||||
dstRecord = NULL;
|
||||
else
|
||||
dstRecord->hasDescriptorSaved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
dstRecord = GetRecord(m_Device);
|
||||
if(m_NULLDescriptorPatternSaved)
|
||||
dstRecord = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
{
|
||||
// sampled/storage/input attachment are identical in the union. Since the type forms part of
|
||||
// our this logic can be done in common
|
||||
if(pDescriptorInfo->data.pSampledImage &&
|
||||
pDescriptorInfo->data.pSampledImage->imageView != VK_NULL_HANDLE)
|
||||
{
|
||||
dstRecord = GetRecord(pDescriptorInfo->data.pSampledImage->imageView);
|
||||
|
||||
DescriptorUniquenessKey descKey(
|
||||
m_IgnoreLayoutForDescriptors
|
||||
? VK_IMAGE_LAYOUT_UNDEFINED
|
||||
: pDescriptorInfo->data.pCombinedImageSampler->imageLayout);
|
||||
|
||||
// this is internally locked
|
||||
if(!dstRecord->resInfo->AddDescriptor(descKey))
|
||||
dstRecord = NULL;
|
||||
}
|
||||
else if(pDescriptorInfo->data.pCombinedImageSampler &&
|
||||
pDescriptorInfo->data.pCombinedImageSampler->imageView == VK_NULL_HANDLE &&
|
||||
pDescriptorInfo->data.pCombinedImageSampler->sampler != VK_NULL_HANDLE)
|
||||
{
|
||||
dstRecord = GetRecord(pDescriptorInfo->data.pCombinedImageSampler->sampler);
|
||||
// don't need to worry about the race here, worst case we save an extra descriptor
|
||||
if(dstRecord->hasNULLDescriptorSaved)
|
||||
dstRecord = NULL;
|
||||
else
|
||||
dstRecord->hasNULLDescriptorSaved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
dstRecord = GetRecord(m_Device);
|
||||
if(m_NULLDescriptorPatternSaved)
|
||||
dstRecord = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
{
|
||||
// uniform/storage are identical in the union. Since the type forms part of our this
|
||||
// logic can be done in common
|
||||
if(pDescriptorInfo->data.pUniformBuffer)
|
||||
{
|
||||
ResourceId id;
|
||||
uint64_t offs = 0;
|
||||
GetResIDFromAddr(pDescriptorInfo->data.pUniformBuffer->address, id, offs);
|
||||
|
||||
dstRecord = GetResourceManager()->GetResourceRecord(id);
|
||||
|
||||
VkFormat fmt = VK_FORMAT_UNDEFINED;
|
||||
if(pDescriptorInfo->type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER ||
|
||||
pDescriptorInfo->type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
|
||||
{
|
||||
fmt = pDescriptorInfo->data.pUniformTexelBuffer->format;
|
||||
}
|
||||
|
||||
DescriptorUniquenessKey descKey(offs, pDescriptorInfo->data.pUniformBuffer->range, fmt);
|
||||
|
||||
// this is internally locked
|
||||
if(!dstRecord->resInfo->AddDescriptor(descKey))
|
||||
dstRecord = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
dstRecord = GetRecord(m_Device);
|
||||
if(m_NULLDescriptorPatternSaved)
|
||||
dstRecord = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
|
||||
{
|
||||
if(pDescriptorInfo->data.accelerationStructure)
|
||||
{
|
||||
ResourceId id;
|
||||
{
|
||||
SCOPED_LOCK(m_ASLookupByAddrLock);
|
||||
id = m_ASLookupByAddr[pDescriptorInfo->data.accelerationStructure];
|
||||
}
|
||||
|
||||
dstRecord = GetResourceManager()->GetResourceRecord(id);
|
||||
// don't need to worry about the race here, worst case we save an extra descriptor
|
||||
if(dstRecord->hasDescriptorSaved)
|
||||
dstRecord = NULL;
|
||||
else
|
||||
dstRecord->hasDescriptorSaved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
dstRecord = GetRecord(m_Device);
|
||||
if(m_NULLDescriptorPatternSaved)
|
||||
dstRecord = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
|
||||
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM:
|
||||
case VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM:
|
||||
case VK_DESCRIPTOR_TYPE_MUTABLE_EXT:
|
||||
case VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV:
|
||||
case VK_DESCRIPTOR_TYPE_MAX_ENUM:
|
||||
RDCERR("Invalid descriptor type passed to vkGetDescriptorEXT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t localSize = 0;
|
||||
if(dstRecord)
|
||||
localSize = dataSize;
|
||||
|
||||
byte tempMem[256] = {};
|
||||
VkDescriptorGetInfoEXT unwrappedInfo = UnwrapInfo(pDescriptorInfo);
|
||||
|
||||
SERIALISE_TIME_CALL(ObjDisp(device)->GetDescriptorEXT(Unwrap(device), &unwrappedInfo, dataSize,
|
||||
dstRecord ? tempMem : pDescriptor));
|
||||
|
||||
// if we needed to serialise this descriptor
|
||||
if(dstRecord)
|
||||
{
|
||||
// copy to the user's memory
|
||||
memcpy(pDescriptor, tempMem, dataSize);
|
||||
|
||||
Chunk *chunk = NULL;
|
||||
|
||||
{
|
||||
CACHE_THREAD_SERIALISER();
|
||||
|
||||
SCOPED_SERIALISE_CHUNK(VulkanChunk::vkGetDescriptorEXT);
|
||||
Serialise_vkGetDescriptorEXT(ser, device, pDescriptorInfo, dataSize, tempMem);
|
||||
|
||||
chunk = scope.Get();
|
||||
}
|
||||
|
||||
dstRecord->AddChunk(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_FUNCTION_SERIALISED(VkResult, vkCreateDescriptorSetLayout, VkDevice device,
|
||||
|
||||
@@ -4291,6 +4291,53 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
|
||||
if(m_EnabledExtensions.ext_EXT_descriptor_buffer && descBufFeats && descBufFeats->descriptorBuffer)
|
||||
{
|
||||
m_DescriptorBuffers = true;
|
||||
|
||||
// if any update after bind feature is enabled, check robustBufferAccessUpdateAfterBind
|
||||
m_DescriptorBufferProperties = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT,
|
||||
};
|
||||
|
||||
VkPhysicalDeviceProperties2 availBase = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
availBase.pNext = &m_DescriptorBufferProperties;
|
||||
ObjDisp(physicalDevice)->GetPhysicalDeviceProperties2(Unwrap(physicalDevice), &availBase);
|
||||
|
||||
bool robustness = false;
|
||||
|
||||
// VkPhysicalDeviceFeatures2 takes priority
|
||||
if(enabledFeatures2)
|
||||
{
|
||||
robustness = enabledFeatures2->features.robustBufferAccess != VK_FALSE;
|
||||
}
|
||||
else if(createInfo.pEnabledFeatures && createInfo.pEnabledFeatures->robustBufferAccess)
|
||||
{
|
||||
robustness = true;
|
||||
}
|
||||
|
||||
// we should have forced on robustness
|
||||
RDCASSERT(robustness);
|
||||
|
||||
m_DescriptorBufferProperties.uniformBufferDescriptorSize =
|
||||
m_DescriptorBufferProperties.robustUniformBufferDescriptorSize;
|
||||
m_DescriptorBufferProperties.storageBufferDescriptorSize =
|
||||
m_DescriptorBufferProperties.robustStorageBufferDescriptorSize;
|
||||
m_DescriptorBufferProperties.uniformTexelBufferDescriptorSize =
|
||||
m_DescriptorBufferProperties.robustUniformTexelBufferDescriptorSize;
|
||||
m_DescriptorBufferProperties.storageTexelBufferDescriptorSize =
|
||||
m_DescriptorBufferProperties.robustStorageTexelBufferDescriptorSize;
|
||||
|
||||
// ensure our fixed-size is large enough for this driver.
|
||||
RDCASSERT(m_DescriptorBufferProperties.accelerationStructureCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
RDCASSERT(m_DescriptorBufferProperties.bufferCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
RDCASSERT(m_DescriptorBufferProperties.imageCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
RDCASSERT(m_DescriptorBufferProperties.imageViewCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
RDCASSERT(m_DescriptorBufferProperties.samplerCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
|
||||
m_IgnoreLayoutForDescriptors = descBufFeats->descriptorBufferImageLayoutIgnored != VK_FALSE;
|
||||
}
|
||||
|
||||
// MoltenVK reports 0x3fffffff for this limit so just ignore that value if it comes up
|
||||
@@ -4877,6 +4924,100 @@ VkResult WrappedVulkan::vkCreateDevice(VkPhysicalDevice physicalDevice,
|
||||
descBufFeatures->descriptorBuffer)
|
||||
{
|
||||
m_DescriptorBuffers = true;
|
||||
|
||||
// if any update after bind feature is enabled, check robustBufferAccessUpdateAfterBind
|
||||
m_DescriptorBufferProperties = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT,
|
||||
};
|
||||
|
||||
VkPhysicalDeviceProperties2 availBase = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
availBase.pNext = &m_DescriptorBufferProperties;
|
||||
ObjDisp(physicalDevice)->GetPhysicalDeviceProperties2(Unwrap(physicalDevice), &availBase);
|
||||
|
||||
bool robustness = false;
|
||||
|
||||
// VkPhysicalDeviceFeatures2 takes priority
|
||||
if(enabledFeatures2)
|
||||
{
|
||||
robustness = enabledFeatures2->features.robustBufferAccess != VK_FALSE;
|
||||
}
|
||||
else if(createInfo.pEnabledFeatures && createInfo.pEnabledFeatures->robustBufferAccess)
|
||||
{
|
||||
robustness = true;
|
||||
}
|
||||
|
||||
// we should have forced on robustness
|
||||
RDCASSERT(robustness);
|
||||
|
||||
m_DescriptorBufferProperties.uniformBufferDescriptorSize =
|
||||
m_DescriptorBufferProperties.robustUniformBufferDescriptorSize;
|
||||
m_DescriptorBufferProperties.storageBufferDescriptorSize =
|
||||
m_DescriptorBufferProperties.robustStorageBufferDescriptorSize;
|
||||
m_DescriptorBufferProperties.uniformTexelBufferDescriptorSize =
|
||||
m_DescriptorBufferProperties.robustUniformTexelBufferDescriptorSize;
|
||||
m_DescriptorBufferProperties.storageTexelBufferDescriptorSize =
|
||||
m_DescriptorBufferProperties.robustStorageTexelBufferDescriptorSize;
|
||||
|
||||
// ensure our fixed-size is large enough for this driver.
|
||||
RDCASSERT(m_DescriptorBufferProperties.accelerationStructureCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
RDCASSERT(m_DescriptorBufferProperties.bufferCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
RDCASSERT(m_DescriptorBufferProperties.imageCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
RDCASSERT(m_DescriptorBufferProperties.imageViewCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
RDCASSERT(m_DescriptorBufferProperties.samplerCaptureReplayDescriptorDataSize <=
|
||||
FixedOpaqueDescriptorCaptureSize);
|
||||
|
||||
m_IgnoreLayoutForDescriptors = descBufFeatures->descriptorBufferImageLayoutIgnored != VK_FALSE;
|
||||
|
||||
VkPhysicalDeviceRobustness2FeaturesKHR *robustness2 =
|
||||
(VkPhysicalDeviceRobustness2FeaturesKHR *)FindNextStruct(
|
||||
&createInfo, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR);
|
||||
|
||||
// record all the NULL descriptors
|
||||
if(IsCaptureMode(m_State) && robustness2 && robustness2->nullDescriptor)
|
||||
{
|
||||
VkResourceRecord *record = GetRecord(*pDevice);
|
||||
RDCASSERT(record);
|
||||
|
||||
VkDescriptorGetInfoEXT getInfo = {
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
|
||||
};
|
||||
|
||||
rdcarray<rdcpair<VkDescriptorType, size_t>> descriptorTypes = {
|
||||
{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
m_DescriptorBufferProperties.sampledImageDescriptorSize},
|
||||
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||
m_DescriptorBufferProperties.storageImageDescriptorSize},
|
||||
{VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
|
||||
m_DescriptorBufferProperties.robustUniformTexelBufferDescriptorSize},
|
||||
{VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
|
||||
m_DescriptorBufferProperties.robustStorageTexelBufferDescriptorSize},
|
||||
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
m_DescriptorBufferProperties.robustUniformBufferDescriptorSize},
|
||||
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
m_DescriptorBufferProperties.robustStorageBufferDescriptorSize},
|
||||
};
|
||||
|
||||
if(m_AccelerationStructures)
|
||||
{
|
||||
descriptorTypes.push_back(
|
||||
{VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
|
||||
m_DescriptorBufferProperties.accelerationStructureDescriptorSize});
|
||||
}
|
||||
|
||||
byte dummy[256];
|
||||
for(rdcpair<VkDescriptorType, size_t> typeAndSize : descriptorTypes)
|
||||
{
|
||||
getInfo.type = typeAndSize.first;
|
||||
|
||||
vkGetDescriptorEXT(*pDevice, &getInfo, typeAndSize.second, dummy);
|
||||
}
|
||||
}
|
||||
|
||||
m_NULLDescriptorPatternSaved = true;
|
||||
}
|
||||
|
||||
m_PhysicalDeviceData.driverInfo =
|
||||
|
||||
@@ -731,6 +731,18 @@ VkResult WrappedVulkan::vkCreateSampler(VkDevice device, const VkSamplerCreateIn
|
||||
VkResourceRecord *ycbcrRecord = GetRecord(ycbcr->conversion);
|
||||
record->AddParent(ycbcrRecord);
|
||||
}
|
||||
|
||||
if(m_DescriptorBuffers)
|
||||
{
|
||||
VkDescriptorGetInfoEXT getDesc = {
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
|
||||
};
|
||||
byte dummy[256];
|
||||
getDesc.type = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||
getDesc.data.pSampler = pSampler;
|
||||
vkGetDescriptorEXT(device, &getDesc, m_DescriptorBufferProperties.samplerDescriptorSize,
|
||||
dummy);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1118,7 +1118,9 @@ void WrappedVulkan::CaptureQueueSubmit(VkQueue queue,
|
||||
|
||||
for(auto refit = refs.sparseRefs.begin(); refit != refs.sparseRefs.end(); ++refit)
|
||||
{
|
||||
GetResourceManager()->MarkSparseMapReferenced((*refit)->resInfo);
|
||||
// for these which are added as image views, step up to the image (if it's not an identity
|
||||
// pointer) - see declaration of parentResInfo
|
||||
GetResourceManager()->MarkSparseMapReferenced((*refit)->resInfo->parentResInfo);
|
||||
}
|
||||
|
||||
UpdateImageStates(refs.bindImageStates);
|
||||
|
||||
@@ -2083,7 +2083,7 @@ VkResult WrappedVulkan::vkCreateBuffer(VkDevice device, const VkBufferCreateInfo
|
||||
|
||||
record->resInfo = NULL;
|
||||
|
||||
if(isSparse || isExternal)
|
||||
if(isSparse || isExternal || m_DescriptorBuffers)
|
||||
{
|
||||
record->resInfo = new ResourceInfo();
|
||||
|
||||
@@ -2686,6 +2686,7 @@ VkResult WrappedVulkan::vkCreateImage(VkDevice device, const VkImageCreateInfo *
|
||||
record->AddChunk(chunk);
|
||||
|
||||
record->resInfo = new ResourceInfo();
|
||||
record->resInfo->parentResInfo = record->resInfo;
|
||||
ResourceInfo &resInfo = *record->resInfo;
|
||||
resInfo.imageInfo = ImageInfo(*pCreateInfo);
|
||||
|
||||
@@ -3067,7 +3068,15 @@ VkResult WrappedVulkan::vkCreateImageView(VkDevice device, const VkImageViewCrea
|
||||
record->baseResource = imageRecord->GetResourceID();
|
||||
record->baseResourceMem = imageRecord->baseResourceMem;
|
||||
record->dedicated = imageRecord->dedicated;
|
||||
record->resInfo = imageRecord->resInfo;
|
||||
if(m_DescriptorBuffers)
|
||||
{
|
||||
record->resInfo = new ResourceInfo(*imageRecord->resInfo);
|
||||
record->resInfo->parentResInfo = imageRecord->resInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
record->resInfo = imageRecord->resInfo;
|
||||
}
|
||||
record->viewRange = pCreateInfo->subresourceRange;
|
||||
record->viewRange.setViewType(pCreateInfo->viewType);
|
||||
}
|
||||
@@ -3677,6 +3686,15 @@ VkResult WrappedVulkan::vkCreateAccelerationStructureKHR(
|
||||
SCOPED_LOCK(m_ASLookupByAddrLock);
|
||||
m_ASLookupByAddr[addr] = id;
|
||||
}
|
||||
|
||||
VkDescriptorGetInfoEXT getDesc = {
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
|
||||
};
|
||||
byte dummy[256];
|
||||
getDesc.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
|
||||
getDesc.data.accelerationStructure = addr;
|
||||
vkGetDescriptorEXT(device, &getDesc,
|
||||
m_DescriptorBufferProperties.accelerationStructureDescriptorSize, dummy);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
Reference in new issue
Block a user