layers: Pass unique error codes through descriptor validation

Descriptor validation builds up error strings at multiple levels such as
UpdateError->WriteUpdate->BufferUpdate->BufferOffset. The final error is
then reported via a log_msg() call at the top level.

In order for this design to allow for the new unique error codes, we need
to pass error codes down the chain in the same way we pass error strings
down the chain.

This change adds error msg passing for descriptor updates. Many error
codes are added in as well as comments for codes that are missing or need
to be updated.

The database file is also updated to account for all of the checks that
were updated and/or reviewed.
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index 653078a..4af5674 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -536,25 +536,30 @@
 }
 // Validate Copy update
 bool cvdescriptorset::DescriptorSet::ValidateCopyUpdate(const debug_report_data *report_data, const VkCopyDescriptorSet *update,
-                                                        const DescriptorSet *src_set, std::string *error) {
+                                                        const DescriptorSet *src_set, UNIQUE_VALIDATION_ERROR_CODE *error_code,
+                                                        std::string *error_msg) {
     // Verify idle ds
     if (in_use.load()) {
+        // TODO : Re-using Allocate Idle error code, need copy update idle error code
+        *error_code = VALIDATION_ERROR_00919;
         std::stringstream error_str;
         error_str << "Cannot call vkUpdateDescriptorSets() to perform copy update on descriptor set " << set_
                   << " that is in use by a command buffer.";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     if (!p_layout_->HasBinding(update->dstBinding)) {
+        *error_code = VALIDATION_ERROR_00966;
         std::stringstream error_str;
         error_str << "DescriptorSet " << set_ << " does not have copy update dest binding of " << update->dstBinding << ".";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     if (!src_set->HasBinding(update->srcBinding)) {
+        *error_code = VALIDATION_ERROR_00964;
         std::stringstream error_str;
         error_str << "DescriptorSet " << set_ << " does not have copy update src binding of " << update->srcBinding << ".";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     // src & dst set bindings are valid
@@ -562,26 +567,31 @@
     auto src_start_idx = src_set->GetGlobalStartIndexFromBinding(update->srcBinding) + update->srcArrayElement;
     if ((src_start_idx + update->descriptorCount) > src_set->GetTotalDescriptorCount()) {
         // SRC update out of bounds
+        *error_code = VALIDATION_ERROR_00965;
         std::stringstream error_str;
         error_str << "Attempting copy update from descriptorSet " << update->srcSet << " binding#" << update->srcBinding
                   << " with offset index of " << src_set->GetGlobalStartIndexFromBinding(update->srcBinding)
                   << " plus update array offset of " << update->srcArrayElement << " and update of " << update->descriptorCount
                   << " descriptors oversteps total number of descriptors in set: " << src_set->GetTotalDescriptorCount() << ".";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     auto dst_start_idx = p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding) + update->dstArrayElement;
     if ((dst_start_idx + update->descriptorCount) > p_layout_->GetTotalDescriptorCount()) {
         // DST update out of bounds
+        *error_code = VALIDATION_ERROR_00967;
         std::stringstream error_str;
         error_str << "Attempting copy update to descriptorSet " << set_ << " binding#" << update->dstBinding
                   << " with offset index of " << p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding)
                   << " plus update array offset of " << update->dstArrayElement << " and update of " << update->descriptorCount
                   << " descriptors oversteps total number of descriptors in set: " << p_layout_->GetTotalDescriptorCount() << ".";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     // Check that types match
+    // TODO : Base default error case going from here is VALIDATION_ERROR_00968 which covers all consistency issues, need more
+    // fine-grained error codes
+    *error_code = VALIDATION_ERROR_00968;
     auto src_type = src_set->GetTypeFromBinding(update->srcBinding);
     auto dst_type = p_layout_->GetTypeFromBinding(update->dstBinding);
     if (src_type != dst_type) {
@@ -589,14 +599,14 @@
         error_str << "Attempting copy update to descriptorSet " << set_ << " binding #" << update->dstBinding << " with type "
                   << string_VkDescriptorType(dst_type) << " from descriptorSet " << src_set->GetSet() << " binding #"
                   << update->srcBinding << " with type " << string_VkDescriptorType(src_type) << ". Types do not match.";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     // Verify consistency of src & dst bindings if update crosses binding boundaries
     if ((!src_set->GetLayout()->VerifyUpdateConsistency(update->srcBinding, update->srcArrayElement, update->descriptorCount,
-                                                        "copy update from", src_set->GetSet(), error)) ||
+                                                        "copy update from", src_set->GetSet(), error_msg)) ||
         (!p_layout_->VerifyUpdateConsistency(update->dstBinding, update->dstArrayElement, update->descriptorCount, "copy update to",
-                                             set_, error))) {
+                                             set_, error_msg))) {
         return false;
     }
     // First make sure source descriptors are updated
@@ -605,12 +615,12 @@
             std::stringstream error_str;
             error_str << "Attempting copy update from descriptorSet " << src_set << " binding #" << update->srcBinding << " but descriptor at array offset "
                       << update->srcArrayElement + i << " has not been updated.";
-            *error = error_str.str();
+            *error_msg = error_str.str();
             return false;
         }
     }
     // Update parameters all look good and descriptor updated so verify update contents
-    if (!VerifyCopyUpdateContents(update, src_set, src_type, src_start_idx, error))
+    if (!VerifyCopyUpdateContents(update, src_set, src_type, src_start_idx, error_code, error_msg))
         return false;
 
     // All checks passed so update is good
@@ -669,13 +679,15 @@
 }
 
 bool cvdescriptorset::ValidateImageUpdate(VkImageView image_view, VkImageLayout image_layout, VkDescriptorType type,
-                                          const core_validation::layer_data *dev_data,
-                                          std::string *error) {
+                                          const core_validation::layer_data *dev_data, UNIQUE_VALIDATION_ERROR_CODE *error_code,
+                                          std::string *error_msg) {
+    // TODO : Defaulting to 00943 for all cases here. Need to create new error codes for various cases.
+    *error_code = VALIDATION_ERROR_00943;
     auto iv_state = getImageViewState(dev_data, image_view);
     if (!iv_state) {
         std::stringstream error_str;
         error_str << "Invalid VkImageView: " << image_view;
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     // Note that when an imageview is created, we validated that memory is bound so no need to re-check here
@@ -691,7 +703,8 @@
         usage = image_node->createInfo.usage;
         // Validate that memory is bound to image
         if (ValidateMemoryIsBoundToImage(dev_data, image_node, "vkUpdateDescriptorSets()")) {
-            *error = "No memory bound to image.";
+            // TODO : Need new code(s) for language in 11.6 Memory Association
+            *error_msg = "No memory bound to image.";
             return false;
         }
     } else {
@@ -708,9 +721,11 @@
     if (format == VK_FORMAT_MAX_ENUM) {
         std::stringstream error_str;
         error_str << "Invalid image (" << image << ") in imageView (" << image_view << ").";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
+    // TODO : The various image aspect and format checks here are based on general spec language in 11.5 Image Views section under
+    // vkCreateImageView(). What's the best way to create unique id for these cases?
     bool ds = vk_format_is_depth_or_stencil(format);
     switch (image_layout) {
     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
@@ -719,7 +734,7 @@
             std::stringstream error_str;
             error_str << "ImageView (" << image_view << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but does "
                                                         "not have VK_IMAGE_ASPECT_COLOR_BIT set.";
-            *error = error_str.str();
+            *error_msg = error_str.str();
             return false;
         }
         // format must NOT be DS
@@ -728,7 +743,7 @@
             error_str << "ImageView (" << image_view
                       << ") uses layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL but the image format is "
                       << string_VkFormat(format) << " which is not a color format.";
-            *error = error_str.str();
+            *error_msg = error_str.str();
             return false;
         }
         break;
@@ -740,7 +755,7 @@
                 // both  must NOT be set
                 std::stringstream error_str;
                 error_str << "ImageView (" << image_view << ") has both STENCIL and DEPTH aspects set";
-                *error = error_str.str();
+                *error_msg = error_str.str();
                 return false;
             }
         } else if (!(aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
@@ -748,7 +763,7 @@
             std::stringstream error_str;
             error_str << "ImageView (" << image_view << ") has layout " << string_VkImageLayout(image_layout)
                       << " but does not have STENCIL or DEPTH aspects set";
-            *error = error_str.str();
+            *error_msg = error_str.str();
             return false;
         }
         // format must be DS
@@ -756,7 +771,7 @@
             std::stringstream error_str;
             error_str << "ImageView (" << image_view << ") has layout " << string_VkImageLayout(image_layout)
                       << " but the image format is " << string_VkFormat(format) << " which is not a depth/stencil format.";
-            *error = error_str.str();
+            *error_msg = error_str.str();
             return false;
         }
         break;
@@ -773,7 +788,7 @@
                                  "image in a descriptor set, please only set either VK_IMAGE_ASPECT_DEPTH_BIT or "
                                  "VK_IMAGE_ASPECT_STENCIL_BIT depending on whether it will be used for depth reads or stencil "
                                  "reads respectively.";
-                    *error = error_str.str();
+                    *error_msg = error_str.str();
                     return false;
                 }
             }
@@ -781,6 +796,10 @@
         break;
     }
     // Now validate that usage flags are correctly set for given type of update
+    // TODO : The various image usage bit requirements are in general spec language for VkImageUsageFlags bit block in 11.3 Images
+    // under vkCreateImage()
+    // TODO : Need to also validate case VALIDATION_ERROR_00952 where STORAGE_IMAGE & INPUT_ATTACH types must have been created with
+    // identify swizzle
     std::string error_usage_bit;
     switch (type) {
     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
@@ -810,7 +829,7 @@
         error_str << "ImageView (" << image_view << ") with usage mask 0x" << usage
                   << " being used for a descriptor update of type " << string_VkDescriptorType(type) << " does not have "
                   << error_usage_bit << " set.";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     return true;
@@ -1000,13 +1019,14 @@
                         "Cannot call vkUpdateDescriptorSets() on descriptor set 0x%" PRIxLEAST64 " that has not been allocated.",
                         reinterpret_cast<uint64_t &>(dest_set));
         } else {
+            UNIQUE_VALIDATION_ERROR_CODE error_code;
             std::string error_str;
-            if (!set_node->ValidateWriteUpdate(report_data, &p_wds[i], &error_str)) {
+            if (!set_node->ValidateWriteUpdate(report_data, &p_wds[i], &error_code, &error_str)) {
                 skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                                     reinterpret_cast<uint64_t &>(dest_set), __LINE__, DRAWSTATE_INVALID_WRITE_UPDATE, "DS",
+                                     reinterpret_cast<uint64_t &>(dest_set), __LINE__, error_code, "DS",
                                      "vkUpdateDescriptorsSets() failed write update validation for Descriptor Set 0x%" PRIx64
-                                     " with error: %s",
-                                     reinterpret_cast<uint64_t &>(dest_set), error_str.c_str());
+                                     " with error: %s. %s",
+                                     reinterpret_cast<uint64_t &>(dest_set), error_str.c_str(), validation_error_map[error_code]);
             }
         }
     }
@@ -1018,25 +1038,26 @@
         auto dst_node = core_validation::getSetNode(dev_data, dst_set);
         if (!src_node) {
             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                                 reinterpret_cast<uint64_t &>(src_set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS",
+                                 reinterpret_cast<uint64_t &>(src_set), __LINE__, VALIDATION_ERROR_00971, "DS",
                                  "Cannot call vkUpdateDescriptorSets() to copy from descriptor set 0x%" PRIxLEAST64
-                                 " that has not been allocated.",
-                                 reinterpret_cast<uint64_t &>(src_set));
+                                 " that has not been allocated. %s",
+                                 reinterpret_cast<uint64_t &>(src_set), validation_error_map[VALIDATION_ERROR_00971]);
         } else if (!dst_node) {
             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                                 reinterpret_cast<uint64_t &>(dst_set), __LINE__, DRAWSTATE_INVALID_DESCRIPTOR_SET, "DS",
+                                 reinterpret_cast<uint64_t &>(dst_set), __LINE__, VALIDATION_ERROR_00972, "DS",
                                  "Cannot call vkUpdateDescriptorSets() to copy to descriptor set 0x%" PRIxLEAST64
-                                 " that has not been allocated.",
-                                 reinterpret_cast<uint64_t &>(dst_set));
+                                 " that has not been allocated. %s",
+                                 reinterpret_cast<uint64_t &>(dst_set), validation_error_map[VALIDATION_ERROR_00972]);
         } else {
+            UNIQUE_VALIDATION_ERROR_CODE error_code;
             std::string error_str;
-            if (!dst_node->ValidateCopyUpdate(report_data, &p_cds[i], src_node, &error_str)) {
-                skip_call |=
-                    log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                            reinterpret_cast<uint64_t &>(dst_set), __LINE__, DRAWSTATE_INVALID_COPY_UPDATE, "DS",
-                            "vkUpdateDescriptorsSets() failed copy update from Descriptor Set 0x%" PRIx64
-                            " to Descriptor Set 0x%" PRIx64 " with error: %s",
-                            reinterpret_cast<uint64_t &>(src_set), reinterpret_cast<uint64_t &>(dst_set), error_str.c_str());
+            if (!dst_node->ValidateCopyUpdate(report_data, &p_cds[i], src_node, &error_code, &error_str)) {
+                skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+                                     reinterpret_cast<uint64_t &>(dst_set), __LINE__, error_code, "DS",
+                                     "vkUpdateDescriptorsSets() failed copy update from Descriptor Set 0x%" PRIx64
+                                     " to Descriptor Set 0x%" PRIx64 " with error: %s. %s",
+                                     reinterpret_cast<uint64_t &>(src_set), reinterpret_cast<uint64_t &>(dst_set),
+                                     error_str.c_str(), validation_error_map[error_code]);
             }
         }
     }
@@ -1074,9 +1095,11 @@
 // Validate the state for a given write update but don't actually perform the update
 //  If an error would occur for this update, return false and fill in details in error_msg string
 bool cvdescriptorset::DescriptorSet::ValidateWriteUpdate(const debug_report_data *report_data, const VkWriteDescriptorSet *update,
-                                                         std::string *error_msg) {
+                                                         UNIQUE_VALIDATION_ERROR_CODE *error_code, std::string *error_msg) {
     // Verify idle ds
     if (in_use.load()) {
+        // TODO : Re-using Allocate Idle error code, need write update idle error code
+        *error_code = VALIDATION_ERROR_00919;
         std::stringstream error_str;
         error_str << "Cannot call vkUpdateDescriptorSets() to perform write update on descriptor set " << set_
                   << " that is in use by a command buffer.";
@@ -1085,6 +1108,7 @@
     }
     // Verify dst binding exists
     if (!p_layout_->HasBinding(update->dstBinding)) {
+        *error_code = VALIDATION_ERROR_00936;
         std::stringstream error_str;
         error_str << "DescriptorSet " << set_ << " does not have binding " << update->dstBinding << ".";
         *error_msg = error_str.str();
@@ -1094,6 +1118,7 @@
     auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(update->dstBinding) + update->dstArrayElement;
     auto type = p_layout_->GetTypeFromBinding(update->dstBinding);
     if (type != update->descriptorType) {
+        *error_code = VALIDATION_ERROR_00937;
         std::stringstream error_str;
         error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with type "
                   << string_VkDescriptorType(type) << " but update type is " << string_VkDescriptorType(update->descriptorType);
@@ -1101,6 +1126,7 @@
         return false;
     }
     if ((start_idx + update->descriptorCount) > p_layout_->GetTotalDescriptorCount()) {
+        *error_code = VALIDATION_ERROR_00938;
         std::stringstream error_str;
         error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
                   << p_layout_->GetTotalDescriptorCount() << " total descriptors but update of " << update->descriptorCount
@@ -1112,10 +1138,12 @@
     }
     // Verify consecutive bindings match (if needed)
     if (!p_layout_->VerifyUpdateConsistency(update->dstBinding, update->dstArrayElement, update->descriptorCount, "write update to",
-                                            set_, error_msg))
+                                            set_, error_msg)) {
+        *error_code = VALIDATION_ERROR_00938;
         return false;
+    }
     // Update is within bounds and consistent so last step is to validate update contents
-    if (!VerifyWriteUpdateContents(update, start_idx, error_msg)) {
+    if (!VerifyWriteUpdateContents(update, start_idx, error_code, error_msg)) {
         std::stringstream error_str;
         error_str << "Write update to descriptor in set " << set_ << " binding #" << update->dstBinding
                   << " failed with error message: " << error_msg->c_str();
@@ -1126,32 +1154,36 @@
     return true;
 }
 // For the given buffer, verify that its creation parameters are appropriate for the given type
-//  If there's an error, update the error string with details and return false, else return true
+//  If there's an error, update the error_msg string with details and return false, else return true
 bool cvdescriptorset::DescriptorSet::ValidateBufferUsage(BUFFER_NODE const *buffer_node, VkDescriptorType type,
-                                                         std::string *error) const {
+                                                         UNIQUE_VALIDATION_ERROR_CODE *error_code, std::string *error_msg) const {
     // Verify that usage bits set correctly for given type
     auto usage = buffer_node->createInfo.usage;
     std::string error_usage_bit;
     switch (type) {
     case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
         if (!(usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT)) {
+            *error_code = VALIDATION_ERROR_00950;
             error_usage_bit = "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT";
         }
         break;
     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
         if (!(usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) {
+            *error_code = VALIDATION_ERROR_00951;
             error_usage_bit = "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT";
         }
         break;
     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
         if (!(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) {
+            *error_code = VALIDATION_ERROR_00946;
             error_usage_bit = "VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT";
         }
         break;
     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
         if (!(usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)) {
+            *error_code = VALIDATION_ERROR_00947;
             error_usage_bit = "VK_BUFFER_USAGE_STORAGE_BUFFER_BIT";
         }
         break;
@@ -1163,7 +1195,7 @@
         error_str << "Buffer (" << buffer_node->buffer << ") with usage mask 0x" << usage
                   << " being used for a descriptor update of type " << string_VkDescriptorType(type) << " does not have "
                   << error_usage_bit << " set.";
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     return true;
@@ -1173,48 +1205,56 @@
 //  2. buffer was created with correct usage flags
 //  3. offset is less than buffer size
 //  4. range is either VK_WHOLE_SIZE or falls in (0, (buffer size - offset)]
-// If there's an error, update the error string with details and return false, else return true
+// If there's an error, update the error_msg string with details and return false, else return true
 bool cvdescriptorset::DescriptorSet::ValidateBufferUpdate(VkDescriptorBufferInfo const *buffer_info, VkDescriptorType type,
-                                                          std::string *error) const {
+                                                          UNIQUE_VALIDATION_ERROR_CODE *error_code, std::string *error_msg) const {
+    // TODO : Defaulting to 00962 for all cases here. Need to create new error codes for a few cases below.
+    *error_code = VALIDATION_ERROR_00962;
     // First make sure that buffer is valid
     auto buffer_node = getBufferNode(device_data_, buffer_info->buffer);
     if (!buffer_node) {
         std::stringstream error_str;
         error_str << "Invalid VkBuffer: " << buffer_info->buffer;
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
     if (ValidateMemoryIsBoundToBuffer(device_data_, buffer_node, "vkUpdateDescriptorSets()")) {
-        *error = "No memory bound to buffer.";
+        // TODO : This is a repeat code, need new code(s) for language in 11.6 Memory Association
+        *error_msg = "No memory bound to buffer.";
         return false;
     }
     // Verify usage bits
-    if (!ValidateBufferUsage(buffer_node, type, error)) {
-        // error will have been updated by ValidateBufferUsage()
+    if (!ValidateBufferUsage(buffer_node, type, error_code, error_msg)) {
+        // error_msg will have been updated by ValidateBufferUsage()
         return false;
     }
+    // TODO : Need to also validate device limit offset requirements captured in VALIDATION_ERROR_00944,945
     // offset must be less than buffer size
     if (buffer_info->offset > buffer_node->createInfo.size) {
+        *error_code = VALIDATION_ERROR_00959;
         std::stringstream error_str;
         error_str << "VkDescriptorBufferInfo offset of " << buffer_info->offset << " is greater than buffer " << buffer_node->buffer
                   << " size of " << buffer_node->createInfo.size;
-        *error = error_str.str();
+        *error_msg = error_str.str();
         return false;
     }
+    // TODO : Need to also validate device limit range requirements captured in VALIDATION_ERROR_00948,949
     if (buffer_info->range != VK_WHOLE_SIZE) {
         // Range must be VK_WHOLE_SIZE or > 0
         if (!buffer_info->range) {
+            *error_code = VALIDATION_ERROR_00960;
             std::stringstream error_str;
             error_str << "VkDescriptorBufferInfo range is not VK_WHOLE_SIZE and is zero, which is not allowed.";
-            *error = error_str.str();
+            *error_msg = error_str.str();
             return false;
         }
         // Range must be VK_WHOLE_SIZE or <= (buffer size - offset)
         if (buffer_info->range > (buffer_node->createInfo.size - buffer_info->offset)) {
+            *error_code = VALIDATION_ERROR_00961;
             std::stringstream error_str;
             error_str << "VkDescriptorBufferInfo range is " << buffer_info->range << " which is greater than buffer size ("
                       << buffer_node->createInfo.size << ") minus requested offset of " << buffer_info->offset;
-            *error = error_str.str();
+            *error_msg = error_str.str();
             return false;
         }
     }
@@ -1223,17 +1263,18 @@
 
 // Verify that the contents of the update are ok, but don't perform actual update
 bool cvdescriptorset::DescriptorSet::VerifyWriteUpdateContents(const VkWriteDescriptorSet *update, const uint32_t index,
-                                                               std::string *error) const {
+                                                               UNIQUE_VALIDATION_ERROR_CODE *error_code,
+                                                               std::string *error_msg) const {
     switch (update->descriptorType) {
     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
             // Validate image
             auto image_view = update->pImageInfo[di].imageView;
             auto image_layout = update->pImageInfo[di].imageLayout;
-            if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, device_data_, error)) {
+            if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, device_data_, error_code, error_msg)) {
                 std::stringstream error_str;
-                error_str << "Attempted write update to combined image sampler descriptor failed due to: " << error->c_str();
-                *error = error_str.str();
+                error_str << "Attempted write update to combined image sampler descriptor failed due to: " << error_msg->c_str();
+                *error_msg = error_str.str();
                 return false;
             }
         }
@@ -1243,10 +1284,11 @@
         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
             if (!descriptors_[index + di].get()->IsImmutableSampler()) {
                 if (!ValidateSampler(update->pImageInfo[di].sampler, device_data_)) {
+                    *error_code = VALIDATION_ERROR_00942;
                     std::stringstream error_str;
                     error_str << "Attempted write update to sampler descriptor with invalid sampler: "
                               << update->pImageInfo[di].sampler << ".";
-                    *error = error_str.str();
+                    *error_msg = error_str.str();
                     return false;
                 }
             } else {
@@ -1261,10 +1303,10 @@
         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
             auto image_view = update->pImageInfo[di].imageView;
             auto image_layout = update->pImageInfo[di].imageLayout;
-            if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, device_data_, error)) {
+            if (!ValidateImageUpdate(image_view, image_layout, update->descriptorType, device_data_, error_code, error_msg)) {
                 std::stringstream error_str;
-                error_str << "Attempted write update to image descriptor failed due to: " << error->c_str();
-                *error = error_str.str();
+                error_str << "Attempted write update to image descriptor failed due to: " << error_msg->c_str();
+                *error_msg = error_str.str();
                 return false;
             }
         }
@@ -1276,16 +1318,17 @@
             auto buffer_view = update->pTexelBufferView[di];
             auto bv_state = getBufferViewState(device_data_, buffer_view);
             if (!bv_state) {
+                *error_code = VALIDATION_ERROR_00940;
                 std::stringstream error_str;
                 error_str << "Attempted write update to texel buffer descriptor with invalid buffer view: " << buffer_view;
-                *error = error_str.str();
+                *error_msg = error_str.str();
                 return false;
             }
             auto buffer = bv_state->create_info.buffer;
-            if (!ValidateBufferUsage(getBufferNode(device_data_, buffer), update->descriptorType, error)) {
+            if (!ValidateBufferUsage(getBufferNode(device_data_, buffer), update->descriptorType, error_code, error_msg)) {
                 std::stringstream error_str;
-                error_str << "Attempted write update to texel buffer descriptor failed due to: " << error->c_str();
-                *error = error_str.str();
+                error_str << "Attempted write update to texel buffer descriptor failed due to: " << error_msg->c_str();
+                *error_msg = error_str.str();
                 return false;
             }
         }
@@ -1296,10 +1339,10 @@
     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
-            if (!ValidateBufferUpdate(update->pBufferInfo + di, update->descriptorType, error)) {
+            if (!ValidateBufferUpdate(update->pBufferInfo + di, update->descriptorType, error_code, error_msg)) {
                 std::stringstream error_str;
-                error_str << "Attempted write update to buffer descriptor failed due to: " << error->c_str();
-                *error = error_str.str();
+                error_str << "Attempted write update to buffer descriptor failed due to: " << error_msg->c_str();
+                *error_msg = error_str.str();
                 return false;
             }
         }
@@ -1314,16 +1357,21 @@
 }
 // Verify that the contents of the update are ok, but don't perform actual update
 bool cvdescriptorset::DescriptorSet::VerifyCopyUpdateContents(const VkCopyDescriptorSet *update, const DescriptorSet *src_set,
-                                                              VkDescriptorType type, uint32_t index, std::string *error) const {
+                                                              VkDescriptorType type, uint32_t index,
+                                                              UNIQUE_VALIDATION_ERROR_CODE *error_code,
+                                                              std::string *error_msg) const {
+    // Note : Repurposing some Write update error codes here as specific details aren't called out for copy updates like they are
+    // for write updates
     switch (src_set->descriptors_[index]->descriptor_class) {
     case PlainSampler: {
         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
             if (!src_set->descriptors_[index + di]->IsImmutableSampler()) {
                 auto update_sampler = static_cast<SamplerDescriptor *>(src_set->descriptors_[index + di].get())->GetSampler();
                 if (!ValidateSampler(update_sampler, device_data_)) {
+                    *error_code = VALIDATION_ERROR_00942;
                     std::stringstream error_str;
                     error_str << "Attempted copy update to sampler descriptor with invalid sampler: " << update_sampler << ".";
-                    *error = error_str.str();
+                    *error_msg = error_str.str();
                     return false;
                 }
             } else {
@@ -1339,9 +1387,10 @@
             if (!img_samp_desc->IsImmutableSampler()) {
                 auto update_sampler = img_samp_desc->GetSampler();
                 if (!ValidateSampler(update_sampler, device_data_)) {
+                    *error_code = VALIDATION_ERROR_00942;
                     std::stringstream error_str;
                     error_str << "Attempted copy update to sampler descriptor with invalid sampler: " << update_sampler << ".";
-                    *error = error_str.str();
+                    *error_msg = error_str.str();
                     return false;
                 }
             } else {
@@ -1350,10 +1399,10 @@
             // Validate image
             auto image_view = img_samp_desc->GetImageView();
             auto image_layout = img_samp_desc->GetImageLayout();
-            if (!ValidateImageUpdate(image_view, image_layout, type, device_data_, error)) {
+            if (!ValidateImageUpdate(image_view, image_layout, type, device_data_, error_code, error_msg)) {
                 std::stringstream error_str;
-                error_str << "Attempted copy update to combined image sampler descriptor failed due to: " << error->c_str();
-                *error = error_str.str();
+                error_str << "Attempted copy update to combined image sampler descriptor failed due to: " << error_msg->c_str();
+                *error_msg = error_str.str();
                 return false;
             }
         }
@@ -1364,10 +1413,10 @@
             auto img_desc = static_cast<const ImageDescriptor *>(src_set->descriptors_[index + di].get());
             auto image_view = img_desc->GetImageView();
             auto image_layout = img_desc->GetImageLayout();
-            if (!ValidateImageUpdate(image_view, image_layout, type, device_data_, error)) {
+            if (!ValidateImageUpdate(image_view, image_layout, type, device_data_, error_code, error_msg)) {
                 std::stringstream error_str;
-                error_str << "Attempted copy update to image descriptor failed due to: " << error->c_str();
-                *error = error_str.str();
+                error_str << "Attempted copy update to image descriptor failed due to: " << error_msg->c_str();
+                *error_msg = error_str.str();
                 return false;
             }
         }
@@ -1378,16 +1427,17 @@
             auto buffer_view = static_cast<TexelDescriptor *>(src_set->descriptors_[index + di].get())->GetBufferView();
             auto bv_state = getBufferViewState(device_data_, buffer_view);
             if (!bv_state) {
+                *error_code = VALIDATION_ERROR_00940;
                 std::stringstream error_str;
                 error_str << "Attempted copy update to texel buffer descriptor with invalid buffer view: " << buffer_view;
-                *error = error_str.str();
+                *error_msg = error_str.str();
                 return false;
             }
             auto buffer = bv_state->create_info.buffer;
-            if (!ValidateBufferUsage(getBufferNode(device_data_, buffer), type, error)) {
+            if (!ValidateBufferUsage(getBufferNode(device_data_, buffer), type, error_code, error_msg)) {
                 std::stringstream error_str;
-                error_str << "Attempted copy update to texel buffer descriptor failed due to: " << error->c_str();
-                *error = error_str.str();
+                error_str << "Attempted copy update to texel buffer descriptor failed due to: " << error_msg->c_str();
+                *error_msg = error_str.str();
                 return false;
             }
         }
@@ -1396,10 +1446,10 @@
     case GeneralBuffer: {
         for (uint32_t di = 0; di < update->descriptorCount; ++di) {
             auto buffer = static_cast<BufferDescriptor *>(src_set->descriptors_[index + di].get())->GetBuffer();
-            if (!ValidateBufferUsage(getBufferNode(device_data_, buffer), type, error)) {
+            if (!ValidateBufferUsage(getBufferNode(device_data_, buffer), type, error_code, error_msg)) {
                 std::stringstream error_str;
-                error_str << "Attempted copy update to buffer descriptor failed due to: " << error->c_str();
-                *error = error_str.str();
+                error_str << "Attempted copy update to buffer descriptor failed due to: " << error_msg->c_str();
+                *error_msg = error_str.str();
                 return false;
             }
         }
@@ -1440,23 +1490,21 @@
     auto pool_node = getPoolNode(dev_data, p_alloc_info->descriptorPool);
     // Track number of descriptorSets allowable in this pool
     if (pool_node->availableSets < p_alloc_info->descriptorSetCount) {
-        skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
-                             reinterpret_cast<uint64_t &>(pool_node->pool), __LINE__, VALIDATION_ERROR_00911, "DS",
-                             "Unable to allocate %u descriptorSets from pool 0x%" PRIxLEAST64
-                             ". This pool only has %d descriptorSets remaining. %s",
-                             p_alloc_info->descriptorSetCount, reinterpret_cast<uint64_t &>(pool_node->pool),
-                             pool_node->availableSets, validation_error_map[VALIDATION_ERROR_00911]);
+        skip_call |= log_msg(
+            report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
+            reinterpret_cast<uint64_t &>(pool_node->pool), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY, "DS",
+            "Unable to allocate %u descriptorSets from pool 0x%" PRIxLEAST64 ". This pool only has %d descriptorSets remaining.",
+            p_alloc_info->descriptorSetCount, reinterpret_cast<uint64_t &>(pool_node->pool), pool_node->availableSets);
     }
     // Determine whether descriptor counts are satisfiable
     for (uint32_t i = 0; i < VK_DESCRIPTOR_TYPE_RANGE_SIZE; i++) {
         if (ds_data->required_descriptors_by_type[i] > pool_node->availableDescriptorTypeCount[i]) {
             skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
-                                 reinterpret_cast<const uint64_t &>(pool_node->pool), __LINE__, VALIDATION_ERROR_00912, "DS",
-                                 "Unable to allocate %u descriptors of type %s from pool 0x%" PRIxLEAST64
-                                 ". This pool only has %d descriptors of this type remaining. %s",
+                                 reinterpret_cast<const uint64_t &>(pool_node->pool), __LINE__, DRAWSTATE_DESCRIPTOR_POOL_EMPTY,
+                                 "DS", "Unable to allocate %u descriptors of type %s from pool 0x%" PRIxLEAST64
+                                       ". This pool only has %d descriptors of this type remaining.",
                                  ds_data->required_descriptors_by_type[i], string_VkDescriptorType(VkDescriptorType(i)),
-                                 reinterpret_cast<uint64_t &>(pool_node->pool), pool_node->availableDescriptorTypeCount[i],
-                                 validation_error_map[VALIDATION_ERROR_00912]);
+                                 reinterpret_cast<uint64_t &>(pool_node->pool), pool_node->availableDescriptorTypeCount[i]);
         }
     }