1 /*
2  * Copyright (c) 2015-2016 Valve Corporation
3  * Copyright (c) 2015-2016 LunarG, Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Author: Jeremy Hayes <jeremy@lunarg.com>
18  */
19 
20 #include <cassert>
21 #include <iostream>
22 #include <unordered_map>
23 #include <vector>
24 
25 #include "vk_dispatch_table_helper.h"
26 #include "vk_layer_data.h"
27 #include "vk_layer_extension_utils.h"
28 
29 namespace test
30 {
31 
32 struct layer_data {
33     VkInstance instance;
34     VkLayerInstanceDispatchTable *instance_dispatch_table;
35 
layer_datatest::layer_data36     layer_data() : instance(VK_NULL_HANDLE), instance_dispatch_table(nullptr) {};
37 };
38 
39 static uint32_t loader_layer_if_version = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
40 
41 static std::unordered_map<void *, layer_data *> layer_data_map;
42 
CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)43 VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
44 		VkInstance* pInstance)
45 {
46     VkLayerInstanceCreateInfo *chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
47     assert(chain_info != nullptr);
48 
49     assert(chain_info->u.pLayerInfo != nullptr);
50     PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
51     assert(fpGetInstanceProcAddr != nullptr);
52 
53     PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance) fpGetInstanceProcAddr(NULL, "vkCreateInstance");
54     if (fpCreateInstance == nullptr)
55     {
56         return VK_ERROR_INITIALIZATION_FAILED;
57     }
58 
59     chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
60     VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
61     if (result != VK_SUCCESS)
62     {
63         return result;
64     }
65 
66     VkLayerInstanceCreateInfo *create_dev_info = get_chain_info(pCreateInfo, VK_LOADER_LAYER_CREATE_DEVICE_CALLBACK);
67     assert(create_dev_info != nullptr);
68     auto layer_create_device = create_dev_info->u.layerDevice.pfnLayerCreateDevice;
69     auto layer_destroy_device = create_dev_info->u.layerDevice.pfnLayerDestroyDevice;
70 
71     layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(*pInstance), layer_data_map);
72     instance_data->instance = *pInstance;
73     instance_data->instance_dispatch_table = new VkLayerInstanceDispatchTable;
74     layer_init_instance_dispatch_table(*pInstance, instance_data->instance_dispatch_table, fpGetInstanceProcAddr);
75 
76     uint32_t count = 0;
77     instance_data->instance_dispatch_table->EnumeratePhysicalDevices(*pInstance, &count, nullptr);
78     std::vector<VkPhysicalDevice> devices(count);
79     instance_data->instance_dispatch_table->EnumeratePhysicalDevices(*pInstance, &count, devices.data());
80     VkDevice device;
81     auto device_create_info = VkDeviceCreateInfo{
82         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,  // sType
83         nullptr,                               // pNext
84         0,                                     // flags
85         0,                                     // queueCreateInfoCount
86         nullptr,                               // pQueueCreateInfos
87         0,                                     // enabledLayerCount
88         nullptr,                               // ppEnabledLayerNames
89         0,                                     // enabledExtensionCount
90         nullptr,                               // ppEnabledExtensionNames
91         nullptr                                // pEnabledFeatures
92     };
93     auto deviceQueue = VkDeviceQueueCreateInfo{};
94     deviceQueue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
95     float prios = 1;
96     deviceQueue.queueFamilyIndex = 0;
97     deviceQueue.queueCount = 1;
98     deviceQueue.pQueuePriorities = &prios;
99     device_create_info.pQueueCreateInfos = &deviceQueue;
100     device_create_info.queueCreateInfoCount = 1;
101 
102     PFN_vkGetDeviceProcAddr newGDPA = nullptr;
103     layer_create_device(*pInstance, devices[0], &device_create_info, nullptr, &device, vkGetInstanceProcAddr, &newGDPA);
104     assert(newGDPA != nullptr);
105     PFN_vkDestroyDevice destroy = (PFN_vkDestroyDevice)newGDPA(device, "vkDestroyDevice");
106     layer_destroy_device(device, nullptr, destroy);
107 
108     std::cout << "VK_LAYER_LUNARG_test: device count " << count << '\n';
109 
110     // Marker for testing.
111     std::cout << "VK_LAYER_LUNARG_test: CreateInstance" << '\n';
112 
113     return result;
114 }
115 
DestroyInstance(VkInstance instance,const VkAllocationCallbacks * pAllocator)116 VKAPI_ATTR void VKAPI_CALL DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator)
117 {
118     dispatch_key key = get_dispatch_key(instance);
119     layer_data *instance_data = GetLayerDataPtr(key, layer_data_map);
120     instance_data->instance_dispatch_table->DestroyInstance(instance, pAllocator);
121 
122     delete instance_data->instance_dispatch_table;
123     layer_data_map.erase(key);
124 
125     // Marker for testing.
126     std::cout << "VK_LAYER_LUNARG_test: DestroyInstance" << '\n';
127 }
128 
GetInstanceProcAddr(VkInstance instance,const char * funcName)129 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char* funcName)
130 {
131     // Return the functions that are intercepted by this layer.
132     static const struct
133     {
134         const char *name;
135         PFN_vkVoidFunction proc;
136     } core_instance_commands[] =
137     {
138         { "vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr) },
139         { "vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(CreateInstance) },
140         { "vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance) }
141     };
142 
143     for (size_t i = 0; i < ARRAY_SIZE(core_instance_commands); i++)
144     {
145         if (!strcmp(core_instance_commands[i].name, funcName))
146         {
147             return core_instance_commands[i].proc;
148         }
149     }
150 
151     // Only call down the chain for Vulkan commands that this layer does not intercept.
152     layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
153     VkLayerInstanceDispatchTable *pTable = instance_data->instance_dispatch_table;
154     if (pTable->GetInstanceProcAddr == nullptr)
155     {
156         return nullptr;
157     }
158 
159     return pTable->GetInstanceProcAddr(instance, funcName);
160 }
161 
GetPhysicalDeviceProcAddr(VkInstance instance,const char * funcName)162 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
163     assert(instance);
164 
165     layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(instance), layer_data_map);
166     VkLayerInstanceDispatchTable *pTable = instance_data->instance_dispatch_table;
167     if (pTable->GetPhysicalDeviceProcAddr == nullptr)
168     {
169         return nullptr;
170     }
171 
172     return pTable->GetPhysicalDeviceProcAddr(instance, funcName);
173 }
174 
175 }
176 
vkGetInstanceProcAddr(VkInstance instance,const char * funcName)177 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
178 {
179     return test::GetInstanceProcAddr(instance, funcName);
180 }
181 
vkEnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pCount,VkExtensionProperties * pProperties)182 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pCount, VkExtensionProperties *pProperties)
183 {
184     return VK_ERROR_LAYER_NOT_PRESENT;
185 }
186 
vkEnumerateInstanceLayerProperties(uint32_t * pCount,VkLayerProperties * pProperties)187 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pCount, VkLayerProperties *pProperties)
188 {
189     return VK_ERROR_LAYER_NOT_PRESENT;
190 }
191 
vk_layerGetPhysicalDeviceProcAddr(VkInstance instance,const char * funcName)192 VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_layerGetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
193     return test::GetPhysicalDeviceProcAddr(instance, funcName);
194 }
195 
vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface * pVersionStruct)196 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct) {
197     assert(pVersionStruct != NULL);
198     assert(pVersionStruct->sType == LAYER_NEGOTIATE_INTERFACE_STRUCT);
199 
200     // Fill in the function pointers if our version is at least capable of having the structure contain them.
201     if (pVersionStruct->loaderLayerInterfaceVersion >= 2) {
202         pVersionStruct->pfnGetInstanceProcAddr = vkGetInstanceProcAddr;
203         pVersionStruct->pfnGetPhysicalDeviceProcAddr = vk_layerGetPhysicalDeviceProcAddr;
204     }
205 
206     if (pVersionStruct->loaderLayerInterfaceVersion < CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
207         test::loader_layer_if_version = pVersionStruct->loaderLayerInterfaceVersion;
208     } else if (pVersionStruct->loaderLayerInterfaceVersion > CURRENT_LOADER_LAYER_INTERFACE_VERSION) {
209         pVersionStruct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
210     }
211 
212     return VK_SUCCESS;
213 }
214