layers:Check all memory bindings
There are a few places in the code where we assume that an image or
buffer doesn't have a sparse binding. These cases break with sparse
bindings.
To fix I added a function to BINDING class to retrieve all memory
bindings and then updated a few spots with bad assumption to make use
of this new GetBoundMemory() function.
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index a4f0d5a..7ccd4b3 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -619,11 +619,13 @@
// Skip validation if this image was created through WSI
if (image_state->binding.mem != MEMTRACKER_SWAP_CHAIN_IMAGE_KEY) {
// First update CB binding in MemObj mini CB list
- DEVICE_MEM_INFO *pMemInfo = getMemObjInfo(dev_data, image_state->binding.mem);
- if (pMemInfo) {
- pMemInfo->cb_bindings.insert(cb_node);
- // Now update CBInfo's Mem reference list
- cb_node->memObjs.insert(image_state->binding.mem);
+ for (auto mem_binding : image_state->GetBoundMemory()) {
+ DEVICE_MEM_INFO *pMemInfo = getMemObjInfo(dev_data, mem_binding);
+ if (pMemInfo) {
+ pMemInfo->cb_bindings.insert(cb_node);
+ // Now update CBInfo's Mem reference list
+ cb_node->memObjs.insert(mem_binding);
+ }
}
// Now update cb binding for image
cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(image_state->image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT});
@@ -647,11 +649,13 @@
// Create binding link between given buffer node and command buffer node
void AddCommandBufferBindingBuffer(const layer_data *dev_data, GLOBAL_CB_NODE *cb_node, BUFFER_NODE *buff_node) {
// First update CB binding in MemObj mini CB list
- DEVICE_MEM_INFO *pMemInfo = getMemObjInfo(dev_data, buff_node->binding.mem);
- if (pMemInfo) {
- pMemInfo->cb_bindings.insert(cb_node);
- // Now update CBInfo's Mem reference list
- cb_node->memObjs.insert(buff_node->binding.mem);
+ for (auto mem_binding : buff_node->GetBoundMemory()) {
+ DEVICE_MEM_INFO *pMemInfo = getMemObjInfo(dev_data, mem_binding);
+ if (pMemInfo) {
+ pMemInfo->cb_bindings.insert(cb_node);
+ // Now update CBInfo's Mem reference list
+ cb_node->memObjs.insert(mem_binding);
+ }
}
// Now update cb binding for buffer
cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(buff_node->buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT});
@@ -5769,9 +5773,11 @@
// Any bound cmd buffers are now invalid
invalidateCommandBuffers(buff_node->cb_bindings,
{reinterpret_cast<uint64_t &>(buff_node->buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT});
- auto mem_info = getMemObjInfo(dev_data, buff_node->binding.mem);
- if (mem_info) {
- RemoveBufferMemoryRange(reinterpret_cast<uint64_t &>(buffer), mem_info);
+ for (auto mem_binding : buff_node->GetBoundMemory()) {
+ auto mem_info = getMemObjInfo(dev_data, mem_binding);
+ if (mem_info) {
+ RemoveBufferMemoryRange(reinterpret_cast<uint64_t &>(buffer), mem_info);
+ }
}
ClearMemoryObjectBindings(dev_data, reinterpret_cast<uint64_t &>(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT);
dev_data->bufferMap.erase(buff_node->buffer);
@@ -5833,9 +5839,11 @@
static void PostCallRecordDestroyImage(layer_data *dev_data, VkImage image, IMAGE_STATE *image_state, VK_OBJECT obj_struct) {
invalidateCommandBuffers(image_state->cb_bindings, obj_struct);
// Clean up memory mapping, bindings and range references for image
- auto mem_info = getMemObjInfo(dev_data, image_state->binding.mem);
- if (mem_info) {
- RemoveImageMemoryRange(obj_struct.handle, mem_info);
+ for (auto mem_binding : image_state->GetBoundMemory()) {
+ auto mem_info = getMemObjInfo(dev_data, mem_binding);
+ if (mem_info) {
+ RemoveImageMemoryRange(obj_struct.handle, mem_info);
+ }
}
ClearMemoryObjectBindings(dev_data, obj_struct.handle, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT);
// Remove image from imageMap
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index 92401f8..cfc034c 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -177,6 +177,18 @@
// TODO : Need to update solution to track all sparse binding data
std::unordered_set<MEM_BINDING> sparse_bindings;
BINDABLE() : sparse(false), binding{}, requirements{}, sparse_bindings{} {};
+ // Return unordered set of memory objects that are bound
+ std::unordered_set<VkDeviceMemory> GetBoundMemory() {
+ std::unordered_set<VkDeviceMemory> mem_set;
+ if (!sparse) {
+ mem_set.insert(binding.mem);
+ } else {
+ for (auto sb : sparse_bindings) {
+ mem_set.insert(sb.mem);
+ }
+ }
+ return mem_set;
+ }
};
class BUFFER_NODE : public BINDABLE {
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index d231543..4d06845 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -406,14 +406,15 @@
*error = error_str.str();
return false;
} else {
- auto mem_entry = getMemObjInfo(device_data_, buffer_node->binding.mem);
- if (!mem_entry) {
- std::stringstream error_str;
- error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
- << " uses buffer " << buffer << " that references invalid memory "
- << buffer_node->binding.mem << ".";
- *error = error_str.str();
- return false;
+ for (auto mem_binding : buffer_node->GetBoundMemory()) {
+ if (!getMemObjInfo(device_data_, mem_binding)) {
+ std::stringstream error_str;
+ error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
+ << " uses buffer " << buffer << " that references invalid memory " << mem_binding
+ << ".";
+ *error = error_str.str();
+ return false;
+ }
}
}
if (descriptors_[i]->IsDynamic()) {