misc: Support Pipeline caches and multi pipeline create, bug 14033 API changes
diff --git a/include/vk_layer.h b/include/vk_layer.h
index c2c5465..3e915b1 100644
--- a/include/vk_layer.h
+++ b/include/vk_layer.h
@@ -69,12 +69,13 @@
     PFN_vkCreateDepthStencilView CreateDepthStencilView;
     PFN_vkCreateShaderModule CreateShaderModule;
     PFN_vkCreateShader CreateShader;
-    PFN_vkCreateGraphicsPipeline CreateGraphicsPipeline;
-    PFN_vkCreateGraphicsPipelineDerivative CreateGraphicsPipelineDerivative;
-    PFN_vkCreateComputePipeline CreateComputePipeline;
-    PFN_vkStorePipeline StorePipeline;
-    PFN_vkLoadPipeline LoadPipeline;
-    PFN_vkLoadPipelineDerivative LoadPipelineDerivative;
+    PFN_vkCreatePipelineCache CreatePipelineCache;
+    PFN_vkDestroyPipelineCache DestroyPipelineCache;
+    PFN_vkGetPipelineCacheSize GetPipelineCacheSize;
+    PFN_vkGetPipelineCacheData GetPipelineCacheData;
+    PFN_vkMergePipelineCaches MergePipelineCaches;
+    PFN_vkCreateGraphicsPipelines CreateGraphicsPipelines;
+    PFN_vkCreateComputePipelines CreateComputePipelines;
     PFN_vkCreatePipelineLayout CreatePipelineLayout;
     PFN_vkCreateSampler CreateSampler;
     PFN_vkCreateDescriptorSetLayout CreateDescriptorSetLayout;
diff --git a/include/vulkan.h b/include/vulkan.h
index 9f3a8c4..8ef46cc 100644
--- a/include/vulkan.h
+++ b/include/vulkan.h
@@ -82,6 +82,7 @@
 VK_DEFINE_NONDISP_SUBCLASS_HANDLE(VkShaderModule, VkNonDispatchable)
 VK_DEFINE_NONDISP_SUBCLASS_HANDLE(VkShader, VkNonDispatchable)
 VK_DEFINE_NONDISP_SUBCLASS_HANDLE(VkPipeline, VkNonDispatchable)
+VK_DEFINE_NONDISP_SUBCLASS_HANDLE(VkPipelineCache, VkNonDispatchable)
 VK_DEFINE_NONDISP_SUBCLASS_HANDLE(VkPipelineLayout, VkNonDispatchable)
 VK_DEFINE_NONDISP_SUBCLASS_HANDLE(VkSampler, VkNonDispatchable)
 VK_DEFINE_NONDISP_SUBCLASS_HANDLE(VkDescriptorSet, VkNonDispatchable)
@@ -104,6 +105,7 @@
 #define VK_MAX_DESCRIPTION          256
 #define VK_MAX_MEMORY_TYPES         32
 #define VK_MAX_MEMORY_HEAPS         16
+#define VK_UUID_LENGTH              16
 #define VK_LOD_CLAMP_NONE           MAX_FLOAT
 #define VK_LAST_MIP_LEVEL           UINT32_MAX
 #define VK_LAST_ARRAY_SLICE         UINT32_MAX
@@ -787,7 +789,8 @@
     VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET                     = 42,
     VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO                    = 43,
     VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO             = 44,
-    VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES                    = 45,
+    VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO              = 45,
+    VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES                    = 46,
 
     VK_ENUM_RANGE(STRUCTURE_TYPE, APPLICATION_INFO, EXTENSION_PROPERTIES)
 } VkStructureType;
@@ -824,7 +827,8 @@
     VK_OBJECT_TYPE_EVENT                                    = 26,
     VK_OBJECT_TYPE_QUERY_POOL                               = 27,
     VK_OBJECT_TYPE_FRAMEBUFFER                              = 28,
-    VK_OBJECT_TYPE_RENDER_PASS                              = 29,
+    VK_OBJECT_TYPE_PIPELINE_CACHE                           = 29,
+    VK_OBJECT_TYPE_RENDER_PASS                              = 30,
 
     // Valid ranges for core Vulkan:
     VK_OBJECT_TYPE_BEGIN_RANGE                              = VK_OBJECT_TYPE_INSTANCE,
@@ -1019,6 +1023,7 @@
 {
     VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT             = VK_BIT(0),
     VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT                = VK_BIT(1),
+    VK_PIPELINE_CREATE_DERIVATIVE_BIT                       = VK_BIT(2),
 } VkPipelineCreateFlagBits;
 
 // Channel flags
@@ -1239,6 +1244,7 @@
     uint32_t                                    deviceId;
     VkPhysicalDeviceType                        deviceType;
     char                                        deviceName[VK_MAX_PHYSICAL_DEVICE_NAME];
+    uint8_t                                     pipelineCacheUUID[VK_UUID_LENGTH];
 } VkPhysicalDeviceProperties;
 
 typedef struct VkPhysicalDeviceFeatures_
@@ -1821,6 +1827,15 @@
     VkShaderCreateFlags                         flags;              // Reserved
 } VkShaderCreateInfo;
 
+typedef struct VkPipelineCacheCreateInfo_
+{
+    VkStructureType                             sType;
+    const void*                                 pNext;
+    size_t                                      initialSize;
+    const void*                                 initialData;
+    size_t                                      maxSize;
+} VkPipelineCacheCreateInfo;
+
 typedef struct VkDescriptorSetLayoutBinding_
 {
     VkDescriptorType                            descriptorType;     // Type of the descriptors in this binding
@@ -1889,6 +1904,8 @@
     VkPipelineShaderStageCreateInfo             cs;
     VkPipelineCreateFlags                       flags;          // Pipeline creation flags
     VkPipelineLayout                            layout;         // Interface layout of the pipeline
+    VkPipeline                                  basePipelineHandle;
+    int32_t                                     basePipelineIndex;
 } VkComputePipelineCreateInfo;
 
 typedef struct VkVertexInputBindingDescription_
@@ -2033,6 +2050,8 @@
     const VkPipelineCbStateCreateInfo*          pCbState;
     VkPipelineCreateFlags                       flags;      // Pipeline creation flags
     VkPipelineLayout                            layout;     // Interface layout of the pipeline
+    VkPipeline                                  basePipelineHandle;
+    int32_t                                     basePipelineIndex;
 } VkGraphicsPipelineCreateInfo;
 
 typedef struct VkPipelineLayoutCreateInfo_
@@ -2290,12 +2309,13 @@
 typedef VkResult (VKAPI *PFN_vkCreateDepthStencilView)(VkDevice device, const VkDepthStencilViewCreateInfo* pCreateInfo, VkDepthStencilView* pView);
 typedef VkResult (VKAPI *PFN_vkCreateShaderModule)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModule* pShaderModule);
 typedef VkResult (VKAPI *PFN_vkCreateShader)(VkDevice device, const VkShaderCreateInfo* pCreateInfo, VkShader* pShader);
-typedef VkResult (VKAPI *PFN_vkCreateGraphicsPipeline)(VkDevice device, const VkGraphicsPipelineCreateInfo* pCreateInfo, VkPipeline* pPipeline);
-typedef VkResult (VKAPI *PFN_vkCreateGraphicsPipelineDerivative)(VkDevice device, const VkGraphicsPipelineCreateInfo* pCreateInfo, VkPipeline basePipeline, VkPipeline* pPipeline);
-typedef VkResult (VKAPI *PFN_vkCreateComputePipeline)(VkDevice device, const VkComputePipelineCreateInfo* pCreateInfo, VkPipeline* pPipeline);
-typedef VkResult (VKAPI *PFN_vkStorePipeline)(VkDevice device, VkPipeline pipeline, size_t* pDataSize, void* pData);
-typedef VkResult (VKAPI *PFN_vkLoadPipeline)(VkDevice device, size_t dataSize, const void* pData, VkPipeline* pPipeline);
-typedef VkResult (VKAPI *PFN_vkLoadPipelineDerivative)(VkDevice device, size_t dataSize, const void* pData, VkPipeline basePipeline, VkPipeline* pPipeline);
+typedef VkResult (VKAPI *PFN_vkCreatePipelineCache)(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, VkPipelineCache* pPipelineCache);
+typedef VkResult (VKAPI *PFN_vkDestroyPipelineCache)(VkDevice device, VkPipelineCache pipelineCache);
+typedef size_t (VKAPI *PFN_vkGetPipelineCacheSize)(VkDevice device, VkPipelineCache pipelineCache);
+typedef VkResult (VKAPI *PFN_vkGetPipelineCacheData)(VkDevice device, VkPipelineCache pipelineCache, void* pData);
+typedef VkResult (VKAPI *PFN_vkMergePipelineCaches)(VkDevice device, VkPipelineCache destCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches);
+typedef VkResult (VKAPI *PFN_vkCreateGraphicsPipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, const VkGraphicsPipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines);
+typedef VkResult (VKAPI *PFN_vkCreateComputePipelines)(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, const VkComputePipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines);
 typedef VkResult (VKAPI *PFN_vkCreatePipelineLayout)(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, VkPipelineLayout* pPipelineLayout);
 typedef VkResult (VKAPI *PFN_vkCreateSampler)(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler);
 typedef VkResult (VKAPI *PFN_vkCreateDescriptorSetLayout)(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayout* pSetLayout);
@@ -2677,41 +2697,43 @@
     VkShader*                                   pShader);
 
 // Pipeline functions
-
-VkResult VKAPI vkCreateGraphicsPipeline(
+VkResult VKAPI vkCreatePipelineCache(
     VkDevice                                    device,
-    const VkGraphicsPipelineCreateInfo*         pCreateInfo,
-    VkPipeline*                                 pPipeline);
+    const VkPipelineCacheCreateInfo*            pCreateInfo,
+    VkPipelineCache*                            pPipelineCache);
 
-VkResult VKAPI vkCreateGraphicsPipelineDerivative(
+VkResult VKAPI vkDestroyPipelineCache(
     VkDevice                                    device,
-    const VkGraphicsPipelineCreateInfo*         pCreateInfo,
-    VkPipeline                                  basePipeline,
-    VkPipeline*                                 pPipeline);
+    VkPipelineCache                             pipelineCache);
 
-VkResult VKAPI vkCreateComputePipeline(
+size_t VKAPI vkGetPipelineCacheSize(
     VkDevice                                    device,
-    const VkComputePipelineCreateInfo*          pCreateInfo,
-    VkPipeline*                                 pPipeline);
+    VkPipelineCache                             pipelineCache);
 
-VkResult VKAPI vkStorePipeline(
+VkResult VKAPI vkGetPipelineCacheData(
     VkDevice                                    device,
-    VkPipeline                                  pipeline,
-    size_t*                                     pDataSize,
+    VkPipelineCache                             pipelineCache,
     void*                                       pData);
 
-VkResult VKAPI vkLoadPipeline(
+VkResult VKAPI vkMergePipelineCaches(
     VkDevice                                    device,
-    size_t                                      dataSize,
-    const void*                                 pData,
-    VkPipeline*                                 pPipeline);
+    VkPipelineCache                             destCache,
+    uint32_t                                    srcCacheCount,
+    const VkPipelineCache*                      pSrcCaches);
 
-VkResult VKAPI vkLoadPipelineDerivative(
+VkResult VKAPI vkCreateGraphicsPipelines(
     VkDevice                                    device,
-    size_t                                      dataSize,
-    const void*                                 pData,
-    VkPipeline                                  basePipeline,
-    VkPipeline*                                 pPipeline);
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    count,
+    const VkGraphicsPipelineCreateInfo*         pCreateInfos,
+    VkPipeline*                                 pPipelines);
+
+VkResult VKAPI vkCreateComputePipelines(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    uint32_t                                    count,
+    const VkComputePipelineCreateInfo*          pCreateInfos,
+    VkPipeline*                                 pPipelines);
 
 // Pipeline layout functions
 
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index c1ad7fb..ff99036 100644
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -1532,23 +1532,69 @@
     return result;
 }
 
-VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipeline(VkDevice device, const VkGraphicsPipelineCreateInfo* pCreateInfo, VkPipeline* pPipeline)
+//TODO handle pipeline caches
+VkResult VKAPI vkCreatePipelineCache(
+    VkDevice                                    device,
+    const VkPipelineCacheCreateInfo*            pCreateInfo,
+    VkPipelineCache*                            pPipelineCache)
+{
+    VkResult result = get_dispatch_table(draw_state_device_table_map, device)->CreatePipelineCache(device, pCreateInfo, pPipelineCache);
+    return result;
+}
+
+VkResult VKAPI vkDestroyPipelineCache(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache)
+{
+    VkResult result = get_dispatch_table(draw_state_device_table_map, device)->DestroyPipelineCache(device, pipelineCache);
+    return result;
+}
+
+size_t VKAPI vkGetPipelineCacheSize(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache)
+{
+    size_t size = get_dispatch_table(draw_state_device_table_map, device)->GetPipelineCacheSize(device, pipelineCache);
+    return size;
+}
+
+VkResult VKAPI vkGetPipelineCacheData(
+    VkDevice                                    device,
+    VkPipelineCache                             pipelineCache,
+    void*                                       pData)
+{
+    VkResult result = get_dispatch_table(draw_state_device_table_map, device)->GetPipelineCacheData(device, pipelineCache, pData);
+    return result;
+}
+
+VkResult VKAPI vkMergePipelineCaches(
+    VkDevice                                    device,
+    VkPipelineCache                             destCache,
+    uint32_t                                    srcCacheCount,
+    const VkPipelineCache*                      pSrcCaches)
+{
+    VkResult result = get_dispatch_table(draw_state_device_table_map, device)->MergePipelineCaches(device, destCache, srcCacheCount, pSrcCaches);
+    return result;
+}
+
+VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, const VkGraphicsPipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines)
 {
     VkResult result = VK_ERROR_BAD_PIPELINE_DATA;
+    //TODO handle count > 1  and handle pipelineCache
     // The order of operations here is a little convoluted but gets the job done
     //  1. Pipeline create state is first shadowed into PIPELINE_NODE struct
     //  2. Create state is then validated (which uses flags setup during shadowing)
     //  3. If everything looks good, we'll then create the pipeline and add NODE to pipelineMap
     loader_platform_thread_lock_mutex(&globalLock);
-    PIPELINE_NODE* pPipeNode = initPipeline(pCreateInfo, NULL);
+    PIPELINE_NODE* pPipeNode = initPipeline(pCreateInfos, NULL);
     bool32_t valid = verifyPipelineCreateState(device, pPipeNode);
     loader_platform_thread_unlock_mutex(&globalLock);
     if (VK_TRUE == valid) {
-        result = get_dispatch_table(draw_state_device_table_map, device)->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
-        log_msg(mdd(device), VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_PIPELINE, *pPipeline, 0, DRAWSTATE_NONE, "DS",
-                "Created Gfx Pipeline %p", (void*)*pPipeline);
+        result = get_dispatch_table(draw_state_device_table_map, device)->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
+        log_msg(mdd(device), VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_PIPELINE, *pPipelines, 0, DRAWSTATE_NONE, "DS",
+                "Created Gfx Pipeline %p", (void*)*pPipelines);
         loader_platform_thread_lock_mutex(&globalLock);
-        pPipeNode->pipeline = *pPipeline;
+        pPipeNode->pipeline = *pPipelines;
         pipelineMap[pPipeNode->pipeline] = pPipeNode;
         loader_platform_thread_unlock_mutex(&globalLock);
     } else {
@@ -1563,38 +1609,6 @@
     return result;
 }
 
-VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipelineDerivative(
-        VkDevice device,
-        const VkGraphicsPipelineCreateInfo* pCreateInfo,
-        VkPipeline basePipeline,
-        VkPipeline* pPipeline)
-{
-    VkResult result = VK_ERROR_BAD_PIPELINE_DATA;
-    loader_platform_thread_lock_mutex(&globalLock);
-    PIPELINE_NODE* pPipeNode = initPipeline(pCreateInfo, NULL);
-    bool32_t valid = verifyPipelineCreateState(device, pipelineMap[basePipeline]);
-    loader_platform_thread_unlock_mutex(&globalLock);
-    if (VK_TRUE == valid) {
-        result = get_dispatch_table(draw_state_device_table_map, device)->CreateGraphicsPipelineDerivative(device, pCreateInfo, basePipeline, pPipeline);
-        log_msg(mdd(device), VK_DBG_REPORT_INFO_BIT, VK_OBJECT_TYPE_PIPELINE, *pPipeline, 0, DRAWSTATE_NONE, "DS",
-                "Created Gfx Pipeline %p (derived from pipeline %p)", (void*)*pPipeline, basePipeline);
-        loader_platform_thread_lock_mutex(&globalLock);
-        pPipeNode->pipeline = *pPipeline;
-        pipelineMap[pPipeNode->pipeline] = pPipeNode;
-        loader_platform_thread_unlock_mutex(&globalLock);
-    }
-    else { // Skipped pipeline creation due to bad CreateInfo data
-        if (pPipeNode) {
-            // If we allocated a pipeNode, need to clean it up here
-            delete[] pPipeNode->pVertexBindingDescriptions;
-            delete[] pPipeNode->pVertexAttributeDescriptions;
-            delete[] pPipeNode->pAttachments;
-            delete pPipeNode;
-        }
-    }
-    return result;
-}
-
 VK_LAYER_EXPORT VkResult VKAPI vkCreateSampler(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler)
 {
     VkResult result = get_dispatch_table(draw_state_device_table_map, device)->CreateSampler(device, pCreateInfo, pSampler);
@@ -2706,10 +2720,18 @@
         return (void*) vkCreateColorAttachmentView;
     if (!strcmp(funcName, "vkCreateDepthStencilView"))
         return (void*) vkCreateDepthStencilView;
-    if (!strcmp(funcName, "vkCreateGraphicsPipeline"))
-        return (void*) vkCreateGraphicsPipeline;
-    if (!strcmp(funcName, "vkCreateGraphicsPipelineDerivative"))
-        return (void*) vkCreateGraphicsPipelineDerivative;
+    if (!strcmp(funcName, "CreatePipelineCache"))
+        return (void*) vkCreatePipelineCache;
+    if (!strcmp(funcName, "DestroyPipelineCache"))
+        return (void*) vkDestroyPipelineCache;
+    if (!strcmp(funcName, "GetPipelineCacheSize"))
+        return (void*) vkGetPipelineCacheSize;
+    if (!strcmp(funcName, "GetPipelineCacheData"))
+        return (void*) vkGetPipelineCacheData;
+    if (!strcmp(funcName, "MergePipelineCaches"))
+        return (void*) vkMergePipelineCaches;
+    if (!strcmp(funcName, "vkCreateGraphicsPipelines"))
+        return (void*) vkCreateGraphicsPipelines;
     if (!strcmp(funcName, "vkCreateSampler"))
         return (void*) vkCreateSampler;
     if (!strcmp(funcName, "vkCreateDescriptorSetLayout"))
diff --git a/layers/mem_tracker.cpp b/layers/mem_tracker.cpp
index 3dc7fb8..5bf41cc 100644
--- a/layers/mem_tracker.cpp
+++ b/layers/mem_tracker.cpp
@@ -1507,45 +1507,34 @@
     return result;
 }
 
-VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipeline(
+//TODO do we need to intercept pipelineCache functions to track objects?
+VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipelines(
     VkDevice                            device,
-    const VkGraphicsPipelineCreateInfo *pCreateInfo,
-    VkPipeline                         *pPipeline)
+    VkPipelineCache                     pipelineCache,
+    uint32_t                            count,
+    const VkGraphicsPipelineCreateInfo *pCreateInfos,
+    VkPipeline                         *pPipelines)
 {
-    VkResult result = get_dispatch_table(mem_tracker_device_table_map, device)->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
+    VkResult result = get_dispatch_table(mem_tracker_device_table_map, device)->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
     if (result == VK_SUCCESS) {
         loader_platform_thread_lock_mutex(&globalLock);
-        add_object_info(*pPipeline, pCreateInfo->sType, pCreateInfo, sizeof(VkGraphicsPipelineCreateInfo), "graphics_pipeline");
+        add_object_info(*pPipelines, pCreateInfos->sType, pCreateInfos, sizeof(VkGraphicsPipelineCreateInfo), "graphics_pipeline");
         loader_platform_thread_unlock_mutex(&globalLock);
     }
     return result;
 }
 
-VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipelineDerivative(
-    VkDevice                            device,
-    const VkGraphicsPipelineCreateInfo *pCreateInfo,
-    VkPipeline                          basePipeline,
-    VkPipeline                         *pPipeline)
-{
-    VkResult result = get_dispatch_table(mem_tracker_device_table_map, device)->CreateGraphicsPipelineDerivative(
-        device, pCreateInfo, basePipeline, pPipeline);
-    if (result == VK_SUCCESS) {
-        loader_platform_thread_lock_mutex(&globalLock);
-        add_object_info(*pPipeline, pCreateInfo->sType, pCreateInfo, sizeof(VkGraphicsPipelineCreateInfo), "graphics_pipeline");
-        loader_platform_thread_unlock_mutex(&globalLock);
-    }
-    return result;
-}
-
-VK_LAYER_EXPORT VkResult VKAPI vkCreateComputePipeline(
+VK_LAYER_EXPORT VkResult VKAPI vkCreateComputePipelines(
     VkDevice                           device,
-    const VkComputePipelineCreateInfo *pCreateInfo,
-    VkPipeline                        *pPipeline)
+    VkPipelineCache                    pipelineCache,
+    uint32_t                           count,
+    const VkComputePipelineCreateInfo *pCreateInfos,
+    VkPipeline                        *pPipelines)
 {
-    VkResult result = get_dispatch_table(mem_tracker_device_table_map, device)->CreateComputePipeline(device, pCreateInfo, pPipeline);
+    VkResult result = get_dispatch_table(mem_tracker_device_table_map, device)->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
     if (result == VK_SUCCESS) {
         loader_platform_thread_lock_mutex(&globalLock);
-        add_object_info(*pPipeline, pCreateInfo->sType, pCreateInfo, sizeof(VkComputePipelineCreateInfo), "compute_pipeline");
+        add_object_info(*pPipelines, pCreateInfos->sType, pCreateInfos, sizeof(VkComputePipelineCreateInfo), "compute_pipeline");
         loader_platform_thread_unlock_mutex(&globalLock);
     }
     return result;
@@ -2261,12 +2250,10 @@
         return (void*) vkCreateDepthStencilView;
     if (!strcmp(funcName, "vkCreateShader"))
         return (void*) vkCreateShader;
-    if (!strcmp(funcName, "vkCreateGraphicsPipeline"))
-        return (void*) vkCreateGraphicsPipeline;
-    if (!strcmp(funcName, "vkCreateGraphicsPipelineDerivative"))
-        return (void*) vkCreateGraphicsPipelineDerivative;
-    if (!strcmp(funcName, "vkCreateComputePipeline"))
-        return (void*) vkCreateComputePipeline;
+    if (!strcmp(funcName, "vkCreateGraphicsPipelines"))
+        return (void*) vkCreateGraphicsPipelines;
+    if (!strcmp(funcName, "vkCreateComputePipelines"))
+        return (void*) vkCreateComputePipelines;
     if (!strcmp(funcName, "vkCreateSampler"))
         return (void*) vkCreateSampler;
     if (!strcmp(funcName, "vkCreateDynamicViewportState"))
diff --git a/layers/multi.cpp b/layers/multi.cpp
index acdfaf6..574e5c2 100644
--- a/layers/multi.cpp
+++ b/layers/multi.cpp
@@ -134,27 +134,21 @@
     return result;
 }
 
-VK_LAYER_EXPORT VkResult VKAPI multi1CreateGraphicsPipeline(VkDevice device, const VkGraphicsPipelineCreateInfo* pCreateInfo,
-                                                                VkPipeline* pPipeline)
+VK_LAYER_EXPORT VkResult VKAPI multi1CreateGraphicsPipelines(
+                                VkDevice device,
+                                VkPipelineCache pipelineCache,
+                                uint32_t count,
+                                const VkGraphicsPipelineCreateInfo* pCreateInfos,
+                                VkPipeline* pPipelines)
 {
     VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device;
 
     printf("At start of multi1 layer vkCreateGraphicsPipeline()\n");
-    VkResult result = device_dispatch_table1(device)->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
+    VkResult result = device_dispatch_table1(device)->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
     printf("Completed multi1 layer vkCreateGraphicsPipeline()\n");
     return result;
 }
 
-VK_LAYER_EXPORT VkResult VKAPI multi1StorePipeline(VkDevice device, VkPipeline pipeline, size_t* pDataSize, void* pData)
-{
-    VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device;
-
-    printf("At start of multi1 layer vkStorePipeline()\n");
-    VkResult result = device_dispatch_table1(device)->StorePipeline(device, pipeline, pDataSize, pData);
-    printf("Completed multi1 layer vkStorePipeline()\n");
-    return result;
-}
-
 VK_LAYER_EXPORT void * VKAPI multi1GetDeviceProcAddr(VkDevice device, const char* pName)
 {
     VkBaseLayerObject* devw = (VkBaseLayerObject *) device;
@@ -172,10 +166,8 @@
         return (void *) multi1DestroyDevice;
     if (!strcmp("vkCreateSampler", pName))
         return (void *) multi1CreateSampler;
-    if (!strcmp("vkCreateGraphicsPipeline", pName))
-        return (void *) multi1CreateGraphicsPipeline;
-    if (!strcmp("vkStorePipeline", pName))
-        return (void *) multi1StorePipeline;
+    if (!strcmp("vkCreateGraphicsPipelines", pName))
+        return (void *) multi1CreateGraphicsPipelines;
     else {
         VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device;
         VkLayerDispatchTable* pTable = device_dispatch_table1(device);
diff --git a/layers/param_checker.cpp b/layers/param_checker.cpp
index 1f55e38..0ee1b7e 100644
--- a/layers/param_checker.cpp
+++ b/layers/param_checker.cpp
@@ -4645,8 +4645,10 @@
     return result;
 }
 
+//TODO handle count > 1
 void PreCreateGraphicsPipeline(
     VkDevice device,
+    uint32_t count,
     const VkGraphicsPipelineCreateInfo* pCreateInfo)
 {
     if(device == nullptr)
@@ -5117,8 +5119,10 @@
     }
 }
 
+//TODO handle count > 1
 void PostCreateGraphicsPipeline(
     VkDevice device,
+    uint32_t count,
     VkPipeline* pPipeline,
     VkResult result)
 {
@@ -5149,549 +5153,26 @@
         return;
     }
 }
-
-VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipeline(
+//TODO add intercept of pipelineCache entrypoints
+VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipelines(
     VkDevice device,
-    const VkGraphicsPipelineCreateInfo* pCreateInfo,
-    VkPipeline* pPipeline)
+    VkPipelineCache pipelineCache,
+    uint32_t  count,
+    const VkGraphicsPipelineCreateInfo* pCreateInfos,
+    VkPipeline* pPipelines)
 {
-    PreCreateGraphicsPipeline(device, pCreateInfo);
-    VkResult result = get_dispatch_table(pc_device_table_map, device)->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
+    PreCreateGraphicsPipeline(device, count, pCreateInfos);
+    VkResult result = get_dispatch_table(pc_device_table_map, device)->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
 
-    PostCreateGraphicsPipeline(device, pPipeline, result);
+    PostCreateGraphicsPipeline(device, count, pPipelines, result);
 
     return result;
 }
 
-void PreCreateGraphicsPipelineDerivative(
-    VkDevice device,
-    const VkGraphicsPipelineCreateInfo* pCreateInfo)
-{
-    if(device == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkDevice device, is null pointer");
-        return;
-    }
-
-    if(pCreateInfo == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkGraphicsPipelineCreateInfo* pCreateInfo, is null pointer");
-        return;
-    }
-    if(pCreateInfo->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pStages == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineShaderStageCreateInfo* pCreateInfo->pStages, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pStages->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pStages->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pStages->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pStages->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pStages->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pStages->stage < VK_SHADER_STAGE_BEGIN_RANGE ||
-        pCreateInfo->pStages->stage > VK_SHADER_STAGE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkShaderStage pCreateInfo->pStages->stage, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pStages->shader == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkShader pCreateInfo->pStages->shader, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pStages->pLinkConstBufferInfo == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkLinkConstBuffer* pCreateInfo->pStages->pLinkConstBufferInfo, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pStages->pLinkConstBufferInfo->pBufferData == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pStages->pLinkConstBufferInfo->pBufferData, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pStages->pSpecializationInfo == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkSpecializationInfo* pCreateInfo->pStages->pSpecializationInfo, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pStages->pSpecializationInfo->pMap == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkSpecializationMapEntry* pCreateInfo->pStages->pSpecializationInfo->pMap, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pStages->pSpecializationInfo->pData == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pStages->pSpecializationInfo->pData, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pVertexInputState == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineVertexInputStateCreateInfo* pCreateInfo->pVertexInputState, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pVertexInputState->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pVertexInputState->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pVertexInputState->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pVertexInputState->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pVertexInputState->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pVertexInputState->pVertexBindingDescriptions == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkVertexInputBindingDescription* pCreateInfo->pVertexInputState->pVertexBindingDescriptions, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pVertexInputState->pVertexBindingDescriptions->stepRate < VK_VERTEX_INPUT_STEP_RATE_BEGIN_RANGE ||
-        pCreateInfo->pVertexInputState->pVertexBindingDescriptions->stepRate > VK_VERTEX_INPUT_STEP_RATE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkVertexInputStepRate pCreateInfo->pVertexInputState->pVertexBindingDescriptions->stepRate, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pVertexInputState->pVertexAttributeDescriptions == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkVertexInputAttributeDescription* pCreateInfo->pVertexInputState->pVertexAttributeDescriptions, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pVertexInputState->pVertexAttributeDescriptions->format < VK_FORMAT_BEGIN_RANGE ||
-        pCreateInfo->pVertexInputState->pVertexAttributeDescriptions->format > VK_FORMAT_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkFormat pCreateInfo->pVertexInputState->pVertexAttributeDescriptions->format, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pIaState == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineIaStateCreateInfo* pCreateInfo->pIaState, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pIaState->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pIaState->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pIaState->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pIaState->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pIaState->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pIaState->topology < VK_PRIMITIVE_TOPOLOGY_BEGIN_RANGE ||
-        pCreateInfo->pIaState->topology > VK_PRIMITIVE_TOPOLOGY_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkPrimitiveTopology pCreateInfo->pIaState->topology, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pTessState == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineTessStateCreateInfo* pCreateInfo->pTessState, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pTessState->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pTessState->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pTessState->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pTessState->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pTessState->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pVpState == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineVpStateCreateInfo* pCreateInfo->pVpState, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pVpState->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pVpState->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pVpState->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pVpState->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pVpState->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pVpState->clipOrigin < VK_COORDINATE_ORIGIN_BEGIN_RANGE ||
-        pCreateInfo->pVpState->clipOrigin > VK_COORDINATE_ORIGIN_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkCoordinateOrigin pCreateInfo->pVpState->clipOrigin, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pVpState->depthMode < VK_DEPTH_MODE_BEGIN_RANGE ||
-        pCreateInfo->pVpState->depthMode > VK_DEPTH_MODE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkDepthMode pCreateInfo->pVpState->depthMode, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pRsState == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineRsStateCreateInfo* pCreateInfo->pRsState, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pRsState->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pRsState->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pRsState->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pRsState->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pRsState->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pRsState->pointOrigin < VK_COORDINATE_ORIGIN_BEGIN_RANGE ||
-        pCreateInfo->pRsState->pointOrigin > VK_COORDINATE_ORIGIN_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkCoordinateOrigin pCreateInfo->pRsState->pointOrigin, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pRsState->provokingVertex < VK_PROVOKING_VERTEX_BEGIN_RANGE ||
-        pCreateInfo->pRsState->provokingVertex > VK_PROVOKING_VERTEX_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkProvokingVertex pCreateInfo->pRsState->provokingVertex, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pRsState->fillMode < VK_FILL_MODE_BEGIN_RANGE ||
-        pCreateInfo->pRsState->fillMode > VK_FILL_MODE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkFillMode pCreateInfo->pRsState->fillMode, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pRsState->cullMode < VK_CULL_MODE_BEGIN_RANGE ||
-        pCreateInfo->pRsState->cullMode > VK_CULL_MODE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkCullMode pCreateInfo->pRsState->cullMode, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pRsState->frontFace < VK_FRONT_FACE_BEGIN_RANGE ||
-        pCreateInfo->pRsState->frontFace > VK_FRONT_FACE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkFrontFace pCreateInfo->pRsState->frontFace, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pMsState == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineMsStateCreateInfo* pCreateInfo->pMsState, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pMsState->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pMsState->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pMsState->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pMsState->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pMsState->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pDsState == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineDsStateCreateInfo* pCreateInfo->pDsState, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pDsState->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pDsState->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pDsState->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pDsState->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pDsState->format < VK_FORMAT_BEGIN_RANGE ||
-        pCreateInfo->pDsState->format > VK_FORMAT_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkFormat pCreateInfo->pDsState->format, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->depthCompareOp < VK_COMPARE_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->depthCompareOp > VK_COMPARE_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkCompareOp pCreateInfo->pDsState->depthCompareOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->front.stencilFailOp < VK_STENCIL_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->front.stencilFailOp > VK_STENCIL_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStencilOp pCreateInfo->pDsState->front.stencilFailOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->front.stencilPassOp < VK_STENCIL_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->front.stencilPassOp > VK_STENCIL_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStencilOp pCreateInfo->pDsState->front.stencilPassOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->front.stencilDepthFailOp < VK_STENCIL_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->front.stencilDepthFailOp > VK_STENCIL_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStencilOp pCreateInfo->pDsState->front.stencilDepthFailOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->front.stencilCompareOp < VK_COMPARE_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->front.stencilCompareOp > VK_COMPARE_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkCompareOp pCreateInfo->pDsState->front.stencilCompareOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->back.stencilFailOp < VK_STENCIL_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->back.stencilFailOp > VK_STENCIL_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStencilOp pCreateInfo->pDsState->back.stencilFailOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->back.stencilPassOp < VK_STENCIL_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->back.stencilPassOp > VK_STENCIL_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStencilOp pCreateInfo->pDsState->back.stencilPassOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->back.stencilDepthFailOp < VK_STENCIL_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->back.stencilDepthFailOp > VK_STENCIL_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStencilOp pCreateInfo->pDsState->back.stencilDepthFailOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pDsState->back.stencilCompareOp < VK_COMPARE_OP_BEGIN_RANGE ||
-        pCreateInfo->pDsState->back.stencilCompareOp > VK_COMPARE_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkCompareOp pCreateInfo->pDsState->back.stencilCompareOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineCbStateCreateInfo* pCreateInfo->pCbState, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pCbState->sType < VK_STRUCTURE_TYPE_BEGIN_RANGE ||
-        pCreateInfo->pCbState->sType > VK_STRUCTURE_TYPE_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkStructureType pCreateInfo->pCbState->sType, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState->pNext == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const void* pCreateInfo->pCbState->pNext, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pCbState->logicOp < VK_LOGIC_OP_BEGIN_RANGE ||
-        pCreateInfo->pCbState->logicOp > VK_LOGIC_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkLogicOp pCreateInfo->pCbState->logicOp, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState->pAttachments == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, const VkPipelineCbAttachmentState* pCreateInfo->pCbState->pAttachments, is null pointer");
-        return;
-    }
-    if(pCreateInfo->pCbState->pAttachments->format < VK_FORMAT_BEGIN_RANGE ||
-        pCreateInfo->pCbState->pAttachments->format > VK_FORMAT_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkFormat pCreateInfo->pCbState->pAttachments->format, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState->pAttachments->srcBlendColor < VK_BLEND_BEGIN_RANGE ||
-        pCreateInfo->pCbState->pAttachments->srcBlendColor > VK_BLEND_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkBlend pCreateInfo->pCbState->pAttachments->srcBlendColor, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState->pAttachments->destBlendColor < VK_BLEND_BEGIN_RANGE ||
-        pCreateInfo->pCbState->pAttachments->destBlendColor > VK_BLEND_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkBlend pCreateInfo->pCbState->pAttachments->destBlendColor, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState->pAttachments->blendOpColor < VK_BLEND_OP_BEGIN_RANGE ||
-        pCreateInfo->pCbState->pAttachments->blendOpColor > VK_BLEND_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkBlendOp pCreateInfo->pCbState->pAttachments->blendOpColor, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState->pAttachments->srcBlendAlpha < VK_BLEND_BEGIN_RANGE ||
-        pCreateInfo->pCbState->pAttachments->srcBlendAlpha > VK_BLEND_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkBlend pCreateInfo->pCbState->pAttachments->srcBlendAlpha, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState->pAttachments->destBlendAlpha < VK_BLEND_BEGIN_RANGE ||
-        pCreateInfo->pCbState->pAttachments->destBlendAlpha > VK_BLEND_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkBlend pCreateInfo->pCbState->pAttachments->destBlendAlpha, is unrecognized enumerator");
-        return;
-    }
-    if(pCreateInfo->pCbState->pAttachments->blendOpAlpha < VK_BLEND_OP_BEGIN_RANGE ||
-        pCreateInfo->pCbState->pAttachments->blendOpAlpha > VK_BLEND_OP_END_RANGE)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkBlendOp pCreateInfo->pCbState->pAttachments->blendOpAlpha, is unrecognized enumerator");
-        return;
-    }
-    if(!ValidateEnumerator((VkChannelFlagBits)pCreateInfo->pCbState->pAttachments->channelWriteMask))
-    {
-        std::string reason = "vkCreateGraphicsPipelineDerivative parameter, VkChannelFlags pCreateInfo->pCbState->pAttachments->channelWriteMask, is " + EnumeratorString((VkChannelFlagBits)pCreateInfo->pCbState->pAttachments->channelWriteMask);
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK", reason.c_str());
-        return;
-    }
-    if(!ValidateEnumerator((VkPipelineCreateFlagBits)pCreateInfo->flags))
-    {
-        std::string reason = "vkCreateGraphicsPipelineDerivative parameter, VkPipelineCreateFlags pCreateInfo->flags, is " + EnumeratorString((VkPipelineCreateFlagBits)pCreateInfo->flags);
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK", reason.c_str());
-        return;
-    }
-    if(pCreateInfo->layout == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkPipelineLayout pCreateInfo->layout, is null pointer");
-        return;
-    }
-}
-
-void PostCreateGraphicsPipelineDerivative(
-    VkDevice device,
-    VkPipeline basePipeline,
-    VkPipeline* pPipeline,
-    VkResult result)
-{
-    if(device == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkDevice device, is null pointer");
-        return;
-    }
-
-    if(basePipeline == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkPipeline basePipeline, is null pointer");
-        return;
-    }
-
-    if(pPipeline == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkPipeline* pPipeline, is null pointer");
-        return;
-    }
-    if((*pPipeline) == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkCreateGraphicsPipelineDerivative parameter, VkPipeline* pPipeline, is null pointer");
-        return;
-    }
-
-    if(result != VK_SUCCESS)
-    {
-        std::string reason = "vkCreateGraphicsPipelineDerivative parameter, VkResult result, is " + EnumeratorString(result);
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK", reason.c_str());
-        return;
-    }
-}
-
-VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipelineDerivative(
-    VkDevice device,
-    const VkGraphicsPipelineCreateInfo* pCreateInfo,
-    VkPipeline basePipeline,
-    VkPipeline* pPipeline)
-{
-    PreCreateGraphicsPipelineDerivative(device, pCreateInfo);
-    VkResult result = get_dispatch_table(pc_device_table_map, device)->CreateGraphicsPipelineDerivative(device, pCreateInfo, basePipeline, pPipeline);
-
-    PostCreateGraphicsPipelineDerivative(device, basePipeline, pPipeline, result);
-
-    return result;
-}
-
+//TODO handle count > 1
 void PreCreateComputePipeline(
     VkDevice device,
+    uint32_t count,
     const VkComputePipelineCreateInfo* pCreateInfo)
 {
     if(device == nullptr)
@@ -5784,8 +5265,10 @@
     }
 }
 
+//TODO handle count > 1
 void PostCreateComputePipeline(
     VkDevice device,
+    uint32_t count,
     VkPipeline* pPipeline,
     VkResult result)
 {
@@ -5817,231 +5300,21 @@
     }
 }
 
-VK_LAYER_EXPORT VkResult VKAPI vkCreateComputePipeline(
+VK_LAYER_EXPORT VkResult VKAPI vkCreateComputePipelines(
     VkDevice device,
-    const VkComputePipelineCreateInfo* pCreateInfo,
-    VkPipeline* pPipeline)
+    VkPipelineCache pipelineCache,
+    uint32_t  count,
+    const VkComputePipelineCreateInfo* pCreateInfos,
+    VkPipeline* pPipelines)
 {
-    PreCreateComputePipeline(device, pCreateInfo);
-    VkResult result = get_dispatch_table(pc_device_table_map, device)->CreateComputePipeline(device, pCreateInfo, pPipeline);
+    PreCreateComputePipeline(device, count, pCreateInfos);
+    VkResult result = get_dispatch_table(pc_device_table_map, device)->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
 
-    PostCreateComputePipeline(device, pPipeline, result);
+    PostCreateComputePipeline(device, count, pPipelines, result);
 
     return result;
 }
 
-void PreStorePipeline(
-    VkDevice device)
-{
-    if(device == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkStorePipeline parameter, VkDevice device, is null pointer");
-        return;
-    }
-}
-
-void PostStorePipeline(
-    VkDevice device,
-    VkPipeline pipeline,
-    size_t* pDataSize,
-    void* pData,
-    VkResult result)
-{
-    if(device == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkStorePipeline parameter, VkDevice device, is null pointer");
-        return;
-    }
-
-    if(pipeline == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkStorePipeline parameter, VkPipeline pipeline, is null pointer");
-        return;
-    }
-
-    if(pDataSize == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkStorePipeline parameter, size_t* pDataSize, is null pointer");
-        return;
-    }
-
-    if(pData == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkStorePipeline parameter, void* pData, is null pointer");
-        return;
-    }
-
-    if(result != VK_SUCCESS)
-    {
-        std::string reason = "vkStorePipeline parameter, VkResult result, is " + EnumeratorString(result);
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK", reason.c_str());
-        return;
-    }
-}
-
-VK_LAYER_EXPORT VkResult VKAPI vkStorePipeline(
-    VkDevice device,
-    VkPipeline pipeline,
-    size_t* pDataSize,
-    void* pData)
-{
-    PreStorePipeline(device);
-    VkResult result = get_dispatch_table(pc_device_table_map, device)->StorePipeline(device, pipeline, pDataSize, pData);
-
-    PostStorePipeline(device, pipeline, pDataSize, pData, result);
-
-    return result;
-}
-
-void PreLoadPipeline(
-    VkDevice device,
-    const void* pData)
-{
-    if(device == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipeline parameter, VkDevice device, is null pointer");
-        return;
-    }
-
-    if(pData == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipeline parameter, const void* pData, is null pointer");
-        return;
-    }
-}
-
-void PostLoadPipeline(
-    VkDevice device,
-    size_t dataSize,
-    VkPipeline* pPipeline,
-    VkResult result)
-{
-    if(device == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipeline parameter, VkDevice device, is null pointer");
-        return;
-    }
-
-
-    if(pPipeline == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipeline parameter, VkPipeline* pPipeline, is null pointer");
-        return;
-    }
-    if((*pPipeline) == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipeline parameter, VkPipeline* pPipeline, is null pointer");
-        return;
-    }
-
-    if(result != VK_SUCCESS)
-    {
-        std::string reason = "vkLoadPipeline parameter, VkResult result, is " + EnumeratorString(result);
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK", reason.c_str());
-        return;
-    }
-}
-
-VK_LAYER_EXPORT VkResult VKAPI vkLoadPipeline(
-    VkDevice device,
-    size_t dataSize,
-    const void* pData,
-    VkPipeline* pPipeline)
-{
-    PreLoadPipeline(device, pData);
-    VkResult result = get_dispatch_table(pc_device_table_map, device)->LoadPipeline(device, dataSize, pData, pPipeline);
-
-    PostLoadPipeline(device, dataSize, pPipeline, result);
-
-    return result;
-}
-
-void PreLoadPipelineDerivative(
-    VkDevice device,
-    const void* pData)
-{
-    if(device == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipelineDerivative parameter, VkDevice device, is null pointer");
-        return;
-    }
-
-    if(pData == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipelineDerivative parameter, const void* pData, is null pointer");
-        return;
-    }
-}
-
-void PostLoadPipelineDerivative(
-    VkDevice device,
-    size_t dataSize,
-    VkPipeline basePipeline,
-    VkPipeline* pPipeline,
-    VkResult result)
-{
-    if(device == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipelineDerivative parameter, VkDevice device, is null pointer");
-        return;
-    }
-
-
-    if(basePipeline == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipelineDerivative parameter, VkPipeline basePipeline, is null pointer");
-        return;
-    }
-
-    if(pPipeline == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipelineDerivative parameter, VkPipeline* pPipeline, is null pointer");
-        return;
-    }
-    if((*pPipeline) == nullptr)
-    {
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK",
-        "vkLoadPipelineDerivative parameter, VkPipeline* pPipeline, is null pointer");
-        return;
-    }
-
-    if(result != VK_SUCCESS)
-    {
-        std::string reason = "vkLoadPipelineDerivative parameter, VkResult result, is " + EnumeratorString(result);
-        log_msg(mdd(device), VK_DBG_REPORT_WARN_BIT, (VkObjectType)0, NULL, 0, 1, "PARAMCHECK", reason.c_str());
-        return;
-    }
-}
-
-VK_LAYER_EXPORT VkResult VKAPI vkLoadPipelineDerivative(
-    VkDevice device,
-    size_t dataSize,
-    const void* pData,
-    VkPipeline basePipeline,
-    VkPipeline* pPipeline)
-{
-    PreLoadPipelineDerivative(device, pData);
-    VkResult result = get_dispatch_table(pc_device_table_map, device)->LoadPipelineDerivative(device, dataSize, pData, basePipeline, pPipeline);
-
-    PostLoadPipelineDerivative(device, dataSize, basePipeline, pPipeline, result);
-
-    return result;
-}
 
 void PreCreatePipelineLayout(
     VkDevice device,
@@ -9562,18 +8835,10 @@
         return (void*) vkCreateDepthStencilView;
     if (!strcmp(funcName, "vkCreateShader"))
         return (void*) vkCreateShader;
-    if (!strcmp(funcName, "vkCreateGraphicsPipeline"))
-        return (void*) vkCreateGraphicsPipeline;
-    if (!strcmp(funcName, "vkCreateGraphicsPipelineDerivative"))
-        return (void*) vkCreateGraphicsPipelineDerivative;
-    if (!strcmp(funcName, "vkCreateComputePipeline"))
-        return (void*) vkCreateComputePipeline;
-    if (!strcmp(funcName, "vkStorePipeline"))
-        return (void*) vkStorePipeline;
-    if (!strcmp(funcName, "vkLoadPipeline"))
-        return (void*) vkLoadPipeline;
-    if (!strcmp(funcName, "vkLoadPipelineDerivative"))
-        return (void*) vkLoadPipelineDerivative;
+    if (!strcmp(funcName, "vkCreateGraphicsPipelines"))
+        return (void*) vkCreateGraphicsPipelines;
+    if (!strcmp(funcName, "vkCreateComputePipelines"))
+        return (void*) vkCreateComputePipelines;
     if (!strcmp(funcName, "vkCreatePipelineLayout"))
         return (void*) vkCreatePipelineLayout;
     if (!strcmp(funcName, "vkCreateSampler"))
diff --git a/layers/shader_checker.cpp b/layers/shader_checker.cpp
index 170b96e..8d1a865 100644
--- a/layers/shader_checker.cpp
+++ b/layers/shader_checker.cpp
@@ -846,8 +846,9 @@
 };
 
 
+//TODO handle count > 1
 static bool
-validate_graphics_pipeline(VkDevice dev, VkGraphicsPipelineCreateInfo const *pCreateInfo)
+validate_graphics_pipeline(VkDevice dev, uint32_t count, VkGraphicsPipelineCreateInfo const *pCreateInfo)
 {
     /* We seem to allow pipeline stages to be specified out of order, so collect and identify them
      * before trying to do anything more: */
@@ -917,19 +918,21 @@
     return pass;
 }
 
-
+//TODO handle pipelineCache entry points
 VK_LAYER_EXPORT VkResult VKAPI
-vkCreateGraphicsPipeline(VkDevice device,
-                         const VkGraphicsPipelineCreateInfo *pCreateInfo,
-                         VkPipeline *pPipeline)
+vkCreateGraphicsPipelines(VkDevice device,
+                         VkPipelineCache pipelineCache,
+                         uint32_t count,
+                         const VkGraphicsPipelineCreateInfo *pCreateInfos,
+                         VkPipeline *pPipelines)
 {
-    bool pass = validate_graphics_pipeline(device, pCreateInfo);
+    bool pass = validate_graphics_pipeline(device, count, pCreateInfos);
 
     if (pass) {
         /* The driver is allowed to crash if passed junk. Only actually create the
          * pipeline if we didn't run into any showstoppers above.
          */
-        return get_dispatch_table(shader_checker_device_table_map, device)->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
+        return get_dispatch_table(shader_checker_device_table_map, device)->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
     }
     else {
         return VK_ERROR_UNKNOWN;
@@ -937,25 +940,6 @@
 }
 
 
-VK_LAYER_EXPORT VkResult VKAPI
-vkCreateGraphicsPipelineDerivative(VkDevice device,
-                                   const VkGraphicsPipelineCreateInfo *pCreateInfo,
-                                   VkPipeline basePipeline,
-                                   VkPipeline *pPipeline)
-{
-    bool pass = validate_graphics_pipeline(device, pCreateInfo);
-
-    if (pass) {
-        /* The driver is allowed to crash if passed junk. Only actually create the
-         * pipeline if we didn't run into any showstoppers above.
-         */
-        return get_dispatch_table(shader_checker_device_table_map, device)->CreateGraphicsPipelineDerivative(device, pCreateInfo, basePipeline, pPipeline);
-    }
-    else {
-        return VK_ERROR_UNKNOWN;
-    }
-}
-
 VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
 {
     VkLayerDispatchTable *pDeviceTable = get_dispatch_table(shader_checker_device_table_map, *pDevice);
@@ -1065,8 +1049,7 @@
     ADD_HOOK(vkCreateShaderModule);
     ADD_HOOK(vkCreateShader);
     ADD_HOOK(vkDestroyDevice);
-    ADD_HOOK(vkCreateGraphicsPipeline);
-    ADD_HOOK(vkCreateGraphicsPipelineDerivative);
+    ADD_HOOK(vkCreateGraphicsPipelines);
 #undef ADD_HOOK
 
     VkLayerDispatchTable* pTable = get_dispatch_table(shader_checker_device_table_map, dev);
diff --git a/loader/gpa_helper.h b/loader/gpa_helper.h
index a54f63b..9532d5d 100644
--- a/loader/gpa_helper.h
+++ b/loader/gpa_helper.h
@@ -149,18 +149,20 @@
         return (void*) vkCreateShaderModule;
     if (!strcmp(name, "CreateShader"))
         return (void*) vkCreateShader;
-    if (!strcmp(name, "CreateGraphicsPipeline"))
-        return (void*) vkCreateGraphicsPipeline;
-    if (!strcmp(name, "CreateGraphicsPipelineDerivative"))
-        return (void*) vkCreateGraphicsPipelineDerivative;
-    if (!strcmp(name, "CreateComputePipeline"))
-        return (void*) vkCreateComputePipeline;
-    if (!strcmp(name, "StorePipeline"))
-        return (void*) vkStorePipeline;
-    if (!strcmp(name, "LoadPipeline"))
-        return (void*) vkLoadPipeline;
-    if (!strcmp(name, "LoadPipelineDerivative"))
-        return (void*) vkLoadPipelineDerivative;
+    if (!strcmp(name, "CreatePipelineCache"))
+        return (void*) vkCreatePipelineCache;
+    if (!strcmp(name, "DestroyPipelineCache"))
+        return (void*) vkDestroyPipelineCache;
+    if (!strcmp(name, "GetPipelineCacheSize"))
+        return (void*) vkGetPipelineCacheSize;
+    if (!strcmp(name, "GetPipelineCacheData"))
+        return (void*) vkGetPipelineCacheData;
+    if (!strcmp(name, "MergePipelineCaches"))
+        return (void*) vkMergePipelineCaches;
+    if (!strcmp(name, "CreateGraphicsPipelines"))
+        return (void*) vkCreateGraphicsPipelines;
+    if (!strcmp(name, "CreateComputePipelines"))
+        return (void*) vkCreateComputePipelines;
     if (!strcmp(name, "CreatePipelineLayout"))
         return (void*) vkCreatePipelineLayout;
     if (!strcmp(name, "CreateSampler"))
diff --git a/loader/table_ops.h b/loader/table_ops.h
index 4f3b501..7563af8 100644
--- a/loader/table_ops.h
+++ b/loader/table_ops.h
@@ -78,12 +78,13 @@
     table->CreateDepthStencilView = (PFN_vkCreateDepthStencilView) gpa(dev, "vkCreateDepthStencilView");
     table->CreateShaderModule = (PFN_vkCreateShaderModule) gpa(dev, "vkCreateShaderModule");
     table->CreateShader = (PFN_vkCreateShader) gpa(dev, "vkCreateShader");
-    table->CreateGraphicsPipeline = (PFN_vkCreateGraphicsPipeline) gpa(dev, "vkCreateGraphicsPipeline");
-    table->CreateGraphicsPipelineDerivative = (PFN_vkCreateGraphicsPipelineDerivative) gpa(dev, "vkCreateGraphicsPipelineDerivative");
-    table->CreateComputePipeline = (PFN_vkCreateComputePipeline) gpa(dev, "vkCreateComputePipeline");
-    table->StorePipeline = (PFN_vkStorePipeline) gpa(dev, "vkStorePipeline");
-    table->LoadPipeline = (PFN_vkLoadPipeline) gpa(dev, "vkLoadPipeline");
-    table->LoadPipelineDerivative = (PFN_vkLoadPipelineDerivative) gpa(dev, "vkLoadPipelineDerivative");
+    table->CreatePipelineCache = (PFN_vkCreatePipelineCache) gpa(dev, "vkCreatePipelineCache");
+    table->DestroyPipelineCache = (PFN_vkDestroyPipelineCache) gpa(dev, "vkDestroyPipelineCache");
+    table->GetPipelineCacheSize = (PFN_vkGetPipelineCacheSize) gpa(dev, "vkGetPipelineCacheSize");
+    table->GetPipelineCacheData = (PFN_vkGetPipelineCacheData) gpa(dev, "vkGetPipelineCacheData");
+    table->MergePipelineCaches = (PFN_vkMergePipelineCaches) gpa(dev, "vkMergePipelineCaches");
+    table->CreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines) gpa(dev, "vkCreateGraphicsPipelines");
+    table->CreateComputePipelines = (PFN_vkCreateComputePipelines) gpa(dev, "vkCreateComputePipelines");
     table->CreatePipelineLayout = (PFN_vkCreatePipelineLayout) gpa(dev, "vkCreatePipelineLayout");
     table->CreateSampler = (PFN_vkCreateSampler) gpa(dev, "vkCreateSampler");
     table->CreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout) gpa(dev, "vkCreateDescriptorSetLayout");
@@ -237,18 +238,20 @@
         return (void *) table->CreateShaderModule;
     if (!strcmp(name, "CreateShader"))
         return (void *) table->CreateShader;
-    if (!strcmp(name, "CreateGraphicsPipeline"))
-        return (void *) table->CreateGraphicsPipeline;
-    if (!strcmp(name, "CreateGraphicsPipelineDerivative"))
-        return (void *) table->CreateGraphicsPipelineDerivative;
-    if (!strcmp(name, "CreateComputePipeline"))
-        return (void *) table->CreateComputePipeline;
-    if (!strcmp(name, "StorePipeline"))
-        return (void *) table->StorePipeline;
-    if (!strcmp(name, "LoadPipeline"))
-        return (void *) table->LoadPipeline;
-    if (!strcmp(name, "LoadPipelineDerivative"))
-        return (void *) table->LoadPipelineDerivative;
+    if (!strcmp(name, "CreatePipelineCache"))
+        return (void*) vkCreatePipelineCache;
+    if (!strcmp(name, "DestroyPipelineCache"))
+        return (void*) vkDestroyPipelineCache;
+    if (!strcmp(name, "GetPipelineCacheSize"))
+        return (void*) vkGetPipelineCacheSize;
+    if (!strcmp(name, "GetPipelineCacheData"))
+        return (void*) vkGetPipelineCacheData;
+    if (!strcmp(name, "MergePipelineCaches"))
+        return (void*) vkMergePipelineCaches;
+    if (!strcmp(name, "CreateGraphicsPipelines"))
+        return (void*) vkCreateGraphicsPipelines;
+    if (!strcmp(name, "CreateComputePipelines"))
+        return (void*) vkCreateComputePipelines;
     if (!strcmp(name, "CreatePipelineLayout"))
         return (void *) table->CreatePipelineLayout;
     if (!strcmp(name, "CreateSampler"))
diff --git a/loader/trampoline.c b/loader/trampoline.c
index 19f1cbb..a7b6037 100644
--- a/loader/trampoline.c
+++ b/loader/trampoline.c
@@ -690,58 +690,67 @@
     return disp->CreateShader(device, pCreateInfo, pShader);
 }
 
-LOADER_EXPORT VkResult VKAPI vkCreateGraphicsPipeline(VkDevice device, const VkGraphicsPipelineCreateInfo* pCreateInfo, VkPipeline* pPipeline)
+LOADER_EXPORT VkResult VKAPI vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, VkPipelineCache* pPipelineCache)
 {
     const VkLayerDispatchTable *disp;
 
     disp = loader_get_dispatch(device);
 
-    return disp->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
+    return disp->CreatePipelineCache(device, pCreateInfo, pPipelineCache);
 }
 
-LOADER_EXPORT VkResult VKAPI vkCreateGraphicsPipelineDerivative(VkDevice device, const VkGraphicsPipelineCreateInfo* pCreateInfo, VkPipeline basePipeline, VkPipeline* pPipeline)
+LOADER_EXPORT VkResult VKAPI vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache)
 {
     const VkLayerDispatchTable *disp;
 
     disp = loader_get_dispatch(device);
 
-    return disp->CreateGraphicsPipelineDerivative(device, pCreateInfo, basePipeline, pPipeline);
+    return disp->DestroyPipelineCache(device, pipelineCache);
 }
 
-LOADER_EXPORT VkResult VKAPI vkCreateComputePipeline(VkDevice device, const VkComputePipelineCreateInfo* pCreateInfo, VkPipeline* pPipeline)
+LOADER_EXPORT size_t VKAPI vkGetPipelineCacheSize(VkDevice device, VkPipelineCache pipelineCache)
 {
     const VkLayerDispatchTable *disp;
 
     disp = loader_get_dispatch(device);
 
-    return disp->CreateComputePipeline(device, pCreateInfo, pPipeline);
+    return disp->GetPipelineCacheSize(device, pipelineCache);
 }
 
-LOADER_EXPORT VkResult VKAPI vkStorePipeline(VkDevice device, VkPipeline pipeline, size_t* pDataSize, void* pData)
+LOADER_EXPORT VkResult VKAPI vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, void* pData)
 {
     const VkLayerDispatchTable *disp;
 
     disp = loader_get_dispatch(device);
 
-    return disp->StorePipeline(device, pipeline, pDataSize, pData);
+    return disp->GetPipelineCacheData(device, pipelineCache, pData);
 }
 
-LOADER_EXPORT VkResult VKAPI vkLoadPipeline(VkDevice device, size_t dataSize, const void* pData, VkPipeline* pPipeline)
+LOADER_EXPORT VkResult VKAPI vkMergePipelineCaches(VkDevice device, VkPipelineCache destCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches)
 {
     const VkLayerDispatchTable *disp;
 
     disp = loader_get_dispatch(device);
 
-    return disp->LoadPipeline(device, dataSize, pData, pPipeline);
+    return disp->MergePipelineCaches(device, destCache, srcCacheCount, pSrcCaches);
 }
 
-LOADER_EXPORT VkResult VKAPI vkLoadPipelineDerivative(VkDevice device, size_t dataSize, const void* pData, VkPipeline basePipeline, VkPipeline* pPipeline)
+LOADER_EXPORT VkResult VKAPI vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, const VkGraphicsPipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines)
 {
     const VkLayerDispatchTable *disp;
 
     disp = loader_get_dispatch(device);
 
-    return disp->LoadPipelineDerivative(device, dataSize, pData, basePipeline, pPipeline);
+    return disp->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
+}
+
+LOADER_EXPORT VkResult VKAPI vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count, const VkComputePipelineCreateInfo* pCreateInfos, VkPipeline* pPipelines)
+{
+    const VkLayerDispatchTable *disp;
+
+    disp = loader_get_dispatch(device);
+
+    return disp->CreateComputePipelines(device, pipelineCache, count, pCreateInfos, pPipelines);
 }
 
 LOADER_EXPORT VkResult VKAPI vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo* pCreateInfo, VkPipelineLayout* pPipelineLayout)
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index a3dbd0e..3f17872 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -1105,9 +1105,20 @@
         .flags             = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,
         .layout            = pipeline_layout,
     };
+    const VkPipelineCacheCreateInfo pc_ci = {
+        .sType             = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
+        .pNext             = NULL,
+        .initialSize       = 0,
+        .initialData       = 0,
+        .maxSize           = 0,
+    };
 
     VkPipeline pipeline;
-    err = vkCreateGraphicsPipeline(m_device->device(), &gp_ci, &pipeline);
+    VkPipelineCache pipelineCache;
+
+    err = vkCreatePipelineCache(m_device->device(), &pc_ci, &pipelineCache);
+    ASSERT_VK_SUCCESS(err);
+    err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, &pipeline);
     ASSERT_VK_SUCCESS(err);
     ASSERT_NO_FATAL_FAILURE(InitState());
     ASSERT_NO_FATAL_FAILURE(InitViewport());
@@ -1214,9 +1225,20 @@
         .flags             = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,
         .layout            = pipeline_layout,
     };
+    const VkPipelineCacheCreateInfo pc_ci = {
+        .sType             = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
+        .pNext             = NULL,
+        .initialSize       = 0,
+        .initialData       = 0,
+        .maxSize           = 0,
+    };
 
     VkPipeline pipeline;
-    err = vkCreateGraphicsPipeline(m_device->device(), &gp_ci, &pipeline);
+    VkPipelineCache pipelineCache;
+
+    err = vkCreatePipelineCache(m_device->device(), &pc_ci, &pipelineCache);
+    ASSERT_VK_SUCCESS(err);
+    err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, &pipeline);
 
     msgFlags = m_errorMonitor->GetState(&msgString);
     ASSERT_TRUE(msgFlags & VK_DBG_REPORT_ERROR_BIT) << "Did not receive error after creating Gfx Pipeline w/o VS.";
@@ -1367,9 +1389,20 @@
         .flags             = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,
         .layout            = pipeline_layout,
     };
+    const VkPipelineCacheCreateInfo pc_ci = {
+        .sType             = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
+        .pNext             = NULL,
+        .initialSize       = 0,
+        .initialData       = 0,
+        .maxSize           = 0,
+    };
 
     VkPipeline pipeline;
-    err = vkCreateGraphicsPipeline(m_device->device(), &gp_ci, &pipeline);
+    VkPipelineCache pipelineCache;
+
+    err = vkCreatePipelineCache(m_device->device(), &pc_ci, &pipelineCache);
+    ASSERT_VK_SUCCESS(err);
+    err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, &pipeline);
     ASSERT_VK_SUCCESS(err);
 
     err= cmdBuffer.BeginCommandBuffer();
@@ -1831,9 +1864,20 @@
         .flags             = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,
         .layout            = pipeline_layout,
     };
+    const VkPipelineCacheCreateInfo pc_ci = {
+        .sType             = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
+        .pNext             = NULL,
+        .initialSize       = 0,
+        .initialData       = 0,
+        .maxSize           = 0,
+    };
 
     VkPipeline pipeline;
-    err = vkCreateGraphicsPipeline(m_device->device(), &gp_ci, &pipeline);
+    VkPipelineCache pipelineCache;
+
+    err = vkCreatePipelineCache(m_device->device(), &pc_ci, &pipelineCache);
+    ASSERT_VK_SUCCESS(err);
+    err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, &pipeline);
     ASSERT_VK_SUCCESS(err);
 
     cmdBuffer.AddRenderTarget(m_renderTargets[0]);
@@ -2043,9 +2087,20 @@
         .flags             = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT,
         .layout            = pipeline_layout,
     };
+    const VkPipelineCacheCreateInfo pc_ci = {
+        .sType             = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
+        .pNext             = NULL,
+        .initialSize       = 0,
+        .initialData       = 0,
+        .maxSize           = 0,
+    };
 
     VkPipeline pipeline;
-    err = vkCreateGraphicsPipeline(m_device->device(), &gp_ci, &pipeline);
+    VkPipelineCache pipelineCache;
+
+    err = vkCreatePipelineCache(m_device->device(), &pc_ci, &pipelineCache);
+    ASSERT_VK_SUCCESS(err);
+    err = vkCreateGraphicsPipelines(m_device->device(), pipelineCache, 1, &gp_ci, &pipeline);
     ASSERT_VK_SUCCESS(err);
 
     cmdBuffer.AddRenderTarget(m_renderTargets[0]);
diff --git a/tests/vktestbinding.cpp b/tests/vktestbinding.cpp
index 9d0a4c1..7b58528 100644
--- a/tests/vktestbinding.cpp
+++ b/tests/vktestbinding.cpp
@@ -808,61 +808,54 @@
 
 void Pipeline::init(const Device &dev, const VkGraphicsPipelineCreateInfo &info)
 {
-    DERIVED_OBJECT_TYPE_INIT(vkCreateGraphicsPipeline, dev, VK_OBJECT_TYPE_PIPELINE, &info);
-    alloc_memory();
+    VkPipelineCache cache;
+    VkPipelineCacheCreateInfo ci;
+    memset((void *) &ci, 0, sizeof(VkPipelineCacheCreateInfo));
+    ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+    VkResult err = vkCreatePipelineCache(dev.obj(), &ci, &cache);
+    if (err == VK_SUCCESS) {
+        DERIVED_OBJECT_TYPE_INIT(vkCreateGraphicsPipelines, dev, VK_OBJECT_TYPE_PIPELINE, cache, 1, &info);
+        alloc_memory();
+        vkDestroyPipelineCache(dev.obj(), cache);
+    }
 }
 
 VkResult Pipeline::init_try(const Device &dev, const VkGraphicsPipelineCreateInfo &info)
 {
     VkPipeline pipe;
+    VkPipelineCache cache;
+    VkPipelineCacheCreateInfo ci;
     dev_ = &dev;
-    VkResult err = vkCreateGraphicsPipeline(dev.obj(), &info, &pipe);
+    memset((void *) &ci, 0, sizeof(VkPipelineCacheCreateInfo));
+    ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+    VkResult err = vkCreatePipelineCache(dev.obj(), &ci, &cache);
     if (err == VK_SUCCESS) {
-        Object::init(pipe, VK_OBJECT_TYPE_PIPELINE);
-        alloc_memory();
+        err = vkCreateGraphicsPipelines(dev.obj(), cache, 1, &info, &pipe);
+        if (err == VK_SUCCESS) {
+            Object::init(pipe, VK_OBJECT_TYPE_PIPELINE);
+            alloc_memory();
+            vkDestroyPipelineCache(dev.obj(), cache);
+        }
     }
 
     return err;
 }
 
-void Pipeline::init(
-        const Device &dev,
-        const VkGraphicsPipelineCreateInfo &info,
-        const VkPipeline basePipeline)
-{
-    DERIVED_OBJECT_TYPE_INIT(vkCreateGraphicsPipelineDerivative, dev, VK_OBJECT_TYPE_PIPELINE, &info, basePipeline);
-    alloc_memory();
-}
 
 void Pipeline::init(const Device &dev, const VkComputePipelineCreateInfo &info)
 {
-    DERIVED_OBJECT_TYPE_INIT(vkCreateComputePipeline, dev, VK_OBJECT_TYPE_PIPELINE, &info);
-    alloc_memory();
+    VkPipelineCache cache;
+    VkPipelineCacheCreateInfo ci;
+    memset((void *) &ci, 0, sizeof(VkPipelineCacheCreateInfo));
+    ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+    VkResult err = vkCreatePipelineCache(dev.obj(), &ci, &cache);
+    if (err == VK_SUCCESS) {
+        DERIVED_OBJECT_TYPE_INIT(vkCreateComputePipelines, dev, VK_OBJECT_TYPE_PIPELINE, cache, 1, &info);
+        alloc_memory();
+        vkDestroyPipelineCache(dev.obj(), cache);
+    }
 }
 
-void Pipeline::init(const Device&dev, size_t size, const void *data)
-{
-    DERIVED_OBJECT_TYPE_INIT(vkLoadPipeline, dev, VK_OBJECT_TYPE_PIPELINE, size, data);
-    alloc_memory();
-}
-
-void Pipeline::init(
-        const Device&dev,
-        size_t size,
-        const void *data,
-        const VkPipeline basePipeline)
-{
-    DERIVED_OBJECT_TYPE_INIT(vkLoadPipelineDerivative, dev, VK_OBJECT_TYPE_PIPELINE, size, data, basePipeline);
-    alloc_memory();
-}
-
-size_t Pipeline::store(size_t size, void *data)
-{
-    if (!EXPECT(vkStorePipeline(dev_->obj(), obj(), &size, data) == VK_SUCCESS))
-        size = 0;
-
-    return size;
-}
 
 void Sampler::init(const Device &dev, const VkSamplerCreateInfo &info)
 {
diff --git a/vk_helper.py b/vk_helper.py
index 9e5b2e6..64b02b9 100755
--- a/vk_helper.py
+++ b/vk_helper.py
@@ -882,12 +882,15 @@
                         else:
                             sh_funcs.append('%s' % lineinfo.get())
                             sh_funcs.append('    ss[%u] << &pStruct->%s;' % (index, self.struct_dict[s][m]['name']))
+                    elif self.struct_dict[s][m]['array']:
+                        sh_funcs.append('%s' % lineinfo.get())
+                        sh_funcs.append('    ss[%u] << (void*)pStruct->%s;' % (index, self.struct_dict[s][m]['name']))
                     elif 'bool' in self.struct_dict[s][m]['type'].lower():
                         sh_funcs.append('%s' % lineinfo.get())
                         sh_funcs.append('    ss[%u].str(pStruct->%s ? "TRUE" : "FALSE");' % (index, self.struct_dict[s][m]['name']))
                     elif 'uint8' in self.struct_dict[s][m]['type'].lower():
                         sh_funcs.append('%s' % lineinfo.get())
-                        sh_funcs.append('    ss[%u] << (uint32_t)pStruct->%s;' % (index, self.struct_dict[s][m]['name']))
+                        sh_funcs.append('    ss[%u] << pStruct->%s;' % (index, self.struct_dict[s][m]['name']))
                     elif 'void' in self.struct_dict[s][m]['type'].lower() and self.struct_dict[s][m]['ptr']:
                         sh_funcs.append('%s' % lineinfo.get())
                         sh_funcs.append('    if (StreamControl::writeAddress)')
diff --git a/vulkan.py b/vulkan.py
index 01112c7..f73942f 100755
--- a/vulkan.py
+++ b/vulkan.py
@@ -198,6 +198,7 @@
         "VkDepthStencilView",
         "VkShader",
         "VkPipeline",
+        "VkPipelineCache",
         "VkSampler",
         "VkDescriptorSet",
         "VkDescriptorSetLayout",
@@ -512,40 +513,43 @@
              Param("const VkShaderCreateInfo*", "pCreateInfo"),
              Param("VkShader*", "pShader")]),
 
-        Proto("VkResult", "CreateGraphicsPipeline",
+        Proto("VkResult", "CreatePipelineCache",
             [Param("VkDevice", "device"),
-             Param("const VkGraphicsPipelineCreateInfo*", "pCreateInfo"),
-             Param("VkPipeline*", "pPipeline")]),
+             Param("const VkPipelineCacheCreateInfo*", "pCreateInfo"),
+             Param("VkPipelineCache*", "pPipelineCache")]),
 
-        Proto("VkResult", "CreateGraphicsPipelineDerivative",
+        Proto("VkResult", "DestroyPipelineCache",
             [Param("VkDevice", "device"),
-             Param("const VkGraphicsPipelineCreateInfo*", "pCreateInfo"),
-             Param("VkPipeline", "basePipeline"),
-             Param("VkPipeline*", "pPipeline")]),
+             Param("VkPipelineCache", "pipelineCache")]),
 
-        Proto("VkResult", "CreateComputePipeline",
+        Proto("size_t", "GetPipelineCacheSize",
             [Param("VkDevice", "device"),
-             Param("const VkComputePipelineCreateInfo*", "pCreateInfo"),
-             Param("VkPipeline*", "pPipeline")]),
+             Param("VkPipelineCache", "pipelineCache")]),
 
-        Proto("VkResult", "StorePipeline",
+        Proto("VkResult", "GetPipelineCacheData",
             [Param("VkDevice", "device"),
-             Param("VkPipeline", "pipeline"),
-             Param("size_t*", "pDataSize"),
+             Param("VkPipelineCache", "pipelineCache"),
              Param("void*", "pData")]),
 
-        Proto("VkResult", "LoadPipeline",
+        Proto("VkResult", "MergePipelineCaches",
             [Param("VkDevice", "device"),
-             Param("size_t", "dataSize"),
-             Param("const void*", "pData"),
-             Param("VkPipeline*", "pPipeline")]),
+             Param("VkPipelineCache", "destCache"),
+             Param("uint32_t", "srcCacheCount"),
+             Param("const VkPipelineCache*", "pSrcCaches")]),
 
-        Proto("VkResult", "LoadPipelineDerivative",
+        Proto("VkResult", "CreateGraphicsPipelines",
             [Param("VkDevice", "device"),
-             Param("size_t", "dataSize"),
-             Param("const void*", "pData"),
-             Param("VkPipeline", "basePipeline"),
-             Param("VkPipeline*", "pPipeline")]),
+             Param("VkPipelineCache", "pipelineCache"),
+             Param("uint32_t", "count"),
+             Param("const VkGraphicsPipelineCreateInfo*", "pCreateInfos"),
+             Param("VkPipeline*", "pPipelines")]),
+
+        Proto("VkResult", "CreateComputePipelines",
+            [Param("VkDevice", "device"),
+             Param("VkPipelineCache", "pipelineCache"),
+             Param("uint32_t", "count"),
+             Param("const VkComputePipelineCreateInfo*", "pCreateInfos"),
+             Param("VkPipeline*", "pPipelines")]),
 
         Proto("VkResult", "CreatePipelineLayout",
             [Param("VkDevice", "device"),
@@ -942,6 +946,7 @@
     "VkDepthStencilView",
     "VkShader",
     "VkPipeline",
+    "VkPipelineCache",
     "VkPipelineLayout",
     "VkSampler",
     "VkDescriptorSet",