aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobin Ehlis <tobin@lunarg.com>2015-10-20 16:16:04 -0600
committerTobin Ehlis <tobin@lunarg.com>2015-10-22 11:12:27 -0600
commit642014905da847d63e6f6e1ce9df11982d68f16b (patch)
treef5d6ecec42a455e9b67a6a3590f262cf7019815e
parent5a611c79f49e554f67d0821a6a903831323a19d7 (diff)
downloadusermoji-642014905da847d63e6f6e1ce9df11982d68f16b.tar.xz
layers: Add DrawState check for DescriptorSet availability in Pool
Prior to allocating descriptors from a Pool, verify that requested number/type of descriptors are available in that Pool, flag error if not. When Pool is reset or when descriptors are allocated, release descriptors back to pool. Added constructor and destructor for POOL_NODE to simplify allocation/cleanup. Added layer documentation for new check and AllocDescriptorFromEmptyPool test to verify that error is correctly flagged.
-rwxr-xr-xlayers/draw_state.cpp82
-rwxr-xr-xlayers/draw_state.h37
-rw-r--r--layers/vk_validation_layer_details.md1
3 files changed, 96 insertions, 24 deletions
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index 63df7069..bb729699 100755
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -990,6 +990,33 @@ static VkBool32 dsUpdate(layer_data* my_data, VkDevice device, VkStructureType t
loader_platform_thread_unlock_mutex(&globalLock);
return skipCall;
}
+// Verify that given pool has descriptors that are being requested for allocation
+static VkBool32 validate_descriptor_availability_in_pool(layer_data* dev_data, POOL_NODE* pPoolNode, uint32_t count, const VkDescriptorSetLayout* pSetLayouts)
+{
+ VkBool32 skipCall = VK_FALSE;
+ uint32_t i = 0, j = 0;
+ for (i=0; i<count; ++i) {
+ LAYOUT_NODE* pLayout = getLayoutNode(dev_data, pSetLayouts[i]);
+ if (NULL == pLayout) {
+ skipCall |= log_msg(dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, pSetLayouts[i].handle, 0, DRAWSTATE_INVALID_LAYOUT, "DS",
+ "Unable to find set layout node for layout %#" PRIxLEAST64 " specified in vkAllocDescriptorSets() call", pSetLayouts[i].handle);
+ } else {
+ uint32_t typeIndex = 0, typeCount = 0;
+ for (j=0; j<pLayout->createInfo.count; ++j) {
+ typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBinding[j].descriptorType);
+ typeCount = pLayout->createInfo.pBinding[j].arraySize;
+ if (typeCount > pPoolNode->availableDescriptorTypeCount[typeIndex]) {
+ skipCall |= log_msg(dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, pLayout->layout.handle, 0, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
+ "Unable to allocate %u descriptors of type %s from pool %#" PRIxLEAST64 ". This pool only has %u descriptors of this type remaining.",
+ typeCount, string_VkDescriptorType(pLayout->createInfo.pBinding[j].descriptorType), pPoolNode->pool.handle, pPoolNode->availableDescriptorTypeCount[typeIndex]);
+ } else { // Decrement available descriptors of this type
+ pPoolNode->availableDescriptorTypeCount[typeIndex] -= typeCount;
+ }
+ }
+ }
+ }
+ return skipCall;
+}
// Free the shadowed update node for this Set
// NOTE : Calls to this function should be wrapped in mutex
static void freeShadowUpdateTree(SET_NODE* pSet)
@@ -1042,9 +1069,6 @@ static void deletePools(layer_data* my_data)
}
delete pFreeSet;
}
- if ((*ii).second->createInfo.pTypeCount) {
- delete[] (*ii).second->createInfo.pTypeCount;
- }
delete (*ii).second;
}
my_data->poolMap.clear();
@@ -1094,6 +1118,10 @@ static void clearDescriptorPool(layer_data* my_data, const VkDevice device, cons
while (pSet) {
clearDescriptorSet(my_data, pSet->set);
}
+ // Reset available count to max count for this pool
+ for (uint32_t i=0; i<pPool->availableDescriptorTypeCount.size(); ++i) {
+ pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
+ }
}
}
// For given CB object, fetch associated CB Node from map
@@ -1876,23 +1904,12 @@ VK_LAYER_EXPORT VkResult VKAPI vkCreateDescriptorPool(VkDevice device, const VkD
"Created Descriptor Pool %#" PRIxLEAST64, (*pDescriptorPool).handle))
return VK_ERROR_VALIDATION_FAILED;
loader_platform_thread_lock_mutex(&globalLock);
- POOL_NODE* pNewNode = new POOL_NODE;
+ POOL_NODE* pNewNode = new POOL_NODE(*pDescriptorPool, pCreateInfo);
if (NULL == pNewNode) {
if (log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (*pDescriptorPool).handle, 0, DRAWSTATE_OUT_OF_MEMORY, "DS",
"Out of memory while attempting to allocate POOL_NODE in vkCreateDescriptorPool()"))
return VK_ERROR_VALIDATION_FAILED;
} else {
- memset(pNewNode, 0, sizeof(POOL_NODE));
- VkDescriptorPoolCreateInfo* pCI = (VkDescriptorPoolCreateInfo*)&pNewNode->createInfo;
- memcpy((void*)pCI, pCreateInfo, sizeof(VkDescriptorPoolCreateInfo));
- if (pNewNode->createInfo.count) {
- size_t typeCountSize = pNewNode->createInfo.count * sizeof(VkDescriptorTypeCount);
- pNewNode->createInfo.pTypeCount = new VkDescriptorTypeCount[typeCountSize];
- memcpy((void*)pNewNode->createInfo.pTypeCount, pCreateInfo->pTypeCount, typeCountSize);
- }
- pNewNode->poolUsage = pCreateInfo->poolUsage;
- pNewNode->maxSets = pCreateInfo->maxSets;
- pNewNode->pool = *pDescriptorPool;
dev_data->poolMap[pDescriptorPool->handle] = pNewNode;
}
loader_platform_thread_unlock_mutex(&globalLock);
@@ -1914,14 +1931,22 @@ VK_LAYER_EXPORT VkResult VKAPI vkResetDescriptorPool(VkDevice device, VkDescript
VK_LAYER_EXPORT VkResult VKAPI vkAllocDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorSetUsage setUsage, uint32_t count, const VkDescriptorSetLayout* pSetLayouts, VkDescriptorSet* pDescriptorSets)
{
+ VkBool32 skipCall = VK_FALSE;
layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+ // Verify that requested descriptorSets are available in pool
+ POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool);
+ if (!pPoolNode) {
+ skipCall |= log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_POOL, descriptorPool.handle, 0, DRAWSTATE_INVALID_POOL, "DS",
+ "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkAllocDescriptorSets() call", descriptorPool.handle);
+ } else { // Make sure pool has all the available descriptors before calling down chain
+ skipCall |= validate_descriptor_availability_in_pool(dev_data, pPoolNode, count, pSetLayouts);
+ }
+ if (skipCall)
+ return VK_ERROR_VALIDATION_FAILED;
VkResult result = dev_data->device_dispatch_table->AllocDescriptorSets(device, descriptorPool, setUsage, count, pSetLayouts, pDescriptorSets);
if (VK_SUCCESS == result) {
POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool);
- if (!pPoolNode) {
- log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_POOL, descriptorPool.handle, 0, DRAWSTATE_INVALID_POOL, "DS",
- "Unable to find pool node for pool %#" PRIxLEAST64 " specified in vkAllocDescriptorSets() call", descriptorPool.handle);
- } else {
+ if (pPoolNode) {
if (count == 0) {
log_msg(mdd(device), VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET, count, 0, DRAWSTATE_NONE, "DS",
"AllocDescriptorSets called with 0 count");
@@ -1972,15 +1997,28 @@ VK_LAYER_EXPORT VkResult VKAPI vkFreeDescriptorSets(VkDevice device, VkDescripto
VkBool32 skipCall = VK_FALSE;
layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
POOL_NODE *pPoolNode = getPoolNode(dev_data, descriptorPool);
- if (pPoolNode && (VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT == pPoolNode->poolUsage)) {
+ if (pPoolNode && (VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT == pPoolNode->createInfo.poolUsage)) {
// Can't Free from a ONE_SHOT pool
- skipCall |= log_msg(mdd(device), VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, (uint64_t)device, 0, DRAWSTATE_CANT_FREE_FROM_ONE_SHOT_POOL, "DS",
+ skipCall |= log_msg(dev_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DEVICE, (uint64_t)device, 0, DRAWSTATE_CANT_FREE_FROM_ONE_SHOT_POOL, "DS",
"It is invalid to call vkFreeDescriptorSets() with a pool created with usage type VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT.");
}
if (skipCall)
return VK_ERROR_VALIDATION_FAILED;
VkResult result = dev_data->device_dispatch_table->FreeDescriptorSets(device, descriptorPool, count, pDescriptorSets);
- // TODO : Clean up any internal data structures using this obj.
+ if (VK_SUCCESS == result) {
+ // For each freed descriptor add it back into the pool as available
+ for (uint32_t i=0; i<count; ++i) {
+ SET_NODE* pSet = dev_data->setMap[pDescriptorSets[i].handle]; // getSetNode() without locking
+ LAYOUT_NODE* pLayout = pSet->pLayout;
+ uint32_t typeIndex = 0, typeCount = 0;
+ for (uint32_t j=0; j<pLayout->createInfo.count; ++j) {
+ typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBinding[j].descriptorType);
+ typeCount = pLayout->createInfo.pBinding[j].arraySize;
+ pPoolNode->availableDescriptorTypeCount[typeIndex] += typeCount;
+ }
+ }
+ }
+ // TODO : Any other clean-up or book-keeping to do here?
return result;
}
diff --git a/layers/draw_state.h b/layers/draw_state.h
index c4acd8d2..5eed63b8 100755
--- a/layers/draw_state.h
+++ b/layers/draw_state.h
@@ -46,6 +46,7 @@ typedef enum _DRAW_STATE_ERROR
DRAWSTATE_OUT_OF_MEMORY, // malloc failed
DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, // Type in layout vs. update are not the same
DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, // Descriptors set for update out of bounds for corresponding layout section
+ DRAWSTATE_DESCRIPTOR_POOL_EMPTY, // Attempt to allocate descriptor from a pool with no more descriptors of that type available
DRAWSTATE_CANT_FREE_FROM_ONE_SHOT_POOL, // Invalid to call vkFreeDescriptorSets on Sets allocated from a ONE_SHOT Pool
DRAWSTATE_INVALID_UPDATE_INDEX, // Index of requested update is invalid for specified descriptors set
DRAWSTATE_INVALID_UPDATE_STRUCT, // Struct in DS Update tree is of invalid type
@@ -170,10 +171,42 @@ typedef struct _SET_NODE {
typedef struct _POOL_NODE {
VkDescriptorPool pool;
- VkDescriptorPoolUsage poolUsage;
- uint32_t maxSets;
VkDescriptorPoolCreateInfo createInfo;
SET_NODE* pSets; // Head of LL of sets for this Pool
+ vector<uint32_t> maxDescriptorTypeCount; // max # of descriptors of each type in this pool
+ vector<uint32_t> availableDescriptorTypeCount; // available # of descriptors of each type in this pool
+
+ _POOL_NODE(const VkDescriptorPool pool, const VkDescriptorPoolCreateInfo* pCreateInfo) :
+ pool(pool), createInfo(*pCreateInfo), pSets(NULL),
+ maxDescriptorTypeCount(VK_DESCRIPTOR_TYPE_END_RANGE), availableDescriptorTypeCount(VK_DESCRIPTOR_TYPE_END_RANGE)
+ {
+ if (createInfo.count) { // Shadow type struct from ptr into local struct
+ size_t typeCountSize = createInfo.count * sizeof(VkDescriptorTypeCount);
+ createInfo.pTypeCount = new VkDescriptorTypeCount[typeCountSize];
+ memcpy((void*)createInfo.pTypeCount, pCreateInfo->pTypeCount, typeCountSize);
+ // Now set max counts for each descriptor type based on count of that type times maxSets
+ int32_t i=0;
+ for (i=0; i<createInfo.count; ++i) {
+ uint32_t typeIndex = static_cast<uint32_t>(createInfo.pTypeCount[i].type);
+ uint32_t typeCount = createInfo.pTypeCount[i].count;
+ maxDescriptorTypeCount[typeIndex] += typeCount;
+ }
+ for (i=0; i<maxDescriptorTypeCount.size(); ++i) {
+ maxDescriptorTypeCount[i] *= createInfo.maxSets;
+ // Initially the available counts are equal to the max counts
+ availableDescriptorTypeCount[i] = maxDescriptorTypeCount[i];
+ }
+ } else {
+ createInfo.pTypeCount = NULL; // Make sure this is NULL so we don't try to clean it up
+ }
+ }
+ ~_POOL_NODE() {
+ if (createInfo.pTypeCount) {
+ delete[] createInfo.pTypeCount;
+ }
+ // TODO : pSets are currently freed in deletePools function which uses freeShadowUpdateTree function
+ // need to migrate that struct to smart ptrs for auto-cleanup
+ }
} POOL_NODE;
// Cmd Buffer Tracking
diff --git a/layers/vk_validation_layer_details.md b/layers/vk_validation_layer_details.md
index 0cade3e5..208e064c 100644
--- a/layers/vk_validation_layer_details.md
+++ b/layers/vk_validation_layer_details.md
@@ -30,6 +30,7 @@ The DrawState layer tracks state leading into Draw cmds. This includes the Pipel
| Valid Secondary CmdBuffer | Validates that no primary command buffers are sent to vkCmdExecuteCommands() are | INVALID_SECONDARY_CMD_BUFFER | vkCmdExecuteCommands | ExecuteCommandsPrimaryCB | NA |
| Descriptor Type | Verify Descriptor type in bound descriptor set layout matches descriptor type specified in update | DESCRIPTOR_TYPE_MISMATCH | vkUpdateDescriptorSets | DSTypeMismatch | With various DS API updates, need to revisit this code |
| DS Update Size | DS update out of bounds for given layout section | DESCRIPTOR_UPDATE_OUT_OF_BOUNDS | vkUpdateDescriptorSets | DSUpdateOutOfBounds | NA |
+| Descriptor Pool empty | Attempt to allocate descriptor type from descriptor pool when no more of that type are available to be allocated. | DESCRIPTOR_POOL_EMPTY | vkAllocDescriptorSets | AllocDescriptorFromEmptyPool | NA |
| Free from ONE_SHOT Pool | It's invalid to call vkFreeDescriptorSets() on Sets that were allocated from a Pool created with ONE_SHOT usage. | CANT_FREE_FROM_ONE_SHOT_POOL | vkFreeDescriptorSets | None | NA |
| DS Update Index | DS update binding too large for layout count | INVALID_UPDATE_INDEX | vkUpdateDescriptorSets | InvalidDSUpdateIndex | NA |
| DS Update Type | Verifies that structs in DS Update tree are properly created, currenly valid, and of the right type | INVALID_UPDATE_STRUCT | vkUpdateDescriptorSets | InvalidDSUpdateStruct | NA |