clear_cmd_buf_and_mem_references(dev_data, getCBNode(dev_data, cb));
}
-// For given MemObjInfo, report Obj & CB bindings
-static bool reportMemReferencesAndCleanUp(layer_data *dev_data, DEVICE_MEM_INFO *pMemObjInfo) {
+// For given MemObjInfo, report Obj & CB bindings. Clear any object bindings.
+static bool ReportMemReferencesAndCleanUp(layer_data *dev_data, DEVICE_MEM_INFO *pMemObjInfo) {
bool skip_call = false;
size_t cmdBufRefCount = pMemObjInfo->command_buffer_bindings.size();
size_t objRefCount = pMemObjInfo->obj_bindings.size();
log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, obj.type, obj.handle, __LINE__,
MEMTRACK_FREED_MEM_REF, "MEM", "VK Object 0x%" PRIxLEAST64 " still has a reference to mem obj 0x%" PRIxLEAST64,
obj.handle, (uint64_t)pMemObjInfo->mem);
+ // Clear mem binding for bound objects
+ switch (obj.type) {
+ case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: {
+ auto image_node = getImageNode(dev_data, reinterpret_cast<VkImage &>(obj.handle));
+ assert(image_node); // Any destroyed images should already be removed from bindings
+ image_node->mem = VK_NULL_HANDLE;
+ break;
+ }
+ case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: {
+ auto buff_node = getBufferNode(dev_data, reinterpret_cast<VkBuffer &>(obj.handle));
+ assert(buff_node); // Any destroyed buffers should already be removed from bindings
+ buff_node->mem = VK_NULL_HANDLE;
+ break;
+ }
+ default:
+ // Should only have buffer or image objects bound to memory
+ assert(0);
+ }
}
// Clear the list of hanging references
pMemObjInfo->obj_bindings.clear();
clear_cmd_buf_and_mem_references(dev_data, cb);
}
}
-
- // Now verify that no references to this mem obj remain and remove bindings
+ // Now check for any remaining references to this mem obj and remove bindings
if (pInfo->command_buffer_bindings.size() || pInfo->obj_bindings.size()) {
- skip_call |= reportMemReferencesAndCleanUp(dev_data, pInfo);
+ skip_call |= ReportMemReferencesAndCleanUp(dev_data, pInfo);
}
// Delete mem obj info
dev_data->memObjMap.erase(dev_data->memObjMap.find(mem));
if (0 == image_node->mem) {
result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
reinterpret_cast<const uint64_t &>(image_node->image), __LINE__, MEMTRACK_OBJECT_NOT_BOUND, "MEM",
- "%s: VkImage object 0x%" PRIxLEAST64 " used without first calling vkBindImageMemory.", api_name,
- reinterpret_cast<const uint64_t &>(image_node->image));
+ "%s: VkImage object 0x%" PRIxLEAST64 " used with no memory bound. Memory should be bound by calling "
+ "vkBindImageMemory() and then the bound memory must not be freed prior to this operation.",
+ api_name, reinterpret_cast<const uint64_t &>(image_node->image));
}
}
return result;
if (0 == buffer_node->mem) {
result = log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
reinterpret_cast<const uint64_t &>(buffer_node->buffer), __LINE__, MEMTRACK_OBJECT_NOT_BOUND, "MEM",
- "%s: VkBuffer object 0x%" PRIxLEAST64 " used without first calling vkBindBufferMemory.", api_name,
- reinterpret_cast<const uint64_t &>(buffer_node->buffer));
+ "%s: VkBuffer object 0x%" PRIxLEAST64 " used with no memory bound. Memory should be bound by calling "
+ "vkBindImageMemory() and then the bound memory must not be freed prior to this operation.",
+ api_name, reinterpret_cast<const uint64_t &>(buffer_node->buffer));
}
}
return result;
}
erase_range->aliases.clear();
mem_info->bound_ranges.erase(handle);
- if (is_image)
+ if (is_image) {
mem_info->bound_images.erase(handle);
- else
+ } else {
mem_info->bound_buffers.erase(handle);
+ }
}
static void RemoveBufferMemoryRange(uint64_t handle, DEVICE_MEM_INFO *mem_info) { RemoveMemoryRange(handle, mem_info, false); }
format = image_node->createInfo.format;
usage = image_node->createInfo.usage;
// Validate that memory is bound to image
- if (ValidateMemoryIsBoundToImage(dev_data, image_node, "vkUpdateDescriptorSets()"))
+ if (ValidateMemoryIsBoundToImage(dev_data, image_node, "vkUpdateDescriptorSets()")) {
+ *error = "No memory bound to image.";
return false;
+ }
} else {
// Also need to check the swapchains.
auto swapchain = getSwapchainFromImage(dev_data, image);
*error = error_str.str();
return false;
}
- if (ValidateMemoryIsBoundToBuffer(device_data_, buffer_node, "vkUpdateDescriptorSets()"))
+ if (ValidateMemoryIsBoundToBuffer(device_data_, buffer_node, "vkUpdateDescriptorSets()")) {
+ *error = "No memory bound to buffer.";
return false;
+ }
// Verify usage bits
if (!ValidateBufferUsage(buffer_node, type, error)) {
// error will have been updated by ValidateBufferUsage()
err = vkAllocateMemory(m_device->device(), &mem_alloc, NULL, &image_mem);
ASSERT_VK_SUCCESS(err);
- // Introduce error, do not call vkBindImageMemory(m_device->device(), image,
- // image_mem, 0);
- m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "used without first calling vkBindImageMemory");
+ // Introduce error, do not call vkBindImageMemory(m_device->device(), image, image_mem, 0);
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ " used with no memory bound. Memory should be bound by calling vkBindImageMemory() and ");
m_commandBuffer->BeginCommandBuffer();
VkClearColorValue ccv;
err = vkAllocateMemory(m_device->device(), &alloc_info, NULL, &mem);
ASSERT_VK_SUCCESS(err);
- // Introduce failure by not calling vkBindBufferMemory(m_device->device(),
- // buffer, mem, 0);
- m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "used without first calling vkBindBufferMemory");
+ // Introduce failure by not calling vkBindBufferMemory(m_device->device(), buffer, mem, 0);
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ " used with no memory bound. Memory should be bound by calling vkBindImageMemory() and ");
VkBufferImageCopy region = {};
region.bufferRowLength = 128;
region.bufferImageHeight = 128;
" no memory bound to it.");
VkResult err;
- m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "used without first calling vkBindBufferMemory");
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ " used with no memory bound. Memory should be bound by calling vkBindImageMemory() and ");
ASSERT_NO_FATAL_FAILURE(InitState());
TEST_DESCRIPTION("Attempt to update a descriptor with a non-sparse buffer "
"that doesn't have memory bound");
VkResult err;
- m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, " used without first calling vkBindBufferMemory.");
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ " used with no memory bound. Memory should be bound by calling vkBindImageMemory() and ");
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ "vkUpdateDescriptorsSets() failed write update validation for Descriptor Set 0x");
ASSERT_NO_FATAL_FAILURE(InitState());
ASSERT_NO_FATAL_FAILURE(InitViewport());
TEST_F(VkLayerTest, CreateImageViewNoMemoryBoundToImage) {
VkResult err;
-
- m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT, "used without first calling vkBindImageMemory");
+ m_errorMonitor->SetDesiredFailureMsg(VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ " used with no memory bound. Memory should be bound by calling vkBindImageMemory() and ");
ASSERT_NO_FATAL_FAILURE(InitState());