layers: Kill false thread errors re: command pool
Change the transitivity of usage counters such that only externally
synchronized command buffers mark their command pool as being an active
writer.
Added additional tracking for non-externally sync'd command buffers
s.t. command pool reset and destroy operations detect usage races.
Change-Id: I839ac8a5902a42ea1a1ba72db37cda2466516d11
diff --git a/layers/threading.cpp b/layers/threading.cpp
index 08020ad..8d4610e 100644
--- a/layers/threading.cpp
+++ b/layers/threading.cpp
@@ -470,6 +470,53 @@
}
}
+VKAPI_ATTR VkResult VKAPI_CALL ResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) {
+ dispatch_key key = get_dispatch_key(device);
+ layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
+ VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
+ VkResult result;
+ bool threadChecks = startMultiThread();
+ if (threadChecks) {
+ startReadObject(my_data, device);
+ startWriteObject(my_data, commandPool);
+ // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands)
+ my_data->c_VkCommandPoolContents.startWrite(my_data->report_data, commandPool);
+ // Host access to commandPool must be externally synchronized
+ }
+ result = pTable->ResetCommandPool(device, commandPool, flags);
+ if (threadChecks) {
+ finishReadObject(my_data, device);
+ finishWriteObject(my_data, commandPool);
+ my_data->c_VkCommandPoolContents.finishWrite(commandPool);
+ // Host access to commandPool must be externally synchronized
+ } else {
+ finishMultiThread();
+ }
+ return result;
+}
+
+VKAPI_ATTR void VKAPI_CALL DestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) {
+ dispatch_key key = get_dispatch_key(device);
+ layer_data *my_data = GetLayerDataPtr(key, layer_data_map);
+ VkLayerDispatchTable *pTable = my_data->device_dispatch_table;
+ bool threadChecks = startMultiThread();
+ if (threadChecks) {
+ startReadObject(my_data, device);
+ startWriteObject(my_data, commandPool);
+ // Check for any uses of non-externally sync'd command buffers (for example from vkCmdExecuteCommands)
+ my_data->c_VkCommandPoolContents.startWrite(my_data->report_data, commandPool);
+ // Host access to commandPool must be externally synchronized
+ }
+ pTable->DestroyCommandPool(device, commandPool, pAllocator);
+ if (threadChecks) {
+ finishReadObject(my_data, device);
+ finishWriteObject(my_data, commandPool);
+ my_data->c_VkCommandPoolContents.finishWrite(commandPool);
+ // Host access to commandPool must be externally synchronized
+ } else {
+ finishMultiThread();
+ }
+}
} // namespace threading
// vk_layer_logging.h expects these to be defined
diff --git a/layers/threading.h b/layers/threading.h
index 4404692..f2e07fe 100644
--- a/layers/threading.h
+++ b/layers/threading.h
@@ -266,6 +266,8 @@
counter<VkInstance> c_VkInstance;
counter<VkQueue> c_VkQueue;
#ifdef DISTINCT_NONDISPATCHABLE_HANDLES
+ // Special entry to allow tracking of command pool Reset and Destroy
+ counter<VkCommandPool> c_VkCommandPoolContents;
counter<VkBuffer> c_VkBuffer;
counter<VkBufferView> c_VkBufferView;
counter<VkCommandPool> c_VkCommandPool;
@@ -299,6 +301,9 @@
counter<VkDebugUtilsMessengerEXT> c_VkDebugUtilsMessengerEXT;
counter<VkAccelerationStructureNVX> c_VkAccelerationStructureNVX;
#else // DISTINCT_NONDISPATCHABLE_HANDLES
+ // Special entry to allow tracking of command pool Reset and Destroy
+ counter<uint64_t> c_VkCommandPoolContents;
+
counter<uint64_t> c_uint64_t;
#endif // DISTINCT_NONDISPATCHABLE_HANDLES
@@ -314,6 +319,7 @@
c_VkDevice("VkDevice", VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT),
c_VkInstance("VkInstance", VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT),
c_VkQueue("VkQueue", VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT),
+ c_VkCommandPoolContents("VkCommandPool", VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT),
#ifdef DISTINCT_NONDISPATCHABLE_HANDLES
c_VkBuffer("VkBuffer", VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT),
c_VkBufferView("VkBufferView", VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT),
@@ -432,7 +438,10 @@
std::unique_lock<std::mutex> lock(command_pool_lock);
VkCommandPool pool = command_pool_map[object];
lock.unlock();
- startReadObject(my_data, pool);
+ // We set up a read guard against the "Contents" counter to catch conflict vs. vkResetCommandPool and vkDestroyCommandPool
+ // while *not* establishing a read guard against the command pool counter itself to avoid false postives for
+ // non-externally sync'd command buffers
+ my_data->c_VkCommandPoolContents.startRead(my_data->report_data, pool);
my_data->c_VkCommandBuffer.startRead(my_data->report_data, object);
}
static void finishReadObject(struct layer_data *my_data, VkCommandBuffer object) {
@@ -440,6 +449,6 @@
std::unique_lock<std::mutex> lock(command_pool_lock);
VkCommandPool pool = command_pool_map[object];
lock.unlock();
- finishReadObject(my_data, pool);
+ my_data->c_VkCommandPoolContents.finishRead(pool);
}
#endif // THREADING_H
diff --git a/scripts/threading_generator.py b/scripts/threading_generator.py
index 5cfb4d7..74d4b8c 100644
--- a/scripts/threading_generator.py
+++ b/scripts/threading_generator.py
@@ -376,6 +376,8 @@
'vkDestroyInstance',
'vkAllocateCommandBuffers',
'vkFreeCommandBuffers',
+ 'vkResetCommandPool',
+ 'vkDestroyCommandPool',
'vkCreateDebugReportCallbackEXT',
'vkDestroyDebugReportCallbackEXT',
'vkAllocateDescriptorSets',