layers: Break out VkDescriptorSetLayout code into its own class

This is the start of a refactor to pull code out of core_validation.cpp
into its own separate classes. I'm starting with descriptor set code as
it isolates reasonably well and it's old and could use some updating anyway.

For this first piece I've broken VkDescriptorSetLayout into its own
class currently called DescriptorSetLayout. I don't know if that's a great
name as it's close to VkDescriptorSetLayout, so I'm open to changing it.
Provided a brief class description in comment in new file descriptor_sets.h.

I made the class interfaces based on what other code is currently using.
I'm planning to pull more descriptor set code into its own classes and I
anticipate that will cause some flux in the class interfaces until most
of the work is done.
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 5d427f6..fe1fe6f 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -56,10 +56,8 @@
 #endif
 #include "vk_struct_size_helper.h"
 #include "core_validation.h"
-#include "vk_layer_config.h"
 #include "vk_layer_table.h"
 #include "vk_layer_data.h"
-#include "vk_layer_logging.h"
 #include "vk_layer_extension_utils.h"
 #include "vk_layer_utils.h"
 
@@ -114,7 +112,7 @@
     unordered_map<VkCommandPool, CMD_POOL_INFO> commandPoolMap;
     unordered_map<VkDescriptorPool, DESCRIPTOR_POOL_NODE *> descriptorPoolMap;
     unordered_map<VkDescriptorSet, SET_NODE *> setMap;
-    unordered_map<VkDescriptorSetLayout, LAYOUT_NODE *> descriptorSetLayoutMap;
+    unordered_map<VkDescriptorSetLayout, DescriptorSetLayout> descriptorSetLayoutMap;
     unordered_map<VkPipelineLayout, PIPELINE_LAYOUT_NODE> pipelineLayoutMap;
     unordered_map<VkDeviceMemory, DEVICE_MEM_INFO> memObjMap;
     unordered_map<VkFence, FENCE_NODE> fenceMap;
@@ -1921,8 +1919,8 @@
     return pass;
 }
 
-// For given pipelineLayout verify that the setLayout at slot.first
-//  has the requested binding at slot.second
+// For given pipelineLayout verify that the set_layout_node at slot.first
+//  has the requested binding at slot.second and return ptr to that binding
 static VkDescriptorSetLayoutBinding const * get_descriptor_binding(layer_data *my_data, PIPELINE_LAYOUT_NODE *pipelineLayout, descriptor_slot_t slot) {
 
     if (!pipelineLayout)
@@ -1931,14 +1929,9 @@
     if (slot.first >= pipelineLayout->descriptorSetLayouts.size())
         return nullptr;
 
-    auto const layout_node = my_data->descriptorSetLayoutMap[pipelineLayout->descriptorSetLayouts[slot.first]];
+    auto &layout_node = my_data->descriptorSetLayoutMap[pipelineLayout->descriptorSetLayouts[slot.first]];
 
-    auto bindingIt = layout_node->bindingToIndexMap.find(slot.second);
-    if ((bindingIt == layout_node->bindingToIndexMap.end()) || (layout_node->createInfo.pBindings == NULL))
-        return nullptr;
-
-    assert(bindingIt->second < layout_node->createInfo.bindingCount);
-    return &layout_node->createInfo.pBindings[bindingIt->second];
+    return layout_node.GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
 }
 
 // Block of code at start here for managing/tracking Pipeline state that this layer cares about
@@ -2155,43 +2148,8 @@
         errorMsg = errorStr.str();
         return false;
     }
-    // Get the specific setLayout from PipelineLayout that overlaps this set
-    LAYOUT_NODE *pLayoutNode = my_data->descriptorSetLayoutMap[pipeline_layout_it->second.descriptorSetLayouts[layoutIndex]];
-    if (pLayoutNode->layout == pSet->pLayout->layout) { // trivial pass case
-        return true;
-    }
-    size_t descriptorCount = pLayoutNode->descriptorTypes.size();
-    if (descriptorCount != pSet->pLayout->descriptorTypes.size()) {
-        stringstream errorStr;
-        errorStr << "setLayout " << layoutIndex << " from pipelineLayout " << layout << " has " << descriptorCount
-                 << " descriptors, but corresponding set being bound has " << pSet->pLayout->descriptorTypes.size()
-                 << " descriptors.";
-        errorMsg = errorStr.str();
-        return false; // trivial fail case
-    }
-    // Now need to check set against corresponding pipelineLayout to verify compatibility
-    for (size_t i = 0; i < descriptorCount; ++i) {
-        // Need to verify that layouts are identically defined
-        //  TODO : Is below sufficient? Making sure that types & stageFlags match per descriptor
-        //    do we also need to check immutable samplers?
-        if (pLayoutNode->descriptorTypes[i] != pSet->pLayout->descriptorTypes[i]) {
-            stringstream errorStr;
-            errorStr << "descriptor " << i << " for descriptorSet being bound is type '"
-                     << string_VkDescriptorType(pSet->pLayout->descriptorTypes[i])
-                     << "' but corresponding descriptor from pipelineLayout is type '"
-                     << string_VkDescriptorType(pLayoutNode->descriptorTypes[i]) << "'";
-            errorMsg = errorStr.str();
-            return false;
-        }
-        if (pLayoutNode->stageFlags[i] != pSet->pLayout->stageFlags[i]) {
-            stringstream errorStr;
-            errorStr << "stageFlags " << i << " for descriptorSet being bound is " << pSet->pLayout->stageFlags[i]
-                     << "' but corresponding descriptor from pipelineLayout has stageFlags " << pLayoutNode->stageFlags[i];
-            errorMsg = errorStr.str();
-            return false;
-        }
-    }
-    return true;
+    auto layout_node = my_data->descriptorSetLayoutMap[pipeline_layout_it->second.descriptorSetLayouts[layoutIndex]];
+    return layout_node.IsCompatible(pSet->p_layout, &errorMsg);
 }
 
 // Validate that data for each specialization entry is fully contained within the buffer.
@@ -2495,7 +2453,7 @@
         // While validating shaders capture which slots are used by the pipeline
         pipeline->active_slots[use.first.first].insert(use.first.second);
 
-        /* find the matching binding */
+        /* verify given pipelineLayout has requested setLayout with requested binding */
         auto binding = get_descriptor_binding(dev_data, pipelineLayout, use.first);
         unsigned required_descriptor_count;
 
@@ -2512,29 +2470,26 @@
                         "Shader uses descriptor slot %u.%u (used "
                         "as type `%s`) but descriptor not "
                         "accessible from stage %s",
-                        use.first.first, use.first.second,
-                        describe_type(module, use.second.type_id).c_str(),
+                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
                         string_VkShaderStageFlagBits(pStage->stage))) {
                 pass = false;
             }
-        } else if (!descriptor_type_match(dev_data, module, use.second.type_id, binding->descriptorType, /*out*/ required_descriptor_count)) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
-                        __LINE__, SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
-                        "Type mismatch on descriptor slot "
-                        "%u.%u (used as type `%s`) but "
-                        "descriptor of type %s",
-                        use.first.first, use.first.second,
-                        describe_type(module, use.second.type_id).c_str(),
+        } else if (!descriptor_type_match(dev_data, module, use.second.type_id, binding->descriptorType,
+                                          /*out*/ required_descriptor_count)) {
+            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
+                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC", "Type mismatch on descriptor slot "
+                                                                       "%u.%u (used as type `%s`) but "
+                                                                       "descriptor of type %s",
+                        use.first.first, use.first.second, describe_type(module, use.second.type_id).c_str(),
                         string_VkDescriptorType(binding->descriptorType))) {
                 pass = false;
             }
         } else if (binding->descriptorCount < required_descriptor_count) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0,
-                        __LINE__, SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
+            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VkDebugReportObjectTypeEXT(0), 0, __LINE__,
+                        SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH, "SC",
                         "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
                         required_descriptor_count, use.first.first, use.first.second,
-                        describe_type(module, use.second.type_id).c_str(),
-                        binding->descriptorCount)) {
+                        describe_type(module, use.second.type_id).c_str(), binding->descriptorCount)) {
                 pass = false;
             }
         }
@@ -2626,29 +2581,6 @@
     }
     return my_data->setMap[set];
 }
-
-// For given Layout Node and binding, return index where that binding begins
-static uint32_t getBindingStartIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) {
-    uint32_t offsetIndex = 0;
-    for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) {
-        if (pLayout->createInfo.pBindings[i].binding == binding)
-            break;
-        offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount;
-    }
-    return offsetIndex;
-}
-
-// For given layout node and binding, return last index that is updated
-static uint32_t getBindingEndIndex(const LAYOUT_NODE *pLayout, const uint32_t binding) {
-    uint32_t offsetIndex = 0;
-    for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) {
-        offsetIndex += pLayout->createInfo.pBindings[i].descriptorCount;
-        if (pLayout->createInfo.pBindings[i].binding == binding)
-            break;
-    }
-    return offsetIndex - 1;
-}
-
 // For the given command buffer, verify and update the state for activeSetBindingsPairs
 //  This includes:
 //  1. Verifying that any dynamic descriptor in that set has a valid dynamic offset bound.
@@ -2666,16 +2598,15 @@
     VkDeviceSize bufferSize = 0;
     for (auto set_bindings_pair : activeSetBindingsPairs) {
         SET_NODE *set_node = set_bindings_pair.first;
-        LAYOUT_NODE *layout_node = set_node->pLayout;
+        auto layout_node = set_node->p_layout;
         for (auto binding : set_bindings_pair.second) {
-            auto binding_index = layout_node->bindingToIndexMap[binding];
-            if ((set_node->pLayout->createInfo.pBindings[binding_index].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) &&
-                (set_node->pLayout->createInfo.pBindings[binding_index].descriptorCount != 0) &&
-                (set_node->pLayout->createInfo.pBindings[binding_index].pImmutableSamplers)) {
+            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 = getBindingStartIndex(layout_node, binding);
-                uint32_t endIdx = getBindingEndIndex(layout_node, binding);
+                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
@@ -2873,13 +2804,18 @@
                     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 && !pSet->pLayout->immutableSamplerCount) {
-                        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",
-                                          "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);
+                    if (!pSet->pUpdateStructs) {
+                        for (auto binding : setBindingPair.second) {
+                            if (!pSet->p_layout->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",
+                                            "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);
+                            }
+                        }
                     }
                 }
             }
@@ -3275,13 +3211,6 @@
     return my_data->descriptorPoolMap[pool];
 }
 
-static LAYOUT_NODE *getLayoutNode(layer_data *my_data, const VkDescriptorSetLayout layout) {
-    if (my_data->descriptorSetLayoutMap.find(layout) == my_data->descriptorSetLayoutMap.end()) {
-        return NULL;
-    }
-    return my_data->descriptorSetLayoutMap[layout];
-}
-
 // Return false if update struct is of valid type, otherwise flag error and return code from callback
 static bool validUpdateStruct(layer_data *my_data, const VkDevice device, const GENERIC_HEADER *pUpdateStruct) {
     switch (pUpdateStruct->sType) {
@@ -3310,25 +3239,22 @@
 }
 
 // For given layout and update, return the first overall index of the layout that is updated
-static uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding,
+static uint32_t getUpdateStartIndex(layer_data *my_data, const VkDevice device, const uint32_t binding_start_index,
                                     const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
-    return getBindingStartIndex(pLayout, binding) + arrayIndex;
+    return binding_start_index + arrayIndex;
 }
-
 // For given layout and update, return the last overall index of the layout that is updated
-static uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout, const uint32_t binding,
+static uint32_t getUpdateEndIndex(layer_data *my_data, const VkDevice device, const uint32_t binding_start_index,
                                   const uint32_t arrayIndex, const GENERIC_HEADER *pUpdateStruct) {
     uint32_t count = getUpdateCount(my_data, device, pUpdateStruct);
-    return getBindingStartIndex(pLayout, binding) + arrayIndex + count - 1;
+    return binding_start_index + arrayIndex + count - 1;
 }
-
 // Verify that the descriptor type in the update struct matches what's expected by the layout
-static bool validateUpdateConsistency(layer_data *my_data, const VkDevice device, const LAYOUT_NODE *pLayout,
+static bool validateUpdateConsistency(layer_data *my_data, const VkDevice device, const VkDescriptorType layout_type,
                                       const GENERIC_HEADER *pUpdateStruct, uint32_t startIndex, uint32_t endIndex) {
     // First get actual type of update
     bool skipCall = false;
     VkDescriptorType actualType = VK_DESCRIPTOR_TYPE_MAX_ENUM;
-    uint32_t i = 0;
     switch (pUpdateStruct->sType) {
     case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
         actualType = ((VkWriteDescriptorSet *)pUpdateStruct)->descriptorType;
@@ -3344,23 +3270,12 @@
                             string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
     }
     if (!skipCall) {
-        // Set first stageFlags as reference and verify that all other updates match it
-        VkShaderStageFlags refStageFlags = pLayout->stageFlags[startIndex];
-        for (i = startIndex; i <= endIndex; i++) {
-            if (pLayout->descriptorTypes[i] != actualType) {
-                skipCall |= log_msg(
-                    my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
-                    DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
-                    "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!",
-                    string_VkDescriptorType(actualType), string_VkDescriptorType(pLayout->descriptorTypes[i]));
-            }
-            if (pLayout->stageFlags[i] != refStageFlags) {
-                skipCall |= log_msg(
-                    my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
-                    DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH, "DS",
-                    "Write descriptor update has stageFlags %x that do not match overlapping binding descriptor stageFlags of %x!",
-                    refStageFlags, pLayout->stageFlags[i]);
-            }
+        if (layout_type != actualType) {
+            skipCall |= log_msg(
+                my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
+                DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
+                "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!",
+                string_VkDescriptorType(actualType), string_VkDescriptorType(layout_type));
         }
     }
     return skipCall;
@@ -3770,7 +3685,7 @@
 }
 
 static bool validateUpdateContents(const layer_data *my_data, const VkWriteDescriptorSet *pWDS,
-                                   const VkDescriptorSetLayoutBinding *pLayoutBinding) {
+                                   const VkSampler *pImmutableSamplers) {
     bool skipCall = false;
     // First verify that for the given Descriptor type, the correct DescriptorInfo data is supplied
     const VkSampler *pSampler = NULL;
@@ -3785,7 +3700,7 @@
         break;
     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
         for (i = 0; i < pWDS->descriptorCount; ++i) {
-            if (NULL == pLayoutBinding->pImmutableSamplers) {
+            if (NULL == pImmutableSamplers) {
                 pSampler = &(pWDS->pImageInfo[i].sampler);
                 if (immutable) {
                     skipCall |= log_msg(
@@ -3808,7 +3723,7 @@
                         i);
                 }
                 immutable = true;
-                pSampler = &(pLayoutBinding->pImmutableSamplers[i]);
+                pSampler = &(pImmutableSamplers[i]);
             }
             skipCall |= validateSampler(my_data, pSampler, immutable);
         }
@@ -3874,9 +3789,6 @@
 static bool dsUpdate(layer_data *my_data, VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pWDS,
                      uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pCDS) {
     bool skipCall = false;
-
-    LAYOUT_NODE *pLayout = NULL;
-    VkDescriptorSetLayoutCreateInfo *pLayoutCI = NULL;
     // Validate Write updates
     uint32_t i = 0;
     for (i = 0; i < descriptorWriteCount; i++) {
@@ -3888,16 +3800,15 @@
         // If set is bound to any cmdBuffers, mark them invalid
         invalidateBoundCmdBuffers(my_data, pSet);
         GENERIC_HEADER *pUpdate = (GENERIC_HEADER *)&pWDS[i];
-        pLayout = pSet->pLayout;
+        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;
-        auto bindingToIndex = pLayout->bindingToIndexMap.find(binding);
         // Make sure that layout being updated has the binding being updated
-        if (bindingToIndex == pLayout->bindingToIndexMap.end()) {
+        if (!layout_node->HasBinding(binding)) {
             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 "
@@ -3906,25 +3817,26 @@
                                 (uint64_t)(ds), binding, string_VkStructureType(pUpdate->sType));
         } else {
             // Next verify that update falls within size of given binding
-            endIndex = getUpdateEndIndex(my_data, device, pLayout, binding, pWDS[i].dstArrayElement, pUpdate);
-            if (getBindingEndIndex(pLayout, binding) < endIndex) {
-                pLayoutCI = &pLayout->createInfo;
-                string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS}    ");
+            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,
-                            (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 w/ CI:\n%s!",
-                            string_VkStructureType(pUpdate->sType), binding, DSstr.c_str());
+                            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, pLayout, binding, pWDS[i].dstArrayElement, pUpdate);
-                // Layout bindings match w/ update, now verify that update type
-                // & stageFlags are the same for entire update
-                if ((skipCall = validateUpdateConsistency(my_data, device, pLayout, pUpdate, startIndex, endIndex)) == false) {
+                startIndex = getUpdateStartIndex(my_data, device, layout_node->GetGlobalStartIndexFromBinding(binding),
+                                                 pWDS[i].dstArrayElement, pUpdate);
+                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],
-                                                           &pLayout->createInfo.pBindings[bindingToIndex->second])) == false) {
+                    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;
@@ -3952,7 +3864,6 @@
     // Now validate copy updates
     for (i = 0; i < descriptorCopyCount; ++i) {
         SET_NODE *pSrcSet = NULL, *pDstSet = NULL;
-        LAYOUT_NODE *pSrcLayout = NULL, *pDstLayout = 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];
@@ -3961,60 +3872,66 @@
         if ((skipCall = validateIdleDescriptorSet(my_data, pDstSet->set, "VkUpdateDescriptorSets")) == true)
             return skipCall;
         invalidateBoundCmdBuffers(my_data, pDstSet);
-        pSrcLayout = pSrcSet->pLayout;
-        pDstLayout = pDstSet->pLayout;
+        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 (pSrcLayout->bindingToIndexMap.find(pCDS[i].srcBinding) == pSrcLayout->bindingToIndexMap.end()) {
-            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, (uint64_t)pSrcLayout->layout, pSrcLayout->createInfo.bindingCount - 1);
-        } else if (pDstLayout->bindingToIndexMap.find(pCDS[i].dstBinding) == pDstLayout->bindingToIndexMap.end()) {
-            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, (uint64_t)pDstLayout->layout, pDstLayout->createInfo.bindingCount - 1);
+        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
-            srcEndIndex = getUpdateEndIndex(my_data, device, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement,
-                                            (const GENERIC_HEADER *)&(pCDS[i]));
-            dstEndIndex = getUpdateEndIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement,
-                                            (const GENERIC_HEADER *)&(pCDS[i]));
-            if (getBindingEndIndex(pSrcLayout, pCDS[i].srcBinding) < srcEndIndex) {
-                pLayoutCI = &pSrcLayout->createInfo;
-                string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS}    ");
+            // 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 w/ CI:\n%s!",
-                            pCDS[i].srcBinding, DSstr.c_str());
-            } else if (getBindingEndIndex(pDstLayout, pCDS[i].dstBinding) < dstEndIndex) {
-                pLayoutCI = &pDstLayout->createInfo;
-                string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{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 w/ CI:\n%s!",
-                            pCDS[i].dstBinding, DSstr.c_str());
+                            "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, pSrcLayout, pCDS[i].srcBinding, pCDS[i].srcArrayElement,
-                                                    (const GENERIC_HEADER *)&(pCDS[i]));
-                dstStartIndex = getUpdateStartIndex(my_data, device, pDstLayout, pCDS[i].dstBinding, pCDS[i].dstArrayElement,
-                                                    (const GENERIC_HEADER *)&(pCDS[i]));
-                for (uint32_t j = 0; j < pCDS[i].descriptorCount; ++j) {
-                    // For copy just make sure that the types match and then perform the update
-                    if (pSrcLayout->descriptorTypes[srcStartIndex + j] != pDstLayout->descriptorTypes[dstStartIndex + j]) {
-                        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, update count #%u, has src update descriptor type %s "
-                                            "that does not match overlapping dest descriptor type of %s!",
-                                            i, j + 1, string_VkDescriptorType(pSrcLayout->descriptorTypes[srcStartIndex + j]),
-                                            string_VkDescriptorType(pDstLayout->descriptorTypes[dstStartIndex + j]));
-                    } 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
@@ -4048,8 +3965,8 @@
     }
 
     for (i = 0; i < count; ++i) {
-        LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pSetLayouts[i]);
-        if (NULL == pLayout) {
+        auto layout_pair = dev_data->descriptorSetLayoutMap.find(pSetLayouts[i]);
+        if (layout_pair == dev_data->descriptorSetLayoutMap.end()) {
             skipCall |=
                 log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
                         (uint64_t)pSetLayouts[i], __LINE__, DRAWSTATE_INVALID_LAYOUT, "DS",
@@ -4057,17 +3974,19 @@
                         (uint64_t)pSetLayouts[i]);
         } else {
             uint32_t typeIndex = 0, poolSizeCount = 0;
-            for (j = 0; j < pLayout->createInfo.bindingCount; ++j) {
-                typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType);
-                poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount;
+            auto layout_node = layout_pair->second;
+            for (j = 0; j < layout_node.GetBindingCount(); ++j) {
+                auto binding_layout = layout_node.GetDescriptorSetLayoutBindingPtrFromIndex(j);
+                typeIndex = static_cast<uint32_t>(binding_layout->descriptorType);
+                poolSizeCount = binding_layout->descriptorCount;
                 if (poolSizeCount > pPoolNode->availableDescriptorTypeCount[typeIndex]) {
-                    skipCall |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                        VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)pLayout->layout, __LINE__,
-                                        DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
-                                        "Unable to allocate %u descriptors of type %s from pool %#" PRIxLEAST64
-                                        ". This pool only has %d descriptors of this type remaining.",
-                                        poolSizeCount, string_VkDescriptorType(pLayout->createInfo.pBindings[j].descriptorType),
-                                        (uint64_t)pPoolNode->pool, pPoolNode->availableDescriptorTypeCount[typeIndex]);
+                    skipCall |= log_msg(
+                        dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
+                        reinterpret_cast<const uint64_t &>(pSetLayouts[i]), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
+                        "Unable to allocate %u descriptors of type %s from pool %#" PRIxLEAST64
+                        ". This pool only has %d descriptors of this type remaining.",
+                        poolSizeCount, string_VkDescriptorType(binding_layout->descriptorType), (uint64_t)pPoolNode->pool,
+                        pPoolNode->availableDescriptorTypeCount[typeIndex]);
                 } else { // Decrement available descriptors of this type
                     pPoolNode->availableDescriptorTypeCount[typeIndex] -= poolSizeCount;
                 }
@@ -4134,7 +4053,6 @@
         while (pSet) {
             pFreeSet = pSet;
             pSet = pSet->pNext;
-            // Freeing layouts handled in deleteLayouts() function
             // Free Update shadow struct tree
             freeShadowUpdateTree(pFreeSet);
             delete pFreeSet;
@@ -4144,24 +4062,6 @@
     my_data->descriptorPoolMap.clear();
 }
 
-// WARN : Once deleteLayouts() called, any layout ptrs in Pool/Set data structure will be invalid
-// NOTE : Calls to this function should be wrapped in mutex
-static void deleteLayouts(layer_data *my_data) {
-    if (my_data->descriptorSetLayoutMap.size() <= 0)
-        return;
-    for (auto ii = my_data->descriptorSetLayoutMap.begin(); ii != my_data->descriptorSetLayoutMap.end(); ++ii) {
-        LAYOUT_NODE *pLayout = (*ii).second;
-        if (pLayout->createInfo.pBindings) {
-            for (uint32_t i = 0; i < pLayout->createInfo.bindingCount; i++) {
-                delete[] pLayout->createInfo.pBindings[i].pImmutableSamplers;
-            }
-            delete[] pLayout->createInfo.pBindings;
-        }
-        delete pLayout;
-    }
-    my_data->descriptorSetLayoutMap.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) {
@@ -4686,7 +4586,7 @@
     deleteRenderPasses(dev_data);
     deleteCommandBuffers(dev_data);
     deletePools(dev_data);
-    deleteLayouts(dev_data);
+    dev_data->descriptorSetLayoutMap.clear();
     dev_data->imageViewMap.clear();
     dev_data->imageMap.clear();
     dev_data->imageSubresourceMap.clear();
@@ -6404,67 +6304,8 @@
     VkResult result = dev_data->device_dispatch_table->CreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
     if (VK_SUCCESS == result) {
         // TODOSC : Capture layout bindings set
-        LAYOUT_NODE *pNewNode = new LAYOUT_NODE;
-        if (NULL == pNewNode) {
-            if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT,
-                        (uint64_t)*pSetLayout, __LINE__, DRAWSTATE_OUT_OF_MEMORY, "DS",
-                        "Out of memory while attempting to allocate LAYOUT_NODE in vkCreateDescriptorSetLayout()"))
-                return VK_ERROR_VALIDATION_FAILED_EXT;
-        }
-        memcpy((void *)&pNewNode->createInfo, pCreateInfo, sizeof(VkDescriptorSetLayoutCreateInfo));
-        pNewNode->createInfo.pBindings = new VkDescriptorSetLayoutBinding[pCreateInfo->bindingCount];
-        memcpy((void *)pNewNode->createInfo.pBindings, pCreateInfo->pBindings,
-               sizeof(VkDescriptorSetLayoutBinding) * pCreateInfo->bindingCount);
-        // g++ does not like reserve with size 0
-        if (pCreateInfo->bindingCount)
-            pNewNode->bindingToIndexMap.reserve(pCreateInfo->bindingCount);
-        uint32_t totalCount = 0;
-        for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
-            if (!pNewNode->bindingToIndexMap.emplace(pCreateInfo->pBindings[i].binding, i).second) {
-                if (log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                            VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT, (uint64_t)*pSetLayout, __LINE__,
-                            DRAWSTATE_INVALID_LAYOUT, "DS", "duplicated binding number in "
-                                                            "VkDescriptorSetLayoutBinding"))
-                    return VK_ERROR_VALIDATION_FAILED_EXT;
-            } else {
-                pNewNode->bindingToIndexMap[pCreateInfo->pBindings[i].binding] = i;
-            }
-            totalCount += pCreateInfo->pBindings[i].descriptorCount;
-            if (pCreateInfo->pBindings[i].pImmutableSamplers) {
-                VkSampler **ppIS = (VkSampler **)&pNewNode->createInfo.pBindings[i].pImmutableSamplers;
-                *ppIS = new VkSampler[pCreateInfo->pBindings[i].descriptorCount];
-                memcpy(*ppIS, pCreateInfo->pBindings[i].pImmutableSamplers,
-                       pCreateInfo->pBindings[i].descriptorCount * sizeof(VkSampler));
-                pNewNode->immutableSamplerCount += pCreateInfo->pBindings[i].descriptorCount;
-            }
-        }
-        pNewNode->layout = *pSetLayout;
-        pNewNode->startIndex = 0;
-        if (totalCount > 0) {
-            pNewNode->descriptorTypes.resize(totalCount);
-            pNewNode->stageFlags.resize(totalCount);
-            uint32_t offset = 0;
-            uint32_t j = 0;
-            VkDescriptorType dType;
-            for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
-                dType = pCreateInfo->pBindings[i].descriptorType;
-                for (j = 0; j < pCreateInfo->pBindings[i].descriptorCount; j++) {
-                    pNewNode->descriptorTypes[offset + j] = dType;
-                    pNewNode->stageFlags[offset + j] = pCreateInfo->pBindings[i].stageFlags;
-                    if ((dType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
-                        (dType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
-                        pNewNode->dynamicDescriptorCount++;
-                    }
-                }
-                offset += j;
-            }
-            pNewNode->endIndex = pNewNode->startIndex + totalCount - 1;
-        } else { // no descriptors
-            pNewNode->endIndex = 0;
-        }
-        // Put new node at Head of global Layer list
         std::lock_guard<std::mutex> lock(global_lock);
-        dev_data->descriptorSetLayoutMap[*pSetLayout] = pNewNode;
+        dev_data->descriptorSetLayoutMap[*pSetLayout] = DescriptorSetLayout(dev_data->report_data, pCreateInfo, *pSetLayout);
     }
     return result;
 }
@@ -6605,8 +6446,8 @@
                     pNewNode->pNext = pPoolNode->pSets;
                     pNewNode->in_use.store(0);
                     pPoolNode->pSets = pNewNode;
-                    LAYOUT_NODE *pLayout = getLayoutNode(dev_data, pAllocateInfo->pSetLayouts[i]);
-                    if (NULL == pLayout) {
+                    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",
@@ -6617,10 +6458,10 @@
                             return VK_ERROR_VALIDATION_FAILED_EXT;
                         }
                     }
-                    pNewNode->pLayout = pLayout;
+                    pNewNode->p_layout = &layout_pair->second;
                     pNewNode->pool = pAllocateInfo->descriptorPool;
                     pNewNode->set = pDescriptorSets[i];
-                    pNewNode->descriptorCount = (pLayout->createInfo.bindingCount != 0) ? pLayout->endIndex + 1 : 0;
+                    pNewNode->descriptorCount = layout_pair->second.GetTotalDescriptorCount();
                     if (pNewNode->descriptorCount) {
                         pNewNode->pDescriptorUpdates.resize(pNewNode->descriptorCount);
                     }
@@ -6663,11 +6504,12 @@
         for (uint32_t i = 0; i < count; ++i) {
             SET_NODE *pSet = dev_data->setMap[pDescriptorSets[i]]; // getSetNode() without locking
             invalidateBoundCmdBuffers(dev_data, pSet);
-            LAYOUT_NODE *pLayout = pSet->pLayout;
+            auto p_layout = pSet->p_layout;
             uint32_t typeIndex = 0, poolSizeCount = 0;
-            for (uint32_t j = 0; j < pLayout->createInfo.bindingCount; ++j) {
-                typeIndex = static_cast<uint32_t>(pLayout->createInfo.pBindings[j].descriptorType);
-                poolSizeCount = pLayout->createInfo.pBindings[j].descriptorCount;
+            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;
                 pPoolNode->availableDescriptorTypeCount[typeIndex] += poolSizeCount;
             }
         }
@@ -7141,9 +6983,9 @@
                                             "pipelineLayout due to: %s",
                                             i, errorString.c_str());
                     }
-                    if (pSet->pLayout->dynamicDescriptorCount) {
+                    if (pSet->p_layout->GetDynamicDescriptorCount()) {
                         // First make sure we won't overstep bounds of pDynamicOffsets array
-                        if ((totalDynamicDescriptors + pSet->pLayout->dynamicDescriptorCount) > dynamicOffsetCount) {
+                        if ((totalDynamicDescriptors + pSet->p_layout->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__,
@@ -7151,13 +6993,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->pLayout->dynamicDescriptorCount,
+                                        i, (uint64_t)pDescriptorSets[i], pSet->p_layout->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->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
+                                if (pSet->p_layout->GetTypeFromIndex(d) == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
                                     if (vk_safe_modulo(
                                             pDynamicOffsets[cur_dyn_offset],
                                             dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment) != 0) {
@@ -7171,7 +7013,7 @@
                                             dev_data->phys_dev_properties.properties.limits.minUniformBufferOffsetAlignment);
                                     }
                                     cur_dyn_offset++;
-                                } else if (pSet->pLayout->descriptorTypes[d] == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
+                                } else if (pSet->p_layout->GetTypeFromIndex(d) == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
                                     if (vk_safe_modulo(
                                             pDynamicOffsets[cur_dyn_offset],
                                             dev_data->phys_dev_properties.properties.limits.minStorageBufferOffsetAlignment) != 0) {
@@ -7188,7 +7030,7 @@
                                 }
                             }
                             // Keep running total of dynamic descriptor count to verify at the end
-                            totalDynamicDescriptors += pSet->pLayout->dynamicDescriptorCount;
+                            totalDynamicDescriptors += pSet->p_layout->GetDynamicDescriptorCount();
                         }
                     }
                 } else {
diff --git a/layers/core_validation.h b/layers/core_validation.h
index f8fe750..d12fc0b 100644
--- a/layers/core_validation.h
+++ b/layers/core_validation.h
@@ -46,41 +46,22 @@
 #define MTMERGE 1
 
 #pragma once
+#include "core_validation_error_enums.h"
+#include "descriptor_sets.h"
+#include "vk_layer_logging.h"
 #include "vk_safe_struct.h"
 #include "vulkan/vk_layer.h"
 #include <atomic>
-#include <vector>
+#include <functional>
+#include <memory>
 #include <unordered_map>
 #include <unordered_set>
-#include <memory>
-#include <functional>
+#include <vector>
 
 using std::vector;
 using std::unordered_set;
 
 #if MTMERGE
-// Mem Tracker ERROR codes
-typedef enum _MEM_TRACK_ERROR {
-    MEMTRACK_NONE,                         // Used for INFO & other non-error messages
-    MEMTRACK_INVALID_CB,                   // Cmd Buffer invalid
-    MEMTRACK_INVALID_MEM_OBJ,              // Invalid Memory Object
-    MEMTRACK_INVALID_ALIASING,             // Invalid Memory Aliasing
-    MEMTRACK_INVALID_LAYOUT,               // Invalid Layout
-    MEMTRACK_INTERNAL_ERROR,               // Bug in Mem Track Layer internal data structures
-    MEMTRACK_FREED_MEM_REF,                // MEM Obj freed while it still has obj and/or CB refs
-    MEMTRACK_MEM_OBJ_CLEAR_EMPTY_BINDINGS, // Clearing bindings on mem obj that doesn't have any bindings
-    MEMTRACK_MISSING_MEM_BINDINGS,         // Trying to retrieve mem bindings, but none found (may be internal error)
-    MEMTRACK_INVALID_OBJECT,               // Attempting to reference generic VK Object that is invalid
-    MEMTRACK_MEMORY_BINDING_ERROR,         // Error during one of many calls that bind memory to object or CB
-    MEMTRACK_MEMORY_LEAK,                  // Failure to call vkFreeMemory on Mem Obj prior to DestroyDevice
-    MEMTRACK_INVALID_STATE,                // Memory not in the correct state
-    MEMTRACK_RESET_CB_WHILE_IN_FLIGHT,     // vkResetCommandBuffer() called on a CB that hasn't completed
-    MEMTRACK_INVALID_FENCE_STATE,          // Invalid Fence State signaled or used
-    MEMTRACK_REBIND_OBJECT,                // Non-sparse object bindings are immutable
-    MEMTRACK_INVALID_USAGE_FLAG,           // Usage flags specified at image/buffer create conflict w/ use of object
-    MEMTRACK_INVALID_MAP,                  // Size flag specified at alloc is too small for mapping range
-} MEM_TRACK_ERROR;
-
 struct MemRange {
     VkDeviceSize offset;
     VkDeviceSize size;
@@ -182,201 +163,6 @@
 };
 
 #endif
-// Draw State ERROR codes
-typedef enum _DRAW_STATE_ERROR {
-    // TODO: Remove the comments here or expand them. There isn't any additional information in the
-    // comments than in the name in almost all cases.
-    DRAWSTATE_NONE,                          // Used for INFO & other non-error messages
-    DRAWSTATE_INTERNAL_ERROR,                // Error with DrawState internal data structures
-    DRAWSTATE_NO_PIPELINE_BOUND,             // Unable to identify a bound pipeline
-    DRAWSTATE_INVALID_POOL,                  // Invalid DS pool
-    DRAWSTATE_INVALID_SET,                   // Invalid DS
-    DRAWSTATE_INVALID_RENDER_AREA,           // Invalid renderArea
-    DRAWSTATE_INVALID_LAYOUT,                // Invalid DS layout
-    DRAWSTATE_INVALID_IMAGE_LAYOUT,          // Invalid Image layout
-    DRAWSTATE_INVALID_PIPELINE,              // Invalid Pipeline handle referenced
-    DRAWSTATE_INVALID_PIPELINE_LAYOUT,       // Invalid PipelineLayout
-    DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, // Attempt to create a pipeline
-                                             // with invalid state
-    DRAWSTATE_INVALID_COMMAND_BUFFER,        // Invalid CommandBuffer referenced
-    DRAWSTATE_INVALID_BARRIER,               // Invalid Barrier
-    DRAWSTATE_INVALID_BUFFER,                // Invalid Buffer
-    DRAWSTATE_INVALID_QUERY,                 // Invalid Query
-    DRAWSTATE_INVALID_FENCE,                 // Invalid Fence
-    DRAWSTATE_INVALID_SEMAPHORE,             // Invalid Semaphore
-    DRAWSTATE_INVALID_EVENT,                 // Invalid Event
-    DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS,       // binding in vkCmdBindVertexData() too
-                                             // large for PSO's
-                                             // pVertexBindingDescriptions array
-    DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR,     // binding offset in
-                                             // vkCmdBindIndexBuffer() out of
-                                             // alignment based on indexType
-    // DRAWSTATE_MISSING_DOT_PROGRAM,              // No "dot" program in order
-    // to generate png image
-    DRAWSTATE_OUT_OF_MEMORY,                          // malloc failed
-    DRAWSTATE_INVALID_DESCRIPTOR_SET,                 // Descriptor Set handle is unknown
-    DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH,               // Type in layout vs. update are not the
-                                                      // same
-    DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH,         // StageFlags in layout are not
-                                                      // the same throughout a single
-                                                      // VkWriteDescriptorSet update
-    DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS,        // Descriptors set for update out
-                                                      // of bounds for corresponding
-                                                      // layout section
-    DRAWSTATE_DESCRIPTOR_POOL_EMPTY,                  // Attempt to allocate descriptor from a
-                                                      // pool with no more descriptors of that
-                                                      // type available
-    DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL,           // Invalid to call
-                                                      // vkFreeDescriptorSets on Sets
-                                                      // allocated from a NON_FREE Pool
-    DRAWSTATE_INVALID_UPDATE_INDEX,                   // Index of requested update is invalid for
-                                                      // specified descriptors set
-    DRAWSTATE_INVALID_UPDATE_STRUCT,                  // Struct in DS Update tree is of invalid
-                                                      // type
-    DRAWSTATE_NUM_SAMPLES_MISMATCH,                   // Number of samples in bound PSO does not
-                                                      // match number in FB of current RenderPass
-    DRAWSTATE_NO_END_COMMAND_BUFFER,                  // Must call vkEndCommandBuffer() before
-                                                      // QueueSubmit on that commandBuffer
-    DRAWSTATE_NO_BEGIN_COMMAND_BUFFER,                // Binding cmds or calling End on CB that
-                                                      // never had vkBeginCommandBuffer()
-                                                      // called on it
-    DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, // Cmd Buffer created with
-    // VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
-    // flag is submitted
-    // multiple times
-    DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, // vkCmdExecuteCommands() called
-                                                // with a primary commandBuffer
-                                                // in pCommandBuffers array
-    DRAWSTATE_VIEWPORT_NOT_BOUND,               // Draw submitted with no viewport state bound
-    DRAWSTATE_SCISSOR_NOT_BOUND,                // Draw submitted with no scissor state bound
-    DRAWSTATE_LINE_WIDTH_NOT_BOUND,             // Draw submitted with no line width state
-                                                // bound
-    DRAWSTATE_DEPTH_BIAS_NOT_BOUND,             // Draw submitted with no depth bias state
-                                                // bound
-    DRAWSTATE_BLEND_NOT_BOUND,                  // Draw submitted with no blend state bound when
-                                                // color write enabled
-    DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND,           // Draw submitted with no depth bounds
-                                                // state bound when depth enabled
-    DRAWSTATE_STENCIL_NOT_BOUND,                // Draw submitted with no stencil state bound
-                                                // when stencil enabled
-    DRAWSTATE_INDEX_BUFFER_NOT_BOUND,           // Draw submitted with no depth-stencil
-                                                // state bound when depth write enabled
-    DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE,    // Draw submitted PSO Pipeline
-                                                // layout that's not compatible
-                                                // with layout from
-                                                // BindDescriptorSets
-    DRAWSTATE_RENDERPASS_INCOMPATIBLE,          // Incompatible renderpasses between
-                                                // secondary cmdBuffer and primary
-                                                // cmdBuffer or framebuffer
-    DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE,         // Incompatible framebuffer between
-                                                // secondary cmdBuffer and active
-                                                // renderPass
-    DRAWSTATE_INVALID_RENDERPASS,               // Use of a NULL or otherwise invalid
-                                                // RenderPass object
-    DRAWSTATE_INVALID_RENDERPASS_CMD,           // Invalid cmd submitted while a
-                                                // RenderPass is active
-    DRAWSTATE_NO_ACTIVE_RENDERPASS,             // Rendering cmd submitted without an active
-                                                // RenderPass
-    DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED,       // DescriptorSet bound but it was
-                                                // never updated. This is a warning
-                                                // code.
-    DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND,         // DescriptorSet used by pipeline at
-                                                // draw time is not bound, or has been
-                                                // disturbed (which would have flagged
-                                                // previous warning)
-    DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT,     // DescriptorSets bound with
-                                                // different number of dynamic
-                                                // descriptors that were included in
-                                                // dynamicOffsetCount
-    DRAWSTATE_CLEAR_CMD_BEFORE_DRAW,            // Clear cmd issued before any Draw in
-                                                // CommandBuffer, should use RenderPass Ops
-                                                // instead
-    DRAWSTATE_BEGIN_CB_INVALID_STATE,           // CB state at Begin call is bad. Can be
-                                                // Primary/Secondary CB created with
-                                                // mismatched FB/RP information or CB in
-                                                // RECORDING state
-    DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE,      // CmdBuffer is being used in
-                                                // violation of
-    // VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT
-    // rules (i.e. simultaneous use w/o
-    // that bit set)
-    DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, // Attempting to call Reset (or
-                                            // Begin on recorded cmdBuffer) that
-                                            // was allocated from Pool w/o
-    // VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
-    // bit set
-    DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH,             // Count for viewports and scissors
-                                                     // mismatch and/or state doesn't match
-                                                     // count
-    DRAWSTATE_INVALID_IMAGE_ASPECT,                  // Image aspect is invalid for the current
-                                                     // operation
-    DRAWSTATE_MISSING_ATTACHMENT_REFERENCE,          // Attachment reference must be
-                                                     // present in active subpass
-    DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR,              // A Descriptor of *_SAMPLER type is
-                                                     // being updated with an invalid or bad
-                                                     // Sampler
-    DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, // Descriptors of
-                                                     // *COMBINED_IMAGE_SAMPLER
-                                                     // type are being updated
-                                                     // where some, but not all,
-                                                     // of the updates use
-                                                     // immutable samplers
-    DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR,            // A Descriptor of *_IMAGE or
-                                                     // *_ATTACHMENT type is being updated
-                                                     // with an invalid or bad ImageView
-    DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR,           // A Descriptor of *_TEXEL_BUFFER
-                                                     // type is being updated with an
-                                                     // invalid or bad BufferView
-    DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR,           // A Descriptor of
-    // *_[UNIFORM|STORAGE]_BUFFER_[DYNAMIC]
-    // type is being updated with an
-    // invalid or bad BufferView
-    DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW,       // At draw time the dynamic offset
-                                             // combined with buffer offset and range
-                                             // oversteps size of buffer
-    DRAWSTATE_DOUBLE_DESTROY,                // Destroying an object twice
-    DRAWSTATE_OBJECT_INUSE,                  // Destroying or modifying an object in use by a
-                                             // command buffer
-    DRAWSTATE_QUEUE_FORWARD_PROGRESS,        // Queue cannot guarantee forward progress
-    DRAWSTATE_INVALID_BUFFER_MEMORY_OFFSET,  // Dynamic Buffer Offset
-                                             // violates memory requirements limit
-    DRAWSTATE_INVALID_TEXEL_BUFFER_OFFSET,   // Dynamic Texel Buffer Offsets
-                                             // violate device limit
-    DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, // Dynamic Uniform Buffer Offsets
-                                             // violate device limit
-    DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, // Dynamic Storage Buffer Offsets
-                                             // violate device limit
-    DRAWSTATE_INDEPENDENT_BLEND,             // If independent blending is not enabled, all
-                                             // elements of pAttachmentsMustBeIdentical
-    DRAWSTATE_DISABLED_LOGIC_OP,             // If logic operations is not enabled, logicOpEnable
-                                             // must be VK_FALSE
-    DRAWSTATE_INVALID_LOGIC_OP,              // If logicOpEnable is VK_TRUE, logicOp must
-                                             // must be a valid VkLogicOp value
-    DRAWSTATE_INVALID_QUEUE_INDEX,           // Specified queue index exceeds number
-                                             // of queried queue families
-    DRAWSTATE_PUSH_CONSTANTS_ERROR,          // Push constants exceed maxPushConstantSize
-} DRAW_STATE_ERROR;
-
-typedef enum _SHADER_CHECKER_ERROR {
-    SHADER_CHECKER_NONE,
-    SHADER_CHECKER_INTERFACE_TYPE_MISMATCH,    // Type mismatch between shader stages or shader and pipeline
-    SHADER_CHECKER_OUTPUT_NOT_CONSUMED,        // Entry appears in output interface, but missing in input
-    SHADER_CHECKER_INPUT_NOT_PRODUCED,         // Entry appears in input interface, but missing in output
-    SHADER_CHECKER_NON_SPIRV_SHADER,           // Shader image is not SPIR-V
-    SHADER_CHECKER_INCONSISTENT_SPIRV,         // General inconsistency within a SPIR-V module
-    SHADER_CHECKER_UNKNOWN_STAGE,              // Stage is not supported by analysis
-    SHADER_CHECKER_INCONSISTENT_VI,            // VI state contains conflicting binding or attrib descriptions
-    SHADER_CHECKER_MISSING_DESCRIPTOR,         // Shader attempts to use a descriptor binding not declared in the layout
-    SHADER_CHECKER_BAD_SPECIALIZATION,         // Specialization map entry points outside specialization data block
-    SHADER_CHECKER_MISSING_ENTRYPOINT,         // Shader module does not contain the requested entrypoint
-    SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, // Push constant variable is not in a push constant range
-    SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, // Push constant range exists, but not accessible from stage
-    SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH,                // Descriptor type does not match shader resource type
-    SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE,    // Descriptor used by shader, but not accessible from stage
-    SHADER_CHECKER_FEATURE_NOT_ENABLED,        // Shader uses capability requiring a feature not enabled on device
-    SHADER_CHECKER_BAD_CAPABILITY,             // Shader uses capability not supported by Vulkan (OpenCL features)
-} SHADER_CHECKER_ERROR;
-
 typedef enum _DRAW_TYPE {
     DRAW = 0,
     DRAW_INDEXED = 1,
@@ -606,28 +392,6 @@
     unordered_set<VkCommandBuffer> referencingCmdBuffers;
     vector<MT_FB_ATTACHMENT_INFO> attachments;
 };
-
-// Descriptor Data structures
-// Layout Node has the core layout data
-typedef struct _LAYOUT_NODE {
-    VkDescriptorSetLayout layout;
-    VkDescriptorSetLayoutCreateInfo createInfo;
-    uint32_t startIndex;                                 // 1st index of this layout
-    uint32_t endIndex;                                   // last index of this layout
-    uint32_t dynamicDescriptorCount;                     // Total count of dynamic descriptors used
-                                                         // by this layout
-    uint32_t immutableSamplerCount;                      // # of immutable samplers in this layout
-    vector<VkDescriptorType> descriptorTypes;            // Type per descriptor in this
-                                                         // layout to verify correct
-                                                         // updates
-    vector<VkShaderStageFlags> stageFlags;               // stageFlags per descriptor in this
-                                                         // layout to verify correct updates
-    unordered_map<uint32_t, uint32_t> bindingToIndexMap; // map set binding # to
-                                                         // createInfo.pBindings index
-    // Default constructor
-    _LAYOUT_NODE() : layout{}, createInfo{}, startIndex(0), endIndex(0), dynamicDescriptorCount(0), immutableSamplerCount(0){};
-} LAYOUT_NODE;
-
 // Store layouts and pushconstants for PipelineLayout
 struct PIPELINE_LAYOUT_NODE {
     vector<VkDescriptorSetLayout> descriptorSetLayouts;
@@ -641,14 +405,13 @@
     VkDescriptorPool pool;
     // Head of LL of all Update structs for this set
     GENERIC_HEADER *pUpdateStructs;
-    // Total num of descriptors in this set (count of its layout plus all prior layouts)
-    uint32_t descriptorCount;
+    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
-    LAYOUT_NODE *pLayout;           // Layout for this set
+    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), pLayout(nullptr),
+        : set(VK_NULL_HANDLE), pool(VK_NULL_HANDLE), pUpdateStructs(nullptr), descriptorCount(0), p_layout(nullptr),
           pNext(nullptr){};
 };
 
diff --git a/layers/core_validation_error_enums.h b/layers/core_validation_error_enums.h
new file mode 100644
index 0000000..f17ee9c
--- /dev/null
+++ b/layers/core_validation_error_enums.h
@@ -0,0 +1,243 @@
+/* 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_ERROR_ENUMS_H_
+#define CORE_VALIDATION_ERROR_ENUMS_H_
+
+// Mem Tracker ERROR codes
+typedef enum _MEM_TRACK_ERROR {
+    MEMTRACK_NONE,                         // Used for INFO & other non-error messages
+    MEMTRACK_INVALID_CB,                   // Cmd Buffer invalid
+    MEMTRACK_INVALID_MEM_OBJ,              // Invalid Memory Object
+    MEMTRACK_INVALID_ALIASING,             // Invalid Memory Aliasing
+    MEMTRACK_INVALID_LAYOUT,               // Invalid Layout
+    MEMTRACK_INTERNAL_ERROR,               // Bug in Mem Track Layer internal data structures
+    MEMTRACK_FREED_MEM_REF,                // MEM Obj freed while it still has obj and/or CB refs
+    MEMTRACK_MEM_OBJ_CLEAR_EMPTY_BINDINGS, // Clearing bindings on mem obj that doesn't have any bindings
+    MEMTRACK_MISSING_MEM_BINDINGS,         // Trying to retrieve mem bindings, but none found (may be internal error)
+    MEMTRACK_INVALID_OBJECT,               // Attempting to reference generic VK Object that is invalid
+    MEMTRACK_MEMORY_BINDING_ERROR,         // Error during one of many calls that bind memory to object or CB
+    MEMTRACK_MEMORY_LEAK,                  // Failure to call vkFreeMemory on Mem Obj prior to DestroyDevice
+    MEMTRACK_INVALID_STATE,                // Memory not in the correct state
+    MEMTRACK_RESET_CB_WHILE_IN_FLIGHT,     // vkResetCommandBuffer() called on a CB that hasn't completed
+    MEMTRACK_INVALID_FENCE_STATE,          // Invalid Fence State signaled or used
+    MEMTRACK_REBIND_OBJECT,                // Non-sparse object bindings are immutable
+    MEMTRACK_INVALID_USAGE_FLAG,           // Usage flags specified at image/buffer create conflict w/ use of object
+    MEMTRACK_INVALID_MAP,                  // Size flag specified at alloc is too small for mapping range
+} MEM_TRACK_ERROR;
+
+// Draw State ERROR codes
+typedef enum _DRAW_STATE_ERROR {
+    // TODO: Remove the comments here or expand them. There isn't any additional information in the
+    // comments than in the name in almost all cases.
+    DRAWSTATE_NONE,                          // Used for INFO & other non-error messages
+    DRAWSTATE_INTERNAL_ERROR,                // Error with DrawState internal data structures
+    DRAWSTATE_NO_PIPELINE_BOUND,             // Unable to identify a bound pipeline
+    DRAWSTATE_INVALID_POOL,                  // Invalid DS pool
+    DRAWSTATE_INVALID_SET,                   // Invalid DS
+    DRAWSTATE_INVALID_RENDER_AREA,           // Invalid renderArea
+    DRAWSTATE_INVALID_LAYOUT,                // Invalid DS layout
+    DRAWSTATE_INVALID_IMAGE_LAYOUT,          // Invalid Image layout
+    DRAWSTATE_INVALID_PIPELINE,              // Invalid Pipeline handle referenced
+    DRAWSTATE_INVALID_PIPELINE_LAYOUT,       // Invalid PipelineLayout
+    DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, // Attempt to create a pipeline
+                                             // with invalid state
+    DRAWSTATE_INVALID_COMMAND_BUFFER,        // Invalid CommandBuffer referenced
+    DRAWSTATE_INVALID_BARRIER,               // Invalid Barrier
+    DRAWSTATE_INVALID_BUFFER,                // Invalid Buffer
+    DRAWSTATE_INVALID_QUERY,                 // Invalid Query
+    DRAWSTATE_INVALID_FENCE,                 // Invalid Fence
+    DRAWSTATE_INVALID_SEMAPHORE,             // Invalid Semaphore
+    DRAWSTATE_INVALID_EVENT,                 // Invalid Event
+    DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS,       // binding in vkCmdBindVertexData() too
+                                             // large for PSO's
+                                             // pVertexBindingDescriptions array
+    DRAWSTATE_VTX_INDEX_ALIGNMENT_ERROR,     // binding offset in
+                                             // vkCmdBindIndexBuffer() out of
+                                             // alignment based on indexType
+    // DRAWSTATE_MISSING_DOT_PROGRAM,              // No "dot" program in order
+    // to generate png image
+    DRAWSTATE_OUT_OF_MEMORY,                          // malloc failed
+    DRAWSTATE_INVALID_DESCRIPTOR_SET,                 // Descriptor Set handle is unknown
+    DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH,               // Type in layout vs. update are not the
+                                                      // same
+    DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH,         // StageFlags in layout are not
+                                                      // the same throughout a single
+                                                      // VkWriteDescriptorSet update
+    DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS,        // Descriptors set for update out
+                                                      // of bounds for corresponding
+                                                      // layout section
+    DRAWSTATE_DESCRIPTOR_POOL_EMPTY,                  // Attempt to allocate descriptor from a
+                                                      // pool with no more descriptors of that
+                                                      // type available
+    DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL,           // Invalid to call
+                                                      // vkFreeDescriptorSets on Sets
+                                                      // allocated from a NON_FREE Pool
+    DRAWSTATE_INVALID_UPDATE_INDEX,                   // Index of requested update is invalid for
+                                                      // specified descriptors set
+    DRAWSTATE_INVALID_UPDATE_STRUCT,                  // Struct in DS Update tree is of invalid
+                                                      // type
+    DRAWSTATE_NUM_SAMPLES_MISMATCH,                   // Number of samples in bound PSO does not
+                                                      // match number in FB of current RenderPass
+    DRAWSTATE_NO_END_COMMAND_BUFFER,                  // Must call vkEndCommandBuffer() before
+                                                      // QueueSubmit on that commandBuffer
+    DRAWSTATE_NO_BEGIN_COMMAND_BUFFER,                // Binding cmds or calling End on CB that
+                                                      // never had vkBeginCommandBuffer()
+                                                      // called on it
+    DRAWSTATE_COMMAND_BUFFER_SINGLE_SUBMIT_VIOLATION, // Cmd Buffer created with
+    // VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
+    // flag is submitted
+    // multiple times
+    DRAWSTATE_INVALID_SECONDARY_COMMAND_BUFFER, // vkCmdExecuteCommands() called
+                                                // with a primary commandBuffer
+                                                // in pCommandBuffers array
+    DRAWSTATE_VIEWPORT_NOT_BOUND,               // Draw submitted with no viewport state bound
+    DRAWSTATE_SCISSOR_NOT_BOUND,                // Draw submitted with no scissor state bound
+    DRAWSTATE_LINE_WIDTH_NOT_BOUND,             // Draw submitted with no line width state
+                                                // bound
+    DRAWSTATE_DEPTH_BIAS_NOT_BOUND,             // Draw submitted with no depth bias state
+                                                // bound
+    DRAWSTATE_BLEND_NOT_BOUND,                  // Draw submitted with no blend state bound when
+                                                // color write enabled
+    DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND,           // Draw submitted with no depth bounds
+                                                // state bound when depth enabled
+    DRAWSTATE_STENCIL_NOT_BOUND,                // Draw submitted with no stencil state bound
+                                                // when stencil enabled
+    DRAWSTATE_INDEX_BUFFER_NOT_BOUND,           // Draw submitted with no depth-stencil
+                                                // state bound when depth write enabled
+    DRAWSTATE_PIPELINE_LAYOUTS_INCOMPATIBLE,    // Draw submitted PSO Pipeline
+                                                // layout that's not compatible
+                                                // with layout from
+                                                // BindDescriptorSets
+    DRAWSTATE_RENDERPASS_INCOMPATIBLE,          // Incompatible renderpasses between
+                                                // secondary cmdBuffer and primary
+                                                // cmdBuffer or framebuffer
+    DRAWSTATE_FRAMEBUFFER_INCOMPATIBLE,         // Incompatible framebuffer between
+                                                // secondary cmdBuffer and active
+                                                // renderPass
+    DRAWSTATE_INVALID_RENDERPASS,               // Use of a NULL or otherwise invalid
+                                                // RenderPass object
+    DRAWSTATE_INVALID_RENDERPASS_CMD,           // Invalid cmd submitted while a
+                                                // RenderPass is active
+    DRAWSTATE_NO_ACTIVE_RENDERPASS,             // Rendering cmd submitted without an active
+                                                // RenderPass
+    DRAWSTATE_DESCRIPTOR_SET_NOT_UPDATED,       // DescriptorSet bound but it was
+                                                // never updated. This is a warning
+                                                // code.
+    DRAWSTATE_DESCRIPTOR_SET_NOT_BOUND,         // DescriptorSet used by pipeline at
+                                                // draw time is not bound, or has been
+                                                // disturbed (which would have flagged
+                                                // previous warning)
+    DRAWSTATE_INVALID_DYNAMIC_OFFSET_COUNT,     // DescriptorSets bound with
+                                                // different number of dynamic
+                                                // descriptors that were included in
+                                                // dynamicOffsetCount
+    DRAWSTATE_CLEAR_CMD_BEFORE_DRAW,            // Clear cmd issued before any Draw in
+                                                // CommandBuffer, should use RenderPass Ops
+                                                // instead
+    DRAWSTATE_BEGIN_CB_INVALID_STATE,           // CB state at Begin call is bad. Can be
+                                                // Primary/Secondary CB created with
+                                                // mismatched FB/RP information or CB in
+                                                // RECORDING state
+    DRAWSTATE_INVALID_CB_SIMULTANEOUS_USE,      // CmdBuffer is being used in
+                                                // violation of
+    // VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT
+    // rules (i.e. simultaneous use w/o
+    // that bit set)
+    DRAWSTATE_INVALID_COMMAND_BUFFER_RESET, // Attempting to call Reset (or
+                                            // Begin on recorded cmdBuffer) that
+                                            // was allocated from Pool w/o
+    // VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
+    // bit set
+    DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH,             // Count for viewports and scissors
+                                                     // mismatch and/or state doesn't match
+                                                     // count
+    DRAWSTATE_INVALID_IMAGE_ASPECT,                  // Image aspect is invalid for the current
+                                                     // operation
+    DRAWSTATE_MISSING_ATTACHMENT_REFERENCE,          // Attachment reference must be
+                                                     // present in active subpass
+    DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR,              // A Descriptor of *_SAMPLER type is
+                                                     // being updated with an invalid or bad
+                                                     // Sampler
+    DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, // Descriptors of
+                                                     // *COMBINED_IMAGE_SAMPLER
+                                                     // type are being updated
+                                                     // where some, but not all,
+                                                     // of the updates use
+                                                     // immutable samplers
+    DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR,            // A Descriptor of *_IMAGE or
+                                                     // *_ATTACHMENT type is being updated
+                                                     // with an invalid or bad ImageView
+    DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR,           // A Descriptor of *_TEXEL_BUFFER
+                                                     // type is being updated with an
+                                                     // invalid or bad BufferView
+    DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR,           // A Descriptor of
+    // *_[UNIFORM|STORAGE]_BUFFER_[DYNAMIC]
+    // type is being updated with an
+    // invalid or bad BufferView
+    DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW,       // At draw time the dynamic offset
+                                             // combined with buffer offset and range
+                                             // oversteps size of buffer
+    DRAWSTATE_DOUBLE_DESTROY,                // Destroying an object twice
+    DRAWSTATE_OBJECT_INUSE,                  // Destroying or modifying an object in use by a
+                                             // command buffer
+    DRAWSTATE_QUEUE_FORWARD_PROGRESS,        // Queue cannot guarantee forward progress
+    DRAWSTATE_INVALID_BUFFER_MEMORY_OFFSET,  // Dynamic Buffer Offset
+                                             // violates memory requirements limit
+    DRAWSTATE_INVALID_TEXEL_BUFFER_OFFSET,   // Dynamic Texel Buffer Offsets
+                                             // violate device limit
+    DRAWSTATE_INVALID_UNIFORM_BUFFER_OFFSET, // Dynamic Uniform Buffer Offsets
+                                             // violate device limit
+    DRAWSTATE_INVALID_STORAGE_BUFFER_OFFSET, // Dynamic Storage Buffer Offsets
+                                             // violate device limit
+    DRAWSTATE_INDEPENDENT_BLEND,             // If independent blending is not enabled, all
+                                             // elements of pAttachmentsMustBeIdentical
+    DRAWSTATE_DISABLED_LOGIC_OP,             // If logic operations is not enabled, logicOpEnable
+                                             // must be VK_FALSE
+    DRAWSTATE_INVALID_LOGIC_OP,              // If logicOpEnable is VK_TRUE, logicOp must
+                                             // must be a valid VkLogicOp value
+    DRAWSTATE_INVALID_QUEUE_INDEX,           // Specified queue index exceeds number
+                                             // of queried queue families
+    DRAWSTATE_PUSH_CONSTANTS_ERROR,          // Push constants exceed maxPushConstantSize
+} DRAW_STATE_ERROR;
+
+typedef enum _SHADER_CHECKER_ERROR {
+    SHADER_CHECKER_NONE,
+    SHADER_CHECKER_INTERFACE_TYPE_MISMATCH,    // Type mismatch between shader stages or shader and pipeline
+    SHADER_CHECKER_OUTPUT_NOT_CONSUMED,        // Entry appears in output interface, but missing in input
+    SHADER_CHECKER_INPUT_NOT_PRODUCED,         // Entry appears in input interface, but missing in output
+    SHADER_CHECKER_NON_SPIRV_SHADER,           // Shader image is not SPIR-V
+    SHADER_CHECKER_INCONSISTENT_SPIRV,         // General inconsistency within a SPIR-V module
+    SHADER_CHECKER_UNKNOWN_STAGE,              // Stage is not supported by analysis
+    SHADER_CHECKER_INCONSISTENT_VI,            // VI state contains conflicting binding or attrib descriptions
+    SHADER_CHECKER_MISSING_DESCRIPTOR,         // Shader attempts to use a descriptor binding not declared in the layout
+    SHADER_CHECKER_BAD_SPECIALIZATION,         // Specialization map entry points outside specialization data block
+    SHADER_CHECKER_MISSING_ENTRYPOINT,         // Shader module does not contain the requested entrypoint
+    SHADER_CHECKER_PUSH_CONSTANT_OUT_OF_RANGE, // Push constant variable is not in a push constant range
+    SHADER_CHECKER_PUSH_CONSTANT_NOT_ACCESSIBLE_FROM_STAGE, // Push constant range exists, but not accessible from stage
+    SHADER_CHECKER_DESCRIPTOR_TYPE_MISMATCH,                // Descriptor type does not match shader resource type
+    SHADER_CHECKER_DESCRIPTOR_NOT_ACCESSIBLE_FROM_STAGE,    // Descriptor used by shader, but not accessible from stage
+    SHADER_CHECKER_FEATURE_NOT_ENABLED,                     // Shader uses capability requiring a feature not enabled on device
+    SHADER_CHECKER_BAD_CAPABILITY,                          // Shader uses capability not supported by Vulkan (OpenCL features)
+} SHADER_CHECKER_ERROR;
+
+#endif // CORE_VALIDATION_ERROR_ENUMS_H_
\ No newline at end of file
diff --git a/layers/descriptor_sets.h b/layers/descriptor_sets.h
new file mode 100644
index 0000000..ad2621c
--- /dev/null
+++ b/layers/descriptor_sets.h
@@ -0,0 +1,262 @@
+/* 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>
+ */
+#ifndef CORE_VALIDATION_DESCRIPTOR_SETS_H_
+#define CORE_VALIDATION_DESCRIPTOR_SETS_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
+
+#pragma once
+#include "core_validation_error_enums.h"
+#include "vk_layer_logging.h"
+#include "vk_safe_struct.h"
+#include "vulkan/vk_layer.h"
+#include <unordered_map>
+#include <vector>
+
+// Descriptor Data structures
+
+/*
+ * DescriptorSetLayout class
+ *
+ * Overview - This class encapsulates the Vulkan VkDescriptorSetLayout data (layout).
+ *   A layout consists of some number of bindings, each of which has a binding#, a
+ *   type, descriptor count, stage flags, and pImmutableSamplers.
+ *
+ * Index vs Binding - A layout is created with an array of VkDescriptorSetLayoutBinding
+ *  where each array index will have a corresponding binding# that is defined in that struct.
+ *  This class, therefore, provides utility functions where you can retrieve data for
+ *  layout bindings based on either the original index into the pBindings array, or based
+ *  on the binding#.
+ *  Typically if you want to cover all of the bindings in a layout, you can do that by
+ *   iterating over GetBindingCount() bindings and using the Get*FromIndex() functions.
+ *  Otherwise, you can use the Get*FromBinding() functions to just grab binding info
+ *   for a particular binding#.
+ *
+ * Global Index - The "Index" referenced above is the index into the original pBindings
+ *  array. So there are as many indices as there are bindings.
+ *  This class also has the concept of a Global Index. For the global index functions,
+ *  there are as many global indices as there are descriptors in the layout.
+ *  For the global index, consider all of the bindings to be a flat array where
+ *  descriptor 0 of pBinding[0] is index 0 and each descriptor in the layout increments
+ *  from there. So if pBinding[0] in this example had descriptorCount of 10, then
+ *  the GlobalStartIndex of pBinding[1] will be 10 where 0-9 are the global indices
+ *  for pBinding[0].
+ */
+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_; };
+    // Return true if given binding is present in this layout
+    bool HasBinding(const uint32_t binding) { return binding_to_index_map_.count(binding); };
+    // 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);
+    // 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);
+    VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t);
+    VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t);
+    // For a particular binding, get the global index
+    uint32_t GetGlobalStartIndexFromBinding(const uint32_t);
+    uint32_t GetGlobalEndIndexFromBinding(const uint32_t);
+
+  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_;
+    uint32_t binding_count_; // # of bindings in this layout
+    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(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_) {
+        if (binding.pImmutableSamplers)
+            delete[] binding.pImmutableSamplers;
+    }
+}
+VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromBinding(const uint32_t binding) {
+    if (!binding_to_index_map_.count(binding))
+        return nullptr;
+    return reinterpret_cast<VkDescriptorSetLayoutBinding const *>(&bindings_[binding_to_index_map_[binding]]);
+}
+VkDescriptorSetLayoutBinding const *DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) {
+    if (index >= bindings_.size())
+        return nullptr;
+    return reinterpret_cast<VkDescriptorSetLayoutBinding const *>(&bindings_[index]);
+}
+// 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 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_sd_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?
+        // VkDescriptorSetLayoutBinding *rh_binding;
+        // rh_ds_layout->FillDescriptorSetLayoutBindingStructFromBinding(binding.binding, rh_binding);
+        if (binding.descriptorCount != rh_ds_layout->GetTotalDescriptorCount()) {
+            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->GetTotalDescriptorCount();
+            *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;
+}
+#endif // CORE_VALIDATION_DESCRIPTOR_SETS_H_
\ No newline at end of file
diff --git a/layers/vk_layer_logging.h b/layers/vk_layer_logging.h
index 1be275e..6a3ec01 100644
--- a/layers/vk_layer_logging.h
+++ b/layers/vk_layer_logging.h
@@ -22,15 +22,16 @@
 #ifndef LAYER_LOGGING_H
 #define LAYER_LOGGING_H
 
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <unordered_map>
-#include <inttypes.h>
-#include "vk_loader_platform.h"
-#include "vulkan/vk_layer.h"
+#include "vk_layer_config.h"
 #include "vk_layer_data.h"
 #include "vk_layer_table.h"
+#include "vk_loader_platform.h"
+#include "vulkan/vk_layer.h"
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unordered_map>
 
 typedef struct _debug_report_data {
     VkLayerDbgFunctionNode *g_pDbgFunctionHead;
diff --git a/layers/vk_layer_table.h b/layers/vk_layer_table.h
index 983bd7a..45b8f6e 100644
--- a/layers/vk_layer_table.h
+++ b/layers/vk_layer_table.h
@@ -19,6 +19,7 @@
 
 #pragma once
 
+#include "vulkan/vk_layer.h"
 #include "vulkan/vulkan.h"
 #include <unordered_map>
 
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index 8a9d4c8..81f5498 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -3049,7 +3049,7 @@
     // descriptors
     m_errorMonitor->SetDesiredFailureMsg(
         VK_DEBUG_REPORT_ERROR_BIT_EXT,
-        ", but corresponding set being bound has 5 descriptors.");
+        " has 2 descriptors, but DescriptorSetLayout ");
     vkCmdBindDescriptorSets(
         m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS,
         pipe_layout_one_desc, 0, 1, &descriptorSet[0], 0, NULL);
@@ -3059,7 +3059,7 @@
     // 4. same # of descriptors but mismatch in type
     m_errorMonitor->SetDesiredFailureMsg(
         VK_DEBUG_REPORT_ERROR_BIT_EXT,
-        " descriptor from pipelineLayout is type 'VK_DESCRIPTOR_TYPE_SAMPLER'");
+        " is type 'VK_DESCRIPTOR_TYPE_SAMPLER' but binding ");
     vkCmdBindDescriptorSets(
         m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS,
         pipe_layout_five_samp, 0, 1, &descriptorSet[0], 0, NULL);
@@ -3069,7 +3069,7 @@
     // 5. same # of descriptors but mismatch in stageFlags
     m_errorMonitor->SetDesiredFailureMsg(
         VK_DEBUG_REPORT_ERROR_BIT_EXT,
-        " descriptor from pipelineLayout has stageFlags ");
+        " has stageFlags 16 but binding 0 for DescriptorSetLayout ");
     vkCmdBindDescriptorSets(
         m_commandBuffer->GetBufferHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS,
         pipe_layout_fs_only, 0, 1, &descriptorSet[0], 0, NULL);
@@ -5159,9 +5159,10 @@
     VkResult err;
 
     m_errorMonitor->SetDesiredFailureMsg(
-        VK_DEBUG_REPORT_ERROR_BIT_EXT, "Copy descriptor update index 0, update "
-                                       "count #1, has src update descriptor "
-                                       "type VK_DESCRIPTOR_TYPE_SAMPLER ");
+        VK_DEBUG_REPORT_ERROR_BIT_EXT,
+        "Copy descriptor update index 0, has src update descriptor "
+        "type VK_DESCRIPTOR_TYPE_SAMPLER that does not match overlapping "
+        "dest ");
 
     ASSERT_NO_FATAL_FAILURE(InitState());
     // VkDescriptorSetObj descriptorSet(m_device);
diff --git a/vk_helper.py b/vk_helper.py
index 23f11dc..c9ee9cd 100755
--- a/vk_helper.py
+++ b/vk_helper.py
@@ -1561,6 +1561,7 @@
     def _generateSafeStructHeader(self):
         header = []
         header.append("//#includes, #defines, globals and such...\n")
+        header.append('#pragma once\n')
         header.append('#include "vulkan/vulkan.h"')
         return "".join(header)
 
diff --git a/vk_layer_documentation_generate.py b/vk_layer_documentation_generate.py
index 485a187..a14e16b 100755
--- a/vk_layer_documentation_generate.py
+++ b/vk_layer_documentation_generate.py
@@ -49,15 +49,15 @@
 # TODO : Need list of known validation layers to use as default input
 #  Just a couple of flat lists right now, but may need to make this input file
 #  or at least a more dynamic data structure
-layer_inputs = { 'draw_state' : {'header' : 'layers/core_validation.h',
+layer_inputs = { 'draw_state' : {'header' : 'layers/core_validation_error_enums.h',
                                  'source' : 'layers/core_validation.cpp',
                                  'generated' : False,
                                  'error_enum' : 'DRAW_STATE_ERROR'},
-                 'shader_checker' : {'header' : 'layers/core_validation.h',
+                 'shader_checker' : {'header' : 'layers/core_validation_error_enums.h',
                                  'source' : 'layers/core_validation.cpp',
                                  'generated' : False,
                                  'error_enum' : 'SHADER_CHECKER_ERROR'},
-                 'mem_tracker' : {'header' : 'layers/core_validation.h',
+                 'mem_tracker' : {'header' : 'layers/core_validation_error_enums.h',
                                   'source' : 'layers/core_validation.cpp',
                                   'generated' : False,
                                   'error_enum' : 'MEM_TRACK_ERROR'},