loader: Support layers that don't have an extension entrypoint

Change all layers and loader interface to init dispatch tables on
GPA("GetXXXProcAddr").  After that initialization rest of dispatch
tables are inited via unwrapped object using the GPA in the dispatch
table.  This also allows App generated GPA calls that the loader can't resolve
to function correctly.
diff --git a/layers/basic.cpp b/layers/basic.cpp
index 0742cb2..1ba3188 100644
--- a/layers/basic.cpp
+++ b/layers/basic.cpp
@@ -58,7 +58,7 @@
         return it->second;
     }
 
-    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instancew->pGPA, (VkInstance) instancew->nextObject);
+    layer_init_instance_dispatch_table(pTable, instancew);
 
     return pTable;
 }
@@ -79,7 +79,7 @@
         return it->second;
     }
 
-    layer_initialize_dispatch_table(pTable, (PFN_vkGetDeviceProcAddr) devw->pGPA, (VkDevice) devw->nextObject);
+    layer_initialize_dispatch_table(pTable, devw);
 
     return pTable;
 }
@@ -207,21 +207,25 @@
     if (device == NULL)
         return NULL;
 
-    initLayerTable((const VkBaseLayerObject *) device);
-
-    if (!strcmp("vkGetDeviceProcAddr", pName))
+    /* loader uses this to force layer initialization; device object is wrapped */
+    if (!strcmp("vkGetDeviceProcAddr", pName)) {
+        initLayerTable((const VkBaseLayerObject *) device);
         return (void *) vkGetDeviceProcAddr;
+    }
+
     if (!strcmp("vkGetFormatInfo", pName))
         return (void *) vkGetFormatInfo;
     if (!strcmp("vkDestroyDevice", pName))
         return (void *) vkDestroyDevice;
     if (!strcmp("vkLayerExtension1", pName))
         return (void *) vkLayerExtension1;
-    else {
-        VkBaseLayerObject* devw = (VkBaseLayerObject *) device;
-        if (devw->pGPA == NULL)
+    else
+    {
+        VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device;
+        VkLayerDispatchTable* pTable = tableMap[*ppDisp];
+        if (pTable->GetDeviceProcAddr == NULL)
             return NULL;
-        return devw->pGPA((VkObject) devw->nextObject, pName);
+        return pTable->GetDeviceProcAddr(device, pName);
     }
 }
 
@@ -230,10 +234,12 @@
     if (instance == NULL)
         return NULL;
 
-    initLayerInstanceTable((const VkBaseLayerObject *) instance);
-
-    if (!strcmp("vkGetInstanceProcAddr", pName))
+    /* loader uses this to force layer initialization; instance object is wrapped */
+    if (!strcmp("vkGetInstanceProcAddr", pName)) {
+        initLayerInstanceTable((const VkBaseLayerObject *) instance);
         return (void *) vkGetInstanceProcAddr;
+    }
+
     if (!strcmp("vkDestroyInstance", pName))
         return (void *) vkDestroyInstance;
     if (!strcmp("vkEnumeratePhysicalDevices", pName))
@@ -242,10 +248,13 @@
         return (void*) vkGetGlobalExtensionInfo;
     if (!strcmp("vkCreateDevice", pName))
         return (void *) vkCreateDevice;
-    else {
-        VkBaseLayerObject* instancew = (VkBaseLayerObject *) instance;
-        if (instancew->pGPA == NULL)
+    else
+    {
+        VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) instance;
+        VkLayerInstanceDispatchTable* pTable = tableInstanceMap[*ppDisp];
+        if (pTable->GetInstanceProcAddr == NULL)
             return NULL;
-        return instancew->pGPA((VkObject) instancew->nextObject, pName);
+        return pTable->GetInstanceProcAddr(instance, pName);
     }
+
 }
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index 54f6813..72b87f3 100644
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -1462,9 +1462,9 @@
         return it->second;
     }
 
-    VkDevice device = (VkDevice) devw->nextObject;
-    layer_initialize_dispatch_table(pTable, (PFN_vkGetDeviceProcAddr) devw->pGPA, device);
+    layer_initialize_dispatch_table(pTable, devw);
 
+    VkDevice device = (VkDevice) devw->baseObject;
     pDebugMarkerTable->CmdDbgMarkerBegin = (PFN_vkCmdDbgMarkerBegin) devw->pGPA(device, "vkCmdDbgMarkerBegin");
     pDebugMarkerTable->CmdDbgMarkerEnd = (PFN_vkCmdDbgMarkerEnd) devw->pGPA(device, "vkCmdDbgMarkerEnd");
     pDebugMarkerTable->DbgSetObjectTag = (PFN_vkDbgSetObjectTag) devw->pGPA(device, "vkDbgSetObjectTag");
@@ -1490,7 +1490,7 @@
         return it->second;
     }
 
-    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);
+    layer_init_instance_dispatch_table(pTable, instw);
 
     return pTable;
 }
@@ -2898,16 +2898,16 @@
 
 VK_LAYER_EXPORT void* VKAPI vkGetDeviceProcAddr(VkDevice dev, const char* funcName)
 {
-    VkBaseLayerObject* devw = (VkBaseLayerObject *) dev;
-
     if (dev == NULL)
         return NULL;
 
     loader_platform_thread_once(&g_initOnce, initDrawState);
-    initDeviceTable((const VkBaseLayerObject *) dev);
 
-    if (!strcmp(funcName, "vkGetDeviceProcAddr"))
+    /* loader uses this to force layer initialization; device object is wrapped */
+    if (!strcmp(funcName, "vkGetDeviceProcAddr")) {
+        initDeviceTable((const VkBaseLayerObject *) dev);
         return (void *) vkGetDeviceProcAddr;
+    }
     if (!strcmp(funcName, "vkDestroyDevice"))
         return (void*) vkDestroyDevice;
     if (!strcmp(funcName, "vkQueueSubmit"))
@@ -3036,31 +3036,39 @@
         return (void*) drawStateDumpCommandBufferDotFile;
     if (!strcmp("drawStateDumpPngFile", funcName))
         return (void*) drawStateDumpPngFile;
-    else {
-        if (devw->pGPA == NULL)
+    else
+    {
+        VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) dev;
+        VkLayerDispatchTable* pTable = tableMap[*ppDisp];
+        if (pTable->GetDeviceProcAddr == NULL)
             return NULL;
-        return devw->pGPA((VkObject)devw->nextObject, funcName);
+        return pTable->GetDeviceProcAddr(dev, funcName);
     }
 }
 
 VK_LAYER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
 {
-    VkBaseLayerObject* instw = (VkBaseLayerObject *) instance;
     if (instance == NULL)
         return NULL;
 
     loader_platform_thread_once(&g_initOnce, initDrawState);
-    initInstanceTable((const VkBaseLayerObject *) instance);
 
-    if (!strcmp(funcName, "vkGetInstanceProcAddr"))
+    /* loader uses this to force layer initialization; instance object is wrapped */
+    if (!strcmp(funcName, "vkGetInstanceProcAddr")) {
+        initInstanceTable((const VkBaseLayerObject *) instance);
         return (void *) vkGetInstanceProcAddr;
+    }
     if (!strcmp(funcName, "vkDestroyInstance"))
         return (void *) vkDestroyInstance;
     if (!strcmp(funcName, "vkCreateDevice"))
         return (void*) vkCreateDevice;
-    else {
-        if (instw->pGPA == NULL)
+    else
+    {
+        VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) instance;
+        VkLayerInstanceDispatchTable* pTable = tableInstanceMap[*ppDisp];
+        if (pTable->GetInstanceProcAddr == NULL)
             return NULL;
-        return instw->pGPA((VkObject) instw->nextObject, funcName);
+        return pTable->GetInstanceProcAddr(instance, funcName);
     }
+
 }
diff --git a/layers/mem_tracker.cpp b/layers/mem_tracker.cpp
index b77b742..3898a54 100644
--- a/layers/mem_tracker.cpp
+++ b/layers/mem_tracker.cpp
@@ -796,7 +796,7 @@
         return it->second;
     }
 
-    layer_initialize_dispatch_table(pTable, (PFN_vkGetDeviceProcAddr) devw->pGPA, (VkDevice) devw->nextObject);
+    layer_initialize_dispatch_table(pTable, devw);
 
     return pTable;
 }
@@ -818,7 +818,7 @@
         return it->second;
     }
 
-    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);
+    layer_init_instance_dispatch_table(pTable, instw);
 
     return pTable;
 }
@@ -2151,17 +2151,17 @@
     VkDevice         dev,
     const char       *funcName)
 {
-    VkBaseLayerObject* devw = (VkBaseLayerObject *) dev;
-
     if (dev == NULL) {
         return NULL;
     }
 
     loader_platform_thread_once(&g_initOnce, initMemTracker);
-    initDeviceTable((const VkBaseLayerObject *) dev);
 
-    if (!strcmp(funcName, "vkGetDeviceProcAddr"))
+    /* loader uses this to force layer initialization; device object is wrapped */
+    if (!strcmp(funcName, "vkGetDeviceProcAddr")) {
+        initDeviceTable((const VkBaseLayerObject *) dev);
         return (void *) vkGetDeviceProcAddr;
+    }
     if (!strcmp(funcName, "vkDestroyDevice"))
         return (void*) vkDestroyDevice;
     if (!strcmp(funcName, "vkQueueSubmit"))
@@ -2296,11 +2296,13 @@
         return (void*) vkDestroySwapChainWSI;
     if (!strcmp(funcName, "vkGetSwapChainInfoWSI"))
         return (void*) vkGetSwapChainInfoWSI;
-    else {
-        if (devw->pGPA == NULL) {
+    else
+    {
+        VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) dev;
+        VkLayerDispatchTable* pTable = tableMap[*ppDisp];
+        if (pTable->GetDeviceProcAddr == NULL)
             return NULL;
-        }
-        return devw->pGPA((VkObject)devw->nextObject, funcName);
+        return pTable->GetDeviceProcAddr(dev, funcName);
     }
 }
 
@@ -2308,25 +2310,28 @@
     VkInstance       instance,
     const char       *funcName)
 {
-    VkBaseLayerObject* instw = (VkBaseLayerObject *) instance;
-
     if (instance == NULL) {
         return NULL;
     }
 
     loader_platform_thread_once(&g_initOnce, initMemTracker);
-    initInstanceTable((const VkBaseLayerObject *) instance);
 
-    if (!strcmp(funcName, "vkGetInstanceProcAddr"))
+    /* loader uses this to force layer initialization; instance object is wrapped */
+    if (!strcmp(funcName, "vkGetInstanceProcAddr")) {
+        initInstanceTable((const VkBaseLayerObject *) instance);
         return (void *) vkGetInstanceProcAddr;
+    }
+
     if (!strcmp(funcName, "vkDestroyInstance"))
         return (void *) vkDestroyInstance;
     if (!strcmp(funcName, "vkCreateDevice"))
         return (void*) vkCreateDevice;
-    else {
-        if (instw->pGPA == NULL) {
+    else
+    {
+        VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) instance;
+        VkLayerInstanceDispatchTable* pTable = tableInstanceMap[*ppDisp];
+        if (pTable->GetInstanceProcAddr == NULL)
             return NULL;
-        }
-        return instw->pGPA((VkObject)instw->nextObject, funcName);
+        return pTable->GetInstanceProcAddr(instance, funcName);
     }
 }
diff --git a/layers/multi.cpp b/layers/multi.cpp
index 2cc9e0c..b0e8f21 100644
--- a/layers/multi.cpp
+++ b/layers/multi.cpp
@@ -149,22 +149,26 @@
     if (device == NULL)
         return NULL;
 
-    getLayer1Table(devw);
 
-    if (!strcmp("vkGetDeviceProcAddr", pName))
+
+    if (!strcmp("vkGetDeviceProcAddr", pName)) {
+        getLayer1Table(devw);
         return (void *) multi1GetDeviceProcAddr;
+    }
     if (!strcmp("vkDestroyDevice", pName))
         return (void *) multi1DestroyDevice;
     if (!strcmp("vkCreateSampler", pName))
         return (void *) multi1CreateSampler;
-    else if (!strcmp("vkCreateGraphicsPipeline", pName))
+    if (!strcmp("vkCreateGraphicsPipeline", pName))
         return (void *) multi1CreateGraphicsPipeline;
-    else if (!strcmp("vkStorePipeline", pName))
+    if (!strcmp("vkStorePipeline", pName))
         return (void *) multi1StorePipeline;
     else {
-        if (devw->pGPA == NULL)
+        VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device;
+        VkLayerDispatchTable* pTable = tableMap1[*ppDisp];
+        if (pTable->GetDeviceProcAddr == NULL)
             return NULL;
-        return devw->pGPA((VkObject) devw->nextObject, pName);
+        return pTable->GetDeviceProcAddr(device, pName);
     }
 }
 
@@ -175,18 +179,22 @@
     if (inst == NULL)
         return NULL;
 
-    getLayer1InstanceTable(instw);
 
-    if (!strcmp("vkGetInstanceProcAddr", pName))
+
+    if (!strcmp("vkGetInstanceProcAddr", pName)) {
+        getLayer1InstanceTable(instw);
         return (void *) multi1GetInstanceProcAddr;
+    }
     if (!strcmp("vkDestroyInstance", pName))
         return (void *) multi1DestroyInstance;
-    else if (!strcmp("GetGlobalExtensionInfo", pName))
+    if (!strcmp("GetGlobalExtensionInfo", pName))
         return (void*) vkGetGlobalExtensionInfo;
     else {
-        if (instw->pGPA == NULL)
+        VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) inst;
+        VkLayerInstanceDispatchTable* pTable = tableInstanceMap1[*ppDisp];
+        if (pTable->GetInstanceProcAddr == NULL)
             return NULL;
-        return instw->pGPA((VkObject) instw->nextObject, pName);
+        return pTable->GetInstanceProcAddr(inst, pName);
     }
 }
 
@@ -310,10 +318,10 @@
     if (device == NULL)
         return NULL;
 
-    getLayer2Table(devw);
-
-    if (!strcmp("vkGetDeviceProcAddr", pName))
+    if (!strcmp("vkGetDeviceProcAddr", pName)) {
+        getLayer2Table(devw);
         return (void *) multi2GetDeviceProcAddr;
+    }
     if (!strcmp("vkDestroyDevice", pName))
         return (void *) multi2DestroyDevice;
     if (!strcmp("vkCreateCommandBuffer", pName))
@@ -321,9 +329,11 @@
     else if (!strcmp("vkBeginCommandBuffer", pName))
         return (void *) multi2BeginCommandBuffer;
     else {
-        if (devw->pGPA == NULL)
+        VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device;
+        VkLayerDispatchTable* pTable = tableMap2[*ppDisp];
+        if (pTable->GetDeviceProcAddr == NULL)
             return NULL;
-        return devw->pGPA((VkObject) devw->nextObject, pName);
+        return pTable->GetDeviceProcAddr(device, pName);
     }
 }
 
@@ -334,10 +344,10 @@
     if (inst == NULL)
         return NULL;
 
-    getLayer2InstanceTable(instw);
-
-    if (!strcmp("vkGetInstanceProcAddr", pName))
+    if (!strcmp("vkGetInstanceProcAddr", pName)) {
+        getLayer2InstanceTable(instw);
         return (void *) multi2GetInstanceProcAddr;
+    }
     if (!strcmp("vkEnumeratePhysicalDevices", pName))
         return (void *) multi2EnumeratePhysicalDevices;
     if (!strcmp("vkDestroyInstance", pName))
@@ -347,27 +357,15 @@
     else if (!strcmp("GetGlobalExtensionInfo", pName))
         return (void*) vkGetGlobalExtensionInfo;
     else {
-        if (instw->pGPA == NULL)
+        VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) inst;
+        VkLayerInstanceDispatchTable* pTable = tableInstanceMap2[*ppDisp];
+        if (pTable->GetInstanceProcAddr == NULL)
             return NULL;
-        return instw->pGPA((VkObject) instw->nextObject, pName);
+        return pTable->GetInstanceProcAddr(inst, pName);
     }
 }
 
 /********************************* Common functions ********************************/
-VK_LAYER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalDevice gpu, size_t maxStringSize,
-                                                 size_t* pLayerCount, char* const* pOutLayers,
-                                                 void* pReserved)
-{
-    if (pLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL || pOutLayers[1] == NULL || pReserved == NULL)
-        return VK_ERROR_INVALID_POINTER;
-
-    if (*pLayerCount < 2)
-        return VK_ERROR_INITIALIZATION_FAILED;
-    *pLayerCount = 2;
-    strncpy((char *) pOutLayers[0], "multi1", maxStringSize);
-    strncpy((char *) pOutLayers[1], "multi2", maxStringSize);
-    return VK_SUCCESS;
-}
 
 struct extProps {
     uint32_t version;
@@ -479,7 +477,7 @@
     if (layerNum == 1 && layer2_first_activated == false)
         layer1_first_activated = true;
 
-    layer_initialize_dispatch_table(pTable, (PFN_vkGetDeviceProcAddr) devw->pGPA, (VkDevice) devw->nextObject);
+    layer_initialize_dispatch_table(pTable, devw);
 }
 
 static void initLayerInstanceTable(const VkBaseLayerObject *instw, VkLayerInstanceDispatchTable *pTable, const unsigned int layerNum)
@@ -489,5 +487,5 @@
     if (layerNum == 1 && layer2_first_activated == false)
         layer1_first_activated = true;
 
-    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);
+    layer_init_instance_dispatch_table(pTable, instw);
 }
diff --git a/layers/param_checker.cpp b/layers/param_checker.cpp
index 4068ac6..a27d54e 100644
--- a/layers/param_checker.cpp
+++ b/layers/param_checker.cpp
@@ -83,9 +83,9 @@
         return it->second;
     }
 
-    VkDevice device = (VkDevice) devw->nextObject;
-    layer_initialize_dispatch_table(pTable, (PFN_vkGetDeviceProcAddr) devw->pGPA, (VkDevice) device);
+    layer_initialize_dispatch_table(pTable, devw);
 
+    VkDevice device = (VkDevice) devw->baseObject;
     pDebugMarkerTable->CmdDbgMarkerBegin = (PFN_vkCmdDbgMarkerBegin) devw->pGPA(device, "vkCmdDbgMarkerBegin");
     pDebugMarkerTable->CmdDbgMarkerEnd   = (PFN_vkCmdDbgMarkerEnd) devw->pGPA(device, "vkCmdDbgMarkerEnd");
     pDebugMarkerTable->DbgSetObjectTag   = (PFN_vkDbgSetObjectTag) devw->pGPA(device, "vkDbgSetObjectTag");
@@ -111,7 +111,7 @@
         return it->second;
     }
 
-    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);
+    layer_init_instance_dispatch_table(pTable, instw);
 
     return pTable;
 }
@@ -1977,8 +1977,6 @@
         return NULL;
 
     name += 2;
-    if (!strcmp(name, "GetDeviceProcAddr"))
-        return (void*) vkGetDeviceProcAddr;
     if (!strcmp(name, "DestroyDevice"))
         return (void*) vkDestroyDevice;
     if (!strcmp(name, "GetDeviceQueue"))
@@ -2201,8 +2199,6 @@
         return NULL;
 
     name += 2;
-    if (!strcmp(name, "GetInstanceProcAddr"))
-        return (void*) vkGetInstanceProcAddr;
     if (!strcmp(name, "CreateInstance"))
         return (void*) vkCreateInstance;
     if (!strcmp(name, "DestroyInstance"))
@@ -2223,46 +2219,56 @@
 
 VK_LAYER_EXPORT void* VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
 {
-    VkBaseLayerObject* devw = (VkBaseLayerObject *) device;
     void* addr;
     if (device == NULL) {
         return NULL;
     }
 
     loader_platform_thread_once(&initOnce, initParamChecker);
-    initDeviceTable((const VkBaseLayerObject *) device);
+
+    /* loader uses this to force layer initialization; device object is wrapped */
+    if (!strcmp(funcName, "vkGetDeviceProcAddr")) {
+        initDeviceTable((const VkBaseLayerObject *) device);
+        return (void*) vkGetDeviceProcAddr;
+    }
 
     addr = layer_intercept_proc(funcName);
     if (addr) {
         return addr;
     }
     else {
-        if (devw->pGPA == NULL) {
+        VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device;
+        VkLayerDispatchTable* pTable = tableMap[*ppDisp];
+        if (pTable->GetDeviceProcAddr == NULL)
             return NULL;
-        }
-        return devw->pGPA((VkObject)devw->nextObject, funcName);
+        return pTable->GetDeviceProcAddr(device, funcName);
     }
 }
 
 VK_LAYER_EXPORT void* VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
 {
-    VkBaseLayerObject* instw = (VkBaseLayerObject *) instance;
     void* addr;
     if (instance == NULL) {
         return NULL;
     }
 
     loader_platform_thread_once(&initOnce, initParamChecker);
-    initInstanceTable((const VkBaseLayerObject *) instance);
+
+    /* loader uses this to force layer initialization; instance object is wrapped */
+    if (!strcmp(funcName, "vkGetInstanceProcAddr")) {
+        initInstanceTable((const VkBaseLayerObject *) instance);
+        return (void*) vkGetInstanceProcAddr;
+    }
 
     addr = layer_intercept_instance_proc(funcName);
     if (addr) {
         return addr;
     }
     else {
-        if (instw->pGPA == NULL) {
+        VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) instance;
+        VkLayerInstanceDispatchTable* pTable = tableInstanceMap[*ppDisp];
+        if (pTable->GetInstanceProcAddr == NULL)
             return NULL;
-        }
-        return instw->pGPA((VkObject)instw->nextObject, funcName);
+        return pTable->GetInstanceProcAddr(instance, funcName);
     }
 }
diff --git a/layers/shader_checker.cpp b/layers/shader_checker.cpp
index 9484cd0..5b66c63 100644
--- a/layers/shader_checker.cpp
+++ b/layers/shader_checker.cpp
@@ -160,7 +160,7 @@
         return it->second;
     }
 
-    layer_initialize_dispatch_table(pTable, (PFN_vkGetDeviceProcAddr) devw->pGPA, (VkDevice) devw->nextObject);
+    layer_initialize_dispatch_table(pTable, devw);
 
     return pTable;
 }
@@ -180,24 +180,11 @@
         return it->second;
     }
 
-    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);
+    layer_init_instance_dispatch_table(pTable, instw);
 
     return pTable;
 }
 
-VK_LAYER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalDevice physicalDevice, size_t maxStringSize, size_t* pLayerCount, char* const* pOutLayers, void* pReserved)
-{
-    if (pLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL || pOutLayers[1] == NULL || pReserved == NULL)
-        return VK_ERROR_INVALID_POINTER;
-
-    if (*pLayerCount < 1)
-        return VK_ERROR_INITIALIZATION_FAILED;
-    *pLayerCount = 1;
-    strncpy((char *) pOutLayers[0], "ShaderChecker", maxStringSize);
-    return VK_SUCCESS;
-}
-
-
 #define SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE 2
 static const VkExtensionProperties shaderCheckerExts[SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE] = {
     {
@@ -966,25 +953,27 @@
     if (device == NULL)
         return NULL;
 
-    initLayerTable((const VkBaseLayerObject *) device);
-
     loader_platform_thread_once(&g_initOnce, initLayer);
 
+    /* loader uses this to force layer initialization; device object is wrapped */
+    if (!strcmp("vkGetDeviceProcAddr", pName)) {
+        initLayerTable((const VkBaseLayerObject *) device);
+        return (void *) vkGetDeviceProcAddr;
+    }
+
 #define ADD_HOOK(fn)    \
     if (!strncmp(#fn, pName, sizeof(#fn))) \
         return (void *) fn
 
-    ADD_HOOK(vkGetDeviceProcAddr);
     ADD_HOOK(vkCreateShader);
     ADD_HOOK(vkDestroyDevice);
     ADD_HOOK(vkCreateGraphicsPipeline);
     ADD_HOOK(vkCreateGraphicsPipelineDerivative);
 #undef ADD_HOOK
-
-    VkBaseLayerObject* devw = (VkBaseLayerObject *) device;
-    if (devw->pGPA == NULL)
+    VkLayerDispatchTable* pTable = tableMap[(VkBaseLayerObject *)device];
+    if (pTable->GetDeviceProcAddr == NULL)
         return NULL;
-    return devw->pGPA((VkObject) devw->nextObject, pName);
+    return pTable->GetDeviceProcAddr(device, pName);
 }
 
 VK_LAYER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance inst, const char* pName)
@@ -992,22 +981,22 @@
     if (inst == NULL)
         return NULL;
 
-    initLayerInstanceTable((const VkBaseLayerObject *) inst);
-
     loader_platform_thread_once(&g_initOnce, initLayer);
 
+    if (!strcmp("vkGetInstanceProcAddr", pName)) {
+        initLayerInstanceTable((const VkBaseLayerObject *) inst);
+        return (void *) vkGetInstanceProcAddr;
+    }
 #define ADD_HOOK(fn)    \
     if (!strncmp(#fn, pName, sizeof(#fn))) \
         return (void *) fn
 
-    ADD_HOOK(vkGetInstanceProcAddr);
     ADD_HOOK(vkDestroyInstance);
-    ADD_HOOK(vkEnumerateLayers);
     ADD_HOOK(vkGetGlobalExtensionInfo);
 #undef ADD_HOOK
 
-    VkBaseLayerObject* instw = (VkBaseLayerObject *) inst;
-    if (instw->pGPA == NULL)
+    VkLayerInstanceDispatchTable* pTable = tableInstanceMap[(VkBaseLayerObject *) inst];
+    if (pTable->GetInstanceProcAddr == NULL)
         return NULL;
-    return instw->pGPA((VkObject) instw->nextObject, pName);
+    return pTable->GetInstanceProcAddr(inst, pName);
 }
diff --git a/loader/loader.c b/loader/loader.c
index 064b3dc..fd23465 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -820,14 +820,12 @@
     VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
     void *addr;
 
+    if (!strcmp(pName, "vkGetInstanceProcAddr"))
+        return (void *) loader_gpa_instance_internal;
+
     if (disp_table == NULL)
         return NULL;
 
-//    addr = debug_report_instance_gpa((struct loader_instance *) inst, pName);
-//    if (addr) {
-//        return addr;
-//    }
-
     addr = loader_lookup_instance_dispatch_table(disp_table, pName);
     if (addr) {
         return addr;
@@ -1138,7 +1136,7 @@
         layer_idx--;
     }
 
-    loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj);
+    loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
 
     return inst->layer_count;
 }
@@ -1225,7 +1223,8 @@
             layer_idx--;
         }
 
-        loader_init_device_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA, (VkPhysicalDevice) nextObj);
+        loader_init_device_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA,
+                           (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
     } else {
         // TODO: Check that active layers match requested?
     }
@@ -1370,7 +1369,7 @@
                     (wrapped_gpus + i)->nextObject = gpus[i];
                     memcpy(pPhysicalDevices + count, gpus, sizeof(*pPhysicalDevices));
                     loader_init_device_dispatch_table(icd->loader_dispatch + i,
-                                               get_proc_addr, gpus[i]);
+                                               get_proc_addr, gpus[i], gpus[i]);
 
                     loader_init_dispatch(gpus[i], ptr_instance->disp);
                 }
diff --git a/loader/loader.h b/loader/loader.h
index 73b780f..8b427b5 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -321,13 +321,6 @@
         size_t*                                 pDataSize,
         void*                                   pData);
 
-VkResult loader_EnumerateLayers(
-        VkPhysicalDevice                        gpu,
-        size_t                                  maxStringSize,
-        size_t*                                 pLayerCount,
-        char* const*                            pOutLayers,
-        void*                                   pReserved);
-
 VkResult loader_GetMultiDeviceCompatibility(
         VkPhysicalDevice                        gpu0,
         VkPhysicalDevice                        gpu1,
diff --git a/loader/table_ops.h b/loader/table_ops.h
index 1fb624b..93131b1 100644
--- a/loader/table_ops.h
+++ b/loader/table_ops.h
@@ -30,9 +30,13 @@
 
 static inline void loader_init_device_dispatch_table(VkLayerDispatchTable *table,
                                                     PFN_vkGetDeviceProcAddr gpa,
+                                                    VkDevice dev_next,
                                                     VkDevice dev)
 {
-    table->GetDeviceProcAddr = gpa;
+    // If layer is next, this will trigger layers to initialize their dispatch tables
+    //then use the gpa in their dispatch for subsequent layers in the chain
+    table->GetDeviceProcAddr = (PFN_vkGetDeviceProcAddr) gpa(dev_next, "vkGetDeviceProcAddr");
+
     table->DestroyDevice = (PFN_vkDestroyDevice) gpa(dev, "vkDestroyDevice");
     table->GetDeviceQueue = (PFN_vkGetDeviceQueue) gpa(dev, "vkGetDeviceQueue");
     table->QueueSubmit = (PFN_vkQueueSubmit) gpa(dev, "vkQueueSubmit");
@@ -137,6 +141,8 @@
     table->CmdBeginRenderPass = (PFN_vkCmdBeginRenderPass) gpa(dev, "vkCmdBeginRenderPass");
     table->CmdEndRenderPass = (PFN_vkCmdEndRenderPass) gpa(dev, "vkCmdEndRenderPass");
 //TODO move into it's own table
+//TODO also consider dropping trampoline code for these device level extensions entirely
+// then don't need loader to know about these at all but then not queryable via GIPA
     table->CreateSwapChainWSI = (PFN_vkCreateSwapChainWSI) gpa(dev, "vkCreateSwapChainWSI");
     table->DestroySwapChainWSI = (PFN_vkDestroySwapChainWSI) gpa(dev, "vkDestroySwapChainWSI");
     table->GetSwapChainInfoWSI = (PFN_vkGetSwapChainInfoWSI) gpa(dev, "vkGetSwapChainInfoWSI");
@@ -359,28 +365,23 @@
         return (void *) table->CmdBeginRenderPass;
     if (!strcmp(name, "CmdEndRenderPass"))
         return (void *) table->CmdEndRenderPass;
-//TODO put in it's own table
-    if (!strcmp(name, "CreateSwapChainWSI"))
-        return (void *) table->CreateSwapChainWSI;
-    if (!strcmp(name, "DestroySwapChainWSI"))
-        return (void *) table->DestroySwapChainWSI;
-    if (!strcmp(name, "GetSwapChainInfoWSI"))
-        return (void *) table->GetSwapChainInfoWSI;
-    if (!strcmp(name, "QueuePresentWSI"))
-        return (void *) table->QueuePresentWSI;
 
     return NULL;
 }
 
 static inline void loader_init_instance_core_dispatch_table(VkLayerInstanceDispatchTable *table,
                                                 PFN_vkGetInstanceProcAddr gpa,
+                                                VkInstance inst_next,
                                                 VkInstance inst)
 {
+    // If layer is next, this will trigger layers to initialize their dispatch tables
+    //then use the gpa in their dispatch for subsequent layers in the chain
+    table->GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) gpa(inst_next, "vkGetInstanceProcAddr");
+
     table->CreateInstance = (PFN_vkCreateInstance) gpa(inst, "vkCreateInstance");
     table->DestroyInstance = (PFN_vkDestroyInstance) gpa(inst, "vkDestroyInstance");
     table->EnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices) gpa(inst, "vkEnumeratePhysicalDevices");
     table->GetPhysicalDeviceInfo = (PFN_vkGetPhysicalDeviceInfo) gpa(inst, "vkGetPhysicalDeviceInfo");
-    table->GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) gpa(inst, "vkGetInstanceProcAddr");
     table->CreateDevice = (PFN_vkCreateDevice) gpa(inst, "vkCreateDevice");
     table->GetGlobalExtensionInfo = (PFN_vkGetGlobalExtensionInfo) gpa(inst,"vkGetGlobalExtensionInfo");
     table->GetPhysicalDeviceExtensionInfo = (PFN_vkGetPhysicalDeviceExtensionInfo) gpa(inst, "vkGetPhysicalDeviceExtensionInfo");
diff --git a/vk-generate.py b/vk-generate.py
index a2ec6bf..790a543 100755
--- a/vk-generate.py
+++ b/vk-generate.py
@@ -110,38 +110,42 @@
                           "#include <vkLayer.h>",
                           "#include <string.h>"])
 
-    def _generate_init(self, type):
+    def _generate_init_dispatch(self, type):
         stmts = []
         func = []
         if type == "device":
+            # GPA has to be first one and uses wrapped object
+            stmts.append("VkDevice device = (VkDevice) devw->nextObject;")
+            stmts.append("PFN_vkGetDeviceProcAddr gpa = (PFN_vkGetDeviceProcAddr) devw->pGPA;")
+            stmts.append("VkDevice baseDevice = (VkDevice) devw->baseObject;")
+            stmts.append("// GPA has to be first entry inited and uses wrapped object since it triggers init")
+            stmts.append("table->GetDeviceProcAddr =(PFN_vkGetDeviceProcAddr)  gpa(device,\"vkGetDeviceProcAddr\");")
             for proto in self.protos:
                 if proto.name == "CreateInstance" or proto.name == "GetGlobalExtensionInfo" or proto.name == "GetDisplayInfoWSI" or proto.params[0].ty == "VkInstance" or proto.params[0].ty == "VkPhysicalDevice":
                     continue
-                if proto.name == "GetDeviceProcAddr":
-                    stmts.append("table->%s = gpa; // direct assignment" % proto.name)
-                else:
-                    stmts.append("table->%s = (PFN_vk%s) gpa(device, \"vk%s\");" %
+                if proto.name != "GetDeviceProcAddr":
+                    stmts.append("table->%s = (PFN_vk%s) gpa(baseDevice, \"vk%s\");" %
                         (proto.name, proto.name, proto.name))
             func.append("static inline void %s_initialize_dispatch_table(VkLayerDispatchTable *table,"
                 % self.prefix)
-            func.append("%s                                              PFN_vkGetDeviceProcAddr gpa,"
-                % (" " * len(self.prefix)))
-            func.append("%s                                              VkDevice device)"
+            func.append("%s                                              const VkBaseLayerObject *devw)"
                 % (" " * len(self.prefix)))
         else:
+            # GPA has to be first one and uses wrapped object
+            stmts.append("VkInstance instance = (VkInstance) instw->nextObject;")
+            stmts.append("PFN_vkGetInstanceProcAddr gpa = (PFN_vkGetInstanceProcAddr) instw->pGPA;")
+            stmts.append("VkInstance baseInstance = (VkInstance) instw->baseObject;")
+            stmts.append("// GPA has to be first entry inited and uses wrapped object since it triggers init")
+            stmts.append("table->GetInstanceProcAddr =(PFN_vkGetInstanceProcAddr)  gpa(instance,\"vkGetInstanceProcAddr\");")
             for proto in self.protos:
                 if proto.name != "CreateInstance"  and proto.name != "GetGlobalExtensionInfo" and proto.name != "GetDisplayInfoWSI" and proto.params[0].ty != "VkInstance" and proto.params[0].ty != "VkPhysicalDevice":
                     continue
-                if proto.name == "GetInstanceProcAddr":
-                    stmts.append("table->%s = gpa; // direct assignment" % proto.name)
-                else:
-                    stmts.append("table->%s = (PFN_vk%s) gpa(instance, \"vk%s\");" %
+                if proto.name != "GetInstanceProcAddr":
+                    stmts.append("table->%s = (PFN_vk%s) gpa(baseInstance, \"vk%s\");" %
                           (proto.name, proto.name, proto.name))
             func.append("static inline void %s_init_instance_dispatch_table(VkLayerInstanceDispatchTable *table,"
                 % self.prefix)
-            func.append("%s                                              PFN_vkGetInstanceProcAddr gpa,"
-                % (" " * len(self.prefix)))
-            func.append("%s                                              VkInstance instance)"
+            func.append("%s                                              const VkBaseLayerObject *instw)"
                 % (" " * len(self.prefix)))
         func.append("{")
         func.append("    %s" % "\n    ".join(stmts))
@@ -150,8 +154,8 @@
         return "\n".join(func)
 
     def generate_body(self):
-        body = [self._generate_init("device"),
-                self._generate_init("instance")]
+        body = [self._generate_init_dispatch("device"),
+                self._generate_init_dispatch("instance")]
 
         return "\n\n".join(body)
 
diff --git a/vk-layer-generate.py b/vk-layer-generate.py
index 184cf36..c1d6fdc 100755
--- a/vk-layer-generate.py
+++ b/vk-layer-generate.py
@@ -223,7 +223,7 @@
         intercepted = []
         for proto in self.protos:
             if proto.name == "GetDeviceProcAddr" or proto.name == "GetInstanceProcAddr":
-                intercepted.append(proto)
+                continue
             else:
                 intercept = self.generate_intercept(proto, qual)
                 if intercept is None:
@@ -352,13 +352,16 @@
         func_body = []
         func_body.append("VK_LAYER_EXPORT void* VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)\n"
                          "{\n"
-                         "    VkBaseLayerObject* devw = (VkBaseLayerObject *) device;\n"
                          "    void* addr;\n"
                          "    if (device == VK_NULL_HANDLE) {\n"
                          "        return NULL;\n"
                          "    }\n"
-                         "    loader_platform_thread_once(&initOnce, init%s);\n"
-                         "    initDeviceTable((const VkBaseLayerObject *) device);\n\n"
+                         "    loader_platform_thread_once(&initOnce, init%s);\n\n"
+                         "    /* loader uses this to force layer initialization; device object is wrapped */\n"
+                         "    if (!strcmp(\"vkGetDeviceProcAddr\", funcName)) {\n"
+                         "        initDeviceTable((const VkBaseLayerObject *) device);\n"
+                         "        return (void *) vkGetDeviceProcAddr;\n"
+                         "    }\n\n"
                          "    addr = layer_intercept_proc(funcName);\n"
                          "    if (addr)\n"
                          "        return addr;" % self.layer_name)
@@ -373,20 +376,25 @@
                 func_body.append('    else if (!strcmp("%s", funcName))\n'
                                  '        return %s%s%s;' % (ext_name, cpp_prefix, ext_name, cpp_postfix))
         func_body.append("    else {\n"
-                         "        if (devw->pGPA == NULL)\n"
+                         "        VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device;\n"
+                         "        VkLayerDispatchTable* pTable = tableMap[*ppDisp];\n"
+                         "        if (pTable->GetDeviceProcAddr == NULL)\n"
                          "            return NULL;\n"
-                         "        return devw->pGPA((VkObject)devw->nextObject, funcName);\n"
+                         "        return pTable->GetDeviceProcAddr(device, funcName);\n"
                          "    }\n"
                          "}\n")
         func_body.append("VK_LAYER_EXPORT void* VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)\n"
                          "{\n"
-                         "    VkBaseLayerObject* instw = (VkBaseLayerObject *) instance;\n"
                          "    void* addr;\n"
                          "    if (instance == VK_NULL_HANDLE) {\n"
                          "        return NULL;\n"
                          "    }\n"
-                         "    loader_platform_thread_once(&initOnce, init%s);\n"
-                         "    initInstanceTable((const VkBaseLayerObject *) instance);\n\n"
+                         "    loader_platform_thread_once(&initOnce, init%s);\n\n"
+                         "    /* loader uses this to force layer initialization; instance object is wrapped */\n"
+                         "    if (!strcmp(\"vkGetInstanceProcAddr\", funcName)) {\n"
+                         "        initInstanceTable((const VkBaseLayerObject *) instance);\n"
+                         "        return (void *) vkGetInstanceProcAddr;\n"
+                         "    }\n\n"
                          "    addr = layer_intercept_instance_proc(funcName);\n"
                          "    if (addr)\n"
                          "        return addr;" % self.layer_name)
@@ -396,9 +404,11 @@
                 func_body.append('    else if (!strcmp("%s", funcName))\n'
                                  '        return %s;' % (ext_name, ext_name))
         func_body.append("    else {\n"
-                         "        if (instw->pGPA == NULL)\n"
+                         "        VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) instance;\n"
+                         "        VkLayerInstanceDispatchTable* pTable = tableInstanceMap[*ppDisp];\n"
+                         "        if (pTable->GetInstanceProcAddr == NULL)\n"
                          "            return NULL;\n"
-                         "        return instw->pGPA((VkObject)instw->nextObject, funcName);\n"
+                         "        return pTable->GetInstanceProcAddr(instance, funcName);\n"
                          "    }\n"
                          "}\n")
         return "\n".join(func_body)
@@ -453,7 +463,7 @@
         func_body.append('        return it->second;')
         func_body.append('    }')
         func_body.append('')
-        func_body.append('    layer_initialize_dispatch_table(pTable, (PFN_vkGetDeviceProcAddr) devw->pGPA, (VkDevice) devw->nextObject);')
+        func_body.append('    layer_initialize_dispatch_table(pTable, devw);')
         func_body.append('')
         func_body.append('    return pTable;')
         func_body.append('}')
@@ -474,7 +484,7 @@
         func_body.append('        return it->second;')
         func_body.append('    }')
         func_body.append('')
-        func_body.append('    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);')
+        func_body.append('    layer_init_instance_dispatch_table(pTable, instw);')
         func_body.append('')
         func_body.append('    return pTable;')
         func_body.append('}')
@@ -773,7 +783,7 @@
         func_body.append('        return it->second;')
         func_body.append('    }')
         func_body.append('')
-        func_body.append('    layer_initialize_dispatch_table(pTable, (PFN_vkGetDeviceProcAddr) devw->pGPA, (VkDevice) devw->nextObject);')
+        func_body.append('    layer_initialize_dispatch_table(pTable, devw);')
         func_body.append('')
         func_body.append('    return pTable;')
         func_body.append('}')
@@ -794,7 +804,7 @@
         func_body.append('        return it->second;')
         func_body.append('    }')
         func_body.append('')
-        func_body.append('    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);')
+        func_body.append('    layer_init_instance_dispatch_table(pTable, instw);')
         func_body.append('')
         func_body.append('    return pTable;')
         func_body.append('}')