VK_EXT_inline_uniform_block
diff --git a/layers/descriptor_sets.cpp b/layers/descriptor_sets.cpp
index 72e87dc..38eb3e1 100644
--- a/layers/descriptor_sets.cpp
+++ b/layers/descriptor_sets.cpp
@@ -359,7 +359,9 @@
 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, const bool descriptor_indexing_ext,
-    const VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing_features) {
+    const VkPhysicalDeviceDescriptorIndexingFeaturesEXT *descriptor_indexing_features,
+    const VkPhysicalDeviceInlineUniformBlockFeaturesEXT *inline_uniform_block_features,
+    const VkPhysicalDeviceInlineUniformBlockPropertiesEXT *inline_uniform_block_props) {
     bool skip = false;
     std::unordered_set<uint32_t> bindings;
     uint64_t total_descriptors = 0;
@@ -386,7 +388,9 @@
 
     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));
+               ((type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) && 
+                (type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) &&
+                (type != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT));
     };
 
     uint32_t max_binding = 0;
@@ -402,10 +406,28 @@
         }
         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,
-                            "VUID-VkDescriptorSetLayoutCreateInfo-flags-00280",
+                            (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) ? 
+                                "VUID-VkDescriptorSetLayoutCreateInfo-flags-02208" :
+                                "VUID-VkDescriptorSetLayoutCreateInfo-flags-00280",
                             "invalid type %s ,for push descriptors in VkDescriptorSetLayoutBinding entry %" PRIu32 ".",
                             string_VkDescriptorType(binding_info.descriptorType), i);
         }
+
+        if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
+            if ((binding_info.descriptorCount % 4) != 0) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkDescriptorSetLayoutBinding-descriptorType-02209",
+                                "descriptorCount =(%" PRIu32 ") must be a multiple of 4",
+                                binding_info.descriptorCount);
+            }
+            if (binding_info.descriptorCount > inline_uniform_block_props->maxInlineUniformBlockSize) {
+                skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                "VUID-VkDescriptorSetLayoutBinding-descriptorType-02210",
+                                "descriptorCount =(%" PRIu32 ") must be less than or equal to maxInlineUniformBlockSize",
+                                binding_info.descriptorCount);
+            }
+        }
+
         total_descriptors += binding_info.descriptorCount;
     }
 
@@ -480,6 +502,13 @@
                                         "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-None-03011",
                                         "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
                     }
+
+                    if (binding_info.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT &&
+                        !inline_uniform_block_features->descriptorBindingInlineUniformBlockUpdateAfterBind) {
+                        skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                        "VUID-VkDescriptorSetLayoutBindingFlagsCreateInfoEXT-descriptorBindingInlineUniformBlockUpdateAfterBind-02211",
+                                        "Invalid flags for VkDescriptorSetLayoutBinding entry %" PRIu32, i);
+                    }
                 }
 
                 if (flags_create_info->pBindingFlags[i] & VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT) {
@@ -605,6 +634,10 @@
                 for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
                     descriptors_.emplace_back(new BufferDescriptor(type));
                 break;
+            case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
+                for (uint32_t di = 0; di < p_layout_->GetDescriptorCountFromIndex(i); ++di)
+                    descriptors_.emplace_back(new InlineUniformDescriptor(type));
+                break;
             default:
                 assert(0);  // Bad descriptor type specified
                 break;
@@ -674,7 +707,8 @@
         }
 
         for (uint32_t i = index_range.start; i < index_range.end; ++i, ++array_idx) {
-            if (p_layout_->GetDescriptorBindingFlagsFromBinding(binding) & VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT) {
+            if ((p_layout_->GetDescriptorBindingFlagsFromBinding(binding) & VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT) ||
+                descriptors_[i]->GetClass() == InlineUniform) {
                 // Can't validate the descriptor because it may not have been updated,
                 // or the view could have been destroyed
                 continue;
@@ -1073,6 +1107,33 @@
         return false;
     }
 
+    if (src_type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
+        if ((update->srcArrayElement % 4) != 0) {
+            *error_code = "VUID-VkCopyDescriptorSet-srcBinding-02223";
+            std::stringstream error_str;
+            error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
+                      << "srcArrayElement " << update->srcArrayElement << " not a multiple of 4";
+            *error_msg = error_str.str();
+            return false;
+        }
+        if ((update->dstArrayElement % 4) != 0) {
+            *error_code = "VUID-VkCopyDescriptorSet-dstBinding-02224";
+            std::stringstream error_str;
+            error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
+                      << "dstArrayElement " << update->dstArrayElement << " not a multiple of 4";
+            *error_msg = error_str.str();
+            return false;
+        }
+        if ((update->descriptorCount % 4) != 0) {
+            *error_code = "VUID-VkCopyDescriptorSet-srcBinding-02225";
+            std::stringstream error_str;
+            error_str << "Attempting copy update to VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT binding with "
+                      << "descriptorCount " << update->descriptorCount << " not a multiple of 4";
+            *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_code, error_msg)) return false;
 
@@ -1653,6 +1714,7 @@
 
     // Create a vector of write structs
     std::vector<VkWriteDescriptorSet> desc_writes;
+    std::vector<VkWriteDescriptorSetInlineUniformBlockEXT> inline_infos(create_info.descriptorUpdateEntryCount);
     auto layout_obj = GetDescriptorSetLayout(device_data, create_info.descriptorSetLayout);
 
     // Create a WriteDescriptorSet struct for each template update entry
@@ -1702,6 +1764,18 @@
                 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
                     write_entry.pTexelBufferView = reinterpret_cast<VkBufferView *>(update_entry);
                     break;
+                case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
+                    {
+                        VkWriteDescriptorSetInlineUniformBlockEXT *inline_info = &inline_infos[i];
+                        inline_info->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT;
+                        inline_info->pNext = nullptr;
+                        inline_info->dataSize = create_info.pDescriptorUpdateEntries[i].descriptorCount;
+                        inline_info->pData = update_entry;
+                        write_entry.pNext = inline_info;
+                        // skip the rest of the array, they just represent bytes in the update
+                        j = create_info.pDescriptorUpdateEntries[i].descriptorCount;
+                        break;
+                    }
                 default:
                     assert(0);
                     break;
@@ -1775,6 +1849,48 @@
         *error_msg = error_str.str();
         return false;
     }
+    if (type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT) {
+        if ((update->dstArrayElement % 4) != 0) {
+            *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02219";
+            std::stringstream error_str;
+            error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+                      << "dstArrayElement " << update->dstArrayElement << " not a multiple of 4";
+            *error_msg = error_str.str();
+            return false;
+        }
+        if ((update->descriptorCount % 4) != 0) {
+            *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02220";
+            std::stringstream error_str;
+            error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+                      << "descriptorCount  " << update->descriptorCount << " not a multiple of 4";
+            *error_msg = error_str.str();
+            return false;
+        }
+        const auto *write_inline_info = lvl_find_in_chain<VkWriteDescriptorSetInlineUniformBlockEXT>(update->pNext);
+        if (!write_inline_info || write_inline_info->dataSize != update->descriptorCount) {
+            *error_code = "VUID-VkWriteDescriptorSet-descriptorType-02221";
+            std::stringstream error_str;
+            if (!write_inline_info) {
+                error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+                          << "VkWriteDescriptorSetInlineUniformBlockEXT missing";
+            } else {
+                error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+                          << "VkWriteDescriptorSetInlineUniformBlockEXT dataSize " << write_inline_info->dataSize << " not equal to "
+                          << "VkWriteDescriptorSet descriptorCount " << update->descriptorCount;
+            }
+            *error_msg = error_str.str();
+            return false;
+        }
+        // This error is probably unreachable due to the previous two errors
+        if (write_inline_info && (write_inline_info->dataSize % 4) != 0) {
+            *error_code = "VUID-VkWriteDescriptorSetInlineUniformBlockEXT-dataSize-02222";
+            std::stringstream error_str;
+            error_str << "Attempting write update to descriptor set " << set_ << " binding #" << update->dstBinding << " with "
+                      << "VkWriteDescriptorSetInlineUniformBlockEXT dataSize " << write_inline_info->dataSize << " not a multiple of 4";
+            *error_msg = error_str.str();
+            return false;
+        }
+    }
     // Verify consecutive bindings match (if needed)
     if (!p_layout_->VerifyUpdateConsistency(update->dstBinding, update->dstArrayElement, update->descriptorCount, "write update to",
                                             set_, error_msg)) {
@@ -2029,6 +2145,8 @@
             }
             break;
         }
+        case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
+            break;
         default:
             assert(0);  // We've already verified update type so should never get here
             break;
@@ -2145,6 +2263,8 @@
             }
             break;
         }
+        case InlineUniform:
+            break;
         default:
             assert(0);  // We've already verified update type so should never get here
             break;
@@ -2206,14 +2326,14 @@
                             p_alloc_info->descriptorSetCount, HandleToUint64(pool_state->pool), pool_state->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_state->availableDescriptorTypeCount[i]) {
+        for (auto it = ds_data->required_descriptors_by_type.begin(); it != ds_data->required_descriptors_by_type.end(); ++it) {
+            if (ds_data->required_descriptors_by_type.at(it->first) > pool_state->availableDescriptorTypeCount[it->first]) {
                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT,
                                 HandleToUint64(pool_state->pool), "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307",
                                 "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)),
-                                HandleToUint64(pool_state->pool), pool_state->availableDescriptorTypeCount[i]);
+                                ds_data->required_descriptors_by_type.at(it->first), string_VkDescriptorType(VkDescriptorType(it->first)),
+                                HandleToUint64(pool_state->pool), pool_state->availableDescriptorTypeCount[it->first]);
             }
         }
     }
@@ -2255,8 +2375,8 @@
     auto pool_state = (*pool_map)[p_alloc_info->descriptorPool];
     // Account for sets and individual descriptors allocated from pool
     pool_state->availableSets -= p_alloc_info->descriptorSetCount;
-    for (uint32_t i = 0; i < VK_DESCRIPTOR_TYPE_RANGE_SIZE; i++) {
-        pool_state->availableDescriptorTypeCount[i] -= ds_data->required_descriptors_by_type[i];
+    for (auto it = ds_data->required_descriptors_by_type.begin(); it != ds_data->required_descriptors_by_type.end(); ++it) {
+        pool_state->availableDescriptorTypeCount[it->first] -= ds_data->required_descriptors_by_type.at(it->first);
     }
 
     const auto *variable_count_info = lvl_find_in_chain<VkDescriptorSetVariableDescriptorCountAllocateInfoEXT>(p_alloc_info->pNext);