layers: Split DescriptorSetLayout data structure
authorJohn Zulauf <jzulauf@lunarg.com>
Fri, 16 Feb 2018 19:58:37 +0000 (12:58 -0700)
committerjzulauf-lunarg <32470354+jzulauf-lunarg@users.noreply.github.com>
Wed, 7 Mar 2018 20:11:29 +0000 (13:11 -0700)
In preparing for use of "common definiton" id's split the
DescriptorSetLayout data structure into handle specific and common (def)
components.  Object interface is preserved.

Change-Id: I5c6b1e726aa70de548c65a5f5ad08726b0a7507b

layers/descriptor_sets.cpp
layers/descriptor_sets.h

index 9294dde..96b7502 100644 (file)
@@ -28,6 +28,7 @@
 #include "buffer_validation.h"
 #include <sstream>
 #include <algorithm>
+#include <memory>
 
 struct BindingNumCmp {
     bool operator()(const VkDescriptorSetLayoutBinding *a, const VkDescriptorSetLayoutBinding *b) const {
@@ -37,14 +38,8 @@ struct BindingNumCmp {
 
 // Construct DescriptorSetLayout instance from given create info
 // Proactively reserve and resize as possible, as the reallocation was visible in profiling
-cvdescriptorset::DescriptorSetLayout::DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *p_create_info,
-                                                          const VkDescriptorSetLayout layout)
-    : layout_(layout),
-      layout_destroyed_(false),
-      flags_(p_create_info->flags),
-      binding_count_(0),
-      descriptor_count_(0),
-      dynamic_descriptor_count_(0) {
+cvdescriptorset::DescriptorSetLayoutDef::DescriptorSetLayoutDef(const VkDescriptorSetLayoutCreateInfo *p_create_info)
+    : flags_(p_create_info->flags), binding_count_(0), descriptor_count_(0), dynamic_descriptor_count_(0) {
     binding_type_stats_ = {0, 0, 0};
     std::set<const VkDescriptorSetLayoutBinding *, BindingNumCmp> sorted_bindings;
     const uint32_t input_bindings_count = p_create_info->bindingCount;
@@ -106,91 +101,39 @@ cvdescriptorset::DescriptorSetLayout::DescriptorSetLayout(const VkDescriptorSetL
     }
 }
 
-// Validate descriptor set layout create info
-bool cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(const debug_report_data *report_data,
-                                                              const VkDescriptorSetLayoutCreateInfo *create_info,
-                                                              const bool push_descriptor_ext, const uint32_t max_push_descriptors) {
-    bool skip = false;
-    std::unordered_set<uint32_t> bindings;
-    uint64_t total_descriptors = 0;
-
-    const bool push_descriptor_set = create_info->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
-    if (push_descriptor_set && !push_descriptor_ext) {
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
-                        DRAWSTATE_EXTENSION_NOT_ENABLED, "DS",
-                        "Attemped to use %s in %s but its required extension %s has not been enabled.\n",
-                        "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR", "VkDescriptorSetLayoutCreateInfo::flags",
-                        VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
-    }
-
-    auto valid_type = [push_descriptor_set](const VkDescriptorType type) {
-        return !push_descriptor_set ||
-               ((type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) && (type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC));
-    };
-
-    for (uint32_t i = 0; i < create_info->bindingCount; ++i) {
-        const auto &binding_info = create_info->pBindings[i];
-        if (!bindings.insert(binding_info.binding).second) {
-            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
-                            VALIDATION_ERROR_0500022e, "DS", "duplicated binding number in VkDescriptorSetLayoutBinding. %s",
-                            validation_error_map[VALIDATION_ERROR_0500022e]);
-        }
-        if (!valid_type(binding_info.descriptorType)) {
-            skip |=
-                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
-                        VALIDATION_ERROR_05000230, "DS",
-                        "invalid type %s ,for push descriptors in VkDescriptorSetLayoutBinding entry %" PRIu32 ". %s",
-                        string_VkDescriptorType(binding_info.descriptorType), i, validation_error_map[VALIDATION_ERROR_05000230]);
-        }
-        total_descriptors += binding_info.descriptorCount;
-    }
-
-    if ((push_descriptor_set) && (total_descriptors > max_push_descriptors)) {
-        const char *undefined = push_descriptor_ext ? "" : " -- undefined";
-        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
-                        VALIDATION_ERROR_05000232, "DS",
-                        "for push descriptor, total descriptor count in layout (%" PRIu64
-                        ") must not be greater than VkPhysicalDevicePushDescriptorPropertiesKHR::maxPushDescriptors (%" PRIu32
-                        "%s). %s",
-                        total_descriptors, max_push_descriptors, undefined, validation_error_map[VALIDATION_ERROR_05000232]);
-    }
-
-    return skip;
-}
-
 // Return valid index or "end" i.e. binding_count_;
 // The asserts in "Get" are reduced to the set where no valid answer(like null or 0) could be given
 // Common code for all binding lookups.
-uint32_t cvdescriptorset::DescriptorSetLayout::GetIndexFromBinding(uint32_t binding) const {
+uint32_t cvdescriptorset::DescriptorSetLayoutDef::GetIndexFromBinding(uint32_t binding) const {
     const auto &bi_itr = binding_to_index_map_.find(binding);
     if (bi_itr != binding_to_index_map_.cend()) return bi_itr->second;
     return GetBindingCount();
 }
-VkDescriptorSetLayoutBinding const *cvdescriptorset::DescriptorSetLayout::GetDescriptorSetLayoutBindingPtrFromIndex(
+VkDescriptorSetLayoutBinding const *cvdescriptorset::DescriptorSetLayoutDef::GetDescriptorSetLayoutBindingPtrFromIndex(
     const uint32_t index) const {
     if (index >= bindings_.size()) return nullptr;
     return bindings_[index].ptr();
 }
 // Return descriptorCount for given index, 0 if index is unavailable
-uint32_t cvdescriptorset::DescriptorSetLayout::GetDescriptorCountFromIndex(const uint32_t index) const {
+uint32_t cvdescriptorset::DescriptorSetLayoutDef::GetDescriptorCountFromIndex(const uint32_t index) const {
     if (index >= bindings_.size()) return 0;
     return bindings_[index].descriptorCount;
 }
 // For the given index, return descriptorType
-VkDescriptorType cvdescriptorset::DescriptorSetLayout::GetTypeFromIndex(const uint32_t index) const {
+VkDescriptorType cvdescriptorset::DescriptorSetLayoutDef::GetTypeFromIndex(const uint32_t index) const {
     assert(index < bindings_.size());
     if (index < bindings_.size()) return bindings_[index].descriptorType;
     return VK_DESCRIPTOR_TYPE_MAX_ENUM;
 }
 // For the given index, return stageFlags
-VkShaderStageFlags cvdescriptorset::DescriptorSetLayout::GetStageFlagsFromIndex(const uint32_t index) const {
+VkShaderStageFlags cvdescriptorset::DescriptorSetLayoutDef::GetStageFlagsFromIndex(const uint32_t index) const {
     assert(index < bindings_.size());
     if (index < bindings_.size()) return bindings_[index].stageFlags;
     return VkShaderStageFlags(0);
 }
 
 // For the given global index, return index
-uint32_t cvdescriptorset::DescriptorSetLayout::GetIndexFromGlobalIndex(const uint32_t global_index) const {
+uint32_t cvdescriptorset::DescriptorSetLayoutDef::GetIndexFromGlobalIndex(const uint32_t global_index) const {
     auto start_it = global_start_to_index_map_.upper_bound(global_index);
     uint32_t index = binding_count_;
     assert(start_it != global_start_to_index_map_.cbegin());
@@ -207,7 +150,7 @@ uint32_t cvdescriptorset::DescriptorSetLayout::GetIndexFromGlobalIndex(const uin
 
 // For the given binding, return the global index range
 // As start and end are often needed in pairs, get both with a single hash lookup.
-const cvdescriptorset::IndexRange &cvdescriptorset::DescriptorSetLayout::GetGlobalIndexRangeFromBinding(
+const cvdescriptorset::IndexRange &cvdescriptorset::DescriptorSetLayoutDef::GetGlobalIndexRangeFromBinding(
     const uint32_t binding) const {
     assert(binding_to_global_index_range_map_.count(binding));
     // In error case max uint32_t so index is out of bounds to break ASAP
@@ -220,7 +163,7 @@ const cvdescriptorset::IndexRange &cvdescriptorset::DescriptorSetLayout::GetGlob
 }
 
 // For given binding, return ptr to ImmutableSampler array
-VkSampler const *cvdescriptorset::DescriptorSetLayout::GetImmutableSamplerPtrFromBinding(const uint32_t binding) const {
+VkSampler const *cvdescriptorset::DescriptorSetLayoutDef::GetImmutableSamplerPtrFromBinding(const uint32_t binding) const {
     const auto &bi_itr = binding_to_index_map_.find(binding);
     if (bi_itr != binding_to_index_map_.end()) {
         return bindings_[bi_itr->second].pImmutableSamplers;
@@ -228,14 +171,14 @@ VkSampler const *cvdescriptorset::DescriptorSetLayout::GetImmutableSamplerPtrFro
     return nullptr;
 }
 // Move to next valid binding having a non-zero binding count
-uint32_t cvdescriptorset::DescriptorSetLayout::GetNextValidBinding(const uint32_t binding) const {
+uint32_t cvdescriptorset::DescriptorSetLayoutDef::GetNextValidBinding(const uint32_t binding) const {
     auto it = non_empty_bindings_.upper_bound(binding);
     assert(it != non_empty_bindings_.cend());
     if (it != non_empty_bindings_.cend()) return *it;
     return GetMaxBinding() + 1;
 }
 // For given index, return ptr to ImmutableSampler array
-VkSampler const *cvdescriptorset::DescriptorSetLayout::GetImmutableSamplerPtrFromIndex(const uint32_t index) const {
+VkSampler const *cvdescriptorset::DescriptorSetLayoutDef::GetImmutableSamplerPtrFromIndex(const uint32_t index) const {
     if (index < bindings_.size()) {
         return bindings_[index].pImmutableSamplers;
     }
@@ -247,11 +190,18 @@ bool cvdescriptorset::DescriptorSetLayout::IsCompatible(DescriptorSetLayout cons
                                                         std::string *error_msg) const {
     // Trivial case
     if (layout_ == rh_ds_layout->GetDescriptorSetLayout()) return true;
-    if (descriptor_count_ != rh_ds_layout->descriptor_count_) {
+    return get_layout_def()->IsCompatible(layout_, rh_ds_layout->GetDescriptorSetLayout(), rh_ds_layout->get_layout_def(),
+                                          error_msg);
+}
+
+bool cvdescriptorset::DescriptorSetLayoutDef::IsCompatible(VkDescriptorSetLayout ds_layout, VkDescriptorSetLayout rh_ds_layout,
+                                                           DescriptorSetLayoutDef const *const rh_ds_layout_def,
+                                                           std::string *error_msg) const {
+    if (descriptor_count_ != rh_ds_layout_def->descriptor_count_) {
         std::stringstream error_str;
-        error_str << "DescriptorSetLayout " << layout_ << " has " << descriptor_count_ << " descriptors, but DescriptorSetLayout "
-                  << rh_ds_layout->GetDescriptorSetLayout() << ", which comes from pipelineLayout, has "
-                  << rh_ds_layout->descriptor_count_ << " descriptors.";
+        error_str << "DescriptorSetLayout " << ds_layout << " has " << descriptor_count_ << " descriptors, but DescriptorSetLayout "
+                  << rh_ds_layout << ", which comes from pipelineLayout, has " << rh_ds_layout_def->descriptor_count_
+                  << " descriptors.";
         *error_msg = error_str.str();
         return false;  // trivial fail case
     }
@@ -260,29 +210,28 @@ bool cvdescriptorset::DescriptorSetLayout::IsCompatible(DescriptorSetLayout cons
     for (auto binding : bindings_) {
         // TODO : Do we also need to check immutable samplers?
         // VkDescriptorSetLayoutBinding *rh_binding;
-        if (binding.descriptorCount != rh_ds_layout->GetDescriptorCountFromBinding(binding.binding)) {
+        if (binding.descriptorCount != rh_ds_layout_def->GetDescriptorCountFromBinding(binding.binding)) {
             std::stringstream error_str;
-            error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " has a descriptorCount of "
+            error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << ds_layout << " has a descriptorCount of "
                       << binding.descriptorCount << " but binding " << binding.binding << " for DescriptorSetLayout "
-                      << rh_ds_layout->GetDescriptorSetLayout() << ", which comes from pipelineLayout, has a descriptorCount of "
-                      << rh_ds_layout->GetDescriptorCountFromBinding(binding.binding);
+                      << rh_ds_layout << ", which comes from pipelineLayout, has a descriptorCount of "
+                      << rh_ds_layout_def->GetDescriptorCountFromBinding(binding.binding);
             *error_msg = error_str.str();
             return false;
-        } else if (binding.descriptorType != rh_ds_layout->GetTypeFromBinding(binding.binding)) {
+        } else if (binding.descriptorType != rh_ds_layout_def->GetTypeFromBinding(binding.binding)) {
             std::stringstream error_str;
-            error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " is type '"
+            error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << ds_layout << " is type '"
                       << string_VkDescriptorType(binding.descriptorType) << "' but binding " << binding.binding
-                      << " for DescriptorSetLayout " << rh_ds_layout->GetDescriptorSetLayout()
-                      << ", which comes from pipelineLayout, is type '"
-                      << string_VkDescriptorType(rh_ds_layout->GetTypeFromBinding(binding.binding)) << "'";
+                      << " for DescriptorSetLayout " << rh_ds_layout << ", which comes from pipelineLayout, is type '"
+                      << string_VkDescriptorType(rh_ds_layout_def->GetTypeFromBinding(binding.binding)) << "'";
             *error_msg = error_str.str();
             return false;
-        } else if (binding.stageFlags != rh_ds_layout->GetStageFlagsFromBinding(binding.binding)) {
+        } else if (binding.stageFlags != rh_ds_layout_def->GetStageFlagsFromBinding(binding.binding)) {
             std::stringstream error_str;
-            error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << layout_ << " has stageFlags "
-                      << binding.stageFlags << " but binding " << binding.binding << " for DescriptorSetLayout "
-                      << rh_ds_layout->GetDescriptorSetLayout() << ", which comes from pipelineLayout, has stageFlags "
-                      << rh_ds_layout->GetStageFlagsFromBinding(binding.binding);
+            error_str << "Binding " << binding.binding << " for DescriptorSetLayout " << ds_layout << " has stageFlags "
+                      << binding.stageFlags << " but binding " << binding.binding << " for DescriptorSetLayout " << rh_ds_layout
+                      << ", which comes from pipelineLayout, has stageFlags "
+                      << rh_ds_layout_def->GetStageFlagsFromBinding(binding.binding);
             *error_msg = error_str.str();
             return false;
         }
@@ -290,7 +239,7 @@ bool cvdescriptorset::DescriptorSetLayout::IsCompatible(DescriptorSetLayout cons
     return true;
 }
 
-bool cvdescriptorset::DescriptorSetLayout::IsNextBindingConsistent(const uint32_t binding) const {
+bool cvdescriptorset::DescriptorSetLayoutDef::IsNextBindingConsistent(const uint32_t binding) const {
     if (!binding_to_index_map_.count(binding + 1)) return false;
     auto const &bi_itr = binding_to_index_map_.find(binding);
     if (bi_itr != binding_to_index_map_.end()) {
@@ -313,9 +262,9 @@ bool cvdescriptorset::DescriptorSetLayout::IsNextBindingConsistent(const uint32_
 //  descriptor updates and verify that for any binding boundaries that are crossed, the next binding(s) are all consistent
 //  Consistency means that their type, stage flags, and whether or not they use immutable samplers matches
 //  If so, return true. If not, fill in error_msg and return false
-bool cvdescriptorset::DescriptorSetLayout::VerifyUpdateConsistency(uint32_t current_binding, uint32_t offset, uint32_t update_count,
-                                                                   const char *type, const VkDescriptorSet set,
-                                                                   std::string *error_msg) const {
+bool cvdescriptorset::DescriptorSetLayoutDef::VerifyUpdateConsistency(uint32_t current_binding, uint32_t offset,
+                                                                      uint32_t update_count, const char *type,
+                                                                      const VkDescriptorSet set, std::string *error_msg) const {
     // Verify consecutive bindings match (if needed)
     auto orig_binding = current_binding;
     // Track count of descriptors in the current_bindings that are remaining to be updated
@@ -346,6 +295,64 @@ bool cvdescriptorset::DescriptorSetLayout::VerifyUpdateConsistency(uint32_t curr
     return true;
 }
 
+// The DescriptorSetLayout stores the per handle data for a descriptor set layout, and references the common defintion for the
+// handle invariant portion
+cvdescriptorset::DescriptorSetLayout::DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *p_create_info,
+                                                          const VkDescriptorSetLayout layout)
+    : layout_(layout), layout_destroyed_(false), layout_id_(std::make_shared<DescriptorSetLayoutDef>(p_create_info)) {}
+
+// Validate descriptor set layout create info
+bool cvdescriptorset::DescriptorSetLayout::ValidateCreateInfo(const debug_report_data *report_data,
+                                                              const VkDescriptorSetLayoutCreateInfo *create_info,
+                                                              const bool push_descriptor_ext, const uint32_t max_push_descriptors) {
+    bool skip = false;
+    std::unordered_set<uint32_t> bindings;
+    uint64_t total_descriptors = 0;
+
+    const bool push_descriptor_set = create_info->flags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
+    if (push_descriptor_set && !push_descriptor_ext) {
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+                        DRAWSTATE_EXTENSION_NOT_ENABLED, "DS",
+                        "Attemped to use %s in %s but its required extension %s has not been enabled.\n",
+                        "VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR", "VkDescriptorSetLayoutCreateInfo::flags",
+                        VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
+    }
+
+    auto valid_type = [push_descriptor_set](const VkDescriptorType type) {
+        return !push_descriptor_set ||
+               ((type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) && (type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC));
+    };
+
+    for (uint32_t i = 0; i < create_info->bindingCount; ++i) {
+        const auto &binding_info = create_info->pBindings[i];
+        if (!bindings.insert(binding_info.binding).second) {
+            skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+                            VALIDATION_ERROR_0500022e, "DS", "duplicated binding number in VkDescriptorSetLayoutBinding. %s",
+                            validation_error_map[VALIDATION_ERROR_0500022e]);
+        }
+        if (!valid_type(binding_info.descriptorType)) {
+            skip |=
+                log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+                        VALIDATION_ERROR_05000230, "DS",
+                        "invalid type %s ,for push descriptors in VkDescriptorSetLayoutBinding entry %" PRIu32 ". %s",
+                        string_VkDescriptorType(binding_info.descriptorType), i, validation_error_map[VALIDATION_ERROR_05000230]);
+        }
+        total_descriptors += binding_info.descriptorCount;
+    }
+
+    if ((push_descriptor_set) && (total_descriptors > max_push_descriptors)) {
+        const char *undefined = push_descriptor_ext ? "" : " -- undefined";
+        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__,
+                        VALIDATION_ERROR_05000232, "DS",
+                        "for push descriptor, total descriptor count in layout (%" PRIu64
+                        ") must not be greater than VkPhysicalDevicePushDescriptorPropertiesKHR::maxPushDescriptors (%" PRIu32
+                        "%s). %s",
+                        total_descriptors, max_push_descriptors, undefined, validation_error_map[VALIDATION_ERROR_05000232]);
+    }
+
+    return skip;
+}
+
 cvdescriptorset::AllocateDescriptorSetsData::AllocateDescriptorSetsData(uint32_t count)
     : required_descriptors_by_type{}, layout_nodes(count, nullptr) {}
 
index ac5bede..a20d602 100644 (file)
@@ -81,16 +81,12 @@ typedef std::map<uint32_t, descriptor_req> BindingReqMap;
  *  10, then the GlobalStartIndex of the 2nd lowest binding# will be 10 where 0-9 are the
  *  global indices for the lowest binding#.
  */
-class DescriptorSetLayout {
+class DescriptorSetLayoutDef {
    public:
     // Constructors and destructor
-    DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *p_create_info, const VkDescriptorSetLayout layout);
-    // Validate create info - should be called prior to creation
-    static bool ValidateCreateInfo(const debug_report_data *, const VkDescriptorSetLayoutCreateInfo *, const bool, const uint32_t);
-    // Straightforward Get functions
-    VkDescriptorSetLayout GetDescriptorSetLayout() const { return layout_; };
-    bool IsDestroyed() const { return layout_destroyed_; }
-    void MarkDestroyed() { layout_destroyed_ = true; }
+    DescriptorSetLayoutDef(const VkDescriptorSetLayoutCreateInfo *p_create_info);
+    size_t hash() const;
+
     uint32_t GetTotalDescriptorCount() const { return descriptor_count_; };
     uint32_t GetDynamicDescriptorCount() const { return dynamic_descriptor_count_; };
     VkDescriptorSetLayoutCreateFlags GetCreateFlags() const { return flags_; }
@@ -102,7 +98,7 @@ class DescriptorSetLayout {
     bool HasBinding(const uint32_t binding) const { return binding_to_index_map_.count(binding) > 0; };
     // Return true if this layout is compatible with passed in layout from a pipelineLayout,
     //   else return false and update error_msg with description of incompatibility
-    bool IsCompatible(DescriptorSetLayout const *const, std::string *) const;
+    bool IsCompatible(VkDescriptorSetLayout, VkDescriptorSetLayout, DescriptorSetLayoutDef const *const, std::string *) const;
     // Return true if binding 1 beyond given exists and has same type, stageFlags & immutable sampler use
     bool IsNextBindingConsistent(const uint32_t) const;
     uint32_t GetIndexFromBinding(uint32_t binding) const;
@@ -113,6 +109,7 @@ class DescriptorSetLayout {
     VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromBinding(uint32_t binding) const {
         return GetDescriptorSetLayoutBindingPtrFromIndex(GetIndexFromBinding(binding));
     }
+    const std::vector<safe_VkDescriptorSetLayoutBinding> &GetBindings() const { return bindings_; }
     uint32_t GetDescriptorCountFromIndex(const uint32_t) const;
     uint32_t GetDescriptorCountFromBinding(const uint32_t binding) const {
         return GetDescriptorCountFromIndex(GetIndexFromBinding(binding));
@@ -157,8 +154,11 @@ class DescriptorSetLayout {
     const BindingTypeStats &GetBindingTypeStats() const { return binding_type_stats_; }
 
    private:
-    VkDescriptorSetLayout layout_;
-    bool layout_destroyed_;
+    // Only the first two are needed for hash and equality checks, the other fields are derivative them uniquely
+    VkDescriptorSetLayoutCreateFlags flags_;
+    std::vector<safe_VkDescriptorSetLayoutBinding> bindings_;
+
+    // Convenience data structures for rapid lookup of various descriptor set layout properties
     std::set<uint32_t> non_empty_bindings_;  // Containing non-emtpy bindings in numerical order
     std::unordered_map<uint32_t, uint32_t> binding_to_index_map_;
     // The following map allows an non-iterative lookup of a binding from a global index...
@@ -166,14 +166,96 @@ class DescriptorSetLayout {
     std::unordered_map<uint32_t, IndexRange> binding_to_global_index_range_map_;  // range is exclusive of .end
     // For a given binding map to associated index in the dynamic offset array
     std::unordered_map<uint32_t, uint32_t> binding_to_dynamic_array_idx_map_;
-    VkDescriptorSetLayoutCreateFlags flags_;
+
     uint32_t binding_count_;  // # of bindings in this layout
-    std::vector<safe_VkDescriptorSetLayoutBinding> bindings_;
     uint32_t descriptor_count_;  // total # descriptors in this layout
     uint32_t dynamic_descriptor_count_;
     BindingTypeStats binding_type_stats_;
 };
 
+using DescriptorSetLayoutId = std::shared_ptr<DescriptorSetLayoutDef>;
+
+class DescriptorSetLayout {
+   public:
+    // Constructors and destructor
+    DescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo *p_create_info, const VkDescriptorSetLayout layout);
+    // Validate create info - should be called prior to creation
+    static bool ValidateCreateInfo(const debug_report_data *, const VkDescriptorSetLayoutCreateInfo *, const bool, const uint32_t);
+    bool HasBinding(const uint32_t binding) const { return layout_id_->HasBinding(binding); }
+    // Return true if this layout is compatible with passed in layout from a pipelineLayout,
+    //   else return false and update error_msg with description of incompatibility
+    bool IsCompatible(DescriptorSetLayout const *const, std::string *) const;
+    // Straightforward Get functions
+    VkDescriptorSetLayout GetDescriptorSetLayout() const { return layout_; };
+    bool IsDestroyed() const { return layout_destroyed_; }
+    void MarkDestroyed() { layout_destroyed_ = true; }
+    const DescriptorSetLayoutDef *get_layout_def() const { return layout_id_.get(); }
+    uint32_t GetTotalDescriptorCount() const { return layout_id_->GetTotalDescriptorCount(); };
+    uint32_t GetDynamicDescriptorCount() const { return layout_id_->GetDynamicDescriptorCount(); };
+    uint32_t GetBindingCount() const { return layout_id_->GetBindingCount(); };
+    VkDescriptorSetLayoutCreateFlags GetCreateFlags() const { return layout_id_->GetCreateFlags(); }
+    bool IsNextBindingConsistent(const uint32_t) const;
+    uint32_t GetIndexFromBinding(uint32_t binding) const { return layout_id_->GetIndexFromBinding(binding); }
+    // Various Get functions that can either be passed a binding#, which will
+    //  be automatically translated into the appropriate index, or the index# can be passed in directly
+    uint32_t GetMaxBinding() const { return layout_id_->GetMaxBinding(); }
+    VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromIndex(const uint32_t index) const {
+        return layout_id_->GetDescriptorSetLayoutBindingPtrFromIndex(index);
+    }
+    VkDescriptorSetLayoutBinding const *GetDescriptorSetLayoutBindingPtrFromBinding(uint32_t binding) const {
+        return layout_id_->GetDescriptorSetLayoutBindingPtrFromBinding(binding);
+    }
+    const std::vector<safe_VkDescriptorSetLayoutBinding> &GetBindings() const { return layout_id_->GetBindings(); }
+    uint32_t GetDescriptorCountFromIndex(const uint32_t index) const { return layout_id_->GetDescriptorCountFromIndex(index); }
+    uint32_t GetDescriptorCountFromBinding(const uint32_t binding) const {
+        return layout_id_->GetDescriptorCountFromBinding(binding);
+    }
+    VkDescriptorType GetTypeFromIndex(const uint32_t index) const { return layout_id_->GetTypeFromIndex(index); }
+    VkDescriptorType GetTypeFromBinding(const uint32_t binding) const { return layout_id_->GetTypeFromBinding(binding); }
+    VkShaderStageFlags GetStageFlagsFromIndex(const uint32_t index) const { return layout_id_->GetStageFlagsFromIndex(index); }
+    VkShaderStageFlags GetStageFlagsFromBinding(const uint32_t binding) const {
+        return layout_id_->GetStageFlagsFromBinding(binding);
+    }
+    uint32_t GetIndexFromGlobalIndex(const uint32_t global_index) const {
+        return layout_id_->GetIndexFromGlobalIndex(global_index);
+    }
+    VkDescriptorType GetTypeFromGlobalIndex(const uint32_t global_index) const {
+        return GetTypeFromIndex(GetIndexFromGlobalIndex(global_index));
+    }
+    VkSampler const *GetImmutableSamplerPtrFromBinding(const uint32_t binding) const {
+        return layout_id_->GetImmutableSamplerPtrFromBinding(binding);
+    }
+    VkSampler const *GetImmutableSamplerPtrFromIndex(const uint32_t index) const {
+        return layout_id_->GetImmutableSamplerPtrFromIndex(index);
+    }
+    // For a given binding and array index, return the corresponding index into the dynamic offset array
+    int32_t GetDynamicOffsetIndexFromBinding(uint32_t binding) const {
+        return layout_id_->GetDynamicOffsetIndexFromBinding(binding);
+    }
+    // For a particular binding, get the global index range
+    //  This call should be guarded by a call to "HasBinding(binding)" to verify that the given binding exists
+    const IndexRange &GetGlobalIndexRangeFromBinding(const uint32_t binding) const {
+        return layout_id_->GetGlobalIndexRangeFromBinding(binding);
+    }
+    // Helper function to get the next valid binding for a descriptor
+    uint32_t GetNextValidBinding(const uint32_t binding) const { return layout_id_->GetNextValidBinding(binding); }
+    // For a particular binding starting at offset and having update_count descriptors
+    //  updated, verify that for any binding boundaries crossed, the update is consistent
+    bool VerifyUpdateConsistency(uint32_t current_binding, uint32_t offset, uint32_t update_count, const char *type,
+                                 const VkDescriptorSet set, std::string *error_msg) const {
+        return layout_id_->VerifyUpdateConsistency(current_binding, offset, update_count, type, set, error_msg);
+    }
+    bool IsPushDescriptor() const { return layout_id_->IsPushDescriptor(); }
+
+    using BindingTypeStats = DescriptorSetLayoutDef::BindingTypeStats;
+    const BindingTypeStats &GetBindingTypeStats() const { return layout_id_->GetBindingTypeStats(); }
+
+   private:
+    VkDescriptorSetLayout layout_;
+    bool layout_destroyed_;
+    DescriptorSetLayoutId layout_id_;
+};
+
 /*
  * Descriptor classes
  *  Descriptor is an abstract base class from which 5 separate descriptor types are derived.
@@ -379,7 +461,7 @@ class DescriptorSet : public BASE_NODE {
     // Perform a CopyUpdate whose contents were just validated using ValidateCopyUpdate
     void PerformCopyUpdate(const VkCopyDescriptorSet *, const DescriptorSet *);
 
-    std::shared_ptr<DescriptorSetLayout const> const GetLayout() const { return p_layout_; };
+    const std::shared_ptr<DescriptorSetLayout const> GetLayout() const { return p_layout_; };
     VkDescriptorSet GetSet() const { return set_; };
     // Return unordered_set of all command buffers that this set is bound to
     std::unordered_set<GLOBAL_CB_NODE *> GetBoundCmdBuffers() const { return cb_bindings; }