blob: 318b87d66c13bb6b16de90fd22f2b16c48ae88bc [file] [log] [blame]
/*
*
* Copyright (C) 2015-2016 Valve Corporation
* Copyright (C) 2015-2016 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Jon Ashburn <jon@lunarg.com>
*
*/
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <unordered_map>
#include "vk_loader_platform.h"
#include "vulkan/vk_layer.h"
#include "vk_layer_table.h"
template<typename T>
VkResult EnumerateProperties(uint32_t src_count, const T *src_props, uint32_t *dst_count, T *dst_props) {
if (!dst_props || !src_props) {
*dst_count = src_count;
return VK_SUCCESS;
}
uint32_t copy_count = (*dst_count < src_count) ? *dst_count : src_count;
memcpy(dst_props, src_props, sizeof(T) * copy_count);
*dst_count = copy_count;
return (copy_count == src_count) ? VK_SUCCESS : VK_INCOMPLETE;
}
#ifdef __cplusplus
extern "C" {
#endif
enum {
LAYER_MULTI1,
LAYER_MULTI2,
LAYER_COUNT,
};
static const VkLayerProperties all_layer_props[LAYER_COUNT] = {
{
"VK_LAYER_LUNARG_multi1",
VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION), // specVersion
1, // implementationVersion
"LunarG Sample multiple layer per library",
},
{
"VK_LAYER_LUNARG_multi2",
VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION), // specVersion
1, // implementationVersion
"LunarG Sample multiple layer per library",
},
};
static const struct {
uint32_t count;
const VkExtensionProperties* extensions;
} all_extension_props[LAYER_COUNT] = {
{ 0, NULL, },
{ 0, NULL, },
};
static device_table_map multi1_device_table_map;
static instance_table_map multi1_instance_table_map;
static std::unordered_map<dispatch_key, VkInstance> multi1_instance_map;
/******************************** Layer multi1 functions **************************/
VKAPI_ATTR VkResult VKAPI_CALL
multi1CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
assert(chain_info->u.pLayerInfo);
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
if (fpCreateInstance == NULL) {
return VK_ERROR_INITIALIZATION_FAILED;
}
// Advance the link info for the next element on the chain
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
if (result != VK_SUCCESS)
return result;
multi1_instance_map[get_dispatch_key(*pInstance)] = *pInstance;
initInstanceTable(*pInstance, fpGetInstanceProcAddr, multi1_instance_table_map);
return result;
}
/* hook DestroyInstance to remove tableInstanceMap entry */
VKAPI_ATTR void VKAPI_CALL multi1DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(multi1_instance_table_map, instance);
dispatch_key key = get_dispatch_key(instance);
printf("At start of wrapped multi1 vkDestroyInstance()\n");
pDisp->DestroyInstance(instance, pAllocator);
multi1_instance_table_map.erase(key);
multi1_instance_map.erase(key);
printf("Completed multi1 layer vkDestroyInstance()\n");
}
VKAPI_ATTR VkResult VKAPI_CALL multi1CreateDevice(VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
printf("At start of multi1 layer vkCreateDevice()\n");
VkLayerDeviceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
assert(chain_info->u.pLayerInfo);
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
VkInstance instance = multi1_instance_map[get_dispatch_key(physicalDevice)];
PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance, "vkCreateDevice");
if (fpCreateDevice == NULL) {
return VK_ERROR_INITIALIZATION_FAILED;
}
// Advance the link info for the next element on the chain
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
VkResult result = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
if (result != VK_SUCCESS) {
return result;
}
initDeviceTable(*pDevice, fpGetDeviceProcAddr, multi1_device_table_map);
printf("Completed multi1 layer vkCreateDevice() call");
return result;
}
/* hook DestroyDevice to remove tableMap entry */
VKAPI_ATTR void VKAPI_CALL multi1DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) {
VkLayerDispatchTable *pDisp = get_dispatch_table(multi1_device_table_map, device);
dispatch_key key = get_dispatch_key(device);
printf("At start of multi1 layer vkDestroyDevice()\n");
pDisp->DestroyDevice(device, pAllocator);
multi1_device_table_map.erase(key);
printf("Completed multi1 layer vkDestroyDevice()\n");
}
VKAPI_ATTR VkResult VKAPI_CALL multi1CreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) {
VkLayerDispatchTable *pDisp = get_dispatch_table(multi1_device_table_map, device);
printf("At start of multi1 layer vkCreateSampler()\n");
VkResult result = pDisp->CreateSampler(device, pCreateInfo, pAllocator, pSampler);
printf("Completed multi1 layer vkCreateSampler()\n");
return result;
}
VKAPI_ATTR VkResult VKAPI_CALL
multi1CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t count,
const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator,
VkPipeline *pPipelines) {
VkLayerDispatchTable *pDisp = get_dispatch_table(multi1_device_table_map, device);
printf("At start of multi1 layer vkCreateGraphicsPipeline()\n");
VkResult result = pDisp->CreateGraphicsPipelines(device, pipelineCache, count, pCreateInfos, pAllocator, pPipelines);
printf("Completed multi1 layer vkCreateGraphicsPipeline()\n");
return result;
}
VKAPI_ATTR VkResult VKAPI_CALL
multi1EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties)
{
return EnumerateProperties(1, &all_layer_props[LAYER_MULTI1], pCount, pProperties);
}
VKAPI_ATTR VkResult VKAPI_CALL
multi1EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties)
{
return EnumerateProperties(1, &all_layer_props[LAYER_MULTI1], pCount, pProperties);
}
VKAPI_ATTR VkResult VKAPI_CALL
multi1EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties)
{
if (pLayerName && !strcmp(pLayerName, all_layer_props[LAYER_MULTI1].layerName)) {
return EnumerateProperties(all_extension_props[LAYER_MULTI1].count,
all_extension_props[LAYER_MULTI1].extensions, pCount, pProperties);
}
return VK_ERROR_LAYER_NOT_PRESENT;
}
VKAPI_ATTR VkResult VKAPI_CALL
multi1EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
const char *pLayerName, uint32_t *pCount,
VkExtensionProperties *pProperties)
{
if (pLayerName && !strcmp(pLayerName, all_layer_props[LAYER_MULTI1].layerName)) {
return EnumerateProperties(all_extension_props[LAYER_MULTI1].count,
all_extension_props[LAYER_MULTI1].extensions, pCount, pProperties);
}
VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(multi1_instance_table_map, physicalDevice);
return pDisp->EnumerateDeviceExtensionProperties(physicalDevice, pLayerName, pCount, pProperties);
}
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL multi1GetDeviceProcAddr(VkDevice device, const char *pName) {
if (!strcmp(pName, "multi1GetDeviceProcAddr") || !strcmp(pName, "vkGetDeviceProcAddr"))
return (PFN_vkVoidFunction)multi1GetDeviceProcAddr;
if (!strcmp("vkDestroyDevice", pName))
return (PFN_vkVoidFunction)multi1DestroyDevice;
if (!strcmp("vkCreateSampler", pName))
return (PFN_vkVoidFunction)multi1CreateSampler;
if (!strcmp("vkCreateGraphicsPipelines", pName))
return (PFN_vkVoidFunction)multi1CreateGraphicsPipelines;
if (device == NULL)
return NULL;
VkLayerDispatchTable *pTable = get_dispatch_table(multi1_device_table_map, device);
if (pTable->GetDeviceProcAddr == NULL)
return NULL;
return pTable->GetDeviceProcAddr(device, pName);
}
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL multi1GetInstanceProcAddr(VkInstance instance, const char *pName) {
if (!strcmp("vkEnumerateInstanceLayerProperties", pName))
return (PFN_vkVoidFunction)multi1EnumerateInstanceLayerProperties;
if (!strcmp("vkEnumerateDeviceLayerProperties", pName))
return (PFN_vkVoidFunction)multi1EnumerateDeviceLayerProperties;
if (!strcmp("vkEnumerateInstanceExtensionProperties", pName))
return (PFN_vkVoidFunction)multi1EnumerateInstanceExtensionProperties;
if (!strcmp("vkEnumerateDeviceExtensionProperties", pName))
return (PFN_vkVoidFunction)multi1EnumerateDeviceExtensionProperties;
if (!strcmp(pName, "multi1GetInstanceProcAddr") || !strcmp(pName, "vkGetInsatnceProcAddr"))
return (PFN_vkVoidFunction)multi1GetInstanceProcAddr;
if (!strcmp("vkCreateInstance", pName))
return (PFN_vkVoidFunction)multi1CreateInstance;
if (!strcmp("vkCreateDevice", pName))
return (PFN_vkVoidFunction)multi1CreateDevice;
if (!strcmp("vkDestroyInstance", pName))
return (PFN_vkVoidFunction)multi1DestroyInstance;
assert(instance);
PFN_vkVoidFunction proc = multi1GetDeviceProcAddr(VK_NULL_HANDLE, pName);
if (proc)
return proc;
VkLayerInstanceDispatchTable *pTable = get_dispatch_table(multi1_instance_table_map, instance);
if (pTable->GetInstanceProcAddr == NULL)
return NULL;
return pTable->GetInstanceProcAddr(instance, pName);
}
static instance_table_map multi2_instance_table_map;
/******************************** Layer multi2 functions **************************/
VKAPI_ATTR VkResult VKAPI_CALL
multi2CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
assert(chain_info->u.pLayerInfo);
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
if (fpCreateInstance == NULL) {
return VK_ERROR_INITIALIZATION_FAILED;
}
// Advance the link info for the next element on the chain
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
if (result != VK_SUCCESS)
return result;
initInstanceTable(*pInstance, fpGetInstanceProcAddr, multi2_instance_table_map);
return result;
}
VKAPI_ATTR VkResult VKAPI_CALL
multi2EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) {
VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(multi2_instance_table_map, instance);
printf("At start of wrapped multi2 vkEnumeratePhysicalDevices()\n");
VkResult result = pDisp->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
printf("Completed multi2 layer vkEnumeratePhysicalDevices()\n");
return result;
}
VKAPI_ATTR void VKAPI_CALL
multi2GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) {
VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(multi2_instance_table_map, physicalDevice);
printf("At start of wrapped multi2 vkGetPhysicalDeviceProperties()\n");
pDisp->GetPhysicalDeviceProperties(physicalDevice, pProperties);
printf("Completed multi2 layer vkGetPhysicalDeviceProperties()\n");
}
VKAPI_ATTR void VKAPI_CALL
multi2GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures) {
VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(multi2_instance_table_map, physicalDevice);
printf("At start of wrapped multi2 vkGetPhysicalDeviceFeatures()\n");
pDisp->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
printf("Completed multi2 layer vkGetPhysicalDeviceFeatures()\n");
}
/* hook DestroyInstance to remove tableInstanceMap entry */
VKAPI_ATTR void VKAPI_CALL multi2DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(multi2_instance_table_map, instance);
dispatch_key key = get_dispatch_key(instance);
printf("At start of wrapped multi2 vkDestroyInstance()\n");
pDisp->DestroyInstance(instance, pAllocator);
multi2_instance_table_map.erase(key);
printf("Completed multi2 layer vkDestroyInstance()\n");
}
VKAPI_ATTR VkResult VKAPI_CALL
multi2EnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties)
{
return EnumerateProperties(1, &all_layer_props[LAYER_MULTI2], pCount, pProperties);
}
VKAPI_ATTR VkResult VKAPI_CALL
multi2EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties)
{
return EnumerateProperties(1, &all_layer_props[LAYER_MULTI2], pCount, pProperties);
}
VKAPI_ATTR VkResult VKAPI_CALL
multi2EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties)
{
if (pLayerName && !strcmp(pLayerName, all_layer_props[LAYER_MULTI2].layerName)) {
return EnumerateProperties(all_extension_props[LAYER_MULTI2].count,
all_extension_props[LAYER_MULTI2].extensions, pCount, pProperties);
}
return VK_ERROR_LAYER_NOT_PRESENT;
}
VKAPI_ATTR VkResult VKAPI_CALL
multi2EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
const char *pLayerName, uint32_t *pCount,
VkExtensionProperties *pProperties)
{
if (pLayerName && !strcmp(pLayerName, all_layer_props[LAYER_MULTI2].layerName)) {
return EnumerateProperties(all_extension_props[LAYER_MULTI2].count,
all_extension_props[LAYER_MULTI2].extensions, pCount, pProperties);
}
VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(multi2_instance_table_map, physicalDevice);
return pDisp->EnumerateDeviceExtensionProperties(physicalDevice, pLayerName, pCount, pProperties);
}
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL multi2GetInstanceProcAddr(VkInstance inst, const char *pName) {
if (!strcmp("vkEnumerateInstanceLayerProperties", pName))
return (PFN_vkVoidFunction)multi2EnumerateInstanceLayerProperties;
if (!strcmp("vkEnumerateDeviceLayerProperties", pName))
return (PFN_vkVoidFunction)multi2EnumerateDeviceLayerProperties;
if (!strcmp("vkEnumerateInstanceExtensionProperties", pName))
return (PFN_vkVoidFunction)multi2EnumerateInstanceExtensionProperties;
if (!strcmp("vkEnumerateDeviceExtensionProperties", pName))
return (PFN_vkVoidFunction)multi2EnumerateDeviceExtensionProperties;
if (!strcmp("vkCreateInstance", pName))
return (PFN_vkVoidFunction)multi2CreateInstance;
if (!strcmp(pName, "multi2GetInstanceProcAddr") || !strcmp(pName, "vkGetInstanceProcAddr"))
return (PFN_vkVoidFunction)multi2GetInstanceProcAddr;
if (!strcmp("vkEnumeratePhysicalDevices", pName))
return (PFN_vkVoidFunction)multi2EnumeratePhysicalDevices;
if (!strcmp("GetPhysicalDeviceProperties", pName))
return (PFN_vkVoidFunction)multi2GetPhysicalDeviceProperties;
if (!strcmp("GetPhysicalDeviceFeatures", pName))
return (PFN_vkVoidFunction)multi2GetPhysicalDeviceFeatures;
if (!strcmp("vkDestroyInstance", pName))
return (PFN_vkVoidFunction)multi2DestroyInstance;
if (inst == NULL)
return NULL;
VkLayerInstanceDispatchTable *pTable = get_dispatch_table(multi2_instance_table_map, inst);
if (pTable->GetInstanceProcAddr == NULL)
return NULL;
return pTable->GetInstanceProcAddr(inst, pName);
}
// loader-layer interface v0
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties)
{
return EnumerateProperties(LAYER_COUNT, all_layer_props, pCount, pProperties);
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pCount, VkLayerProperties *pProperties)
{
// multi2 does not intercept any device-level command
return multi1EnumerateDeviceLayerProperties(physicalDevice, pCount, pProperties);
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties)
{
assert(pLayerName);
for (int i = 0; i < LAYER_COUNT; i++) {
if (!strcmp(pLayerName, all_layer_props[i].layerName)) {
return EnumerateProperties(all_extension_props[i].count,
all_extension_props[i].extensions, pCount, pProperties);
}
}
assert(!"unreachable");
*pCount = 0;
return VK_SUCCESS;
}
VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL
vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
const char *pLayerName, uint32_t *pCount,
VkExtensionProperties *pProperties)
{
assert(physicalDevice == VK_NULL_HANDLE && pLayerName);
for (int i = 0; i < LAYER_COUNT; i++) {
if (!strcmp(pLayerName, all_layer_props[i].layerName)) {
return EnumerateProperties(all_extension_props[i].count,
all_extension_props[i].extensions, pCount, pProperties);
}
}
assert(!"unreachable");
*pCount = 0;
return VK_SUCCESS;
}
VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL VK_LAYER_LUNARG_multi1GetDeviceProcAddr(VkDevice device, const char *pName) {
return multi1GetDeviceProcAddr(device, pName);
}
VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL VK_LAYER_LUNARG_multi1GetInstanceProcAddr(VkInstance instance, const char *pName) {
if (!strcmp(pName, "vkEnumerateInstanceLayerProperties"))
return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceLayerProperties);
if (!strcmp(pName, "vkEnumerateDeviceLayerProperties"))
return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateDeviceLayerProperties);
if (!strcmp(pName, "vkEnumerateInstanceExtensionProperties"))
return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceExtensionProperties);
if (!strcmp(pName, "vkGetInstanceProcAddr"))
return reinterpret_cast<PFN_vkVoidFunction>(VK_LAYER_LUNARG_multi1GetInstanceProcAddr);
return multi1GetInstanceProcAddr(instance, pName);
}
VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL VK_LAYER_LUNARG_multi2GetInstanceProcAddr(VkInstance instance, const char *pName) {
if (!strcmp(pName, "vkEnumerateInstanceLayerProperties"))
return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceLayerProperties);
if (!strcmp(pName, "vkEnumerateDeviceLayerProperties"))
return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateDeviceLayerProperties);
if (!strcmp(pName, "vkEnumerateInstanceExtensionProperties"))
return reinterpret_cast<PFN_vkVoidFunction>(vkEnumerateInstanceExtensionProperties);
if (!strcmp(pName, "vkGetInstanceProcAddr"))
return reinterpret_cast<PFN_vkVoidFunction>(VK_LAYER_LUNARG_multi2GetInstanceProcAddr);
return multi2GetInstanceProcAddr(instance, pName);
}
#ifdef __cplusplus
} // extern "C"
#endif