blob: 574e5c23c3d84f39b0fa95c26ae861cd73c6eb31 [file] [log] [blame]
/*
* 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);
}