layers: Add VK_EXT_validation_cache implementation for shaders
diff --git a/layers/shader_validation.cpp b/layers/shader_validation.cpp
index 11fcbdc..aa215fa 100644
--- a/layers/shader_validation.cpp
+++ b/layers/shader_validation.cpp
@@ -35,6 +35,7 @@
 #include "core_validation_types.h"
 #include "shader_validation.h"
 #include "spirv-tools/libspirv.h"
+#include "xxhash.h"
 
 enum FORMAT_TYPE {
     FORMAT_TYPE_FLOAT = 1,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
@@ -1517,6 +1518,20 @@
     return validate_pipeline_shader_stage(dev_data, &pCreateInfo->stage, pipeline, &module, &entrypoint);
 }
 
+uint32_t ValidationCache::MakeShaderHash(VkShaderModuleCreateInfo const *smci) {
+        return XXH32(smci->pCode, smci->codeSize * sizeof(uint32_t), 0);
+}
+
+static ValidationCache *GetValidationCacheInfo(
+    VkShaderModuleCreateInfo const *pCreateInfo) {
+    while ((pCreateInfo = (VkShaderModuleCreateInfo const *)pCreateInfo->pNext) != nullptr) {
+        if (pCreateInfo->sType == VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT)
+            return (ValidationCache *)((VkShaderModuleValidationCacheCreateInfoEXT const *)pCreateInfo)->validationCache;
+    }
+
+    return nullptr;
+}
+
 bool PreCallValidateCreateShaderModule(layer_data *dev_data, VkShaderModuleCreateInfo const *pCreateInfo, bool *spirv_valid) {
     bool skip = false;
     spv_result_t spv_valid = SPV_SUCCESS;
@@ -1534,6 +1549,14 @@
                         "SPIR-V module not valid: Codesize must be a multiple of 4 but is " PRINTF_SIZE_T_SPECIFIER ". %s",
                         pCreateInfo->codeSize, validation_error_map[VALIDATION_ERROR_12a00ac0]);
     } else {
+        auto cache = GetValidationCacheInfo(pCreateInfo);
+        uint32_t hash = 0;
+        if (cache) {
+            hash = ValidationCache::MakeShaderHash(pCreateInfo);
+            if (cache->Contains(hash))
+                return false;
+        }
+
         // Use SPIRV-Tools validator to try and catch any issues with the module itself
         spv_context ctx = spvContextCreate(SPV_ENV_VULKAN_1_0);
         spv_const_binary_t binary{ pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t) };
@@ -1547,6 +1570,10 @@
                                 VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, SHADER_CHECKER_INCONSISTENT_SPIRV, "SC",
                                 "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
             }
+        } else {
+            if (cache) {
+                cache->Insert(hash);
+            }
         }
 
         spvDiagnosticDestroy(diag);