layers: Add initialization of instance dispatch table

Make the layer init  separate from either device or instance dispatch
table init, since these are done at different times.
diff --git a/layers/basic.cpp b/layers/basic.cpp
index e889e31..9f43c6d 100644
--- a/layers/basic.cpp
+++ b/layers/basic.cpp
@@ -33,6 +33,27 @@
 #include "loader_platform.h"
 
 static std::unordered_map<void *, VkLayerDispatchTable *> tableMap;
+static std::unordered_map<void *, VkLayerInstanceDispatchTable *> tableInstanceMap;
+
+static VkLayerInstanceDispatchTable * initLayerInstanceTable(const VkBaseLayerObject *instancew)
+{
+    VkLayerInstanceDispatchTable *pTable;
+
+    assert(instancew);
+    std::unordered_map<void *, VkLayerInstanceDispatchTable *>::const_iterator it = tableInstanceMap.find((void *) instancew->baseObject);
+    if (it == tableInstanceMap.end())
+    {
+        pTable =  new VkLayerInstanceDispatchTable;
+        tableInstanceMap[(void *) instancew->baseObject] = pTable;
+    } else
+    {
+        return it->second;
+    }
+
+    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instancew->pGPA, (VkInstance) instancew->nextObject);
+
+    return pTable;
+}
 
 static VkLayerDispatchTable * initLayerTable(const VkBaseLayerObject *gpuw)
 {
@@ -198,7 +219,7 @@
     if (instance == NULL)
         return NULL;
 
-    // TODO initInstanceLayerTable((const VkBaseLayerObject *) instance);
+    initLayerInstanceTable((const VkBaseLayerObject *) instance);
 
     if (!strcmp("vkGetInstanceProcAddr", pName))
         return (void *) vkGetInstanceProcAddr;
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index 95fa1f5..cedf652 100755
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -59,8 +59,12 @@
 unordered_map<VkFramebuffer, VkFramebufferCreateInfo*> frameBufferMap;
 
 static VkLayerDispatchTable nextTable;
+static VkLayerInstanceDispatchTable nextInstanceTable;
 static VkBaseLayerObject *pCurObj;
 static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_initOnce);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_tabDeviceOnce);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_tabInstanceOnce);
+
 // TODO : This can be much smarter, using separate locks for separate global data
 static int globalLockInitialized = 0;
 static loader_platform_thread_mutex globalLock;
@@ -1438,6 +1442,23 @@
     }
 }
 
+// TODO handle multiple GPUs/instances for both instance and device dispatch tables
+static void initDeviceTable(void)
+{
+    PFN_vkGetProcAddr fpNextGPA;
+    fpNextGPA = (PFN_vkGetProcAddr) pCurObj->pGPA;
+    assert(fpNextGPA);
+    layer_initialize_dispatch_table(&nextTable, fpNextGPA, (VkPhysicalDevice) pCurObj->nextObject);
+}
+
+static void initInstanceTable(void)
+{
+    PFN_vkGetInstanceProcAddr fpNextGPA;
+    fpNextGPA = (PFN_vkGetInstanceProcAddr) pCurObj->pGPA;
+    assert(fpNextGPA);
+    layer_init_instance_dispatch_table(&nextInstanceTable, fpNextGPA, (VkInstance) pCurObj->nextObject);
+}
+
 static void initDrawState(void)
 {
     const char *strOpt;
@@ -1455,13 +1476,6 @@
         if (g_logFile == NULL)
             g_logFile = stdout;
     }
-    // initialize Layer dispatch table
-    // TODO handle multiple GPUs
-    PFN_vkGetProcAddr fpNextGPA;
-    fpNextGPA = (PFN_vkGetProcAddr) pCurObj->pGPA;
-    assert(fpNextGPA);
-
-    layer_initialize_dispatch_table(&nextTable, fpNextGPA, (VkPhysicalDevice) pCurObj->nextObject);
 
     if (!globalLockInitialized)
     {
@@ -1477,8 +1491,6 @@
 
 VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
 {
-    pCurObj = (VkBaseLayerObject *) gpu;
-    loader_platform_thread_once(&g_initOnce, initDrawState);
     VkResult result = nextTable.CreateDevice(gpu, pCreateInfo, pDevice);
     return result;
 }
@@ -2732,6 +2744,7 @@
         return NULL;
     pCurObj = gpuw;
     loader_platform_thread_once(&g_initOnce, initDrawState);
+    loader_platform_thread_once(&g_tabDeviceOnce, initDeviceTable);
 
     if (!strcmp(funcName, "vkGetProcAddr"))
         return (void *) vkGetProcAddr;
@@ -2882,9 +2895,9 @@
     if (instance == NULL)
         return NULL;
 
-    //TODO
-    //pCurObj = gpuw;
-    //loader_platform_thread_once(&g_initInstanceOnce, initInstanceDrawState);
+    pCurObj = instw;
+    loader_platform_thread_once(&g_initOnce, initDrawState);
+    loader_platform_thread_once(&g_tabInstanceOnce, initInstanceTable);
 
     if (!strcmp(funcName, "vkGetInstanceProcAddr"))
         return (void *) vkGetInstanceProcAddr;
diff --git a/layers/mem_tracker.cpp b/layers/mem_tracker.cpp
index 2e9307d..20a69c3 100644
--- a/layers/mem_tracker.cpp
+++ b/layers/mem_tracker.cpp
@@ -43,8 +43,12 @@
 #include "layers_msg.h"
 
 static VkLayerDispatchTable nextTable;
+static VkLayerInstanceDispatchTable nextInstanceTable;
 static VkBaseLayerObject *pCurObj;
 static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_initOnce);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_tabDeviceOnce);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_tabInstanceOnce);
+
 // TODO : This can be much smarter, using separate locks for separate global data
 static int globalLockInitialized = 0;
 static loader_platform_thread_mutex globalLock;
@@ -771,6 +775,23 @@
     }
 }
 
+// TODO handle multiple GPUs/instances for both instance and device dispatch tables
+static void initDeviceTable(void)
+{
+    PFN_vkGetProcAddr fpNextGPA;
+    fpNextGPA = (PFN_vkGetProcAddr) pCurObj->pGPA;
+    assert(fpNextGPA);
+    layer_initialize_dispatch_table(&nextTable, fpNextGPA, (VkPhysicalDevice) pCurObj->nextObject);
+}
+
+static void initInstanceTable(void)
+{
+    PFN_vkGetInstanceProcAddr fpNextGPA;
+    fpNextGPA = (PFN_vkGetInstanceProcAddr) pCurObj->pGPA;
+    assert(fpNextGPA);
+    layer_init_instance_dispatch_table(&nextInstanceTable, fpNextGPA, (VkInstance) pCurObj->nextObject);
+}
+
 static void initMemTracker(
     void)
 {
@@ -790,14 +811,6 @@
         }
     }
 
-    // initialize Layer dispatch table
-    // TODO handle multiple GPUs
-    PFN_vkGetProcAddr fpNextGPA;
-    fpNextGPA = (PFN_vkGetProcAddr) pCurObj->pGPA;
-    assert(fpNextGPA);
-
-    layer_initialize_dispatch_table(&nextTable, fpNextGPA, (VkPhysicalDevice) pCurObj->nextObject);
-
     if (!globalLockInitialized)
     {
         // TODO/TBD: Need to delete this mutex sometime.  How???  One
@@ -815,8 +828,6 @@
     const VkDeviceCreateInfo *pCreateInfo,
     VkDevice                 *pDevice)
 {
-    pCurObj = (VkBaseLayerObject *) gpu;
-    loader_platform_thread_once(&g_initOnce, initMemTracker);
     VkResult result = nextTable.CreateDevice(gpu, pCreateInfo, pDevice);
     // Save off device in case we need it to create Fences
     globalDevice = *pDevice;
@@ -925,6 +936,7 @@
     {
         pCurObj = (VkBaseLayerObject *)  gpu;
         loader_platform_thread_once(&g_initOnce, initMemTracker);
+        loader_platform_thread_once(&g_tabDeviceOnce, initDeviceTable);
         VkResult result = nextTable.EnumerateLayers(gpu,
             maxStringSize, pLayerCount, pOutLayers, pReserved);
         return result;
@@ -2149,6 +2161,7 @@
     }
     pCurObj = gpuw;
     loader_platform_thread_once(&g_initOnce, initMemTracker);
+    loader_platform_thread_once(&g_tabDeviceOnce, initDeviceTable);
 
     if (!strcmp(funcName, "vkGetProcAddr"))
         return (void *) vkGetProcAddr;
@@ -2311,9 +2324,10 @@
     if (instance == NULL) {
         return NULL;
     }
-    //TODO
-    //pCurObj = instw;
-    //loader_platform_thread_once(&g_initInstanceOnce, initInstanceMemTracker);
+
+    pCurObj = instw;
+    loader_platform_thread_once(&g_initOnce, initMemTracker);
+    loader_platform_thread_once(&g_tabInstanceOnce, initInstanceTable);
 
     if (!strcmp(funcName, "vkGetProcAddr"))
         return (void *) vkGetProcAddr;
diff --git a/layers/multi.cpp b/layers/multi.cpp
index 78ee302..9732654 100644
--- a/layers/multi.cpp
+++ b/layers/multi.cpp
@@ -35,9 +35,11 @@
 #include "loader_platform.h"
 
 static void initLayerTable(const VkBaseLayerObject *gpuw, VkLayerDispatchTable *pTable, const unsigned int layerNum);
+static void initLayerInstanceTable(const VkBaseLayerObject *instw, VkLayerInstanceDispatchTable *pTable, const unsigned int layerNum);
 
 /******************************** Layer multi1 functions **************************/
 static std::unordered_map<void *, VkLayerDispatchTable *> tableMap1;
+static std::unordered_map<void *, VkLayerInstanceDispatchTable *> tableInstanceMap1;
 static bool layer1_first_activated = false;
 
 static VkLayerDispatchTable * getLayer1Table(const VkBaseLayerObject *gpuw)
@@ -57,6 +59,23 @@
         return it->second;
     }
 }
+static VkLayerInstanceDispatchTable * getLayer1InstanceTable(const VkBaseLayerObject *instw)
+{
+    VkLayerInstanceDispatchTable *pTable;
+
+    assert(instw);
+    std::unordered_map<void *, VkLayerInstanceDispatchTable *>::const_iterator it = tableInstanceMap1.find((void *) instw->baseObject);
+    if (it == tableInstanceMap1.end())
+    {
+        pTable =  new VkLayerInstanceDispatchTable;
+        tableInstanceMap1[(void *) instw->baseObject] = pTable;
+        initLayerInstanceTable(instw, pTable, 1);
+        return pTable;
+    } else
+    {
+        return it->second;
+    }
+}
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -137,14 +156,14 @@
     }
 }
 
-VK_LAYER_EXPORT void * VKAPI multi1InstanceGetProcAddr(VkInstance inst, const char* pName)
+VK_LAYER_EXPORT void * VKAPI multi1GetInstanceProcAddr(VkInstance inst, const char* pName)
 {
     VkBaseLayerObject* instw = (VkBaseLayerObject *) inst;
 
     if (inst == NULL)
         return NULL;
 
-    //TODO getLayer1InstanceTable(instw);
+    getLayer1InstanceTable(instw);
 
     if (!strcmp("vkCreateDevice", pName))
         return (void *) multi1CreateDevice;
@@ -161,8 +180,27 @@
 
 /******************************** Layer multi2 functions **************************/
 static std::unordered_map<void *, VkLayerDispatchTable *> tableMap2;
+static std::unordered_map<void *, VkLayerInstanceDispatchTable *> tableInstanceMap2;
 static bool layer2_first_activated = false;
 
+static VkLayerInstanceDispatchTable * getLayer2InstanceTable(const VkBaseLayerObject *instw)
+{
+    VkLayerInstanceDispatchTable *pTable;
+
+    assert(instw);
+    std::unordered_map<void *, VkLayerInstanceDispatchTable *>::const_iterator it = tableInstanceMap2.find((void *) instw->baseObject);
+    if (it == tableInstanceMap2.end())
+    {
+        pTable =  new VkLayerInstanceDispatchTable;
+        tableInstanceMap2[(void *) instw->baseObject] = pTable;
+        initLayerInstanceTable(instw, pTable, 2);
+        return pTable;
+    } else
+    {
+        return it->second;
+    }
+}
+
 static VkLayerDispatchTable * getLayer2Table(const VkBaseLayerObject *gpuw)
 {
     VkLayerDispatchTable *pTable;
@@ -259,14 +297,14 @@
     }
 }
 
-VK_LAYER_EXPORT void * VKAPI multi2InstanceGetProcAddr(VkInstance inst, const char* pName)
+VK_LAYER_EXPORT void * VKAPI multi2GetInstanceProcAddr(VkInstance inst, const char* pName)
 {
     VkBaseLayerObject* instw = (VkBaseLayerObject *) inst;
 
     if (inst == NULL)
         return NULL;
 
-    //TODO getLayer2InstanceTable(instw);
+    getLayer2InstanceTable(instw);
 
     if (!strcmp("vkCreateDevice", pName))
         return (void *) multi2CreateDevice;
@@ -379,17 +417,17 @@
     else if (!strcmp("vkGetProcAddr", pName))
         return (void *) vkGetProcAddr;
     else if (!strcmp("multi1GetInstanceProcAddr", pName))
-        return (void *) multi1GetProcAddr;
+        return (void *) multi1GetInstanceProcAddr;
     else if (!strcmp("multi2GetInstanceProcAddr", pName))
-        return (void *) multi2GetProcAddr;
+        return (void *) multi2GetInstanceProcAddr;
     else if (!strcmp("vkGetInstanceProcAddr", pName))
         return (void *) vkGetProcAddr;
 
     // use first layer activated as GPA dispatch table activation happens in order
     else if (layer1_first_activated)
-        return multi1InstanceGetProcAddr(inst, pName);
+        return multi1GetInstanceProcAddr(inst, pName);
     else if (layer2_first_activated)
-        return multi2InstanceGetProcAddr(inst, pName);
+        return multi2GetInstanceProcAddr(inst, pName);
     else
         return NULL;
 
@@ -407,3 +445,13 @@
 
     layer_initialize_dispatch_table(pTable, (PFN_vkGetProcAddr) gpuw->pGPA, (VkPhysicalDevice) gpuw->nextObject);
 }
+
+static void initLayerInstanceTable(const VkBaseLayerObject *instw, VkLayerInstanceDispatchTable *pTable, const unsigned int layerNum)
+{
+    if (layerNum == 2 && layer1_first_activated == false)
+        layer2_first_activated = true;
+    if (layerNum == 1 && layer2_first_activated == false)
+        layer1_first_activated = true;
+
+    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);
+}
diff --git a/layers/param_checker.cpp b/layers/param_checker.cpp
index a63e4a9..8ed6d28 100644
--- a/layers/param_checker.cpp
+++ b/layers/param_checker.cpp
@@ -41,10 +41,31 @@
 #include "layers_msg.h"
 
 static VkLayerDispatchTable nextTable;
+static VkLayerInstanceDispatchTable nextInstanceTable;
 static VkBaseLayerObject *pCurObj;
-static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(tabOnce);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(initOnce);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(tabDeviceOnce);
+static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(tabInstanceOnce);
 
 #include "vk_dispatch_table_helper.h"
+
+// TODO handle multiple GPUs/instances for both instance and device dispatch tables
+static void initDeviceTable(void)
+{
+    PFN_vkGetProcAddr fpNextGPA;
+    fpNextGPA = (PFN_vkGetProcAddr) pCurObj->pGPA;
+    assert(fpNextGPA);
+    layer_initialize_dispatch_table(&nextTable, fpNextGPA, (VkPhysicalDevice) pCurObj->nextObject);
+}
+
+static void initInstanceTable(void)
+{
+    PFN_vkGetInstanceProcAddr fpNextGPA;
+    fpNextGPA = (PFN_vkGetInstanceProcAddr) pCurObj->pGPA;
+    assert(fpNextGPA);
+    layer_init_instance_dispatch_table(&nextInstanceTable, fpNextGPA, (VkInstance) pCurObj->nextObject);
+}
+
 static void initParamChecker(void)
 {
 
@@ -64,11 +85,6 @@
             g_logFile = stdout;
     }
 
-    PFN_vkGetProcAddr fpNextGPA;
-    fpNextGPA = (PFN_vkGetProcAddr) pCurObj->pGPA;
-    assert(fpNextGPA);
-
-    layer_initialize_dispatch_table(&nextTable, fpNextGPA, (VkPhysicalDevice) pCurObj->nextObject);
 }
 
 void PreCreateInstance(const VkApplicationInfo* pAppInfo, const VkAllocCallbacks* pAllocCb)
@@ -141,8 +157,6 @@
 
 VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceInfo(VkPhysicalDevice gpu, VkPhysicalDeviceInfoType infoType, size_t* pDataSize, void* pData)
 {
-    pCurObj = (VkBaseLayerObject *) gpu;
-    loader_platform_thread_once(&tabOnce, initParamChecker);
     char str[1024];
     if (!validate_VkPhysicalDeviceInfoType(infoType)) {
         sprintf(str, "Parameter infoType to function GetPhysicalDeviceInfo has invalid value of %i.", (int)infoType);
@@ -228,8 +242,6 @@
 
 VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
 {
-    pCurObj = (VkBaseLayerObject *) gpu;
-    loader_platform_thread_once(&tabOnce, initParamChecker);
     PreCreateDevice(gpu, pCreateInfo);
     VkResult result = nextTable.CreateDevice(gpu, pCreateInfo, pDevice);
     PostCreateDevice(result, pDevice);
@@ -313,7 +325,8 @@
         sprintf(str, "At start of layered EnumerateLayers\n");
         layerCbMsg(VK_DBG_MSG_UNKNOWN, VK_VALIDATION_LEVEL_0, nullptr, 0, 0, "PARAMCHECK", str);
         pCurObj = (VkBaseLayerObject *) gpu;
-        loader_platform_thread_once(&tabOnce, initParamChecker);
+        loader_platform_thread_once(&initOnce, initParamChecker);
+        loader_platform_thread_once(&tabDeviceOnce, initDeviceTable);
         VkResult result = nextTable.EnumerateLayers(gpu, maxStringSize, pLayerCount, pOutLayers, pReserved);
         sprintf(str, "Completed layered EnumerateLayers\n");
         layerCbMsg(VK_DBG_MSG_UNKNOWN, VK_VALIDATION_LEVEL_0, nullptr, 0, 0, "PARAMCHECK", str);
@@ -431,8 +444,6 @@
 
 VK_LAYER_EXPORT VkResult VKAPI vkGetMultiDeviceCompatibility(VkPhysicalDevice gpu0, VkPhysicalDevice gpu1, VkPhysicalDeviceCompatibilityInfo* pInfo)
 {
-    pCurObj = (VkBaseLayerObject *) gpu0;
-    loader_platform_thread_once(&tabOnce, initParamChecker);
 
     VkResult result = nextTable.GetMultiDeviceCompatibility(gpu0, gpu1, pInfo);
     return result;
@@ -2250,7 +2261,8 @@
     if (gpu == NULL)
         return NULL;
     pCurObj = gpuw;
-    loader_platform_thread_once(&tabOnce, initParamChecker);
+    loader_platform_thread_once(&initOnce, initParamChecker);
+    loader_platform_thread_once(&tabDeviceOnce, initDeviceTable);
 
     addr = layer_intercept_proc(funcName);
     if (addr)
@@ -2268,8 +2280,9 @@
     void* addr;
     if (inst == NULL)
         return NULL;
-    //TODO pCurObj = instw;
-    //TODO loader_platform_thread_once(&tabOnce, initParamChecker);
+    pCurObj = instw;
+    loader_platform_thread_once(&initOnce, initParamChecker);
+    loader_platform_thread_once(&tabInstanceOnce, initInstanceTable);
 
     addr = layer_intercept_instance_proc(funcName);
     if (addr)
diff --git a/layers/shader_checker.cpp b/layers/shader_checker.cpp
index f36fee3..8de9239 100644
--- a/layers/shader_checker.cpp
+++ b/layers/shader_checker.cpp
@@ -44,6 +44,7 @@
 
 static std::unordered_map<void *, VkLayerDispatchTable *> tableMap;
 static VkBaseLayerObject *pCurObj;
+static std::unordered_map<void *, VkLayerInstanceDispatchTable *> tableInstanceMap;
 static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(g_initOnce);
 // TODO : This can be much smarter, using separate locks for separate global data
 static int globalLockInitialized = 0;
@@ -164,6 +165,25 @@
     return pTable;
 }
 
+static VkLayerInstanceDispatchTable * initLayerInstanceTable(const VkBaseLayerObject *instw)
+{
+    VkLayerInstanceDispatchTable *pTable;
+
+    assert(instw);
+    std::unordered_map<void *, VkLayerInstanceDispatchTable *>::const_iterator it = tableInstanceMap.find((void *) instw->baseObject);
+    if (it == tableInstanceMap.end())
+    {
+        pTable =  new VkLayerInstanceDispatchTable;
+        tableInstanceMap[(void *) instw->baseObject] = pTable;
+    } else
+    {
+        return it->second;
+    }
+
+    layer_init_instance_dispatch_table(pTable, (PFN_vkGetInstanceProcAddr) instw->pGPA, (VkInstance) instw->nextObject);
+
+    return pTable;
+}
 
 VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
 {
@@ -1029,9 +1049,9 @@
     if (inst == NULL)
         return NULL;
 
-    //TODO initLayerTable((const VkBaseLayerObject *) inst);
+    initLayerInstanceTable((const VkBaseLayerObject *) inst);
 
-    // TODO loader_platform_thread_once(&g_initOnce, initInstanceLayer);
+    loader_platform_thread_once(&g_initOnce, initLayer);
 
 #define ADD_HOOK(fn)    \
     if (!strncmp(#fn, pName, sizeof(#fn))) \