layers: Clean up PIPELINE_NODE using safe_struct

PIPELINE_NODE was storing ptrs from the app and has some ugly initialization code
for the gfx pipeline create struct. This commit switches pipeline node to use
safe_struct wrappers for Gfx and Compute create info.
There were also some bugs found in the safe_struct wrappers making this migration
so those are cleaned up in this commit as well.
diff --git a/buildAndroid/jni/Android.mk b/buildAndroid/jni/Android.mk
index 334c0f7..6015b07 100644
--- a/buildAndroid/jni/Android.mk
+++ b/buildAndroid/jni/Android.mk
@@ -31,6 +31,7 @@
 LOCAL_MODULE := VkLayer_core_validation
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/core_validation.cpp
 LOCAL_SRC_FILES += $(SRC_DIR)/layers/vk_layer_table.cpp
+LOCAL_SRC_FILES += $(MY_PATH)/../generated/vk_safe_struct.cpp
 LOCAL_C_INCLUDES += $(SRC_DIR)/include \
                     $(MY_PATH)/../generated \
                     $(SRC_DIR)/loader \
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index d23cbad..82e1495 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -145,7 +145,7 @@
 else()
     install(TARGETS layer_utils DESTINATION ${PROJECT_BINARY_DIR}/install_staging)
 endif()
-add_vk_layer(core_validation core_validation.cpp vk_layer_table.cpp)
+add_vk_layer(core_validation core_validation.cpp vk_layer_table.cpp vk_safe_struct.cpp)
 add_vk_layer(device_limits device_limits.cpp vk_layer_table.cpp vk_layer_utils.cpp)
 add_vk_layer(image image.cpp vk_layer_table.cpp)
 add_vk_layer(swapchain swapchain.cpp vk_layer_table.cpp)
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 7cc7979..f8ed342 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -2136,12 +2136,13 @@
                              "Dynamic viewport state not set for this command buffer");
     result |= validate_status(dev_data, pCB, CBSTATUS_SCISSOR_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT, DRAWSTATE_SCISSOR_NOT_BOUND,
                               "Dynamic scissor state not set for this command buffer");
-    if ((pPipe->iaStateCI.topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
-        (pPipe->iaStateCI.topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP)) {
+    if (pPipe->graphicsPipelineCI.pInputAssemblyState &&
+        ((pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) ||
+         (pPipe->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP))) {
         result |= validate_status(dev_data, pCB, CBSTATUS_LINE_WIDTH_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                   DRAWSTATE_LINE_WIDTH_NOT_BOUND, "Dynamic line width state not set for this command buffer");
     }
-    if (pPipe->rsStateCI.depthBiasEnable) {
+    if (pPipe->graphicsPipelineCI.pRasterizationState && pPipe->graphicsPipelineCI.pRasterizationState->depthBiasEnable) {
         result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BIAS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                   DRAWSTATE_DEPTH_BIAS_NOT_BOUND, "Dynamic depth bias state not set for this command buffer");
     }
@@ -2149,11 +2150,11 @@
         result |= validate_status(dev_data, pCB, CBSTATUS_BLEND_CONSTANTS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                   DRAWSTATE_BLEND_NOT_BOUND, "Dynamic blend constants state not set for this command buffer");
     }
-    if (pPipe->dsStateCI.depthBoundsTestEnable) {
+    if (pPipe->graphicsPipelineCI.pDepthStencilState && pPipe->graphicsPipelineCI.pDepthStencilState->depthBoundsTestEnable) {
         result |= validate_status(dev_data, pCB, CBSTATUS_DEPTH_BOUNDS_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                   DRAWSTATE_DEPTH_BOUNDS_NOT_BOUND, "Dynamic depth bounds state not set for this command buffer");
     }
-    if (pPipe->dsStateCI.stencilTestEnable) {
+    if (pPipe->graphicsPipelineCI.pDepthStencilState && pPipe->graphicsPipelineCI.pDepthStencilState->stencilTestEnable) {
         result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_READ_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                   DRAWSTATE_STENCIL_NOT_BOUND, "Dynamic stencil read mask state not set for this command buffer");
         result |= validate_status(dev_data, pCB, CBSTATUS_STENCIL_WRITE_MASK_SET, VK_DEBUG_REPORT_ERROR_BIT_EXT,
@@ -2679,7 +2680,7 @@
 // Validate that the shaders used by the given pipeline and store the active_slots
 //  that are actually used by the pipeline into pPipeline->active_slots
 static VkBool32 validate_and_capture_pipeline_shader_state(layer_data *my_data, PIPELINE_NODE *pPipeline) {
-    VkGraphicsPipelineCreateInfo const *pCreateInfo = &pPipeline->graphicsPipelineCI;
+    auto pCreateInfo = reinterpret_cast<VkGraphicsPipelineCreateInfo const *>(&pPipeline->graphicsPipelineCI);
     int vertex_stage = get_shader_stage_id(VK_SHADER_STAGE_VERTEX_BIT);
     int fragment_stage = get_shader_stage_id(VK_SHADER_STAGE_FRAGMENT_BIT);
 
@@ -2693,7 +2694,8 @@
     auto pipelineLayout = pCreateInfo->layout != VK_NULL_HANDLE ? &my_data->pipelineLayoutMap[pCreateInfo->layout] : nullptr;
 
     for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
-        VkPipelineShaderStageCreateInfo const *pStage = &pCreateInfo->pStages[i];
+        VkPipelineShaderStageCreateInfo const *pStage =
+            reinterpret_cast<VkPipelineShaderStageCreateInfo const *>(&pCreateInfo->pStages[i]);
         auto stage_id = get_shader_stage_id(pStage->stage);
         pass &= validate_pipeline_shader_stage(my_data, pStage, pPipeline, pipelineLayout,
                                                &shaders[stage_id], &entrypoints[stage_id]);
@@ -2739,7 +2741,7 @@
 }
 
 static VkBool32 validate_compute_pipeline(layer_data *my_data, PIPELINE_NODE *pPipeline) {
-    VkComputePipelineCreateInfo const *pCreateInfo = &pPipeline->computePipelineCI;
+    auto pCreateInfo = reinterpret_cast<VkComputePipelineCreateInfo const *>(&pPipeline->computePipelineCI);
 
     auto pipelineLayout = pCreateInfo->layout != VK_NULL_HANDLE ? &my_data->pipelineLayoutMap[pCreateInfo->layout] : nullptr;
 
@@ -3139,26 +3141,35 @@
     // VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive topology is only valid for tessellation pipelines.
     // Mismatching primitive topology and tessellation fails graphics pipeline creation.
     if (pPipeline->active_shaders & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
-        (pPipeline->iaStateCI.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
+        (!pPipeline->graphicsPipelineCI.pInputAssemblyState ||
+         pPipeline->graphicsPipelineCI.pInputAssemblyState->topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)) {
         skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
                             DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
                                                                            "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST must be set as IA "
                                                                            "topology for tessellation pipelines");
     }
-    if (pPipeline->iaStateCI.topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
+    if (pPipeline->graphicsPipelineCI.pInputAssemblyState &&
+        pPipeline->graphicsPipelineCI.pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
         if (~pPipeline->active_shaders & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
                                                                                "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
                                                                                "topology is only valid for tessellation pipelines");
         }
-        if (!pPipeline->tessStateCI.patchControlPoints || (pPipeline->tessStateCI.patchControlPoints > 32)) {
+        if (!pPipeline->graphicsPipelineCI.pTessellationState) {
+            skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
+                                DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS",
+                                "Invalid Pipeline CreateInfo State: "
+                                "pTessellationState is NULL when VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
+                                "topology used. pTessellationState must not be NULL in this case.");
+        } else if (!pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints ||
+                   (pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints > 32)) {
             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
                                 DRAWSTATE_INVALID_PIPELINE_CREATE_STATE, "DS", "Invalid Pipeline CreateInfo State: "
                                                                                "VK_PRIMITIVE_TOPOLOGY_PATCH_LIST primitive "
                                                                                "topology used with patchControlPoints value %u."
                                                                                " patchControlPoints should be >0 and <=32.",
-                                pPipeline->tessStateCI.patchControlPoints);
+                                pPipeline->graphicsPipelineCI.pTessellationState->patchControlPoints);
         }
     }
     // Viewport state must be included if rasterization is enabled.
@@ -3176,7 +3187,8 @@
             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__,
                                 DRAWSTATE_VIEWPORT_SCISSOR_MISMATCH, "DS",
                                 "Gfx Pipeline viewport count (%u) must match scissor count (%u).",
-                                pPipeline->vpStateCI.viewportCount, pPipeline->vpStateCI.scissorCount);
+                                pPipeline->graphicsPipelineCI.pViewportState->viewportCount,
+                                pPipeline->graphicsPipelineCI.pViewportState->scissorCount);
         } else {
             // If viewport or scissor are not dynamic, then verify that data is appropriate for count
             VkBool32 dynViewport = isDynamic(pPipeline, VK_DYNAMIC_STATE_VIEWPORT);
@@ -3208,130 +3220,12 @@
     return skipCall;
 }
 
-// Init the pipeline mapping info based on pipeline create info LL tree
-//  Threading note : Calls to this function should wrapped in mutex
-// TODO : this should really just be in the constructor for PIPELINE_NODE
-static PIPELINE_NODE *initGraphicsPipeline(layer_data *dev_data, const VkGraphicsPipelineCreateInfo *pCreateInfo) {
-    PIPELINE_NODE *pPipeline = new PIPELINE_NODE;
-
-    // First init create info
-    memcpy(&pPipeline->graphicsPipelineCI, pCreateInfo, sizeof(VkGraphicsPipelineCreateInfo));
-
-    size_t bufferSize = 0;
-    const VkPipelineVertexInputStateCreateInfo *pVICI = NULL;
-    const VkPipelineColorBlendStateCreateInfo *pCBCI = NULL;
-
-    for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
-        const VkPipelineShaderStageCreateInfo *pPSSCI = &pCreateInfo->pStages[i];
-
-        switch (pPSSCI->stage) {
-        case VK_SHADER_STAGE_VERTEX_BIT:
-            memcpy(&pPipeline->vsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
-            pPipeline->active_shaders |= VK_SHADER_STAGE_VERTEX_BIT;
-            break;
-        case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
-            memcpy(&pPipeline->tcsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
-            pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
-            break;
-        case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
-            memcpy(&pPipeline->tesCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
-            pPipeline->active_shaders |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
-            break;
-        case VK_SHADER_STAGE_GEOMETRY_BIT:
-            memcpy(&pPipeline->gsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
-            pPipeline->active_shaders |= VK_SHADER_STAGE_GEOMETRY_BIT;
-            break;
-        case VK_SHADER_STAGE_FRAGMENT_BIT:
-            memcpy(&pPipeline->fsCI, pPSSCI, sizeof(VkPipelineShaderStageCreateInfo));
-            pPipeline->active_shaders |= VK_SHADER_STAGE_FRAGMENT_BIT;
-            break;
-        case VK_SHADER_STAGE_COMPUTE_BIT:
-            // TODO : Flag error, CS is specified through VkComputePipelineCreateInfo
-            pPipeline->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT;
-            break;
-        default:
-            // TODO : Flag error
-            break;
-        }
-    }
-    // Copy over GraphicsPipelineCreateInfo structure embedded pointers
-    if (pCreateInfo->stageCount != 0) {
-        pPipeline->graphicsPipelineCI.pStages = new VkPipelineShaderStageCreateInfo[pCreateInfo->stageCount];
-        bufferSize = pCreateInfo->stageCount * sizeof(VkPipelineShaderStageCreateInfo);
-        memcpy((void *)pPipeline->graphicsPipelineCI.pStages, pCreateInfo->pStages, bufferSize);
-    }
-    if (pCreateInfo->pVertexInputState != NULL) {
-        pPipeline->vertexInputCI = *pCreateInfo->pVertexInputState;
-        // Copy embedded ptrs
-        pVICI = pCreateInfo->pVertexInputState;
-        if (pVICI->vertexBindingDescriptionCount) {
-            pPipeline->vertexBindingDescriptions = std::vector<VkVertexInputBindingDescription>(
-                pVICI->pVertexBindingDescriptions, pVICI->pVertexBindingDescriptions + pVICI->vertexBindingDescriptionCount);
-        }
-        if (pVICI->vertexAttributeDescriptionCount) {
-            pPipeline->vertexAttributeDescriptions = std::vector<VkVertexInputAttributeDescription>(
-                pVICI->pVertexAttributeDescriptions, pVICI->pVertexAttributeDescriptions + pVICI->vertexAttributeDescriptionCount);
-        }
-        pPipeline->graphicsPipelineCI.pVertexInputState = &pPipeline->vertexInputCI;
-    }
-    if (pCreateInfo->pInputAssemblyState != NULL) {
-        pPipeline->iaStateCI = *pCreateInfo->pInputAssemblyState;
-        pPipeline->graphicsPipelineCI.pInputAssemblyState = &pPipeline->iaStateCI;
-    }
-    if (pCreateInfo->pTessellationState != NULL) {
-        pPipeline->tessStateCI = *pCreateInfo->pTessellationState;
-        pPipeline->graphicsPipelineCI.pTessellationState = &pPipeline->tessStateCI;
-    }
-    if (pCreateInfo->pViewportState != NULL) {
-        pPipeline->vpStateCI = *pCreateInfo->pViewportState;
-        pPipeline->graphicsPipelineCI.pViewportState = &pPipeline->vpStateCI;
-    }
-    if (pCreateInfo->pRasterizationState != NULL) {
-        pPipeline->rsStateCI = *pCreateInfo->pRasterizationState;
-        pPipeline->graphicsPipelineCI.pRasterizationState = &pPipeline->rsStateCI;
-    }
-    if (pCreateInfo->pMultisampleState != NULL) {
-        pPipeline->msStateCI = *pCreateInfo->pMultisampleState;
-        pPipeline->graphicsPipelineCI.pMultisampleState = &pPipeline->msStateCI;
-    }
-    if (pCreateInfo->pDepthStencilState != NULL) {
-        pPipeline->dsStateCI = *pCreateInfo->pDepthStencilState;
-        pPipeline->graphicsPipelineCI.pDepthStencilState = &pPipeline->dsStateCI;
-    }
-    if (pCreateInfo->pColorBlendState != NULL) {
-        pPipeline->cbStateCI = *pCreateInfo->pColorBlendState;
-        // Copy embedded ptrs
-        pCBCI = pCreateInfo->pColorBlendState;
-        if (pCBCI->attachmentCount) {
-            pPipeline->attachments = std::vector<VkPipelineColorBlendAttachmentState>(
-                pCBCI->pAttachments, pCBCI->pAttachments + pCBCI->attachmentCount);
-        }
-        pPipeline->graphicsPipelineCI.pColorBlendState = &pPipeline->cbStateCI;
-    }
-    if (pCreateInfo->pDynamicState != NULL) {
-        pPipeline->dynStateCI = *pCreateInfo->pDynamicState;
-        if (pPipeline->dynStateCI.dynamicStateCount) {
-            pPipeline->dynStateCI.pDynamicStates = new VkDynamicState[pPipeline->dynStateCI.dynamicStateCount];
-            bufferSize = pPipeline->dynStateCI.dynamicStateCount * sizeof(VkDynamicState);
-            memcpy((void *)pPipeline->dynStateCI.pDynamicStates, pCreateInfo->pDynamicState->pDynamicStates, bufferSize);
-        }
-        pPipeline->graphicsPipelineCI.pDynamicState = &pPipeline->dynStateCI;
-    }
-    return pPipeline;
-}
-
 // Free the Pipeline nodes
 static void deletePipelines(layer_data *my_data) {
     if (my_data->pipelineMap.size() <= 0)
         return;
-    for (auto ii = my_data->pipelineMap.begin(); ii != my_data->pipelineMap.end(); ++ii) {
-        if ((*ii).second->graphicsPipelineCI.stageCount != 0) {
-            delete[](*ii).second->graphicsPipelineCI.pStages;
-        }
-        if ((*ii).second->dynStateCI.dynamicStateCount != 0) {
-            delete[](*ii).second->dynStateCI.pDynamicStates;
-        }
-        delete (*ii).second;
+    for (auto &pipe_map_pair : my_data->pipelineMap) {
+        delete pipe_map_pair.second;
     }
     my_data->pipelineMap.clear();
 }
@@ -3339,8 +3233,9 @@
 // For given pipeline, return number of MSAA samples, or one if MSAA disabled
 static VkSampleCountFlagBits getNumSamples(layer_data *my_data, const VkPipeline pipeline) {
     PIPELINE_NODE *pPipe = my_data->pipelineMap[pipeline];
-    if (VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pPipe->msStateCI.sType) {
-        return pPipe->msStateCI.rasterizationSamples;
+    if (pPipe->graphicsPipelineCI.pMultisampleState &&
+        (VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO == pPipe->graphicsPipelineCI.pMultisampleState->sType)) {
+        return pPipe->graphicsPipelineCI.pMultisampleState->rasterizationSamples;
     }
     return VK_SAMPLE_COUNT_1_BIT;
 }
@@ -4543,15 +4438,16 @@
 // Set PSO-related status bits for CB, including dynamic state set via PSO
 static void set_cb_pso_status(GLOBAL_CB_NODE *pCB, const PIPELINE_NODE *pPipe) {
     // Account for any dynamic state not set via this PSO
-    if (!pPipe->dynStateCI.dynamicStateCount) { // All state is static
+    if (!pPipe->graphicsPipelineCI.pDynamicState ||
+        !pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount) { // All state is static
         pCB->status = CBSTATUS_ALL;
     } else {
         // First consider all state on
         // Then unset any state that's noted as dynamic in PSO
         // Finally OR that into CB statemask
         CBStatusFlags psoDynStateMask = CBSTATUS_ALL;
-        for (uint32_t i = 0; i < pPipe->dynStateCI.dynamicStateCount; i++) {
-            switch (pPipe->dynStateCI.pDynamicStates[i]) {
+        for (uint32_t i = 0; i < pPipe->graphicsPipelineCI.pDynamicState->dynamicStateCount; i++) {
+            switch (pPipe->graphicsPipelineCI.pDynamicState->pDynamicStates[i]) {
             case VK_DYNAMIC_STATE_VIEWPORT:
                 psoDynStateMask &= ~CBSTATUS_VIEWPORT_SET;
                 break;
@@ -4599,7 +4495,9 @@
         } else {
             skipCall |= log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0,
                                 __LINE__, DRAWSTATE_NONE, "DS", "%s",
-                                vk_print_vkgraphicspipelinecreateinfo(&pPipeTrav->graphicsPipelineCI, "{DS}").c_str());
+                                vk_print_vkgraphicspipelinecreateinfo(
+                                    reinterpret_cast<const VkGraphicsPipelineCreateInfo *>(&pPipeTrav->graphicsPipelineCI), "{DS}")
+                                    .c_str());
         }
     }
     return skipCall;
@@ -6604,7 +6502,8 @@
     loader_platform_thread_lock_mutex(&globalLock);
 
     for (i = 0; i < count; i++) {
-        pPipeNode[i] = initGraphicsPipeline(dev_data, &pCreateInfos[i]);
+        pPipeNode[i] = new PIPELINE_NODE;
+        pPipeNode[i]->initGraphicsPipeline(&pCreateInfos[i]);
         skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode, i);
     }
 
@@ -6646,7 +6545,8 @@
 
         // Create and initialize internal tracking data structure
         pPipeNode[i] = new PIPELINE_NODE;
-        memcpy(&pPipeNode[i]->computePipelineCI, (const void *)&pCreateInfos[i], sizeof(VkComputePipelineCreateInfo));
+        pPipeNode[i]->initComputePipeline(&pCreateInfos[i]);
+        // memcpy(&pPipeNode[i]->computePipelineCI, (const void *)&pCreateInfos[i], sizeof(VkComputePipelineCreateInfo));
 
         // TODO: Add Compute Pipeline Verification
         // skipCall |= verifyPipelineCreateState(dev_data, device, pPipeNode[i]);
diff --git a/layers/core_validation.h b/layers/core_validation.h
index 8830097..866eeaf 100644
--- a/layers/core_validation.h
+++ b/layers/core_validation.h
@@ -53,6 +53,7 @@
 #define MTMERGE 1
 
 #pragma once
+#include "vk_safe_struct.h"
 #include "vulkan/vk_layer.h"
 #include <atomic>
 #include <vector>
@@ -437,25 +438,11 @@
     const void *pNext;
 } GENERIC_HEADER;
 
-typedef struct _PIPELINE_NODE {
+class PIPELINE_NODE {
+  public:
     VkPipeline pipeline;
-    VkGraphicsPipelineCreateInfo graphicsPipelineCI;
-    VkPipelineVertexInputStateCreateInfo vertexInputCI;
-    VkPipelineInputAssemblyStateCreateInfo iaStateCI;
-    VkPipelineTessellationStateCreateInfo tessStateCI;
-    VkPipelineViewportStateCreateInfo vpStateCI;
-    VkPipelineRasterizationStateCreateInfo rsStateCI;
-    VkPipelineMultisampleStateCreateInfo msStateCI;
-    VkPipelineColorBlendStateCreateInfo cbStateCI;
-    VkPipelineDepthStencilStateCreateInfo dsStateCI;
-    VkPipelineDynamicStateCreateInfo dynStateCI;
-    VkPipelineShaderStageCreateInfo vsCI;
-    VkPipelineShaderStageCreateInfo tcsCI;
-    VkPipelineShaderStageCreateInfo tesCI;
-    VkPipelineShaderStageCreateInfo gsCI;
-    VkPipelineShaderStageCreateInfo fsCI;
-    // Compute shader is include in VkComputePipelineCreateInfo
-    VkComputePipelineCreateInfo computePipelineCI;
+    safe_VkGraphicsPipelineCreateInfo graphicsPipelineCI;
+    safe_VkComputePipelineCreateInfo computePipelineCI;
     // Flag of which shader stages are active for this pipeline
     uint32_t active_shaders;
     // Capture which slots (set#->bindings) are actually used by the shaders of this pipeline
@@ -466,11 +453,78 @@
     std::vector<VkPipelineColorBlendAttachmentState> attachments;
     bool blendConstantsEnabled; // Blend constants enabled for any attachments
     // Default constructor
-    _PIPELINE_NODE()
-        : pipeline{}, graphicsPipelineCI{}, vertexInputCI{}, iaStateCI{}, tessStateCI{}, vpStateCI{}, rsStateCI{}, msStateCI{},
-          cbStateCI{}, dsStateCI{}, dynStateCI{}, vsCI{}, tcsCI{}, tesCI{}, gsCI{}, fsCI{}, computePipelineCI{}, active_shaders(0),
-          active_slots(), vertexBindingDescriptions(), vertexAttributeDescriptions(), attachments(), blendConstantsEnabled(false) {}
-} PIPELINE_NODE;
+    PIPELINE_NODE()
+        : pipeline{}, graphicsPipelineCI{}, computePipelineCI{}, active_shaders(0), active_slots(), vertexBindingDescriptions(),
+          vertexAttributeDescriptions(), attachments(), blendConstantsEnabled(false) {}
+
+    void initGraphicsPipeline(const VkGraphicsPipelineCreateInfo *pCreateInfo) {
+        graphicsPipelineCI.initialize(pCreateInfo);
+        // Make sure compute pipeline is null
+        VkComputePipelineCreateInfo emptyComputeCI = {};
+        computePipelineCI.initialize(&emptyComputeCI);
+        for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
+            const VkPipelineShaderStageCreateInfo *pPSSCI = &pCreateInfo->pStages[i];
+
+            switch (pPSSCI->stage) {
+            case VK_SHADER_STAGE_VERTEX_BIT:
+                this->active_shaders |= VK_SHADER_STAGE_VERTEX_BIT;
+                break;
+            case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
+                this->active_shaders |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+                break;
+            case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
+                this->active_shaders |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+                break;
+            case VK_SHADER_STAGE_GEOMETRY_BIT:
+                this->active_shaders |= VK_SHADER_STAGE_GEOMETRY_BIT;
+                break;
+            case VK_SHADER_STAGE_FRAGMENT_BIT:
+                this->active_shaders |= VK_SHADER_STAGE_FRAGMENT_BIT;
+                break;
+            case VK_SHADER_STAGE_COMPUTE_BIT:
+                // TODO : Flag error, CS is specified through VkComputePipelineCreateInfo
+                this->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT;
+                break;
+            default:
+                // TODO : Flag error
+                break;
+            }
+        }
+        if (pCreateInfo->pVertexInputState) {
+            const VkPipelineVertexInputStateCreateInfo *pVICI = pCreateInfo->pVertexInputState;
+            if (pVICI->vertexBindingDescriptionCount) {
+                this->vertexBindingDescriptions = std::vector<VkVertexInputBindingDescription>(
+                    pVICI->pVertexBindingDescriptions, pVICI->pVertexBindingDescriptions + pVICI->vertexBindingDescriptionCount);
+            }
+            if (pVICI->vertexAttributeDescriptionCount) {
+                this->vertexAttributeDescriptions = std::vector<VkVertexInputAttributeDescription>(
+                    pVICI->pVertexAttributeDescriptions,
+                    pVICI->pVertexAttributeDescriptions + pVICI->vertexAttributeDescriptionCount);
+            }
+        }
+        if (pCreateInfo->pColorBlendState) {
+            const VkPipelineColorBlendStateCreateInfo *pCBCI = pCreateInfo->pColorBlendState;
+            if (pCBCI->attachmentCount) {
+                this->attachments = std::vector<VkPipelineColorBlendAttachmentState>(pCBCI->pAttachments,
+                                                                                     pCBCI->pAttachments + pCBCI->attachmentCount);
+            }
+        }
+    }
+    void initComputePipeline(const VkComputePipelineCreateInfo *pCreateInfo) {
+        computePipelineCI.initialize(pCreateInfo);
+        // Make sure gfx pipeline is null
+        VkGraphicsPipelineCreateInfo emptyGraphicsCI = {};
+        graphicsPipelineCI.initialize(&emptyGraphicsCI);
+        switch (computePipelineCI.stage.stage) {
+        case VK_SHADER_STAGE_COMPUTE_BIT:
+            this->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT;
+            break;
+        default:
+            // TODO : Flag error
+            break;
+        }
+    }
+};
 
 class BASE_NODE {
   public:
diff --git a/vk_helper.py b/vk_helper.py
index 88f1fa2..a976f24 100755
--- a/vk_helper.py
+++ b/vk_helper.py
@@ -1637,7 +1637,7 @@
     def _generateSafeStructSourceHeader(self):
         header = []
         header.append("//#includes, #defines, globals and such...\n")
-        header.append('#include "vk_safe_struct.h"')
+        header.append('#include "vk_safe_struct.h"\n#include <string.h>\n\n')
         return "".join(header)
 
     def _generateSafeStructSource(self):
@@ -1650,7 +1650,7 @@
             ss_name = self._getSafeStructName(s)
             init_list = '' # list of members in struct constructor initializer
             init_func_txt = '' # Txt for initialize() function that takes struct ptr and inits members
-            construct_txt = ''
+            construct_txt = '' # Body of constuctor as well as body of initialize() func following init_func_txt
             destruct_txt = ''
             # VkWriteDescriptorSet is special case because pointers may be non-null but ignored
             # TODO : This is ugly, figure out better way to do this
@@ -1697,8 +1697,29 @@
                 if is_type(m_type, 'struct') and self._hasSafeStruct(m_type):
                     m_type = self._getSafeStructName(m_type)
                 if self.struct_dict[s][m]['ptr'] and 'safe_' not in m_type and not self._typeHasObject(m_type, vulkan.object_non_dispatch_list):# in ['char', 'float', 'uint32_t', 'void', 'VkPhysicalDeviceFeatures']) or 'pp' == self.struct_dict[s][m]['name'][0:1]:
-                    init_list += '\n\t%s(pInStruct->%s),' % (m_name, m_name)
-                    init_func_txt += '    %s = pInStruct->%s;\n' % (m_name, m_name)
+                    # Ptr types w/o a safe_struct, for non-null case need to allocate new ptr and copy data in
+                    if 'KHR' in ss_name or m_type in ['void', 'char']:
+                        # For these exceptions just copy initial value over for now
+                        init_list += '\n\t%s(pInStruct->%s),' % (m_name, m_name)
+                        init_func_txt += '    %s = pInStruct->%s;\n' % (m_name, m_name)
+                    else:
+                        init_list += '\n\t%s(nullptr),' % (m_name)
+                        init_func_txt += '    %s = nullptr;\n' % (m_name)
+                        if 'pNext' != m_name and 'void' not in m_type:
+                            if not self.struct_dict[s][m]['array']:
+                                construct_txt += '    if (pInStruct->%s) {\n' % (m_name)
+                                construct_txt += '        %s = new %s(*pInStruct->%s);\n' % (m_name, m_type, m_name)
+                                construct_txt += '    }\n'
+                                destruct_txt += '    if (%s)\n' % (m_name)
+                                destruct_txt += '        delete %s;\n' % (m_name)
+                            else: # new array and then init each element
+                                construct_txt += '    if (pInStruct->%s) {\n' % (m_name)
+                                construct_txt += '        %s = new %s[pInStruct->%s];\n' % (m_name, m_type, self.struct_dict[s][m]['array_size'])
+                                #construct_txt += '        std::copy (pInStruct->%s, pInStruct->%s+pInStruct->%s, %s);\n' % (m_name, m_name, self.struct_dict[s][m]['array_size'], m_name)
+                                construct_txt += '        memcpy ((void *)%s, (void *)pInStruct->%s, sizeof(%s)*pInStruct->%s);\n' % (m_name, m_name, m_type, self.struct_dict[s][m]['array_size'])
+                                construct_txt += '    }\n'
+                                destruct_txt += '    if (%s)\n' % (m_name)
+                                destruct_txt += '        delete[] %s;\n' % (m_name)
                 elif self.struct_dict[s][m]['array']:
                     # Init array ptr to NULL
                     init_list += '\n\t%s(NULL),' % (m_name)