| /* | 
 |  * Vulkan | 
 |  * | 
 |  * Copyright (C) 2014 LunarG, Inc. | 
 |  * | 
 |  * Permission is hereby granted, free of charge, to any person obtaining a | 
 |  * copy of this software and associated documentation files (the "Software"), | 
 |  * to deal in the Software without restriction, including without limitation | 
 |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | 
 |  * and/or sell copies of the Software, and to permit persons to whom the | 
 |  * Software is furnished to do so, subject to the following conditions: | 
 |  * | 
 |  * The above copyright notice and this permission notice shall be included | 
 |  * in all copies or substantial portions of the Software. | 
 |  * | 
 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | 
 |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | 
 |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
 |  * DEALINGS IN THE SOFTWARE. | 
 |  * | 
 |  */ | 
 |  | 
 | #include <string.h> | 
 | #include <stdlib.h> | 
 | #include <assert.h> | 
 | #include <unordered_map> | 
 | #include "vk_loader_platform.h" | 
 | #include "vk_dispatch_table_helper.h" | 
 | #include "vk_layer.h" | 
 | // The following is #included again to catch certain OS-specific functions | 
 | // being used: | 
 | #include "vk_loader_platform.h" | 
 | #include "vk_layer_extension_utils.h" | 
 |  | 
 | static void initLayerTable(const VkBaseLayerObject *devw, VkLayerDispatchTable *pTable, const unsigned int layerNum); | 
 | static void initLayerInstanceTable(const VkBaseLayerObject *instw, VkLayerInstanceDispatchTable *pTable, const unsigned int layerNum); | 
 | /* Various dispatchable objects will use the same underlying dispatch table if they | 
 |  * are created from that "parent" object. Thus use pointer to dispatch table | 
 |  * as the key to table maps (tableMap1, tableInstanceMap1, tableMap2, tableInstanceMap2. | 
 |  *    Instance -> PhysicalDevice | 
 |  *    Device -> CmdBuffer or Queue | 
 |  * If use the object themselves as key to map then implies Create entrypoints have to be intercepted | 
 |  * and a new key inserted into map */ | 
 | /******************************** Layer multi1 functions **************************/ | 
 | static std::unordered_map<void *, VkLayerDispatchTable *> tableMap1; | 
 | static std::unordered_map<void *, VkLayerInstanceDispatchTable *> tableInstanceMap1; | 
 | static bool layer1_first_activated = false; | 
 |  | 
 | // Map lookup must be thread safe | 
 | static inline VkLayerDispatchTable *device_dispatch_table1(VkObject object) | 
 | { | 
 |     VkLayerDispatchTable *pDisp  = *(VkLayerDispatchTable **) object; | 
 |     std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap1.find((void *) pDisp); | 
 |     assert(it != tableMap1.end() && "Not able to find device dispatch entry"); | 
 |     return it->second; | 
 | } | 
 |  | 
 | static inline VkLayerInstanceDispatchTable *instance_dispatch_table1(VkObject object) | 
 | { | 
 |     VkLayerInstanceDispatchTable *pDisp = *(VkLayerInstanceDispatchTable **) object; | 
 |     std::unordered_map<void *, VkLayerInstanceDispatchTable *>::const_iterator it = tableInstanceMap1.find((void *) pDisp); | 
 |     assert(it != tableInstanceMap1.end() && "Not able to find instance dispatch entry"); | 
 |     return it->second; | 
 | } | 
 |  | 
 | static VkLayerDispatchTable *getLayer1Table(const VkBaseLayerObject *devw) | 
 | { | 
 |     VkLayerDispatchTable *pTable; | 
 |     assert(devw); | 
 |     VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) devw->baseObject; | 
 |  | 
 |     std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap1.find((void *) *ppDisp); | 
 |     if (it == tableMap1.end()) | 
 |     { | 
 |         pTable =  new VkLayerDispatchTable; | 
 |         tableMap1[(void *) *ppDisp] = pTable; | 
 |         initLayerTable(devw, pTable, 1); | 
 |         return pTable; | 
 |     } else | 
 |     { | 
 |         return it->second; | 
 |     } | 
 | } | 
 | static VkLayerInstanceDispatchTable *getLayer1InstanceTable(const VkBaseLayerObject *instw) | 
 | { | 
 |     VkLayerInstanceDispatchTable *pTable; | 
 |     assert(instw); | 
 |     VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) instw->baseObject; | 
 |  | 
 |     std::unordered_map<void *, VkLayerInstanceDispatchTable *>::const_iterator it = tableInstanceMap1.find((void *) *ppDisp); | 
 |     if (it == tableInstanceMap1.end()) | 
 |     { | 
 |         pTable =  new VkLayerInstanceDispatchTable; | 
 |         tableInstanceMap1[(void *) *ppDisp] = pTable; | 
 |         initLayerInstanceTable(instw, pTable, 1); | 
 |         return pTable; | 
 |     } else | 
 |     { | 
 |         return it->second; | 
 |     } | 
 | } | 
 | #ifdef __cplusplus | 
 | extern "C" { | 
 | #endif | 
 |  | 
 | /* hook DestroyDevice to remove tableMap entry */ | 
 | VK_LAYER_EXPORT VkResult VKAPI multi1DestroyDevice(VkDevice device) | 
 | { | 
 |     VkLayerDispatchTable *pDisp = *(VkLayerDispatchTable **) device; | 
 |     VkResult res = device_dispatch_table1(device)->DestroyDevice(device); | 
 |     tableMap1.erase(pDisp); | 
 |     return res; | 
 | } | 
 |  | 
 | /* hook DestroyInstance to remove tableInstanceMap entry */ | 
 | VK_LAYER_EXPORT VkResult VKAPI multi1DestroyInstance(VkInstance instance) | 
 | { | 
 |     VkLayerInstanceDispatchTable *pDisp = *(VkLayerInstanceDispatchTable **) instance; | 
 |     VkResult res = instance_dispatch_table1(instance)->DestroyInstance(instance); | 
 |     tableInstanceMap1.erase(pDisp); | 
 |     return res; | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI multi1CreateSampler(VkDevice device, const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler) | 
 | { | 
 |     VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device; | 
 |  | 
 |     printf("At start of multi1 layer vkCreateSampler()\n"); | 
 |     VkResult result = device_dispatch_table1(device)->CreateSampler(device, pCreateInfo, pSampler); | 
 |     printf("Completed multi1 layer vkCreateSampler()\n"); | 
 |     return result; | 
 | } | 
 |  | 
 | 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)->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pPipelines); | 
 |     printf("Completed multi1 layer vkCreateGraphicsPipeline()\n"); | 
 |     return result; | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT void * VKAPI multi1GetDeviceProcAddr(VkDevice device, const char* pName) | 
 | { | 
 |     VkBaseLayerObject* devw = (VkBaseLayerObject *) device; | 
 |  | 
 |     if (device == NULL) | 
 |         return NULL; | 
 |  | 
 |  | 
 |  | 
 |     if (!strcmp("vkGetDeviceProcAddr", pName)) { | 
 |         getLayer1Table(devw); | 
 |         return (void *) multi1GetDeviceProcAddr; | 
 |     } | 
 |     if (!strcmp("vkDestroyDevice", pName)) | 
 |         return (void *) multi1DestroyDevice; | 
 |     if (!strcmp("vkCreateSampler", pName)) | 
 |         return (void *) multi1CreateSampler; | 
 |     if (!strcmp("vkCreateGraphicsPipelines", pName)) | 
 |         return (void *) multi1CreateGraphicsPipelines; | 
 |     else { | 
 |         VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device; | 
 |         VkLayerDispatchTable* pTable = device_dispatch_table1(device); | 
 |         if (pTable->GetDeviceProcAddr == NULL) | 
 |             return NULL; | 
 |         return pTable->GetDeviceProcAddr(device, pName); | 
 |     } | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT void * VKAPI multi1GetInstanceProcAddr(VkInstance inst, const char* pName) | 
 | { | 
 |     VkBaseLayerObject* instw = (VkBaseLayerObject *) inst; | 
 |  | 
 |     if (inst == NULL) | 
 |         return NULL; | 
 |  | 
 |  | 
 |  | 
 |     if (!strcmp("vkGetInstanceProcAddr", pName)) { | 
 |         getLayer1InstanceTable(instw); | 
 |         return (void *) multi1GetInstanceProcAddr; | 
 |     } | 
 |     if (!strcmp("vkDestroyInstance", pName)) | 
 |         return (void *) multi1DestroyInstance; | 
 |     if (!strcmp("GetGlobalExtensionProperties", pName)) | 
 |         return (void*) vkGetGlobalExtensionProperties; | 
 |     if (!strcmp("GetGlobalLayerProperties", pName)) | 
 |         return (void*) vkGetGlobalLayerProperties; | 
 |     if (!strcmp("GetPhysicalDeviceExtensionProperties", pName)) | 
 |         return (void*) vkGetPhysicalDeviceExtensionProperties; | 
 |     if (!strcmp("GetPhysicalDeviceLayerProperties", pName)) | 
 |         return (void*) vkGetPhysicalDeviceLayerProperties; | 
 |     else { | 
 |         VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) inst; | 
 |         VkLayerInstanceDispatchTable* pTable = instance_dispatch_table1(inst); | 
 |         if (pTable->GetInstanceProcAddr == NULL) | 
 |             return NULL; | 
 |         return pTable->GetInstanceProcAddr(inst, pName); | 
 |     } | 
 | } | 
 |  | 
 | /******************************** Layer multi2 functions **************************/ | 
 | static std::unordered_map<void *, VkLayerDispatchTable *> tableMap2; | 
 | static std::unordered_map<void *, VkLayerInstanceDispatchTable *> tableInstanceMap2; | 
 | static bool layer2_first_activated = false; | 
 |  | 
 | // Map lookup must be thread safe | 
 | static inline VkLayerDispatchTable *device_dispatch_table2(VkObject object) | 
 | { | 
 |     VkLayerDispatchTable *pDisp  = *(VkLayerDispatchTable **) object; | 
 |     std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap2.find((void *) pDisp); | 
 |     assert(it != tableMap2.end() && "Not able to find device dispatch entry"); | 
 |     return it->second; | 
 | } | 
 |  | 
 | static inline VkLayerInstanceDispatchTable *instance_dispatch_table2(VkObject object) | 
 | { | 
 |     VkLayerInstanceDispatchTable *pDisp = *(VkLayerInstanceDispatchTable **) object; | 
 |     std::unordered_map<void *, VkLayerInstanceDispatchTable *>::const_iterator it = tableInstanceMap2.find((void *) pDisp); | 
 |     assert(it != tableInstanceMap2.end() && "Not able to find instance dispatch entry"); | 
 |     return it->second; | 
 | } | 
 |  | 
 | static VkLayerInstanceDispatchTable *getLayer2InstanceTable(const VkBaseLayerObject *instw) | 
 | { | 
 |     VkLayerInstanceDispatchTable *pTable; | 
 |     assert(instw); | 
 |     VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) instw->baseObject; | 
 |  | 
 |     std::unordered_map<void *, VkLayerInstanceDispatchTable *>::const_iterator it = tableInstanceMap2.find((void *) *ppDisp); | 
 |     if (it == tableInstanceMap2.end()) | 
 |     { | 
 |         pTable =  new VkLayerInstanceDispatchTable; | 
 |         tableInstanceMap2[(void *) *ppDisp] = pTable; | 
 |         initLayerInstanceTable(instw, pTable, 2); | 
 |         return pTable; | 
 |     } else | 
 |     { | 
 |         return it->second; | 
 |     } | 
 | } | 
 |  | 
 | static VkLayerDispatchTable *getLayer2Table(const VkBaseLayerObject *devw) | 
 | { | 
 |     VkLayerDispatchTable *pTable; | 
 |     assert(devw); | 
 |     VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) devw->baseObject; | 
 |  | 
 |     std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap2.find((void *) *ppDisp); | 
 |     if (it == tableMap2.end()) | 
 |     { | 
 |         pTable =  new VkLayerDispatchTable; | 
 |         tableMap2[(void *) *ppDisp] = pTable; | 
 |         initLayerTable(devw, pTable, 2); | 
 |         return pTable; | 
 |     } else | 
 |     { | 
 |         return it->second; | 
 |     } | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI multi2EnumeratePhysicalDevices( | 
 |                                             VkInstance instance, | 
 |                                             uint32_t* pPhysicalDeviceCount, | 
 |                                             VkPhysicalDevice* pPhysicalDevices) | 
 | { | 
 |     VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) instance; | 
 |  | 
 |     printf("At start of wrapped multi2 vkEnumeratePhysicalDevices()\n"); | 
 |     VkResult result = instance_dispatch_table2(instance)->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices); | 
 |     printf("Completed multi2 layer vkEnumeratePhysicalDevices()\n"); | 
 |     return result; | 
 | } | 
 |  | 
 | /* hook DextroyDevice to remove tableMap entry */ | 
 | VK_LAYER_EXPORT VkResult VKAPI multi2DestroyDevice(VkDevice device) | 
 | { | 
 |     VkLayerDispatchTable *pDisp = *(VkLayerDispatchTable **) device; | 
 |     VkResult res = device_dispatch_table2(device)->DestroyDevice(device); | 
 |     tableMap2.erase(pDisp); | 
 |     return res; | 
 | } | 
 |  | 
 | /* hook DestroyInstance to remove tableInstanceMap entry */ | 
 | VK_LAYER_EXPORT VkResult VKAPI multi2DestroyInstance(VkInstance instance) | 
 | { | 
 |     VkLayerInstanceDispatchTable *pDisp = *(VkLayerInstanceDispatchTable **) instance; | 
 |     VkResult res = instance_dispatch_table2(instance)->DestroyInstance(instance); | 
 |     tableInstanceMap2.erase(pDisp); | 
 |     return res; | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI multi2CreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, | 
 |                                                       VkDevice* pDevice) | 
 | { | 
 |     printf("At start of multi2 vkCreateDevice()\n"); | 
 |     VkResult result = device_dispatch_table2(*pDevice)->CreateDevice(gpu, pCreateInfo, pDevice); | 
 |     printf("Completed multi2 layer vkCreateDevice()\n"); | 
 |     return result; | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI multi2CreateCommandBuffer(VkDevice device, const VkCmdBufferCreateInfo* pCreateInfo, | 
 |                                                              VkCmdBuffer* pCmdBuffer) | 
 | { | 
 |     VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device; | 
 |  | 
 |     printf("At start of multi2 layer vkCreateCommandBuffer()\n"); | 
 |     VkResult result = device_dispatch_table2(device)->CreateCommandBuffer(device, pCreateInfo, pCmdBuffer); | 
 |     printf("Completed multi2 layer vkCreateCommandBuffer()\n"); | 
 |     return result; | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI multi2BeginCommandBuffer(VkCmdBuffer cmdBuffer, const VkCmdBufferBeginInfo* pBeginInfo) | 
 | { | 
 |     VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) cmdBuffer; | 
 |  | 
 |     printf("At start of multi2 layer vkBeginCommandBuffer()\n"); | 
 |     VkResult result = device_dispatch_table2(cmdBuffer)->BeginCommandBuffer(cmdBuffer, pBeginInfo); | 
 |     printf("Completed multi2 layer vkBeginCommandBuffer()\n"); | 
 |     return result; | 
 |  | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT void * VKAPI multi2GetDeviceProcAddr(VkDevice device, const char* pName) | 
 | { | 
 |     VkBaseLayerObject* devw = (VkBaseLayerObject *) device; | 
 |  | 
 |     if (device == NULL) | 
 |         return NULL; | 
 |  | 
 |     if (!strcmp("vkGetDeviceProcAddr", pName)) { | 
 |         getLayer2Table(devw); | 
 |         return (void *) multi2GetDeviceProcAddr; | 
 |     } | 
 |     if (!strcmp("vkCreateDevice", pName)) | 
 |         return (void *) multi2CreateDevice; | 
 |     if (!strcmp("vkDestroyDevice", pName)) | 
 |         return (void *) multi2DestroyDevice; | 
 |     if (!strcmp("vkCreateCommandBuffer", pName)) | 
 |         return (void *) multi2CreateCommandBuffer; | 
 |     else if (!strcmp("vkBeginCommandBuffer", pName)) | 
 |         return (void *) multi2BeginCommandBuffer; | 
 |     else { | 
 |         VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device; | 
 |         VkLayerDispatchTable* pTable = device_dispatch_table2(device); | 
 |         if (pTable->GetDeviceProcAddr == NULL) | 
 |             return NULL; | 
 |         return pTable->GetDeviceProcAddr(device, pName); | 
 |     } | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT void * VKAPI multi2GetInstanceProcAddr(VkInstance inst, const char* pName) | 
 | { | 
 |     VkBaseLayerObject* instw = (VkBaseLayerObject *) inst; | 
 |  | 
 |     if (inst == NULL) | 
 |         return NULL; | 
 |  | 
 |     if (!strcmp("vkGetInstanceProcAddr", pName)) { | 
 |         getLayer2InstanceTable(instw); | 
 |         return (void *) multi2GetInstanceProcAddr; | 
 |     } | 
 |     if (!strcmp("vkEnumeratePhysicalDevices", pName)) | 
 |         return (void *) multi2EnumeratePhysicalDevices; | 
 |     if (!strcmp("vkDestroyInstance", pName)) | 
 |         return (void *) multi2DestroyInstance; | 
 |     if (!strcmp("GetGlobalExtensionProperties", pName)) | 
 |         return (void*) vkGetGlobalExtensionProperties; | 
 |     if (!strcmp("GetGlobalLayerProperties", pName)) | 
 |         return (void*) vkGetGlobalLayerProperties; | 
 |     if (!strcmp("GetPhysicalDeviceExtensionProperties", pName)) | 
 |         return (void*) vkGetPhysicalDeviceExtensionProperties; | 
 |     if (!strcmp("GetPhysicalDeviceLayerProperties", pName)) | 
 |         return (void*) vkGetPhysicalDeviceLayerProperties; | 
 |     else { | 
 |         VkLayerInstanceDispatchTable **ppDisp = (VkLayerInstanceDispatchTable **) inst; | 
 |         VkLayerInstanceDispatchTable* pTable = instance_dispatch_table2(inst); | 
 |         if (pTable->GetInstanceProcAddr == NULL) | 
 |             return NULL; | 
 |         return pTable->GetInstanceProcAddr(inst, pName); | 
 |     } | 
 | } | 
 |  | 
 | /********************************* Common functions ********************************/ | 
 |  | 
 | struct extProps { | 
 |     uint32_t version; | 
 |     const char * const name; | 
 | }; | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties( | 
 |         const char *pLayerName, | 
 |         uint32_t *pCount, | 
 |         VkExtensionProperties* pProperties) | 
 | { | 
 |     /* multi does not have any global extensions */ | 
 |     return util_GetExtensionProperties(0, NULL, pCount, pProperties); | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties( | 
 |         uint32_t *pCount, | 
 |         VkLayerProperties*    pProperties) | 
 | { | 
 |     /* multi does not have any global layers */ | 
 |     return util_GetLayerProperties(0, NULL, pCount, pProperties); | 
 | } | 
 |  | 
 | #define MULTI_LAYER_ARRAY_SIZE 1 | 
 | static const VkLayerProperties multi_device_layers[MULTI_LAYER_ARRAY_SIZE] = { | 
 |     { | 
 |         "Multi1", | 
 |         VK_API_VERSION, | 
 |         VK_MAKE_VERSION(0, 1, 0), | 
 |         "Sample layer: multi", | 
 |     } | 
 | }; | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceExtensionProperties( | 
 |         VkPhysicalDevice                            physicalDevice, | 
 |         const char*                                 pLayerName, | 
 |         uint32_t*                                   pCount, | 
 |         VkExtensionProperties*                      pProperties) | 
 | { | 
 |     /* Multi does not have any physical device extensions */ | 
 |     return util_GetExtensionProperties(0, NULL, pCount, pProperties); | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceLayerProperties( | 
 |         VkPhysicalDevice                            physicalDevice, | 
 |         uint32_t*                                   pCount, | 
 |         VkLayerProperties*                          pProperties) | 
 | { | 
 |     return util_GetLayerProperties(MULTI_LAYER_ARRAY_SIZE, multi_device_layers, | 
 |                                    pCount, pProperties); | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char* pName) | 
 | { | 
 |     // to find each layers GPA routine Loader will search via "<layerName>GetDeviceProcAddr" | 
 |     if (!strcmp("multi1GetDeviceProcAddr", pName)) | 
 |         return (void *) multi1GetDeviceProcAddr; | 
 |     else if (!strcmp("multi2GetDeviceProcAddr", pName)) | 
 |         return (void *) multi2GetDeviceProcAddr; | 
 |     else if (!strcmp("vkGetDeviceProcAddr", pName)) | 
 |         return (void *) vkGetDeviceProcAddr; | 
 |  | 
 |     // use first layer activated as GPA dispatch table activation happens in order | 
 |     else if (layer1_first_activated) | 
 |         return multi1GetDeviceProcAddr(device, pName); | 
 |     else if (layer2_first_activated) | 
 |         return multi2GetDeviceProcAddr(device, pName); | 
 |     else | 
 |         return NULL; | 
 |  | 
 | } | 
 |  | 
 | VK_LAYER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance inst, const char* pName) | 
 | { | 
 |     // to find each layers GPA routine Loader will search via "<layerName>GetInstanceProcAddr" | 
 |     if (!strcmp("multi1GetInstanceProcAddr", pName)) | 
 |         return (void *) multi1GetInstanceProcAddr; | 
 |     else if (!strcmp("multi2GetInstanceProcAddr", pName)) | 
 |         return (void *) multi2GetInstanceProcAddr; | 
 |     else if (!strcmp("vkGetInstanceProcAddr", pName)) | 
 |         return (void *) vkGetInstanceProcAddr; | 
 |  | 
 |     // use first layer activated as GPA dispatch table activation happens in order | 
 |     else if (layer1_first_activated) | 
 |         return multi1GetInstanceProcAddr(inst, pName); | 
 |     else if (layer2_first_activated) | 
 |         return multi2GetInstanceProcAddr(inst, pName); | 
 |     else | 
 |         return NULL; | 
 |  | 
 | } | 
 | #ifdef __cplusplus | 
 | }    //extern "C" | 
 | #endif | 
 |  | 
 | static void initLayerTable(const VkBaseLayerObject *devw, VkLayerDispatchTable *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_initialize_dispatch_table(pTable, devw); | 
 | } | 
 |  | 
 | 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, instw); | 
 | } |