layers: Rearchitect Descriptor Set validation code
This change pulls all of the DescriptorSet code out of core_validation.cpp and into
its own files/classes in descriptor_set.h/cpp.
See header file for complete class documentation.
These changes pass tri/cube/smoketest --validate.
All related layer validation tests are also updated and passing.
Finally, I ran it through mustpass CTS and did not hit any issues related to these changes.
These changes not only update the descriptor interface but fix some known lingering
bugs with how descriptor updates occurred. This includes now correctly handling
updates that cross binding boundaries and updates that write a subset of a binding.
Going forward this is a general outline for how we would like to evolve core_validation.
That is, we'd like to move the functionality of the checks into reasonable classes and
just have core_validation call into those classes to do the majority of the work.
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index 9b4e6a4..9847cfb 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -155,7 +155,7 @@
install(TARGETS VkLayer_utils DESTINATION ${PROJECT_BINARY_DIR}/install_staging)
endif()
-add_vk_layer(core_validation core_validation.cpp vk_layer_table.cpp vk_safe_struct.cpp)
+add_vk_layer(core_validation core_validation.cpp vk_layer_table.cpp vk_safe_struct.cpp descriptor_sets.cpp)
add_vk_layer(device_limits device_limits.cpp vk_layer_table.cpp)
add_vk_layer(image image.cpp vk_layer_table.cpp)
add_vk_layer(swapchain swapchain.cpp vk_layer_table.cpp)
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index d88fac0..1be1016 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -42,8 +42,6 @@
#include <stdlib.h>
#include <string.h>
#include <string>
-#include <unordered_map>
-#include <unordered_set>
#include "vk_loader_platform.h"
#include "vk_dispatch_table_helper.h"
@@ -104,7 +102,7 @@
// Global set of all cmdBuffers that are inFlight on this device
unordered_set<VkCommandBuffer> globalInFlightCmdBuffers;
// Layer specific data
- unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> sampleMap;
+ unordered_map<VkSampler, unique_ptr<SAMPLER_NODE>> samplerMap;
unordered_map<VkImageView, VkImageViewCreateInfo> imageViewMap;
unordered_map<VkImage, IMAGE_NODE> imageMap;
unordered_map<VkBufferView, VkBufferViewCreateInfo> bufferViewMap;
@@ -113,7 +111,7 @@
unordered_map<VkCommandPool, CMD_POOL_INFO> commandPoolMap;
unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_NODE *> descriptorPoolMap;
unordered_map<VkDescriptorSet, SET_NODE *> setMap;
- unordered_map<VkDescriptorSetLayout, DescriptorSetLayout *> descriptorSetLayoutMap;
+ unordered_map<VkDescriptorSetLayout, cvdescriptorset::DescriptorSetLayout *> descriptorSetLayoutMap;
unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> memObjMap;
unordered_map<VkFence, FENCE_NODE> fenceMap;
@@ -2148,7 +2146,7 @@
return false;
}
auto layout_node = my_data->descriptorSetLayoutMap[pipeline_layout_it->second.descriptorSetLayouts[layoutIndex]];
- return layout_node->IsCompatible(pSet->p_layout, &errorMsg);
+ return pSet->descriptor_set->IsCompatible(layout_node, &errorMsg);
}
// Validate that data for each specialization entry is fully contained within the buffer.
@@ -2590,143 +2588,26 @@
layer_data *dev_data, GLOBAL_CB_NODE *pCB,
const vector<std::pair<SET_NODE *, unordered_set<uint32_t>>> &activeSetBindingsPairs) {
bool result = false;
-
- VkWriteDescriptorSet *pWDS = NULL;
- uint32_t dynOffsetIndex = 0;
- VkDeviceSize bufferSize = 0;
for (auto set_bindings_pair : activeSetBindingsPairs) {
SET_NODE *set_node = set_bindings_pair.first;
- auto layout_node = set_node->p_layout;
- for (auto binding : set_bindings_pair.second) {
- if ((set_node->p_layout->GetTypeFromBinding(binding) == VK_DESCRIPTOR_TYPE_SAMPLER) &&
- (set_node->p_layout->GetDescriptorCountFromBinding(binding) != 0) &&
- (set_node->p_layout->GetImmutableSamplerPtrFromBinding(binding))) {
- // No work for immutable sampler binding
- } else {
- uint32_t startIdx = layout_node->GetGlobalStartIndexFromBinding(binding);
- uint32_t endIdx = layout_node->GetGlobalEndIndexFromBinding(binding);
- for (uint32_t i = startIdx; i <= endIdx; ++i) {
- // We did check earlier to verify that set was updated, but now make sure given slot was updated
- // TODO : Would be better to store set# that set is bound to so we can report set.binding[index] not updated
- // For immutable sampler w/o combined image, don't need to update
- if (!set_node->pDescriptorUpdates[i]) {
- result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
- DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
- "DS %#" PRIxLEAST64 " bound and active but it never had binding %u updated. It is now being used to draw so "
- "this will result in undefined behavior.",
- reinterpret_cast<const uint64_t &>(set_node->set), binding);
- } else {
- switch (set_node->pDescriptorUpdates[i]->sType) {
- case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
- pWDS = (VkWriteDescriptorSet *)set_node->pDescriptorUpdates[i];
-
- // Verify uniform and storage buffers actually are bound to valid memory at draw time.
- if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
- (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
- (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
- (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
- for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
- auto buffer_node = dev_data->bufferMap.find(pWDS->pBufferInfo[j].buffer);
- if (buffer_node == dev_data->bufferMap.end()) {
- result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
- DRAWSTATE_INVALID_BUFFER, "DS",
- "VkDescriptorSet (%#" PRIxLEAST64 ") %s (%#" PRIxLEAST64 ") at index #%u"
- " is not defined! Has vkCreateBuffer been called?",
- reinterpret_cast<const uint64_t &>(set_node->set),
- string_VkDescriptorType(pWDS->descriptorType),
- reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), i);
- } else {
- auto mem_entry = dev_data->memObjMap.find(buffer_node->second.mem);
- if (mem_entry == dev_data->memObjMap.end()) {
- result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
- DRAWSTATE_INVALID_BUFFER, "DS",
- "VkDescriptorSet (%#" PRIxLEAST64 ") %s (%#" PRIxLEAST64 ") at index"
- " #%u, has no memory bound to it!",
- reinterpret_cast<const uint64_t &>(set_node->set),
- string_VkDescriptorType(pWDS->descriptorType),
- reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), i);
- }
- }
- // If it's a dynamic buffer, make sure the offsets are within the buffer.
- if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
- (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
- bufferSize = dev_data->bufferMap[pWDS->pBufferInfo[j].buffer].createInfo.size;
- uint32_t dynOffset =
- pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].dynamicOffsets[dynOffsetIndex];
- if (pWDS->pBufferInfo[j].range == VK_WHOLE_SIZE) {
- if ((dynOffset + pWDS->pBufferInfo[j].offset) > bufferSize) {
- result |= log_msg(
- dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
- DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
- "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has range of "
- "VK_WHOLE_SIZE but dynamic offset %#" PRIxLEAST32 ". "
- "combined with offset %#" PRIxLEAST64 " oversteps its buffer (%#" PRIxLEAST64
- ") which has a size of %#" PRIxLEAST64 ".",
- reinterpret_cast<const uint64_t &>(set_node->set), i, dynOffset,
- pWDS->pBufferInfo[j].offset,
- reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
- }
- } else if ((dynOffset + pWDS->pBufferInfo[j].offset + pWDS->pBufferInfo[j].range) >
- bufferSize) {
- result |=
- log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
- DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
- "VkDescriptorSet (%#" PRIxLEAST64
- ") bound as set #%u has dynamic offset %#" PRIxLEAST32 ". "
- "Combined with offset %#" PRIxLEAST64 " and range %#" PRIxLEAST64
- " from its update, this oversteps its buffer "
- "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".",
- reinterpret_cast<const uint64_t &>(set_node->set), i, dynOffset,
- pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range,
- reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
- }
- dynOffsetIndex++;
- }
- }
- }
- if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
- for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
- pCB->updateImages.insert(pWDS->pImageInfo[j].imageView);
- }
- } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
- for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
- assert(dev_data->bufferViewMap.find(pWDS->pTexelBufferView[j]) != dev_data->bufferViewMap.end());
- pCB->updateBuffers.insert(dev_data->bufferViewMap[pWDS->pTexelBufferView[j]].buffer);
- }
- } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
- pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
- for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
- pCB->updateBuffers.insert(pWDS->pBufferInfo[j].buffer);
- }
- }
- i += pWDS->descriptorCount; // Advance i to end of this set of descriptors (++i at end of for loop will move 1
- // index past last of these descriptors)
- break;
- default: // Currently only shadowing Write update nodes so shouldn't get here
- assert(0);
- continue;
- }
- }
- }
- }
+ std::string err_str;
+ if (!set_node->descriptor_set->ValidateDrawState(
+ set_bindings_pair.second, pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].dynamicOffsets, &err_str)) {
+ // Report error here
+ auto set = set_node->descriptor_set->GetSet();
+ result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+ reinterpret_cast<const uint64_t &>(set), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
+ "DS %#" PRIxLEAST64 " encountered the following validation error at draw time: %s",
+ reinterpret_cast<const uint64_t &>(set), err_str.c_str());
}
+ set_node->descriptor_set->GetStorageUpdates(set_bindings_pair.second, &pCB->updateBuffers, &pCB->updateImages);
}
return result;
}
// TODO : This is a temp function that naively updates bound storage images and buffers based on which descriptor sets are bound.
-// When validate_and_update_draw_state() handles computer shaders so that active_slots is correct for compute pipelines, this
+// When validate_and_update_draw_state() handles compute shaders so that active_slots is correct for compute pipelines, this
// function can be killed and validate_and_update_draw_state() used instead
static void update_shader_storage_images_and_buffers(layer_data *dev_data, GLOBAL_CB_NODE *pCB) {
- VkWriteDescriptorSet *pWDS = nullptr;
SET_NODE *pSet = nullptr;
// For the bound descriptor sets, pull off any storage images and buffers
// This may be more than are actually updated depending on which are active, but for now this is a stop-gap for compute
@@ -2734,27 +2615,7 @@
for (auto set : pCB->lastBound[VK_PIPELINE_BIND_POINT_COMPUTE].uniqueBoundSets) {
// Get the set node
pSet = getSetNode(dev_data, set);
- // For each update in the set
- for (auto pUpdate : pSet->pDescriptorUpdates) {
- // If it's a write update to STORAGE type capture image/buffer being updated
- if (pUpdate && (pUpdate->sType == VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET)) {
- pWDS = reinterpret_cast<VkWriteDescriptorSet *>(pUpdate);
- if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
- for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
- pCB->updateImages.insert(pWDS->pImageInfo[j].imageView);
- }
- } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) {
- for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
- pCB->updateBuffers.insert(dev_data->bufferViewMap[pWDS->pTexelBufferView[j]].buffer);
- }
- } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
- pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
- for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
- pCB->updateBuffers.insert(pWDS->pBufferInfo[j].buffer);
- }
- }
- }
- }
+ pSet->descriptor_set->GetAllStorageUpdates(&pCB->updateBuffers, &pCB->updateImages);
}
}
@@ -2801,7 +2662,7 @@
} else if (!verify_set_layout_compatibility(my_data, my_data->setMap[state.boundDescriptorSets[setIndex]],
pPipe->graphicsPipelineCI.layout, setIndex, errorString)) {
// Set is bound but not compatible w/ overlapping pipelineLayout from PSO
- VkDescriptorSet setHandle = my_data->setMap[state.boundDescriptorSets[setIndex]]->set;
+ VkDescriptorSet setHandle = my_data->setMap[state.boundDescriptorSets[setIndex]]->descriptor_set->GetSet();
result |=
log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
(uint64_t)setHandle, __LINE__, DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE, "DS",
@@ -2815,15 +2676,15 @@
activeSetBindingsPairs.push_back(std::make_pair(pSet, setBindingPair.second));
// Make sure set has been updated if it has no immutable samplers
// If it has immutable samplers, we'll flag error later as needed depending on binding
- if (!pSet->pUpdateStructs) {
+ if (!pSet->descriptor_set->IsUpdated()) {
for (auto binding : setBindingPair.second) {
- if (!pSet->p_layout->GetImmutableSamplerPtrFromBinding(binding)) {
+ if (!pSet->descriptor_set->GetImmutableSamplerPtrFromBinding(binding)) {
result |= log_msg(
my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- (uint64_t)pSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
+ (uint64_t)pSet->descriptor_set->GetSet(), __LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
"DS %#" PRIxLEAST64 " bound but it was never updated. It is now being used to draw so "
"this will result in undefined behavior.",
- (uint64_t)pSet->set);
+ (uint64_t)pSet->descriptor_set->GetSet());
}
}
}
@@ -3349,29 +3210,6 @@
return skipCall;
}
-// Verify that given sampler is valid
-static bool validateSampler(const layer_data *my_data, const VkSampler *pSampler, const bool immutable) {
- bool skipCall = false;
- auto sampIt = my_data->sampleMap.find(*pSampler);
- if (sampIt == my_data->sampleMap.end()) {
- if (!immutable) {
- skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
- (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS",
- "vkUpdateDescriptorSets: Attempt to update descriptor with invalid sampler %#" PRIxLEAST64,
- (uint64_t)*pSampler);
- } else { // immutable
- skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
- (uint64_t)*pSampler, __LINE__, DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR, "DS",
- "vkUpdateDescriptorSets: Attempt to update descriptor whose binding has an invalid immutable "
- "sampler %#" PRIxLEAST64,
- (uint64_t)*pSampler);
- }
- } else {
- // TODO : Any further checks we want to do on the sampler?
- }
- return skipCall;
-}
-
//TODO: Consolidate functions
bool FindLayout(const GLOBAL_CB_NODE *pCB, ImageSubresourcePair imgpair, IMAGE_CMD_BUF_LAYOUT_NODE &node, const VkImageAspectFlags aspectMask) {
layer_data *my_data = get_my_data_ptr(get_dispatch_key(pCB->commandBuffer), layer_data_map);
@@ -3561,209 +3399,6 @@
}
}
-// Verify that given imageView is valid
-static bool validateImageView(const layer_data *my_data, const VkImageView *pImageView, const VkImageLayout imageLayout) {
- bool skipCall = false;
- auto ivIt = my_data->imageViewMap.find(*pImageView);
- if (ivIt == my_data->imageViewMap.end()) {
- skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
- (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
- "vkUpdateDescriptorSets: Attempt to update descriptor with invalid imageView %#" PRIxLEAST64,
- (uint64_t)*pImageView);
- } else {
- // Validate that imageLayout is compatible with aspectMask and image format
- VkImageAspectFlags aspectMask = ivIt->second.subresourceRange.aspectMask;
- VkImage image = ivIt->second.image;
- // TODO : Check here in case we have a bad image
- VkFormat format = VK_FORMAT_MAX_ENUM;
- auto imgIt = my_data->imageMap.find(image);
- if (imgIt != my_data->imageMap.end()) {
- format = (*imgIt).second.createInfo.format;
- } else {
- // Also need to check the swapchains.
- auto swapchainIt = my_data->device_extensions.imageToSwapchainMap.find(image);
- if (swapchainIt != my_data->device_extensions.imageToSwapchainMap.end()) {
- VkSwapchainKHR swapchain = swapchainIt->second;
- auto swapchain_nodeIt = my_data->device_extensions.swapchainMap.find(swapchain);
- if (swapchain_nodeIt != my_data->device_extensions.swapchainMap.end()) {
- SWAPCHAIN_NODE *pswapchain_node = swapchain_nodeIt->second;
- format = pswapchain_node->createInfo.imageFormat;
- }
- }
- }
- if (format == VK_FORMAT_MAX_ENUM) {
- skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
- (uint64_t)image, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
- "vkUpdateDescriptorSets: Attempt to update descriptor with invalid image %#" PRIxLEAST64
- " in imageView %#" PRIxLEAST64,
- (uint64_t)image, (uint64_t)*pImageView);
- } else {
- bool ds = vk_format_is_depth_or_stencil(format);
- switch (imageLayout) {
- case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
- // Only Color bit must be set
- if ((aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
- (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
- "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL "
- "and imageView %#" PRIxLEAST64 ""
- " that does not have VK_IMAGE_ASPECT_COLOR_BIT set.",
- (uint64_t)*pImageView);
- }
- // format must NOT be DS
- if (ds) {
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
- (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
- "vkUpdateDescriptorSets: Updating descriptor with layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL "
- "and imageView %#" PRIxLEAST64 ""
- " but the image format is %s which is not a color format.",
- (uint64_t)*pImageView, string_VkFormat(format));
- }
- break;
- case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
- case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
- // Depth or stencil bit must be set, but both must NOT be set
- if (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) {
- if (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) {
- // both must NOT be set
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
- (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
- "vkUpdateDescriptorSets: Updating descriptor with imageView %#" PRIxLEAST64 ""
- " that has both STENCIL and DEPTH aspects set",
- (uint64_t)*pImageView);
- }
- } else if (!(aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
- // Neither were set
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
- (uint64_t)*pImageView, __LINE__, DRAWSTATE_INVALID_IMAGE_ASPECT, "DS",
- "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 ""
- " that does not have STENCIL or DEPTH aspect set.",
- string_VkImageLayout(imageLayout), (uint64_t)*pImageView);
- }
- // format must be DS
- if (!ds) {
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT,
- (uint64_t)*pImageView, __LINE__, DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR, "DS",
- "vkUpdateDescriptorSets: Updating descriptor with layout %s and imageView %#" PRIxLEAST64 ""
- " but the image format is %s which is not a depth/stencil format.",
- string_VkImageLayout(imageLayout), (uint64_t)*pImageView, string_VkFormat(format));
- }
- break;
- default:
- // anything to check for other layouts?
- break;
- }
- }
- }
- return skipCall;
-}
-
-// Verify that given bufferView is valid
-static bool validateBufferView(const layer_data *my_data, const VkBufferView *pBufferView) {
- bool skipCall = false;
- auto sampIt = my_data->bufferViewMap.find(*pBufferView);
- if (sampIt == my_data->bufferViewMap.end()) {
- skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT,
- (uint64_t)*pBufferView, __LINE__, DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR, "DS",
- "vkUpdateDescriptorSets: Attempt to update descriptor with invalid bufferView %#" PRIxLEAST64,
- (uint64_t)*pBufferView);
- } else {
- // TODO : Any further checks we want to do on the bufferView?
- }
- return skipCall;
-}
-
-// Verify that given bufferInfo is valid
-static bool validateBufferInfo(const layer_data *my_data, const VkDescriptorBufferInfo *pBufferInfo) {
- bool skipCall = false;
- auto sampIt = my_data->bufferMap.find(pBufferInfo->buffer);
- if (sampIt == my_data->bufferMap.end()) {
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
- (uint64_t)pBufferInfo->buffer, __LINE__, DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR, "DS",
- "vkUpdateDescriptorSets: Attempt to update descriptor where bufferInfo has invalid buffer %#" PRIxLEAST64,
- (uint64_t)pBufferInfo->buffer);
- } else {
- // TODO : Any further checks we want to do on the bufferView?
- }
- return skipCall;
-}
-
-static bool validateUpdateContents(const layer_data *my_data, const VkWriteDescriptorSet *pWDS,
- const VkSampler *pImmutableSamplers) {
- bool skipCall = false;
- // First verify that for the given Descriptor type, the correct DescriptorInfo data is supplied
- const VkSampler *pSampler = NULL;
- bool immutable = false;
- uint32_t i = 0;
- // For given update type, verify that update contents are correct
- switch (pWDS->descriptorType) {
- case VK_DESCRIPTOR_TYPE_SAMPLER:
- for (i = 0; i < pWDS->descriptorCount; ++i) {
- skipCall |= validateSampler(my_data, &(pWDS->pImageInfo[i].sampler), immutable);
- }
- break;
- case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
- for (i = 0; i < pWDS->descriptorCount; ++i) {
- if (NULL == pImmutableSamplers) {
- pSampler = &(pWDS->pImageInfo[i].sampler);
- if (immutable) {
- skipCall |= log_msg(
- my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
- (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS",
- "vkUpdateDescriptorSets: Update #%u is not an immutable sampler %#" PRIxLEAST64
- ", but previous update(s) from this "
- "VkWriteDescriptorSet struct used an immutable sampler. All updates from a single struct must either "
- "use immutable or non-immutable samplers.",
- i, (uint64_t)*pSampler);
- }
- } else {
- if (i > 0 && !immutable) {
- skipCall |= log_msg(
- my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
- (uint64_t)*pSampler, __LINE__, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS",
- "vkUpdateDescriptorSets: Update #%u is an immutable sampler, but previous update(s) from this "
- "VkWriteDescriptorSet struct used a non-immutable sampler. All updates from a single struct must either "
- "use immutable or non-immutable samplers.",
- i);
- }
- immutable = true;
- pSampler = &(pImmutableSamplers[i]);
- }
- skipCall |= validateSampler(my_data, pSampler, immutable);
- }
- // Intentionally fall through here to also validate image stuff
- case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
- case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
- case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
- for (i = 0; i < pWDS->descriptorCount; ++i) {
- skipCall |= validateImageView(my_data, &(pWDS->pImageInfo[i].imageView), pWDS->pImageInfo[i].imageLayout);
- }
- break;
- case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
- case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
- for (i = 0; i < pWDS->descriptorCount; ++i) {
- skipCall |= validateBufferView(my_data, &(pWDS->pTexelBufferView[i]));
- }
- break;
- case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
- case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
- case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
- case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
- for (i = 0; i < pWDS->descriptorCount; ++i) {
- skipCall |= validateBufferInfo(my_data, &(pWDS->pBufferInfo[i]));
- }
- break;
- default:
- break;
- }
- return skipCall;
-}
// Validate that given set is valid and that it's not being used by an in-flight CmdBuffer
// func_str is the name of the calling function
// Return false if no errors occur
@@ -3788,7 +3423,7 @@
}
static void invalidateBoundCmdBuffers(layer_data *dev_data, const SET_NODE *pSet) {
// Flag any CBs this set is bound to as INVALID
- for (auto cb : pSet->boundCmdBuffers) {
+ for (auto cb : pSet->descriptor_set->GetBoundCmdBuffers()) {
auto cb_node = dev_data->commandBufferMap.find(cb);
if (cb_node != dev_data->commandBufferMap.end()) {
cb_node->second->state = CB_INVALID;
@@ -3810,146 +3445,36 @@
// If set is bound to any cmdBuffers, mark them invalid
invalidateBoundCmdBuffers(my_data, pSet);
GENERIC_HEADER *pUpdate = (GENERIC_HEADER *)&pWDS[i];
- auto layout_node = pSet->p_layout;
// First verify valid update struct
if ((skipCall = validUpdateStruct(my_data, device, pUpdate)) == true) {
break;
}
- uint32_t binding = 0, endIndex = 0;
- binding = pWDS[i].dstBinding;
- // Make sure that layout being updated has the binding being updated
- if (!layout_node->HasBinding(binding)) {
+ string error_str;
+ if (!pSet->descriptor_set->WriteUpdate(my_data->report_data, &pWDS[i], &error_str)) {
skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
(uint64_t)(ds), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
- "Descriptor Set %" PRIu64 " does not have binding to match "
- "update binding %u for update type "
- "%s!",
- (uint64_t)(ds), binding, string_VkStructureType(pUpdate->sType));
- } else {
- // Next verify that update falls within size of given binding
- endIndex = getUpdateEndIndex(my_data, device, layout_node->GetGlobalStartIndexFromBinding(binding),
- pWDS[i].dstArrayElement, pUpdate);
- if (layout_node->GetGlobalEndIndexFromBinding(binding) < endIndex) {
- auto ds_layout = layout_node->GetDescriptorSetLayout();
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- reinterpret_cast<uint64_t &>(ds), __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
- "Descriptor update type of %s is out of bounds for matching binding %u in Layout %" PRIu64 "!",
- string_VkStructureType(pUpdate->sType), binding, reinterpret_cast<uint64_t &>(ds_layout));
- } else { // TODO : should we skip update on a type mismatch or force it?
- uint32_t startIndex;
- startIndex = getUpdateStartIndex(my_data, device, layout_node->GetGlobalStartIndexFromBinding(binding),
- pWDS[i].dstArrayElement, pUpdate);
- const auto & layout_binding = layout_node->GetDescriptorSetLayoutBindingPtrFromBinding(binding);
- // Layout bindings match w/ update, now verify that update type & stageFlags are the same for entire update
- if ((skipCall = validateUpdateConsistency(my_data, device, layout_binding->descriptorType, pUpdate, startIndex,
- endIndex)) == false) {
- // The update is within bounds and consistent, but need to
- // make sure contents make sense as well
- if ((skipCall = validateUpdateContents(my_data, &pWDS[i], layout_binding->pImmutableSamplers)) == false) {
- // Update is good. Save the update info
- // Create new update struct for this set's shadow copy
- GENERIC_HEADER *pNewNode = NULL;
- skipCall |= shadowUpdateNode(my_data, device, pUpdate, &pNewNode);
- if (NULL == pNewNode) {
- skipCall |= log_msg(
- my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- (uint64_t)(ds), __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
- "Out of memory while attempting to allocate UPDATE struct in vkUpdateDescriptors()");
- } else {
- // Insert shadow node into LL of updates for this set
- pNewNode->pNext = pSet->pUpdateStructs;
- pSet->pUpdateStructs = pNewNode;
- // Now update appropriate descriptor(s) to point to new Update node
- for (uint32_t j = startIndex; j <= endIndex; j++) {
- assert(j < pSet->descriptorCount);
- pSet->pDescriptorUpdates[j] = pNewNode;
- }
- }
- }
- }
- }
+ "vkUpdateDescriptorsSets() failed write update for Descriptor Set %" PRIu64 " with error: %s",
+ reinterpret_cast<uint64_t &>(ds), error_str.c_str());
}
}
// Now validate copy updates
for (i = 0; i < descriptorCopyCount; ++i) {
SET_NODE *pSrcSet = NULL, *pDstSet = NULL;
- uint32_t srcStartIndex = 0, srcEndIndex = 0, dstStartIndex = 0, dstEndIndex = 0;
// For each copy make sure that update falls within given layout and that types match
pSrcSet = my_data->setMap[pCDS[i].srcSet];
pDstSet = my_data->setMap[pCDS[i].dstSet];
// Set being updated cannot be in-flight
- if ((skipCall = validateIdleDescriptorSet(my_data, pDstSet->set, "VkUpdateDescriptorSets")) == true)
+ if ((skipCall = validateIdleDescriptorSet(my_data, pDstSet->descriptor_set->GetSet(), "VkUpdateDescriptorSets")) == true)
return skipCall;
invalidateBoundCmdBuffers(my_data, pDstSet);
- auto src_layout_node = pSrcSet->p_layout;
- auto dst_layout_node = pDstSet->p_layout;
- // Validate that src binding is valid for src set layout
- if (!src_layout_node->HasBinding(pCDS[i].srcBinding)) {
- auto s_layout = src_layout_node->GetDescriptorSetLayout();
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
- "Copy descriptor update %u has srcBinding %u "
- "which is out of bounds for underlying SetLayout "
- "%#" PRIxLEAST64 " which only has bindings 0-%u.",
- i, pCDS[i].srcBinding, reinterpret_cast<uint64_t &>(s_layout), src_layout_node->GetBindingCount() - 1);
- } else if (!dst_layout_node->HasBinding(pCDS[i].dstBinding)) {
- auto d_layout = dst_layout_node->GetDescriptorSetLayout();
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
- "Copy descriptor update %u has dstBinding %u "
- "which is out of bounds for underlying SetLayout "
- "%#" PRIxLEAST64 " which only has bindings 0-%u.",
- i, pCDS[i].dstBinding, reinterpret_cast<uint64_t &>(d_layout), dst_layout_node->GetBindingCount() - 1);
- } else {
- // Proceed with validation. Bindings are ok, but make sure update is within bounds of given layout and binding
- srcEndIndex = getUpdateEndIndex(my_data, device, src_layout_node->GetGlobalStartIndexFromBinding(pCDS[i].srcBinding),
- pCDS[i].srcArrayElement, (const GENERIC_HEADER *)&(pCDS[i]));
- dstEndIndex = getUpdateEndIndex(my_data, device, dst_layout_node->GetGlobalStartIndexFromBinding(pCDS[i].dstBinding),
- pCDS[i].dstArrayElement, (const GENERIC_HEADER *)&(pCDS[i]));
- if (src_layout_node->GetGlobalEndIndexFromBinding(pCDS[i].srcBinding) < srcEndIndex) {
- auto s_layout = src_layout_node->GetDescriptorSetLayout();
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- (uint64_t)pSrcSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
- "Copy descriptor src update is out of bounds for matching binding %u in Layout %" PRIu64 "!",
- pCDS[i].srcBinding, reinterpret_cast<uint64_t &>(s_layout));
- } else if (dst_layout_node->GetGlobalEndIndexFromBinding(pCDS[i].dstBinding) < dstEndIndex) {
- auto d_layout = dst_layout_node->GetDescriptorSetLayout();
- skipCall |=
- log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
- (uint64_t)pDstSet->set, __LINE__, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
- "Copy descriptor dest update is out of bounds for matching binding %u in Layout %" PRIu64 "!",
- pCDS[i].dstBinding, reinterpret_cast<uint64_t &>(d_layout));
- } else {
- srcStartIndex =
- getUpdateStartIndex(my_data, device, src_layout_node->GetGlobalStartIndexFromBinding(pCDS[i].srcBinding),
- pCDS[i].srcArrayElement, (const GENERIC_HEADER *)&(pCDS[i]));
- dstStartIndex =
- getUpdateStartIndex(my_data, device, dst_layout_node->GetGlobalStartIndexFromBinding(pCDS[i].dstBinding),
- pCDS[i].dstArrayElement, (const GENERIC_HEADER *)&(pCDS[i]));
- auto s_binding = src_layout_node->GetDescriptorSetLayoutBindingPtrFromBinding(pCDS[i].srcBinding);
- auto d_binding = dst_layout_node->GetDescriptorSetLayoutBindingPtrFromBinding(pCDS[i].dstBinding);
- // For copy, just make sure types match and then perform update
- if (s_binding->descriptorType != d_binding->descriptorType) {
- skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
- __LINE__, DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
- "Copy descriptor update index %u, has src update descriptor type %s "
- "that does not match overlapping dest descriptor type of %s!",
- i, string_VkDescriptorType(s_binding->descriptorType),
- string_VkDescriptorType(d_binding->descriptorType));
- } else {
- for (uint32_t j = 0; j < pCDS[i].descriptorCount; ++j) {
- // point dst descriptor at corresponding src descriptor
- // TODO : This may be a hole. I believe copy should be its own copy,
- // otherwise a subsequent write update to src will incorrectly affect the copy
- pDstSet->pDescriptorUpdates[j + dstStartIndex] = pSrcSet->pDescriptorUpdates[j + srcStartIndex];
- pDstSet->pUpdateStructs = pSrcSet->pUpdateStructs;
- }
- }
- }
+ std::string error_str;
+ if (!pDstSet->descriptor_set->CopyUpdate(my_data->report_data, &pCDS[i], pSrcSet->descriptor_set, &error_str)) {
+ skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+ reinterpret_cast<const uint64_t &>(pCDS[i].dstSet), __LINE__, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
+ "vkUpdateDescriptorsSets() failed copy update from Descriptor Set %" PRIu64
+ " to Descriptor Set %" PRIu64 " with error: %s",
+ reinterpret_cast<const uint64_t &>(pCDS[i].srcSet),
+ reinterpret_cast<const uint64_t &>(pCDS[i].dstSet), error_str.c_str());
}
}
return skipCall;
@@ -4006,83 +3531,20 @@
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) {
- GENERIC_HEADER *pShadowUpdate = pSet->pUpdateStructs;
- pSet->pUpdateStructs = NULL;
- GENERIC_HEADER *pFreeUpdate = pShadowUpdate;
- // Clear the descriptor mappings as they will now be invalid
- pSet->pDescriptorUpdates.clear();
- while (pShadowUpdate) {
- pFreeUpdate = pShadowUpdate;
- pShadowUpdate = (GENERIC_HEADER *)pShadowUpdate->pNext;
- VkWriteDescriptorSet *pWDS = NULL;
- switch (pFreeUpdate->sType) {
- case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
- pWDS = (VkWriteDescriptorSet *)pFreeUpdate;
- switch (pWDS->descriptorType) {
- case VK_DESCRIPTOR_TYPE_SAMPLER:
- case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
- case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
- case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
- delete[] pWDS->pImageInfo;
- } break;
- case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
- case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
- delete[] pWDS->pTexelBufferView;
- } break;
- case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
- case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
- case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
- case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
- delete[] pWDS->pBufferInfo;
- } break;
- default:
- break;
- }
- break;
- case VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET:
- break;
- default:
- assert(0);
- break;
- }
- delete pFreeUpdate;
- }
-}
-
// Free all DS Pools including their Sets & related sub-structs
// NOTE : Calls to this function should be wrapped in mutex
static void deletePools(layer_data *my_data) {
if (my_data->descriptorPoolMap.size() <= 0)
return;
for (auto ii = my_data->descriptorPoolMap.begin(); ii != my_data->descriptorPoolMap.end(); ++ii) {
- SET_NODE *pSet = (*ii).second->pSets;
- SET_NODE *pFreeSet = pSet;
- while (pSet) {
- pFreeSet = pSet;
- pSet = pSet->pNext;
- // Free Update shadow struct tree
- freeShadowUpdateTree(pFreeSet);
- delete pFreeSet;
+ // TODODS : Is this correct now?
+ for (auto ds : (*ii).second->sets) {
+ delete ds;
}
- delete (*ii).second;
}
my_data->descriptorPoolMap.clear();
}
-// Currently clearing a set is removing all previous updates to that set
-// TODO : Validate if this is correct clearing behavior
-static void clearDescriptorSet(layer_data *my_data, VkDescriptorSet set) {
- SET_NODE *pSet = getSetNode(my_data, set);
- if (!pSet) {
- // TODO : Return error
- } else {
- freeShadowUpdateTree(pSet);
- }
-}
-
static void clearDescriptorPool(layer_data *my_data, const VkDevice device, const VkDescriptorPool pool,
VkDescriptorPoolResetFlags flags) {
DESCRIPTOR_POOL_NODE *pPool = getPoolNode(my_data, pool);
@@ -4093,16 +3555,10 @@
} else {
// TODO: validate flags
// For every set off of this pool, clear it, remove from setMap, and free SET_NODE
- SET_NODE *pSet = pPool->pSets;
- SET_NODE *pFreeSet = pSet;
- while (pSet) {
- clearDescriptorSet(my_data, pSet->set);
- my_data->setMap.erase(pSet->set);
- pFreeSet = pSet;
- pSet = pSet->pNext;
- delete pFreeSet;
+ // TODODS : Updated this code for new DescriptorSet class, is below all we need?
+ for (auto ds : pPool->sets) {
+ delete ds;
}
- pPool->pSets = nullptr;
// Reset available count for each type and available sets for this pool
for (uint32_t i = 0; i < pPool->availableDescriptorTypeCount.size(); ++i) {
pPool->availableDescriptorTypeCount[i] = pPool->maxDescriptorTypeCount[i];
@@ -4279,7 +3735,7 @@
for (auto set : pCB->lastBound[i].uniqueBoundSets) {
auto set_node = dev_data->setMap.find(set);
if (set_node != dev_data->setMap.end()) {
- set_node->second->boundCmdBuffers.erase(pCB->commandBuffer);
+ set_node->second->descriptor_set->RemoveBoundCommandBuffer(pCB->commandBuffer);
}
}
pCB->lastBound[i].reset();
@@ -6348,7 +5804,7 @@
VkResult result = dev_data->device_dispatch_table->CreateSampler(device, pCreateInfo, pAllocator, pSampler);
if (VK_SUCCESS == result) {
std::lock_guard<std::mutex> lock(global_lock);
- dev_data->sampleMap[*pSampler] = unique_ptr<SAMPLER_NODE>(new SAMPLER_NODE(pSampler, pCreateInfo));
+ dev_data->samplerMap[*pSampler] = unique_ptr<SAMPLER_NODE>(new SAMPLER_NODE(pSampler, pCreateInfo));
}
return result;
}
@@ -6361,7 +5817,8 @@
if (VK_SUCCESS == result) {
// TODOSC : Capture layout bindings set
std::lock_guard<std::mutex> lock(global_lock);
- dev_data->descriptorSetLayoutMap[*pSetLayout] = new DescriptorSetLayout(dev_data->report_data, pCreateInfo, *pSetLayout);
+ dev_data->descriptorSetLayoutMap[*pSetLayout] =
+ new cvdescriptorset::DescriptorSetLayout(dev_data->report_data, pCreateInfo, *pSetLayout);
}
return result;
}
@@ -6484,8 +5941,22 @@
log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
(uint64_t)pDescriptorSets[i], __LINE__, DRAWSTATE_NONE, "DS", "Created Descriptor Set %#" PRIxLEAST64,
(uint64_t)pDescriptorSets[i]);
+ auto layout_pair = dev_data->descriptorSetLayoutMap.find(pAllocateInfo->pSetLayouts[i]);
+ if (layout_pair == dev_data->descriptorSetLayoutMap.end()) {
+ if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pAllocateInfo->pSetLayouts[i],
+ __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS", "Unable to find set layout node for layout %#" PRIxLEAST64
+ " specified in vkAllocateDescriptorSets() call",
+ (uint64_t)pAllocateInfo->pSetLayouts[i])) {
+ lock.unlock();
+ return VK_ERROR_VALIDATION_FAILED_EXT;
+ }
+ }
// Create new set node and add to head of pool nodes
- SET_NODE *pNewNode = new SET_NODE;
+ SET_NODE *pNewNode =
+ new SET_NODE(pDescriptorSets[i], layout_pair->second, &dev_data->bufferMap, &dev_data->memObjMap,
+ &dev_data->bufferViewMap, &dev_data->samplerMap, &dev_data->imageViewMap, &dev_data->imageMap,
+ &dev_data->device_extensions.imageToSwapchainMap, &dev_data->device_extensions.swapchainMap);
if (NULL == pNewNode) {
if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
@@ -6498,29 +5969,9 @@
// TODO : Pool should store a total count of each type of Descriptor available
// When descriptors are allocated, decrement the count and validate here
// that the count doesn't go below 0. One reset/free need to bump count back up.
- // Insert set at head of Set LL for this pool
- pNewNode->pNext = pPoolNode->pSets;
+ // Insert set into this pool
+ pPoolNode->sets.insert(pNewNode);
pNewNode->in_use.store(0);
- pPoolNode->pSets = pNewNode;
- auto layout_pair = dev_data->descriptorSetLayoutMap.find(pAllocateInfo->pSetLayouts[i]);
- if (layout_pair == dev_data->descriptorSetLayoutMap.end()) {
- if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pAllocateInfo->pSetLayouts[i],
- __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
- "Unable to find set layout node for layout %#" PRIxLEAST64
- " specified in vkAllocateDescriptorSets() call",
- (uint64_t)pAllocateInfo->pSetLayouts[i])) {
- lock.unlock();
- return VK_ERROR_VALIDATION_FAILED_EXT;
- }
- }
- pNewNode->p_layout = layout_pair->second;
- pNewNode->pool = pAllocateInfo->descriptorPool;
- pNewNode->set = pDescriptorSets[i];
- pNewNode->descriptorCount = layout_pair->second->GetTotalDescriptorCount();
- if (pNewNode->descriptorCount) {
- pNewNode->pDescriptorUpdates.resize(pNewNode->descriptorCount);
- }
dev_data->setMap[pDescriptorSets[i]] = pNewNode;
}
}
@@ -6560,12 +6011,10 @@
for (uint32_t i = 0; i < count; ++i) {
SET_NODE *pSet = dev_data->setMap[pDescriptorSets[i]]; // getSetNode() without locking
invalidateBoundCmdBuffers(dev_data, pSet);
- auto p_layout = pSet->p_layout;
uint32_t typeIndex = 0, poolSizeCount = 0;
- for (uint32_t j = 0; j < p_layout->GetBindingCount(); ++j) {
- auto layout_binding = p_layout->GetDescriptorSetLayoutBindingPtrFromIndex(j);
- typeIndex = static_cast<uint32_t>(layout_binding->descriptorType);
- poolSizeCount = layout_binding->descriptorCount;
+ for (uint32_t j = 0; j < pSet->descriptor_set->GetBindingCount(); ++j) {
+ typeIndex = static_cast<uint32_t>(pSet->descriptor_set->GetTypeFromIndex(j));
+ poolSizeCount = pSet->descriptor_set->GetDescriptorCountFromIndex(j);
pPoolNode->availableDescriptorTypeCount[typeIndex] += poolSizeCount;
}
}
@@ -7015,14 +6464,14 @@
SET_NODE *pSet = getSetNode(dev_data, pDescriptorSets[i]);
if (pSet) {
pCB->lastBound[pipelineBindPoint].uniqueBoundSets.insert(pDescriptorSets[i]);
- pSet->boundCmdBuffers.insert(commandBuffer);
+ pSet->descriptor_set->BindCommandBuffer(commandBuffer);
pCB->lastBound[pipelineBindPoint].pipelineLayout = layout;
pCB->lastBound[pipelineBindPoint].boundDescriptorSets[i + firstSet] = pDescriptorSets[i];
skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT,
VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
DRAWSTATE_NONE, "DS", "DS %#" PRIxLEAST64 " bound on pipeline %s",
(uint64_t)pDescriptorSets[i], string_VkPipelineBindPoint(pipelineBindPoint));
- if (!pSet->pUpdateStructs && (pSet->descriptorCount != 0)) {
+ if (!pSet->descriptor_set->IsUpdated() && (pSet->descriptor_set->GetTotalDescriptorCount() != 0)) {
skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT,
VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i],
__LINE__, DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED, "DS",
@@ -7039,9 +6488,9 @@
"at index %u of pipelineLayout %#" PRIxLEAST64 " due to: %s",
i, i + firstSet, reinterpret_cast<uint64_t &>(layout), errorString.c_str());
}
- if (pSet->p_layout->GetDynamicDescriptorCount()) {
+ if (pSet->descriptor_set->GetDynamicDescriptorCount()) {
// First make sure we won't overstep bounds of pDynamicOffsets array
- if ((totalDynamicDescriptors + pSet->p_layout->GetDynamicDescriptorCount()) > dynamicOffsetCount) {
+ if ((totalDynamicDescriptors + pSet->descriptor_set->GetDynamicDescriptorCount()) > dynamicOffsetCount) {
skipCall |=
log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT, (uint64_t)pDescriptorSets[i], __LINE__,
@@ -7049,13 +6498,13 @@
"descriptorSet #%u (%#" PRIxLEAST64
") requires %u dynamicOffsets, but only %u dynamicOffsets are left in pDynamicOffsets "
"array. There must be one dynamic offset for each dynamic descriptor being bound.",
- i, (uint64_t)pDescriptorSets[i], pSet->p_layout->GetDynamicDescriptorCount(),
+ i, (uint64_t)pDescriptorSets[i], pSet->descriptor_set->GetDynamicDescriptorCount(),
(dynamicOffsetCount - totalDynamicDescriptors));
} else { // Validate and store dynamic offsets with the set
// Validate Dynamic Offset Minimums
uint32_t cur_dyn_offset = totalDynamicDescriptors;
- for (uint32_t d = 0; d < pSet->descriptorCount; d++) {
- if (pSet->p_layout->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
+ for (uint32_t d = 0; d < pSet->descriptor_set->GetTotalDescriptorCount(); d++) {
+ if (pSet->descriptor_set->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
if (vk_safe_modulo(
pDynamicOffsets[cur_dyn_offset],
dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
@@ -7069,7 +6518,8 @@
dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment);
}
cur_dyn_offset++;
- } else if (pSet->p_layout->GetTypeFromGlobalIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
+ } else if (pSet->descriptor_set->GetTypeFromGlobalIndex(d) ==
+ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
if (vk_safe_modulo(
pDynamicOffsets[cur_dyn_offset],
dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
@@ -7086,7 +6536,7 @@
}
}
// Keep running total of dynamic descriptor count to verify at the end
- totalDynamicDescriptors += pSet->p_layout->GetDynamicDescriptorCount();
+ totalDynamicDescriptors += pSet->descriptor_set->GetDynamicDescriptorCount();
}
}
} else {
diff --git a/layers/core_validation.h b/layers/core_validation.h
index a753bcb..106f212 100644
--- a/layers/core_validation.h
+++ b/layers/core_validation.h
@@ -47,6 +47,7 @@
#pragma once
#include "core_validation_error_enums.h"
+#include "core_validation_types.h"
#include "descriptor_sets.h"
#include "vk_layer_logging.h"
#include "vk_safe_struct.h"
@@ -62,10 +63,6 @@
using std::unordered_set;
#if MTMERGE
-struct MemRange {
- VkDeviceSize offset;
- VkDeviceSize size;
-};
/*
* MTMTODO : Update this comment
@@ -98,48 +95,6 @@
// TODO : Is there a way to track when Cmd Buffer finishes & remove mem references at that point?
// TODO : Could potentially store a list of freed mem allocs to flag when they're incorrectly used
-// Simple struct to hold handle and type of object so they can be uniquely identified and looked up in appropriate map
-struct MT_OBJ_HANDLE_TYPE {
- uint64_t handle;
- VkDebugReportObjectTypeEXT type;
-};
-
-bool operator==(MT_OBJ_HANDLE_TYPE a, MT_OBJ_HANDLE_TYPE b) NOEXCEPT{
- return a.handle == b.handle && a.type == b.type;
-}
-
-namespace std {
- template<>
- struct hash<MT_OBJ_HANDLE_TYPE> {
- size_t operator()(MT_OBJ_HANDLE_TYPE obj) const NOEXCEPT{
- return hash<uint64_t>()(obj.handle) ^
- hash<uint32_t>()(obj.type);
- }
- };
-}
-
-struct MEMORY_RANGE {
- uint64_t handle;
- VkDeviceMemory memory;
- VkDeviceSize start;
- VkDeviceSize end;
-};
-
-// Data struct for tracking memory object
-struct DEVICE_MEM_INFO {
- void *object; // Dispatchable object used to create this memory (device of swapchain)
- bool valid; // Stores if the memory has valid data or not
- VkDeviceMemory mem;
- VkMemoryAllocateInfo allocInfo;
- unordered_set<MT_OBJ_HANDLE_TYPE> objBindings; // objects bound to this memory
- unordered_set<VkCommandBuffer> commandBufferBindings; // cmd buffers referencing this memory
- vector<MEMORY_RANGE> bufferRanges;
- vector<MEMORY_RANGE> imageRanges;
- VkImage image; // If memory is bound to image, this will have VkImage handle, else VK_NULL_HANDLE
- MemRange memRange;
- void *pData, *pDriverData;
-};
-
struct MT_FB_ATTACHMENT_INFO {
VkImage image;
VkDeviceMemory mem;
@@ -249,27 +204,6 @@
}
};
-class BASE_NODE {
- public:
- std::atomic_int in_use;
-};
-
-typedef struct _SAMPLER_NODE {
- VkSampler sampler;
- VkSamplerCreateInfo createInfo;
-
- _SAMPLER_NODE(const VkSampler *ps, const VkSamplerCreateInfo *pci) : sampler(*ps), createInfo(*pci){};
-} SAMPLER_NODE;
-
-class IMAGE_NODE : public BASE_NODE {
- public:
- VkImageCreateInfo createInfo;
- VkDeviceMemory mem;
- bool valid; // If this is a swapchain image backing memory track valid here as it doesn't have DEVICE_MEM_INFO
- VkDeviceSize memOffset;
- VkDeviceSize memSize;
-};
-
typedef struct _IMAGE_LAYOUT_NODE {
VkImageLayout layout;
VkFormat format;
@@ -285,13 +219,6 @@
VkImageLayout layout;
};
-class BUFFER_NODE : public BASE_NODE {
- public:
- using BASE_NODE::in_use;
- VkDeviceMemory mem;
- VkBufferCreateInfo createInfo;
-};
-
// Store the DAG.
struct DAGNode {
uint32_t pass;
@@ -405,18 +332,21 @@
class SET_NODE : public BASE_NODE {
public:
using BASE_NODE::in_use;
- VkDescriptorSet set;
- VkDescriptorPool pool;
- // Head of LL of all Update structs for this set
- GENERIC_HEADER *pUpdateStructs;
- uint32_t descriptorCount; // Total num of descriptors in this set
- vector<GENERIC_HEADER*> pDescriptorUpdates; // Vector where each index points to update node for its slot
- DescriptorSetLayout *p_layout; // DescriptorSetLayout for this set
- SET_NODE *pNext;
- unordered_set<VkCommandBuffer> boundCmdBuffers; // Cmd buffers that this set has been bound to
- SET_NODE()
- : set(VK_NULL_HANDLE), pool(VK_NULL_HANDLE), pUpdateStructs(nullptr), descriptorCount(0), p_layout(nullptr),
- pNext(nullptr){};
+ cvdescriptorset::DescriptorSet *descriptor_set;
+ SET_NODE() : descriptor_set(nullptr){};
+ SET_NODE(const VkDescriptorSet set, const cvdescriptorset::DescriptorSetLayout *layout,
+ const std::unordered_map<VkBuffer, BUFFER_NODE> *buffer_map,
+ const std::unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> *memory_map,
+ const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *bufferview_map,
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map,
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map,
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map,
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map) {
+ descriptor_set = new cvdescriptorset::DescriptorSet(set, layout, buffer_map, memory_map, bufferview_map, sampler_map,
+ image_view_map, image_map, image_to_swapchain_map, swapchain_map);
+ };
+ ~SET_NODE() { delete descriptor_set; };
};
typedef struct _DESCRIPTOR_POOL_NODE {
@@ -425,12 +355,12 @@
uint32_t availableSets; // Available descriptor sets in this pool
VkDescriptorPoolCreateInfo createInfo;
- SET_NODE *pSets; // Head of LL of sets for this Pool
+ unordered_set<SET_NODE *> sets; // Collection of all sets in 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
_DESCRIPTOR_POOL_NODE(const VkDescriptorPool pool, const VkDescriptorPoolCreateInfo *pCreateInfo)
- : pool(pool), maxSets(pCreateInfo->maxSets), availableSets(pCreateInfo->maxSets), createInfo(*pCreateInfo), pSets(NULL),
+ : pool(pool), maxSets(pCreateInfo->maxSets), availableSets(pCreateInfo->maxSets), createInfo(*pCreateInfo),
maxDescriptorTypeCount(VK_DESCRIPTOR_TYPE_RANGE_SIZE, 0), availableDescriptorTypeCount(VK_DESCRIPTOR_TYPE_RANGE_SIZE, 0) {
if (createInfo.poolSizeCount) { // Shadow type struct from ptr into local struct
size_t poolSizeCountSize = createInfo.poolSizeCount * sizeof(VkDescriptorPoolSize);
@@ -677,17 +607,3 @@
vector<std::function<bool(VkQueue)>> eventUpdates;
};
-class SWAPCHAIN_NODE {
- public:
- VkSwapchainCreateInfoKHR createInfo;
- uint32_t *pQueueFamilyIndices;
- std::vector<VkImage> images;
- SWAPCHAIN_NODE(const VkSwapchainCreateInfoKHR *pCreateInfo) : createInfo(*pCreateInfo), pQueueFamilyIndices(NULL) {
- if (pCreateInfo->queueFamilyIndexCount && pCreateInfo->imageSharingMode == VK_SHARING_MODE_CONCURRENT) {
- pQueueFamilyIndices = new uint32_t[pCreateInfo->queueFamilyIndexCount];
- memcpy(pQueueFamilyIndices, pCreateInfo->pQueueFamilyIndices, pCreateInfo->queueFamilyIndexCount * sizeof(uint32_t));
- createInfo.pQueueFamilyIndices = pQueueFamilyIndices;
- }
- }
- ~SWAPCHAIN_NODE() { delete[] pQueueFamilyIndices; }
-};
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
new file mode 100644
index 0000000..f7c17d1
--- /dev/null
+++ b/layers/core_validation_types.h
@@ -0,0 +1,136 @@
+/* Copyright (c) 2015-2016 The Khronos Group Inc.
+ * Copyright (c) 2015-2016 Valve Corporation
+ * Copyright (c) 2015-2016 LunarG, Inc.
+ * Copyright (C) 2015-2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Courtney Goeltzenleuchter <courtneygo@google.com>
+ * Author: Tobin Ehlis <tobine@google.com>
+ * Author: Chris Forbes <chrisf@ijw.co.nz>
+ * Author: Mark Lobodzinski <mark@lunarg.com>
+ */
+#ifndef CORE_VALIDATION_TYPES_H_
+#define CORE_VALIDATION_TYPES_H_
+
+// Check for noexcept support
+#if defined(__clang__)
+#if __has_feature(cxx_noexcept)
+#define HAS_NOEXCEPT
+#endif
+#else
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46
+#define HAS_NOEXCEPT
+#else
+#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 && defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS
+#define HAS_NOEXCEPT
+#endif
+#endif
+#endif
+
+#ifdef HAS_NOEXCEPT
+#define NOEXCEPT noexcept
+#else
+#define NOEXCEPT
+#endif
+
+#include "vulkan/vulkan.h"
+#include <atomic>
+#include <string.h>
+#include <unordered_set>
+#include <vector>
+
+class BASE_NODE {
+ public:
+ std::atomic_int in_use;
+};
+
+class BUFFER_NODE : public BASE_NODE {
+ public:
+ using BASE_NODE::in_use;
+ VkDeviceMemory mem;
+ VkBufferCreateInfo createInfo;
+};
+
+typedef struct _SAMPLER_NODE {
+ VkSampler sampler;
+ VkSamplerCreateInfo createInfo;
+
+ _SAMPLER_NODE(const VkSampler *ps, const VkSamplerCreateInfo *pci) : sampler(*ps), createInfo(*pci){};
+} SAMPLER_NODE;
+
+class IMAGE_NODE : public BASE_NODE {
+ public:
+ VkImageCreateInfo createInfo;
+ VkDeviceMemory mem;
+ bool valid; // If this is a swapchain image backing memory track valid here as it doesn't have DEVICE_MEM_INFO
+ VkDeviceSize memOffset;
+ VkDeviceSize memSize;
+};
+
+// Simple struct to hold handle and type of object so they can be uniquely identified and looked up in appropriate map
+struct MT_OBJ_HANDLE_TYPE {
+ uint64_t handle;
+ VkDebugReportObjectTypeEXT type;
+};
+
+inline bool operator==(MT_OBJ_HANDLE_TYPE a, MT_OBJ_HANDLE_TYPE b) NOEXCEPT { return a.handle == b.handle && a.type == b.type; }
+
+namespace std {
+template <> struct hash<MT_OBJ_HANDLE_TYPE> {
+ size_t operator()(MT_OBJ_HANDLE_TYPE obj) const NOEXCEPT { return hash<uint64_t>()(obj.handle) ^ hash<uint32_t>()(obj.type); }
+};
+}
+
+struct MemRange {
+ VkDeviceSize offset;
+ VkDeviceSize size;
+};
+
+struct MEMORY_RANGE {
+ uint64_t handle;
+ VkDeviceMemory memory;
+ VkDeviceSize start;
+ VkDeviceSize end;
+};
+
+// Data struct for tracking memory object
+struct DEVICE_MEM_INFO {
+ void *object; // Dispatchable object used to create this memory (device of swapchain)
+ bool valid; // Stores if the memory has valid data or not
+ VkDeviceMemory mem;
+ VkMemoryAllocateInfo allocInfo;
+ std::unordered_set<MT_OBJ_HANDLE_TYPE> objBindings; // objects bound to this memory
+ std::unordered_set<VkCommandBuffer> commandBufferBindings; // cmd buffers referencing this memory
+ std::vector<MEMORY_RANGE> bufferRanges;
+ std::vector<MEMORY_RANGE> imageRanges;
+ VkImage image; // If memory is bound to image, this will have VkImage handle, else VK_NULL_HANDLE
+ MemRange memRange;
+ void *pData, *pDriverData;
+};
+
+class SWAPCHAIN_NODE {
+ public:
+ VkSwapchainCreateInfoKHR createInfo;
+ uint32_t *pQueueFamilyIndices;
+ std::vector<VkImage> images;
+ SWAPCHAIN_NODE(const VkSwapchainCreateInfoKHR *pCreateInfo) : createInfo(*pCreateInfo), pQueueFamilyIndices(NULL) {
+ if (pCreateInfo->queueFamilyIndexCount && pCreateInfo->imageSharingMode == VK_SHARING_MODE_CONCURRENT) {
+ pQueueFamilyIndices = new uint32_t[pCreateInfo->queueFamilyIndexCount];
+ memcpy(pQueueFamilyIndices, pCreateInfo->pQueueFamilyIndices, pCreateInfo->queueFamilyIndexCount * sizeof(uint32_t));
+ createInfo.pQueueFamilyIndices = pQueueFamilyIndices;
+ }
+ }
+ ~SWAPCHAIN_NODE() { delete[] pQueueFamilyIndices; }
+};
+#endif // CORE_VALIDATION_TYPES_H_
\ No newline at end of file
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
new file mode 100644
index 0000000..dc2d03b
--- /dev/null
+++ b/layers/descriptor_sets.cpp
@@ -0,0 +1,942 @@
+/* Copyright (c) 2015-2016 The Khronos Group Inc.
+ * Copyright (c) 2015-2016 Valve Corporation
+ * Copyright (c) 2015-2016 LunarG, Inc.
+ * Copyright (C) 2015-2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Tobin Ehlis <tobine@google.com>
+ */
+
+#include "descriptor_sets.h"
+#include "vk_enum_string_helper.h"
+#include "vk_safe_struct.h"
+#include <sstream>
+
+// Construct DescriptorSetLayout instance from given create info
+cvdescriptorset::DescriptorSetLayout::DescriptorSetLayout(debug_report_data *report_data,
+ const VkDescriptorSetLayoutCreateInfo *p_create_info,
+ const VkDescriptorSetLayout layout)
+ : layout_(layout), binding_count_(p_create_info->bindingCount), descriptor_count_(0), dynamic_descriptor_count_(0) {
+ uint32_t global_index = 0;
+ for (uint32_t i = 0; i < binding_count_; ++i) {
+ descriptor_count_ += p_create_info->pBindings[i].descriptorCount;
+ if (!binding_to_index_map_.emplace(p_create_info->pBindings[i].binding, i).second) {
+ log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
+ reinterpret_cast<uint64_t &>(layout_), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
+ "duplicated binding number in "
+ "VkDescriptorSetLayoutBinding");
+ }
+ binding_to_global_start_index_map_[p_create_info->pBindings[i].binding] = global_index;
+ global_index += p_create_info->pBindings[i].descriptorCount ? p_create_info->pBindings[i].descriptorCount - 1 : 0;
+ binding_to_global_end_index_map_[p_create_info->pBindings[i].binding] = global_index;
+ global_index++;
+ bindings_.push_back(new safe_VkDescriptorSetLayoutBinding(&p_create_info->pBindings[i]));
+ // In cases where we should ignore pImmutableSamplers make sure it's NULL
+ if ((p_create_info->pBindings[i].pImmutableSamplers) &&
+ ((p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) &&
+ (p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))) {
+ bindings_.back()->pImmutableSamplers = nullptr;
+ }
+ if (p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
+ p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
+ dynamic_descriptor_count_++;
+ }
+ }
+}
+cvdescriptorset::DescriptorSetLayout::~DescriptorSetLayout() {
+ for (auto binding : bindings_)
+ delete binding;
+}
+// put all bindings into the given set
+void cvdescriptorset::DescriptorSetLayout::FillBindingSet(std::unordered_set<uint32_t> *binding_set) const {
+ for (auto binding_index_pair : binding_to_index_map_)
+ binding_set->insert(binding_index_pair.first);
+}
+VkDescriptorSetLayoutBinding const *
+cvdescriptorset::DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t binding) const {
+ if (!binding_to_index_map_.count(binding))
+ return nullptr;
+ return bindings_.at(binding_to_index_map_.at(binding))->ptr();
+}
+VkDescriptorSetLayoutBinding const *
+cvdescriptorset::DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) const {
+ if (index >= bindings_.size())
+ return nullptr;
+ return bindings_[index]->ptr();
+}
+// Return descriptorCount for given binding, 0 if index is unavailable
+uint32_t cvdescriptorset::DescriptorSetLayout::GetDescriptorCountFromBinding(const uint32_t binding) const {
+ if (!binding_to_index_map_.count(binding))
+ return 0;
+ return bindings_.at(binding_to_index_map_.at(binding))->descriptorCount;
+}
+// Return descriptorCount for given index, 0 if index is unavailable
+uint32_t cvdescriptorset::DescriptorSetLayout::GetDescriptorCountFromIndex(const uint32_t index) const {
+ if (index >= bindings_.size())
+ return 0;
+ return bindings_[index]->descriptorCount;
+}
+// For the given binding, return descriptorType
+VkDescriptorType cvdescriptorset::DescriptorSetLayout::GetTypeFromBinding(const uint32_t binding) const {
+ assert(binding_to_index_map_.count(binding));
+ return bindings_.at(binding_to_index_map_.at(binding))->descriptorType;
+}
+// For the given index, return descriptorType
+VkDescriptorType cvdescriptorset::DescriptorSetLayout::GetTypeFromIndex(const uint32_t index) const {
+ assert(index < bindings_.size());
+ return bindings_[index]->descriptorType;
+}
+// For the given global index, return descriptorType
+// Currently just counting up through bindings_, may improve this in future
+VkDescriptorType cvdescriptorset::DescriptorSetLayout::GetTypeFromGlobalIndex(const uint32_t index) const {
+ uint32_t global_offset = 0;
+ for (auto binding : bindings_) {
+ global_offset += binding->descriptorCount;
+ if (index < global_offset)
+ return binding->descriptorType;
+ }
+ assert(0); // requested global index is out of bounds
+ return VK_DESCRIPTOR_TYPE_MAX_ENUM;
+}
+// For the given binding, return stageFlags
+VkShaderStageFlags cvdescriptorset::DescriptorSetLayout::GetStageFlagsFromBinding(const uint32_t binding) const {
+ assert(binding_to_index_map_.count(binding));
+ return bindings_.at(binding_to_index_map_.at(binding))->stageFlags;
+}
+// For the given binding, return start index
+uint32_t cvdescriptorset::DescriptorSetLayout::GetGlobalStartIndexFromBinding(const uint32_t binding) const {
+ assert(binding_to_global_start_index_map_.count(binding));
+ return binding_to_global_start_index_map_.at(binding);
+}
+// For the given binding, return end index
+uint32_t cvdescriptorset::DescriptorSetLayout::GetGlobalEndIndexFromBinding(const uint32_t binding) const {
+ assert(binding_to_global_end_index_map_.count(binding));
+ return binding_to_global_end_index_map_.at(binding);
+}
+// For given binding, return ptr to ImmutableSampler array
+VkSampler const *cvdescriptorset::DescriptorSetLayout::GetImmutableSamplerPtrFromBinding(const uint32_t binding) const {
+ assert(binding_to_index_map_.count(binding));
+ return bindings_.at(binding_to_index_map_.at(binding))->pImmutableSamplers;
+}
+// For given index, return ptr to ImmutableSampler array
+VkSampler const *cvdescriptorset::DescriptorSetLayout::GetImmutableSamplerPtrFromIndex(const uint32_t index) const {
+ assert(index < bindings_.size());
+ return bindings_[index]->pImmutableSamplers;
+}
+// If our layout is compatible with rh_ds_layout, return true,
+// else return false and fill in error_msg will description of what causes incompatibility
+bool cvdescriptorset::DescriptorSetLayout::IsCompatible(const DescriptorSetLayout *rh_ds_layout, std::string *error_msg) const {
+ // Trivial case
+ if (layout_ == rh_ds_layout->GetDescriptorSetLayout())
+ return true;
+ if (descriptor_count_ != rh_ds_layout->descriptor_count_) {
+ std::stringstream error_str;
+ error_str << "DescriptorSetLayout " << layout_ << " has " << descriptor_count_ << " descriptors, but DescriptorSetLayout "
+ << rh_ds_layout->GetDescriptorSetLayout() << " has " << rh_ds_layout->descriptor_count_ << " descriptors.";
+ *error_msg = error_str.str();
+ return false; // trivial fail case
+ }
+ // Descriptor counts match so need to go through bindings one-by-one
+ // and verify that type and stageFlags match
+ for (auto binding : bindings_) {
+ // TODO : Do we also need to check immutable samplers?
+ // VkDescriptorSetLayoutBinding *rh_binding;
+ // rh_ds_layout->FillDescriptorSetLayoutBindingStructFromBinding(binding->binding, rh_binding);
+ if (binding->descriptorCount != rh_ds_layout->GetDescriptorCountFromBinding(binding->binding)) {
+ std::stringstream error_str;
+ error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " has a descriptorCount of "
+ << binding->descriptorCount << " but binding " << binding->binding << " for DescriptorSetLayout "
+ << rh_ds_layout->GetDescriptorSetLayout() << " has a descriptorCount of "
+ << rh_ds_layout->GetDescriptorCountFromBinding(binding->binding);
+ *error_msg = error_str.str();
+ return false;
+ } else if (binding->descriptorType != rh_ds_layout->GetTypeFromBinding(binding->binding)) {
+ std::stringstream error_str;
+ error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " is type '"
+ << string_VkDescriptorType(binding->descriptorType) << "' but binding " << binding->binding
+ << " for DescriptorSetLayout " << rh_ds_layout->GetDescriptorSetLayout() << " is type '"
+ << string_VkDescriptorType(rh_ds_layout->GetTypeFromBinding(binding->binding)) << "'";
+ *error_msg = error_str.str();
+ return false;
+ } else if (binding->stageFlags != rh_ds_layout->GetStageFlagsFromBinding(binding->binding)) {
+ std::stringstream error_str;
+ error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " has stageFlags "
+ << binding->stageFlags << " but binding " << binding->binding << " for DescriptorSetLayout "
+ << rh_ds_layout->GetDescriptorSetLayout() << " has stageFlags "
+ << rh_ds_layout->GetStageFlagsFromBinding(binding->binding);
+ *error_msg = error_str.str();
+ return false;
+ }
+ }
+ return true;
+}
+
+bool cvdescriptorset::DescriptorSetLayout::IsNextBindingConsistent(const uint32_t binding) const {
+ if (!binding_to_index_map_.count(binding + 1))
+ return false;
+ auto type = bindings_.at(binding_to_index_map_.at(binding))->descriptorType;
+ auto stage_flags = bindings_.at(binding_to_index_map_.at(binding))->stageFlags;
+ auto immut_samp = bindings_.at(binding_to_index_map_.at(binding))->pImmutableSamplers ? true : false;
+ if ((type != bindings_.at(binding_to_index_map_.at(binding + 1))->descriptorType) ||
+ (stage_flags != bindings_.at(binding_to_index_map_.at(binding + 1))->stageFlags) ||
+ (immut_samp != (bindings_.at(binding_to_index_map_.at(binding + 1))->pImmutableSamplers ? true : false))) {
+ return false;
+ }
+ return true;
+}
+
+cvdescriptorset::DescriptorSet::DescriptorSet(const VkDescriptorSet set, const DescriptorSetLayout *layout,
+ const std::unordered_map<VkBuffer, BUFFER_NODE> *buffer_map,
+ const std::unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> *memory_map,
+ const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *buffer_view_map,
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map,
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map,
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map,
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map)
+ : some_update_(false), full_update_(false), set_(set), p_layout_(layout), buffer_map_(buffer_map), memory_map_(memory_map),
+ buffer_view_map_(buffer_view_map), sampler_map_(sampler_map), image_view_map_(image_view_map), image_map_(image_map),
+ image_to_swapchain_map_(image_to_swapchain_map), swapchain_map_(swapchain_map) {
+ // Foreach binding, create default descriptors of given type
+ for (uint32_t i = 0; i < p_layout_->GetBindingCount(); ++i) {
+ auto type = p_layout_->GetTypeFromIndex(i);
+ switch (type) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER: {
+ auto immut_sampler = p_layout_->GetImmutableSamplerPtrFromIndex(i);
+ for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di) {
+ if (immut_sampler)
+ descriptors_.push_back(std::unique_ptr<Descriptor>(new SamplerDescriptor(immut_sampler + di, sampler_map_)));
+ else
+ descriptors_.push_back(std::unique_ptr<Descriptor>(new SamplerDescriptor(sampler_map_)));
+ }
+ break;
+ }
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
+ auto immut = p_layout_->GetImmutableSamplerPtrFromIndex(i);
+ for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di) {
+ if (immut)
+ descriptors_.push_back(std::unique_ptr<Descriptor>(new ImageSamplerDescriptor(
+ immut + di, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_, sampler_map_)));
+ else
+ descriptors_.push_back(std::unique_ptr<Descriptor>(new ImageSamplerDescriptor(
+ image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_, sampler_map_)));
+ }
+ break;
+ }
+ // ImageDescriptors
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
+ descriptors_.push_back(std::unique_ptr<Descriptor>(
+ new ImageDescriptor(type, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_)));
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
+ descriptors_.push_back(std::unique_ptr<Descriptor>(new TexelDescriptor(type, buffer_view_map_)));
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
+ descriptors_.push_back(std::unique_ptr<Descriptor>(new BufferDescriptor(type, buffer_map_)));
+ break;
+ default:
+ break;
+ }
+ }
+}
+// For given global_index return bool of whether or not the underlying descriptor has been updated
+bool cvdescriptorset::DescriptorSet::IsUpdated(const uint32_t global_index) const {
+ if (global_index >= descriptors_.size() || !descriptors_.at(global_index))
+ return false;
+ return descriptors_.at(global_index)->updated;
+}
+// Is this sets underlying layout compatible with passed in layout according to "Pipeline Layout Compatibility" in spec?
+bool cvdescriptorset::DescriptorSet::IsCompatible(const DescriptorSetLayout *layout, std::string *error) const {
+ return layout->IsCompatible(p_layout_, error);
+}
+// Validate that the state of this set is appropriate for the given bindings and dynami_offsets at Draw time
+// This includes validating that all descriptors in the given bindings are updated,
+// that any update buffers are valid, and that any dynamic offsets are within the bounds of their buffers.
+// Return true if state is acceptable, or false and write an error message into error string
+bool cvdescriptorset::DescriptorSet::ValidateDrawState(const std::unordered_set<uint32_t> &bindings,
+ const std::vector<uint32_t> &dynamic_offsets, std::string *error) const {
+ for (auto binding : bindings) {
+ auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(binding);
+ if (descriptors_.at(start_idx)->IsImmutableSampler()) {
+ // Nothing to do for strictly immutable sampler
+ } else {
+ auto end_idx = p_layout_->GetGlobalEndIndexFromBinding(binding);
+ auto dyn_offset_index = 0;
+ for (uint32_t i = start_idx; i <= end_idx; ++i) {
+ if (!descriptors_.at(i)->updated) {
+ std::stringstream error_str;
+ error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
+ << " is being used in draw but has not been updated.";
+ *error = error_str.str();
+ return false;
+ } else {
+ if (GeneralBuffer == descriptors_.at(i)->GetClass()) {
+ // Verify that buffers are valid
+ auto buffer = static_cast<BufferDescriptor *>(descriptors_.at(i).get())->GetBuffer();
+ auto buffer_node = buffer_map_->find(buffer);
+ if (buffer_node == buffer_map_->end()) {
+ std::stringstream error_str;
+ error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
+ << " references invalid buffer " << buffer << ".";
+ *error = error_str.str();
+ return false;
+ } else {
+ auto mem_entry = memory_map_->find(buffer_node->second.mem);
+ if (mem_entry == memory_map_->end()) {
+ std::stringstream error_str;
+ error_str << "Descriptor in binding #" << binding << " at global descriptor index " << i
+ << " uses buffer " << buffer << " that references invalid memory "
+ << buffer_node->second.mem << ".";
+ *error = error_str.str();
+ return false;
+ }
+ }
+ if (descriptors_.at(i)->IsDynamic()) {
+ // Validate that dynamic offsets are within the buffer
+ auto buffer_size = buffer_node->second.createInfo.size;
+ auto range = static_cast<BufferDescriptor *>(descriptors_.at(i).get())->GetRange();
+ auto desc_offset = static_cast<BufferDescriptor *>(descriptors_.at(i).get())->GetOffset();
+ auto dyn_offset = dynamic_offsets[dyn_offset_index++];
+ if (VK_WHOLE_SIZE == range) {
+ if ((dyn_offset + desc_offset) > buffer_size) {
+ std::stringstream error_str;
+ error_str << "Dynamic descriptor in binding #" << binding << " at global descriptor index " << i
+ << " uses buffer " << buffer
+ << " with update range of VK_WHOLE_SIZE has dynamic offset " << dyn_offset
+ << " combined with offset " << desc_offset << " that oversteps the buffer size of "
+ << buffer_size << ".";
+ *error = error_str.str();
+ return false;
+ }
+ } else {
+ if ((dyn_offset + desc_offset + range) > buffer_size) {
+ std::stringstream error_str;
+ error_str << "Dynamic descriptor in binding #" << binding << " at global descriptor index " << i
+ << " uses buffer " << buffer << " with dynamic offset " << dyn_offset
+ << " combined with offset " << desc_offset << " and range " << range
+ << " that oversteps the buffer size of " << buffer_size << ".";
+ *error = error_str.str();
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+// For given bindings, place any update buffers or images into the passed-in unordered_sets
+uint32_t cvdescriptorset::DescriptorSet::GetStorageUpdates(const std::unordered_set<uint32_t> &bindings,
+ std::unordered_set<VkBuffer> *buffer_set,
+ std::unordered_set<VkImageView> *image_set) const {
+ auto num_updates = 0;
+ for (auto binding : bindings) {
+ auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(binding);
+ if (descriptors_.at(start_idx)->IsStorage()) {
+ if (Image == descriptors_.at(start_idx)->descriptor_class) {
+ for (uint32_t i = 0; i < p_layout_->GetDescriptorCountFromBinding(binding); ++i) {
+ if (descriptors_.at(start_idx + i)->updated) {
+ image_set->insert(static_cast<ImageDescriptor *>(descriptors_.at(start_idx + i).get())->GetImageView());
+ num_updates++;
+ }
+ }
+ } else if (TexelBuffer == descriptors_.at(start_idx)->descriptor_class) {
+ for (uint32_t i = 0; i < p_layout_->GetDescriptorCountFromBinding(binding); ++i) {
+ if (descriptors_.at(start_idx + i)->updated) {
+ auto bufferview = static_cast<TexelDescriptor *>(descriptors_.at(start_idx + i).get())->GetBufferView();
+ auto buffer = buffer_view_map_->at(bufferview).buffer;
+ buffer_set->insert(buffer);
+ num_updates++;
+ }
+ }
+ } else if (GeneralBuffer == descriptors_.at(start_idx)->descriptor_class) {
+ for (uint32_t i = 0; i < p_layout_->GetDescriptorCountFromBinding(binding); ++i) {
+ if (descriptors_.at(start_idx + i)->updated) {
+ buffer_set->insert(static_cast<BufferDescriptor *>(descriptors_.at(start_idx + i).get())->GetBuffer());
+ num_updates++;
+ }
+ }
+ }
+ }
+ }
+ return num_updates;
+}
+// This is a special case for compute shaders that should eventually be removed once we have proper valid binding info for compute
+// case
+uint32_t cvdescriptorset::DescriptorSet::GetAllStorageUpdates(std::unordered_set<VkBuffer> *buffer_set,
+ std::unordered_set<VkImageView> *image_set) const {
+ std::unordered_set<uint32_t> binding_set;
+ p_layout_->FillBindingSet(&binding_set);
+ return GetStorageUpdates(binding_set, buffer_set, image_set);
+}
+// Starting at given current_binding with binding_remaining descriptors, parse over update_count
+// descriptor updates and verify that for any binding boundaries that are crossed, the next binding(s) are all consistent
+// Consistency means that their type, stage flags, and whether or not they use immutable samplers matches
+// If so, return true. If not, fill in error_msg and return false
+bool cvdescriptorset::DescriptorSet::VerifyUpdateConsistency(uint32_t current_binding, uint32_t binding_remaining,
+ uint32_t update_count, const char *type,
+ std::string *error_msg) const {
+ // Verify consecutive bindings match (if needed)
+ auto orig_binding = current_binding;
+ while (update_count > binding_remaining) { // While our updates overstep current binding
+ // Verify next consecutive binding matches type, stage flags & immutable sampler use
+ if (!p_layout_->IsNextBindingConsistent(current_binding++)) {
+ std::stringstream error_str;
+ error_str << "Attempting " << type << " descriptor set " << set_ << " binding #" << orig_binding << " with #"
+ << update_count << " descriptors being updated but this update oversteps the bounds of this binding and then "
+ "next binding is not consistent with current binding so this update is invalid.";
+ *error_msg = error_str.str();
+ return false;
+ }
+ // For sake of this check consider the bindings updated and advance to next binding
+ update_count -= binding_remaining;
+ binding_remaining = p_layout_->GetDescriptorCountFromBinding(current_binding);
+ }
+ return true;
+}
+// Perform write update in given update struct
+// If an error occurs, return false and fill in details in error_msg string
+bool cvdescriptorset::DescriptorSet::WriteUpdate(debug_report_data *report_data, const VkWriteDescriptorSet *update,
+ std::string *error_msg) {
+ auto num_updates = 0;
+ // Verify dst binding exists
+ if (!p_layout_->HasBinding(update->dstBinding)) {
+ std::stringstream error_str;
+ error_str << "DescriptorSet " << set_ << " does not have binding " << update->dstBinding << ".";
+ *error_msg = error_str.str();
+ return false;
+ } else {
+ // We know that binding is valid, verify update and do update on each descriptor
+ auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding) + update->dstArrayElement;
+ auto type = p_layout_->GetTypeFromBinding(update->dstBinding);
+ if (type != update->descriptorType) {
+ std::stringstream error_str;
+ error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with type "
+ << string_VkDescriptorType(type) << " but update type is " << string_VkDescriptorType(update->descriptorType);
+ *error_msg = error_str.str();
+ return false;
+ }
+ if ((start_idx + update->descriptorCount) > p_layout_->GetTotalDescriptorCount()) {
+ std::stringstream error_str;
+ error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+ << p_layout_->GetTotalDescriptorCount() << " total descriptors but update of " << update->descriptorCount
+ << " descriptors starting at binding offset of "
+ << p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding)
+ << " combined with update array element offset of " << update->dstArrayElement
+ << " oversteps the size of this descriptor set.";
+ *error_msg = error_str.str();
+ return false;
+ }
+ // Verify consecutive bindings match (if needed)
+ auto binding_remaining = p_layout_->GetDescriptorCountFromBinding(update->dstBinding) - update->dstArrayElement;
+ if (!VerifyUpdateConsistency(update->dstBinding, binding_remaining, update->descriptorCount, "write update to", error_msg))
+ return false;
+ // Update is within bounds and consistent so perform update
+ for (uint32_t di = 0; di < update->descriptorCount; ++di) {
+ if (!descriptors_[start_idx + di]->WriteUpdate(update, di, error_msg)) {
+ std::stringstream error_str;
+ error_str << "Write update to descriptor at global index " << start_idx + di << " within set " << set_
+ << " binding #" << update->dstBinding << " failed with error message: " << error_msg->c_str();
+ *error_msg = error_str.str();
+ return false;
+ }
+ ++num_updates;
+ }
+ }
+ if (num_updates != 0) {
+ some_update_ = true;
+ full_update_ = (descriptors_.size() == num_updates);
+ }
+ return true;
+}
+// Copy update
+bool cvdescriptorset::DescriptorSet::CopyUpdate(debug_report_data *report_data, const VkCopyDescriptorSet *update,
+ const DescriptorSet *src_set, std::string *error) {
+ auto num_updates = 0;
+ if (!p_layout_->HasBinding(update->dstBinding)) {
+ std::stringstream error_str;
+ error_str << "DescriptorSet " << set_ << " does not have copy update dest binding of " << update->dstBinding << ".";
+ *error = error_str.str();
+ return false;
+ }
+ if (!src_set->HasBinding(update->srcBinding)) {
+ std::stringstream error_str;
+ error_str << "DescriptorSet " << set_ << " does not have copy update src binding of " << update->srcBinding << ".";
+ *error = error_str.str();
+ return false;
+ }
+ // src & dst set bindings are valid
+ // Check bounds of src & dst
+ auto src_start_idx = src_set->GetGlobalStartIndexFromBinding(update->srcBinding) + update->srcArrayElement;
+ if ((src_start_idx + update->descriptorCount) > src_set->GetTotalDescriptorCount()) {
+ // SRC update out of bounds
+ std::stringstream error_str;
+ error_str << "Attempting copy update from descriptorSet " << update->srcSet << " binding#" << update->srcBinding
+ << " with offset index of " << src_set->GetGlobalStartIndexFromBinding(update->srcBinding)
+ << " plus update array offset of " << update->srcArrayElement << " and update of " << update->descriptorCount
+ << " descriptors oversteps total number of descriptors in set: " << src_set->GetTotalDescriptorCount() << ".";
+ *error = error_str.str();
+ return false;
+ }
+ auto dst_start_idx = p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding) + update->dstArrayElement;
+ if ((dst_start_idx + update->descriptorCount) > p_layout_->GetTotalDescriptorCount()) {
+ // DST update out of bounds
+ std::stringstream error_str;
+ error_str << "Attempting copy update to descriptorSet " << set_ << " binding#" << update->dstBinding
+ << " with offset index of " << p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding)
+ << " plus update array offset of " << update->dstArrayElement << " and update of " << update->descriptorCount
+ << " descriptors oversteps total number of descriptors in set: " << p_layout_->GetTotalDescriptorCount() << ".";
+ *error = error_str.str();
+ return false;
+ }
+ // Check that types match
+ auto src_type = src_set->GetTypeFromBinding(update->srcBinding);
+ auto dst_type = p_layout_->GetTypeFromBinding(update->dstBinding);
+ if (src_type != dst_type) {
+ std::stringstream error_str;
+ error_str << "Attempting copy update to descriptorSet " << set_ << " binding #" << update->dstBinding << " with type "
+ << string_VkDescriptorType(dst_type) << " from descriptorSet " << src_set->GetSet() << " binding #"
+ << update->srcBinding << " with type " << string_VkDescriptorType(src_type) << ". Types do not match.";
+ *error = error_str.str();
+ return false;
+ }
+ // Verify consistency of src & dst bindings if update crosses binding boundaries
+ auto src_binding_remaining = src_set->GetDescriptorCountFromBinding(update->srcBinding) - update->srcArrayElement;
+ auto dst_binding_remaining = p_layout_->GetDescriptorCountFromBinding(update->dstBinding) - update->dstArrayElement;
+ if ((!VerifyUpdateConsistency(update->srcBinding, src_binding_remaining, update->descriptorCount, "copy update from", error)) ||
+ (!VerifyUpdateConsistency(update->dstBinding, dst_binding_remaining, update->descriptorCount, "copy update to", error))) {
+ return false;
+ }
+ // Update parameters all look good so perform update
+ for (uint32_t di = 0; di < update->descriptorCount; ++di) {
+ if (!descriptors_.at(dst_start_idx)->CopyUpdate(src_set->descriptors_.at(src_start_idx).get(), error))
+ return false;
+ ++num_updates;
+ }
+ if (num_updates != 0) {
+ some_update_ = true;
+ full_update_ = (descriptors_.size() == num_updates);
+ }
+ return true;
+}
+cvdescriptorset::SamplerDescriptor::SamplerDescriptor(
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map)
+ : sampler_(VK_NULL_HANDLE), immutable_(false), sampler_map_(sampler_map) {
+ updated = false;
+ descriptor_class = PlainSampler;
+};
+
+cvdescriptorset::SamplerDescriptor::SamplerDescriptor(
+ const VkSampler *immut, const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map)
+ : sampler_(VK_NULL_HANDLE), immutable_(false), sampler_map_(sampler_map) {
+ updated = false;
+ descriptor_class = PlainSampler;
+ if (immut) {
+ sampler_ = *immut;
+ immutable_ = true;
+ updated = true;
+ }
+}
+bool cvdescriptorset::ValidateSampler(const VkSampler sampler,
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map) {
+ return (sampler_map->count(sampler) != 0) ? true : false;
+}
+bool cvdescriptorset::ValidateImageUpdate(const VkImageView image_view, const VkImageLayout image_layout,
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map,
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map,
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map,
+ std::string *error) {
+ auto image_pair = image_view_map->find(image_view);
+ if (image_pair == image_view_map->end()) {
+ std::stringstream error_str;
+ error_str << "Invalid VkImageView: " << image_view;
+ *error = error_str.str();
+ return false;
+ } else {
+ // Validate that imageLayout is compatible with aspect_mask and image format
+ VkImageAspectFlags aspect_mask = image_pair->second.subresourceRange.aspectMask;
+ VkImage image = image_pair->second.image;
+ VkFormat format = VK_FORMAT_MAX_ENUM;
+ auto img_pair = image_map->find(image);
+ if (img_pair != image_map->end()) {
+ format = img_pair->second.createInfo.format;
+ } else {
+ // Also need to check the swapchains.
+ auto swapchain_pair = image_to_swapchain_map->find(image);
+ if (swapchain_pair != image_to_swapchain_map->end()) {
+ VkSwapchainKHR swapchain = swapchain_pair->second;
+ auto swapchain_pair = swapchain_map->find(swapchain);
+ if (swapchain_pair != swapchain_map->end()) {
+ format = swapchain_pair->second->createInfo.imageFormat;
+ }
+ }
+ }
+ if (format == VK_FORMAT_MAX_ENUM) {
+ std::stringstream error_str;
+ error_str << "Invalid image (" << image << ") in imageView (" << image_view << ").";
+ *error = error_str.str();
+ return false;
+ } else {
+ bool ds = vk_format_is_depth_or_stencil(format);
+ switch (image_layout) {
+ case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+ // Only Color bit must be set
+ if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
+ std::stringstream error_str;
+ error_str << "ImageView (" << image_view << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but does "
+ "not have VK_IMAGE_ASPECT_COLOR_BIT set.";
+ *error = error_str.str();
+ return false;
+ }
+ // format must NOT be DS
+ if (ds) {
+ std::stringstream error_str;
+ error_str << "ImageView (" << image_view
+ << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but the image format is "
+ << string_VkFormat(format) << " which is not a color format.";
+ *error = error_str.str();
+ return false;
+ }
+ break;
+ case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
+ case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
+ // Depth or stencil bit must be set, but both must NOT be set
+ if (aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) {
+ if (aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) {
+ // both must NOT be set
+ std::stringstream error_str;
+ error_str << "ImageView (" << image_view << ") has both STENCIL and DEPTH aspects set";
+ *error = error_str.str();
+ return false;
+ }
+ } else if (!(aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ // Neither were set
+ std::stringstream error_str;
+ error_str << "ImageView (" << image_view << ") has layout " << string_VkImageLayout(image_layout)
+ << " but does not have STENCIL or DEPTH aspects set";
+ *error = error_str.str();
+ return false;
+ }
+ // format must be DS
+ if (!ds) {
+ std::stringstream error_str;
+ error_str << "ImageView (" << image_view << ") has layout " << string_VkImageLayout(image_layout)
+ << " but the image format is " << string_VkFormat(format) << " which is not a depth/stencil format.";
+ *error = error_str.str();
+ return false;
+ }
+ break;
+ default:
+ // anything to check for other layouts?
+ break;
+ }
+ }
+ }
+ return true;
+}
+bool cvdescriptorset::SamplerDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index, std::string *error) {
+ if (!immutable_) {
+ if (!ValidateSampler(update->pImageInfo[index].sampler, sampler_map_)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to sampler descriptor with invalid sampler: " << update->pImageInfo[index].sampler
+ << ".";
+ *error = error_str.str();
+ return false;
+ }
+ sampler_ = update->pImageInfo[index].sampler;
+ } else {
+ if (!ValidateSampler(sampler_, sampler_map_)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to immutable sampler descriptor which has invalid immutable sampler: " << sampler_
+ << ".";
+ *error = error_str.str();
+ return false;
+ }
+ // TODO : Do we want a way to warn here in case of updating immutable sampler (which can't be updated)?
+ }
+ updated = true;
+ return true;
+}
+
+bool cvdescriptorset::SamplerDescriptor::CopyUpdate(const Descriptor *src, std::string *error) {
+ if (!immutable_) {
+ auto update_sampler = static_cast<const SamplerDescriptor *>(src)->sampler_;
+ if (!ValidateSampler(update_sampler, sampler_map_)) {
+ std::stringstream error_str;
+ error_str << "Attempted copy update to sampler descriptor with invalid sampler: " << update_sampler << ".";
+ *error = error_str.str();
+ return false;
+ }
+ sampler_ = update_sampler;
+ } else {
+ if (!ValidateSampler(sampler_, sampler_map_)) {
+ std::stringstream error_str;
+ error_str << "Attempted copy update to immutable sampler descriptor which has invalid immutable sampler: " << sampler_
+ << ".";
+ *error = error_str.str();
+ return false;
+ }
+ // TODO : Do we want a way to warn here in case of updating immutable sampler (which can't be updated)?
+ }
+ updated = true;
+ return true;
+}
+cvdescriptorset::ImageSamplerDescriptor::ImageSamplerDescriptor(
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map,
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map,
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map,
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map)
+ : sampler_(VK_NULL_HANDLE), immutable_(false), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED),
+ sampler_map_(sampler_map), image_view_map_(image_view_map), image_map_(image_map),
+ image_to_swapchain_map_(image_to_swapchain_map), swapchain_map_(swapchain_map) {
+ updated = false;
+ descriptor_class = ImageSampler;
+}
+
+cvdescriptorset::ImageSamplerDescriptor::ImageSamplerDescriptor(
+ const VkSampler *immut, const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map,
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map,
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map,
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map)
+ : sampler_(VK_NULL_HANDLE), immutable_(true), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED),
+ sampler_map_(sampler_map), image_view_map_(image_view_map), image_map_(image_map),
+ image_to_swapchain_map_(image_to_swapchain_map), swapchain_map_(swapchain_map) {
+ updated = false;
+ descriptor_class = ImageSampler;
+ if (immut) {
+ sampler_ = *immut;
+ immutable_ = true;
+ updated = true;
+ }
+}
+bool cvdescriptorset::ImageSamplerDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index,
+ std::string *error) {
+ // First check sampler
+ if (!immutable_) {
+ if (!ValidateSampler(update->pImageInfo[index].sampler, sampler_map_)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to combined image sampler descriptor with invalid sampler: "
+ << update->pImageInfo[index].sampler << ".";
+ *error = error_str.str();
+ return false;
+ }
+ sampler_ = update->pImageInfo[index].sampler;
+ } else {
+ if (!ValidateSampler(sampler_, sampler_map_)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to combined image sampler descriptor with immutable sampler which has invalid "
+ "immutable sampler: "
+ << sampler_ << ".";
+ *error = error_str.str();
+ return false;
+ }
+ // TODO : Do we want a way to warn here in case of updating immutable sampler (which can't be updated)?
+ }
+ // Now validate images
+ auto image_view = update->pImageInfo[index].imageView;
+ auto image_layout = update->pImageInfo[index].imageLayout;
+ if (!ValidateImageUpdate(image_view, image_layout, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_,
+ error)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to combined image sampler descriptor failed due to: " << error->c_str();
+ *error = error_str.str();
+ return false;
+ }
+ updated = true;
+ image_view_ = image_view;
+ image_layout_ = image_layout;
+ return true;
+}
+
+bool cvdescriptorset::ImageSamplerDescriptor::CopyUpdate(const Descriptor *src, std::string *error) {
+ if (!immutable_) {
+ auto update_sampler = static_cast<const ImageSamplerDescriptor *>(src)->sampler_;
+ if (!ValidateSampler(update_sampler, sampler_map_)) {
+ std::stringstream error_str;
+ error_str << "Attempted copy update to combined image sampler descriptor with invalid sampler: " << update_sampler
+ << ".";
+ *error = error_str.str();
+ return false;
+ }
+ sampler_ = update_sampler;
+ } else {
+ if (!ValidateSampler(sampler_, sampler_map_)) {
+ std::stringstream error_str;
+ error_str << "Attempted copy update to combined image sampler descriptor with immutable sampler that has invalid "
+ "immutable sampler: "
+ << sampler_ << ".";
+ *error = error_str.str();
+ return false;
+ }
+ // TODO : Do we want a way to warn here in case of updating immutable sampler (which can't be updated)?
+ }
+ // Now validate images
+ auto image_view = static_cast<const ImageSamplerDescriptor *>(src)->image_view_;
+ auto image_layout = static_cast<const ImageSamplerDescriptor *>(src)->image_layout_;
+ if (!ValidateImageUpdate(image_view, image_layout, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_,
+ error)) {
+ std::stringstream error_str;
+ error_str << "Attempted copy update to combined image sampler descriptor failed due to: " << error->c_str();
+ *error = error_str.str();
+ return false;
+ }
+ updated = true;
+ image_view_ = image_view;
+ image_layout_ = image_layout;
+ return true;
+}
+
+cvdescriptorset::ImageDescriptor::ImageDescriptor(const VkDescriptorType type,
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map,
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map,
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map)
+ : storage_(false), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED), image_view_map_(image_view_map),
+ image_map_(image_map), image_to_swapchain_map_(image_to_swapchain_map), swapchain_map_(swapchain_map) {
+ updated = false;
+ descriptor_class = Image;
+ if (VK_DESCRIPTOR_TYPE_STORAGE_IMAGE == type)
+ storage_ = true;
+};
+
+bool cvdescriptorset::ImageDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index, std::string *error) {
+ // First validate that the write update is valid
+ auto image_view = update->pImageInfo[index].imageView;
+ auto image_layout = update->pImageInfo[index].imageLayout;
+ if (!ValidateImageUpdate(image_view, image_layout, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_,
+ error)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to image descriptor failed due to: " << error->c_str();
+ *error = error_str.str();
+ return false;
+ }
+ // Update is clean so process it
+ updated = true;
+ image_view_ = image_view;
+ image_layout_ = image_layout;
+ return true;
+}
+
+bool cvdescriptorset::ImageDescriptor::CopyUpdate(const Descriptor *src, std::string *error) {
+ // First validate update
+ auto image_view = static_cast<const ImageDescriptor *>(src)->image_view_;
+ auto image_layout = static_cast<const ImageDescriptor *>(src)->image_layout_;
+ if (!ValidateImageUpdate(image_view, image_layout, image_view_map_, image_map_, image_to_swapchain_map_, swapchain_map_,
+ error)) {
+ std::stringstream error_str;
+ error_str << "Attempted copy update to image descriptor failed due to: " << error->c_str();
+ *error = error_str.str();
+ return false;
+ }
+ updated = true;
+ image_view_ = image_view;
+ image_layout_ = image_layout;
+ return true;
+}
+
+cvdescriptorset::BufferDescriptor::BufferDescriptor(const VkDescriptorType type,
+ const std::unordered_map<VkBuffer, BUFFER_NODE> *buffer_map)
+ : storage_(false), dynamic_(false), buffer_(VK_NULL_HANDLE), offset_(0), range_(0), buffer_map_(buffer_map) {
+ updated = false;
+ descriptor_class = GeneralBuffer;
+ if (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC == type) {
+ dynamic_ = true;
+ } else if (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER == type) {
+ storage_ = true;
+ } else if (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC == type) {
+ dynamic_ = true;
+ storage_ = true;
+ }
+}
+bool cvdescriptorset::BufferDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index, std::string *error) {
+ // First validate bufferinfo
+ auto buffer = update->pBufferInfo[index].buffer;
+ if (!buffer_map_->count(buffer)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to buffer descriptor with invalid buffer: " << buffer;
+ *error = error_str.str();
+ return false;
+ }
+ updated = true;
+ buffer_ = buffer;
+ offset_ = update->pBufferInfo[index].offset;
+ range_ = update->pBufferInfo[index].range;
+ return true;
+}
+
+bool cvdescriptorset::BufferDescriptor::CopyUpdate(const Descriptor *src, std::string *error) {
+ // First validate bufferinfo
+ auto buffer = static_cast<const BufferDescriptor *>(src)->buffer_;
+ if (!buffer_map_->count(buffer)) {
+ std::stringstream error_str;
+ error_str << "Attempted copy update to buffer descriptor with invalid buffer: " << buffer;
+ *error = error_str.str();
+ return false;
+ }
+ updated = true;
+ buffer_ = buffer;
+ offset_ = static_cast<const BufferDescriptor *>(src)->offset_;
+ range_ = static_cast<const BufferDescriptor *>(src)->range_;
+ return true;
+}
+
+cvdescriptorset::TexelDescriptor::TexelDescriptor(const VkDescriptorType type,
+ const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *buffer_view_map)
+ : buffer_view_(VK_NULL_HANDLE), storage_(false), buffer_view_map_(buffer_view_map) {
+ updated = false;
+ descriptor_class = TexelBuffer;
+ if (VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER == type)
+ storage_ = true;
+};
+bool cvdescriptorset::TexelDescriptor::WriteUpdate(const VkWriteDescriptorSet *update, const uint32_t index, std::string *error) {
+ // First validate buffer view
+ auto buffer_view = update->pTexelBufferView[index];
+ if (!buffer_view_map_->count(buffer_view)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to texel buffer descriptor with invalid buffer view: " << buffer_view;
+ *error = error_str.str();
+ return false;
+ }
+ updated = true;
+ buffer_view_ = buffer_view;
+ return true;
+}
+
+bool cvdescriptorset::TexelDescriptor::CopyUpdate(const Descriptor *src, std::string *error) {
+ // First validate buffer view
+ auto buffer_view = static_cast<const TexelDescriptor *>(src)->buffer_view_;
+ if (!buffer_view_map_->count(buffer_view)) {
+ std::stringstream error_str;
+ error_str << "Attempted write update to texel buffer descriptor with invalid buffer view: " << buffer_view;
+ *error = error_str.str();
+ return false;
+ }
+ updated = true;
+ buffer_view_ = buffer_view;
+ return true;
+}
\ No newline at end of file
diff --git a/layers/descriptor_sets.h b/layers/descriptor_sets.h
index 3bd8bc6..fb08e3d 100644
--- a/layers/descriptor_sets.h
+++ b/layers/descriptor_sets.h
@@ -41,12 +41,15 @@
#define NOEXCEPT
#endif
-#pragma once
#include "core_validation_error_enums.h"
+#include "core_validation_types.h"
#include "vk_layer_logging.h"
+#include "vk_layer_utils.h"
#include "vk_safe_struct.h"
#include "vulkan/vk_layer.h"
+#include <memory>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
// Descriptor Data structures
@@ -78,195 +81,287 @@
* the GlobalStartIndex of pBinding[1] will be 10 where 0-9 are the global indices
* for pBinding[0].
*/
+namespace cvdescriptorset {
class DescriptorSetLayout {
public:
// Constructors and destructor
- DescriptorSetLayout();
DescriptorSetLayout(debug_report_data *report_data, const VkDescriptorSetLayoutCreateInfo *p_create_info,
const VkDescriptorSetLayout layout);
~DescriptorSetLayout();
// Straightforward Get functions
- VkDescriptorSetLayout GetDescriptorSetLayout() { return layout_; };
- uint32_t GetTotalDescriptorCount() { return descriptor_count_; };
- uint32_t GetDynamicDescriptorCount() { return dynamic_descriptor_count_; };
- uint32_t GetBindingCount() { return binding_count_; };
+ VkDescriptorSetLayout GetDescriptorSetLayout() const { return layout_; };
+ uint32_t GetTotalDescriptorCount() const { return descriptor_count_; };
+ uint32_t GetDynamicDescriptorCount() const { return dynamic_descriptor_count_; };
+ uint32_t GetBindingCount() const { return binding_count_; };
+ // Fill passed-in set with bindings
+ void FillBindingSet(std::unordered_set<uint32_t> *) const;
// Return true if given binding is present in this layout
- bool HasBinding(const uint32_t binding) { return binding_to_index_map_.count(binding) > 0; };
+ bool HasBinding(const uint32_t binding) const { return binding_to_index_map_.count(binding) > 0; };
// Return true if this layout is compatible with passed in layout,
// else return false and update error_msg with description of incompatibility
- bool IsCompatible(DescriptorSetLayout *, string *error_msg);
+ bool IsCompatible(const DescriptorSetLayout *, std::string *) const;
+ // Return true if binding 1 beyond given exists and has same type, stageFlags & immutable sampler use
+ bool IsNextBindingConsistent(const uint32_t) const;
// Various Get functions that can either be passed a binding#, which will
// be automatically translated into the appropriate index from the original
// pBindings array, or the index# can be passed in directly
- VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t);
- VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t);
- uint32_t GetDescriptorCountFromBinding(const uint32_t);
- uint32_t GetDescriptorCountFromIndex(const uint32_t);
- VkDescriptorType GetTypeFromBinding(const uint32_t);
- VkDescriptorType GetTypeFromIndex(const uint32_t);
- VkDescriptorType GetTypeFromGlobalIndex(const uint32_t);
- VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t);
- VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t);
+ VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t) const;
+ VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t) const;
+ uint32_t GetDescriptorCountFromBinding(const uint32_t) const;
+ uint32_t GetDescriptorCountFromIndex(const uint32_t) const;
+ VkDescriptorType GetTypeFromBinding(const uint32_t) const;
+ VkDescriptorType GetTypeFromIndex(const uint32_t) const;
+ VkDescriptorType GetTypeFromGlobalIndex(const uint32_t) const;
+ VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t) const;
+ VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t) const;
+ VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t) const;
// For a particular binding, get the global index
- uint32_t GetGlobalStartIndexFromBinding(const uint32_t);
- uint32_t GetGlobalEndIndexFromBinding(const uint32_t);
+ uint32_t GetGlobalStartIndexFromBinding(const uint32_t) const;
+ uint32_t GetGlobalEndIndexFromBinding(const uint32_t) const;
private:
VkDescriptorSetLayout layout_;
- unordered_map<uint32_t, uint32_t> binding_to_index_map_;
- unordered_map<uint32_t, uint32_t> binding_to_global_start_index_map_;
- unordered_map<uint32_t, uint32_t> binding_to_global_end_index_map_;
- //VkDescriptorSetLayoutCreateFlags flags_;
+ std::unordered_map<uint32_t, uint32_t> binding_to_index_map_;
+ std::unordered_map<uint32_t, uint32_t> binding_to_global_start_index_map_;
+ std::unordered_map<uint32_t, uint32_t> binding_to_global_end_index_map_;
+ // VkDescriptorSetLayoutCreateFlags flags_;
uint32_t binding_count_; // # of bindings in this layout
- vector<safe_VkDescriptorSetLayoutBinding *> bindings_;
+ std::vector<safe_VkDescriptorSetLayoutBinding *> bindings_;
uint32_t descriptor_count_; // total # descriptors in this layout
uint32_t dynamic_descriptor_count_;
};
-DescriptorSetLayout::DescriptorSetLayout()
- : layout_(VK_NULL_HANDLE), /*flags_(0),*/ binding_count_(0), descriptor_count_(0), dynamic_descriptor_count_(0) {}
-// Construct DescriptorSetLayout instance from given create info
-DescriptorSetLayout::DescriptorSetLayout(debug_report_data *report_data, const VkDescriptorSetLayoutCreateInfo *p_create_info,
- const VkDescriptorSetLayout layout)
- : layout_(layout), /*flags_(p_create_info->flags),*/ binding_count_(p_create_info->bindingCount), descriptor_count_(0),
- dynamic_descriptor_count_(0) {
- uint32_t global_index = 0;
- for (uint32_t i = 0; i < binding_count_; ++i) {
- descriptor_count_ += p_create_info->pBindings[i].descriptorCount;
- if (!binding_to_index_map_.emplace(p_create_info->pBindings[i].binding, i).second) {
- log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
- reinterpret_cast<uint64_t &>(layout_), __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
- "duplicated binding number in "
- "VkDescriptorSetLayoutBinding");
- }
- binding_to_global_start_index_map_[p_create_info->pBindings[i].binding] = global_index;
- global_index += p_create_info->pBindings[i].descriptorCount ? p_create_info->pBindings[i].descriptorCount - 1 : 0;
- binding_to_global_end_index_map_[p_create_info->pBindings[i].binding] = global_index;
- global_index++;
- bindings_.push_back(new safe_VkDescriptorSetLayoutBinding(&p_create_info->pBindings[i]));
- // In cases where we should ignore pImmutableSamplers make sure it's NULL
- if ((p_create_info->pBindings[i].pImmutableSamplers) &&
- ((p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_SAMPLER) &&
- (p_create_info->pBindings[i].descriptorType != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))) {
- bindings_.back()->pImmutableSamplers = nullptr;
- }
- if (p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
- p_create_info->pBindings[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
- dynamic_descriptor_count_++;
- }
- }
-}
-DescriptorSetLayout::~DescriptorSetLayout() {
- for (auto binding : bindings_)
- delete binding;
+
+/*
+ * Descriptor classes
+ * Descriptor is an abstract base class from which 5 separate descriptor types are derived.
+ * This allows the WriteUpdate() and CopyUpdate() operations to be specialized per
+ * descriptor type, but all descriptors in a set can be accessed via the common Descriptor*.
+ */
+
+// Slightly broader than type, each c++ "class" will has a corresponding "DescriptorClass"
+typedef enum _DescriptorClass { PlainSampler, ImageSampler, Image, TexelBuffer, GeneralBuffer } DescriptorClass;
+
+class Descriptor {
+ public:
+ virtual ~Descriptor(){};
+ virtual bool WriteUpdate(const VkWriteDescriptorSet *, const uint32_t, std::string *) = 0;
+ virtual bool CopyUpdate(const Descriptor *, std::string *) = 0;
+ virtual DescriptorClass GetClass() const { return descriptor_class; };
+ // Special fast-path check for SamplerDescriptors that are immutable
+ virtual bool IsImmutableSampler() const { return false; };
+ // Check for dynamic descriptor type
+ virtual bool IsDynamic() const { return false; };
+ // Check for storage descriptor type
+ virtual bool IsStorage() const { return false; };
+ bool updated; // Has descriptor been updated?
+ DescriptorClass descriptor_class;
+};
+// Shared helper functions - These are useful because the shared sampler image descriptor type
+// performs common functions with both sampler and image descriptors so they can share their common functions
+bool ValidateSampler(const VkSampler, const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *);
+bool ValidateImageUpdate(const VkImageView, const VkImageLayout, const std::unordered_map<VkImageView, VkImageViewCreateInfo> *,
+ const std::unordered_map<VkImage, IMAGE_NODE> *, const std::unordered_map<VkImage, VkSwapchainKHR> *,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *, std::string *);
+
+class SamplerDescriptor : public Descriptor {
+ public:
+ SamplerDescriptor(const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *);
+ SamplerDescriptor(const VkSampler *, const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *);
+ bool WriteUpdate(const VkWriteDescriptorSet *, const uint32_t, std::string *) override;
+ bool CopyUpdate(const Descriptor *, std::string *) override;
+ virtual bool IsImmutableSampler() const override { return immutable_; };
+
+ private:
+ // bool ValidateSampler(const VkSampler) const;
+ VkSampler sampler_;
+ bool immutable_;
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map_;
};
-VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t binding) {
- if (!binding_to_index_map_.count(binding))
- return nullptr;
- return bindings_[binding_to_index_map_[binding]]->ptr();
-}
-VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) {
- if (index >= bindings_.size())
- return nullptr;
- return bindings_[index]->ptr();
-}
-// Return descriptorCount for given binding, 0 if index is unavailable
-uint32_t DescriptorSetLayout::GetDescriptorCountFromBinding(const uint32_t binding) {
- if (!binding_to_index_map_.count(binding))
- return 0;
- return bindings_[binding_to_index_map_[binding]]->descriptorCount;
-}
-// Return descriptorCount for given index, 0 if index is unavailable
-uint32_t DescriptorSetLayout::GetDescriptorCountFromIndex(const uint32_t index) {
- if (index >= bindings_.size())
- return 0;
- return bindings_[index]->descriptorCount;
-}
-// For the given binding, return descriptorType
-VkDescriptorType DescriptorSetLayout::GetTypeFromBinding(const uint32_t binding) {
- assert(binding_to_index_map_.count(binding));
- return bindings_[binding_to_index_map_[binding]]->descriptorType;
-}
-// For the given index, return descriptorType
-VkDescriptorType DescriptorSetLayout::GetTypeFromIndex(const uint32_t index) {
- assert(index < bindings_.size());
- return bindings_[index]->descriptorType;
-}
-// For the given global index, return descriptorType
-// Currently just counting up through bindings_, may improve this in future
-VkDescriptorType DescriptorSetLayout::GetTypeFromGlobalIndex(const uint32_t index) {
- uint32_t global_offset = 0;
- for (auto binding : bindings_) {
- global_offset += binding->descriptorCount;
- if (index < global_offset)
- return binding->descriptorType;
- }
- assert(0); // requested global index is out of bounds
- return VK_DESCRIPTOR_TYPE_MAX_ENUM;
-}
-// For the given binding, return stageFlags
-VkShaderStageFlags DescriptorSetLayout::GetStageFlagsFromBinding(const uint32_t binding) {
- assert(binding_to_index_map_.count(binding));
- return bindings_[binding_to_index_map_[binding]]->stageFlags;
-}
-// For the given binding, return start index
-uint32_t DescriptorSetLayout::GetGlobalStartIndexFromBinding(const uint32_t binding) {
- assert(binding_to_global_start_index_map_.count(binding));
- return binding_to_global_start_index_map_[binding];
-}
-// For the given binding, return end index
-uint32_t DescriptorSetLayout::GetGlobalEndIndexFromBinding(const uint32_t binding) {
- assert(binding_to_global_end_index_map_.count(binding));
- return binding_to_global_end_index_map_[binding];
-}
-//
-VkSampler const *DescriptorSetLayout::GetImmutableSamplerPtrFromBinding(const uint32_t binding) {
- assert(binding_to_index_map_.count(binding));
- return bindings_[binding_to_index_map_[binding]]->pImmutableSamplers;
-}
-// If our layout is compatible with rh_ds_layout, return true,
-// else return false and fill in error_msg will description of what causes incompatibility
-bool DescriptorSetLayout::IsCompatible(DescriptorSetLayout *rh_ds_layout, string *error_msg) {
- // Trivial case
- if (layout_ == rh_ds_layout->GetDescriptorSetLayout())
- return true;
- if (descriptor_count_ != rh_ds_layout->descriptor_count_) {
- stringstream error_str;
- error_str << "DescriptorSetLayout " << layout_ << " has " << descriptor_count_ << " descriptors, but DescriptorSetLayout "
- << rh_ds_layout->GetDescriptorSetLayout() << " has " << rh_ds_layout->descriptor_count_ << " descriptors.";
- *error_msg = error_str.str();
- return false; // trivial fail case
- }
- // Descriptor counts match so need to go through bindings one-by-one
- // and verify that type and stageFlags match
- for (auto binding : bindings_) {
- // TODO : Do we also need to check immutable samplers?
- if (binding->descriptorCount != rh_ds_layout->GetDescriptorCountFromBinding(binding->binding)) {
- stringstream error_str;
- error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " has a descriptorCount of "
- << binding->descriptorCount << " but binding " << binding->binding << " for DescriptorSetLayout "
- << rh_ds_layout->GetDescriptorSetLayout() << " has a descriptorCount of "
- << rh_ds_layout->GetDescriptorCountFromBinding(binding->binding);
- *error_msg = error_str.str();
- return false;
- } else if (binding->descriptorType != rh_ds_layout->GetTypeFromBinding(binding->binding)) {
- stringstream error_str;
- error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " is type '"
- << string_VkDescriptorType(binding->descriptorType) << "' but binding " << binding->binding
- << " for DescriptorSetLayout " << rh_ds_layout->GetDescriptorSetLayout() << " is type '"
- << string_VkDescriptorType(rh_ds_layout->GetTypeFromBinding(binding->binding)) << "'";
- *error_msg = error_str.str();
- return false;
- } else if (binding->stageFlags != rh_ds_layout->GetStageFlagsFromBinding(binding->binding)) {
- stringstream error_str;
- error_str << "Binding " << binding->binding << " for DescriptorSetLayout " << layout_ << " has stageFlags "
- << binding->stageFlags << " but binding " << binding->binding << " for DescriptorSetLayout "
- << rh_ds_layout->GetDescriptorSetLayout() << " has stageFlags "
- << rh_ds_layout->GetStageFlagsFromBinding(binding->binding);
- *error_msg = error_str.str();
- return false;
- }
- }
- return true;
+class ImageSamplerDescriptor : public Descriptor {
+ public:
+ ImageSamplerDescriptor(const std::unordered_map<VkImageView, VkImageViewCreateInfo> *,
+ const std::unordered_map<VkImage, IMAGE_NODE> *, const std::unordered_map<VkImage, VkSwapchainKHR> *,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *,
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *);
+ ImageSamplerDescriptor(const VkSampler *, const std::unordered_map<VkImageView, VkImageViewCreateInfo> *,
+ const std::unordered_map<VkImage, IMAGE_NODE> *, const std::unordered_map<VkImage, VkSwapchainKHR> *,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *,
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *);
+ bool WriteUpdate(const VkWriteDescriptorSet *, const uint32_t, std::string *) override;
+ bool CopyUpdate(const Descriptor *, std::string *) override;
+
+ private:
+ VkSampler sampler_;
+ bool immutable_;
+ VkImageView image_view_;
+ VkImageLayout image_layout_;
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map_;
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map_;
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map_;
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map_;
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map_;
+};
+
+class ImageDescriptor : public Descriptor {
+ public:
+ ImageDescriptor(const VkDescriptorType, const std::unordered_map<VkImageView, VkImageViewCreateInfo> *,
+ const std::unordered_map<VkImage, IMAGE_NODE> *, const std::unordered_map<VkImage, VkSwapchainKHR> *,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *);
+ bool WriteUpdate(const VkWriteDescriptorSet *, const uint32_t, std::string *) override;
+ bool CopyUpdate(const Descriptor *, std::string *) override;
+ VkImageView GetImageView() const { return image_view_; }
+ VkImageLayout GetImageLayout() const { return image_layout_; }
+
+ private:
+ bool storage_;
+ VkImageView image_view_;
+ VkImageLayout image_layout_;
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map_;
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map_;
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map_;
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map_;
+};
+
+class TexelDescriptor : public Descriptor {
+ public:
+ TexelDescriptor(const VkDescriptorType, const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *);
+ bool WriteUpdate(const VkWriteDescriptorSet *, const uint32_t, std::string *) override;
+ bool CopyUpdate(const Descriptor *, std::string *) override;
+ VkBufferView GetBufferView() const { return buffer_view_; };
+
+ private:
+ VkBufferView buffer_view_;
+ bool storage_;
+ const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *buffer_view_map_;
+};
+
+class BufferDescriptor : public Descriptor {
+ public:
+ BufferDescriptor(const VkDescriptorType, const std::unordered_map<VkBuffer, BUFFER_NODE> *);
+ bool WriteUpdate(const VkWriteDescriptorSet *, const uint32_t, std::string *) override;
+ bool CopyUpdate(const Descriptor *, std::string *) override;
+ virtual bool IsDynamic() const override { return dynamic_; }
+ virtual bool IsStorage() const override { return storage_; }
+ VkBuffer GetBuffer() const { return buffer_; }
+ VkDeviceSize GetOffset() const { return offset_; }
+ VkDeviceSize GetRange() const { return range_; }
+
+ private:
+ bool storage_;
+ bool dynamic_;
+ VkBuffer buffer_;
+ VkDeviceSize offset_;
+ VkDeviceSize range_;
+ const std::unordered_map<VkBuffer, BUFFER_NODE> *buffer_map_;
+};
+/*
+ * DescriptorSet class
+ *
+ * Overview - This class encapsulates the Vulkan VkDescriptorSet data (set).
+ * A set has an underlying layout which defines the bindings in the set and the
+ * types and numbers of descriptors in each descriptor slot. Most of the layout
+ * interfaces are exposed through identically-named functions in the set class.
+ * Please refer to the DescriptorSetLayout comment above for a description of
+ * index, binding, and global index.
+ *
+ * At construction a vector of Descriptor* is created with types corresponding to the
+ * layout. The primary operation performed on the descriptors is to update them
+ * via write or copy updates, and validate that the update contents are correct.
+ * In order to validate update contents, the DescriptorSet stores a bunch of ptrs
+ * to data maps where various Vulkan objects can be looked up. The management of
+ * those maps is performed externally. The set class relies on their contents to
+ * be correct at the time of update.
+ */
+class DescriptorSet {
+ public:
+ DescriptorSet(const VkDescriptorSet, const DescriptorSetLayout *, const std::unordered_map<VkBuffer, BUFFER_NODE> *,
+ const std::unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> *,
+ const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *,
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *,
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *, const std::unordered_map<VkImage, IMAGE_NODE> *,
+ const std::unordered_map<VkImage, VkSwapchainKHR> *,
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *);
+ ~DescriptorSet(){};
+ // A number of common Get* functions that return data based on layout from which this set was created
+ uint32_t GetTotalDescriptorCount() const { return p_layout_ ? p_layout_->GetTotalDescriptorCount() : 0; };
+ uint32_t GetDynamicDescriptorCount() const { return p_layout_ ? p_layout_->GetDynamicDescriptorCount() : 0; };
+ uint32_t GetBindingCount() const { return p_layout_ ? p_layout_->GetBindingCount() : 0; };
+ VkDescriptorType GetTypeFromIndex(const uint32_t index) const {
+ return p_layout_ ? p_layout_->GetTypeFromIndex(index) : VK_DESCRIPTOR_TYPE_MAX_ENUM;
+ };
+ VkDescriptorType GetTypeFromGlobalIndex(const uint32_t index) const {
+ return p_layout_ ? p_layout_->GetTypeFromGlobalIndex(index) : VK_DESCRIPTOR_TYPE_MAX_ENUM;
+ };
+ VkDescriptorType GetTypeFromBinding(const uint32_t binding) const {
+ return p_layout_ ? p_layout_->GetTypeFromBinding(binding) : VK_DESCRIPTOR_TYPE_MAX_ENUM;
+ };
+ uint32_t GetDescriptorCountFromIndex(const uint32_t index) const {
+ return p_layout_ ? p_layout_->GetDescriptorCountFromIndex(index) : 0;
+ };
+ uint32_t GetDescriptorCountFromBinding(const uint32_t binding) const {
+ return p_layout_ ? p_layout_->GetDescriptorCountFromBinding(binding) : 0;
+ };
+ // Return true if given binding is present in this set
+ bool HasBinding(const uint32_t binding) const { return p_layout_->HasBinding(binding); };
+ // Is this set compatible with the given layout?
+ bool IsCompatible(const DescriptorSetLayout *, std::string *) const;
+ // For given bindings validate state at time of draw is correct, returning false on error and writing error details into string*
+ bool ValidateDrawState(const std::unordered_set<uint32_t> &, const std::vector<uint32_t> &, std::string *) const;
+ // For given set of bindings, add any buffers and images that will be updated to their respective unordered_sets & return number
+ // of objects inserted
+ uint32_t GetStorageUpdates(const std::unordered_set<uint32_t> &, std::unordered_set<VkBuffer> *,
+ std::unordered_set<VkImageView> *) const;
+ // For all descriptors in a set, add any buffers and images that may be updated to their respective unordered_sets & return
+ // number of objects inserted
+ uint32_t GetAllStorageUpdates(std::unordered_set<VkBuffer> *, std::unordered_set<VkImageView> *) const;
+ // Perform write update based on update struct
+ bool WriteUpdate(debug_report_data *, const VkWriteDescriptorSet *, std::string *);
+ // Perform copy update, using 'this' set as the dest and the passed-in DescriptorSet as the src
+ bool CopyUpdate(debug_report_data *, const VkCopyDescriptorSet *, const DescriptorSet *, std::string *);
+
+ VkDescriptorSet GetSet() const { return set_; };
+ // Return unordered_set of all command buffers that this set is bound to
+ std::unordered_set<VkCommandBuffer> GetBoundCmdBuffers() const { return bound_cmd_buffers_; }
+ // Bind given cmd_buffer to this descriptor set
+ void BindCommandBuffer(const VkCommandBuffer cmd_buffer) { bound_cmd_buffers_.insert(cmd_buffer); }
+ // If given cmd_buffer is in the bound_cmd_buffers_ set, remove it
+ void RemoveBoundCommandBuffer(const VkCommandBuffer cmd_buffer) { bound_cmd_buffers_.erase(cmd_buffer); }
+ VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t index) const {
+ return p_layout_->GetImmutableSamplerPtrFromBinding(index);
+ };
+ // For a particular binding, get the global index
+ uint32_t GetGlobalStartIndexFromBinding(const uint32_t binding) const {
+ return p_layout_->GetGlobalStartIndexFromBinding(binding);
+ };
+ uint32_t GetGlobalEndIndexFromBinding(const uint32_t binding) const {
+ return p_layout_->GetGlobalEndIndexFromBinding(binding);
+ };
+ // Return true if any part of set has ever been updated
+ bool IsUpdated() const { return some_update_; };
+ // Return true if the binding at the given global index has been updated
+ bool IsUpdated(const uint32_t global_index) const;
+
+ private:
+ bool ValidateUpdate(const VkWriteDescriptorSet *, const uint32_t, std::string *) const;
+ bool VerifyUpdateConsistency(uint32_t, uint32_t, uint32_t, const char *, std::string *) const;
+ bool some_update_; // has any part of the set ever been updated?
+ bool full_update_; // has every descriptor in the set been updated?
+ VkDescriptorSet set_;
+ uint32_t descriptor_count_; // Count of all descriptors in this set
+ const DescriptorSetLayout *p_layout_;
+ std::unordered_set<VkCommandBuffer> bound_cmd_buffers_;
+ std::vector<std::unique_ptr<Descriptor>> descriptors_;
+ // Ptrs to object containers to verify bound data
+ const std::unordered_map<VkBuffer, BUFFER_NODE> *buffer_map_;
+ const std::unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> *memory_map_;
+ const std::unordered_map<VkBufferView, VkBufferViewCreateInfo> *buffer_view_map_;
+ const std::unordered_map<VkSampler, std::unique_ptr<SAMPLER_NODE>> *sampler_map_;
+ const std::unordered_map<VkImageView, VkImageViewCreateInfo> *image_view_map_;
+ // TODO : For next 3 maps all we really need (currently) is an image to format mapping
+ const std::unordered_map<VkImage, IMAGE_NODE> *image_map_;
+ const std::unordered_map<VkImage, VkSwapchainKHR> *image_to_swapchain_map_;
+ const std::unordered_map<VkSwapchainKHR, SWAPCHAIN_NODE *> *swapchain_map_;
+};
}
#endif // CORE_VALIDATION_DESCRIPTOR_SETS_H_
diff --git a/layers/vk_layer_config.h b/layers/vk_layer_config.h
index a83d6f1..92865f6 100644
--- a/layers/vk_layer_config.h
+++ b/layers/vk_layer_config.h
@@ -17,7 +17,9 @@
* Author: Jon Ashburn <jon@lunarg.com>
**************************************************************************/
#pragma once
+#include "vulkan/vulkan.h"
#include <stdbool.h>
+#include <stdio.h>
#ifdef __cplusplus
extern "C" {