/* * 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 #include #include #include #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 tableMap1; static std::unordered_map 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::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::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::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::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 multi1CreateGraphicsPipeline(VkDevice device, const VkGraphicsPipelineCreateInfo* pCreateInfo, VkPipeline* pPipeline) { VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device; printf("At start of multi1 layer vkCreateGraphicsPipeline()\n"); VkResult result = device_dispatch_table1(device)->CreateGraphicsPipeline(device, pCreateInfo, pPipeline); printf("Completed multi1 layer vkCreateGraphicsPipeline()\n"); return result; } VK_LAYER_EXPORT VkResult VKAPI multi1StorePipeline(VkDevice device, VkPipeline pipeline, size_t* pDataSize, void* pData) { VkLayerDispatchTable **ppDisp = (VkLayerDispatchTable **) device; printf("At start of multi1 layer vkStorePipeline()\n"); VkResult result = device_dispatch_table1(device)->StorePipeline(device, pipeline, pDataSize, pData); printf("Completed multi1 layer vkStorePipeline()\n"); return result; } VK_LAYER_EXPORT void * VKAPI multi1GetDeviceProcAddr(VkDevice device, const char* pName) { VkBaseLayerObject* devw = (VkBaseLayerObject *) device; 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("vkCreateGraphicsPipeline", pName)) return (void *) multi1CreateGraphicsPipeline; if (!strcmp("vkStorePipeline", pName)) return (void *) multi1StorePipeline; 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 tableMap2; static std::unordered_map 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::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::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::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::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 "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 "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); }