1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
2  * Copyright (c) 2015-2016 Valve Corporation
3  * Copyright (c) 2015-2016 LunarG, Inc.
4  * Copyright (c) 2015-2016 Google, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and/or associated documentation files (the "Materials"), to
8  * deal in the Materials without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Materials, and to permit persons to whom the Materials
11  * are furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice(s) and this permission notice shall be included
14  * in all copies or substantial portions of the Materials.
15  *
16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23  * USE OR OTHER DEALINGS IN THE MATERIALS
24  *
25  * Author: Tobin Ehlis <tobin@lunarg.com>
26  */
27 #include <assert.h>
28 #include <unordered_map>
29 #include "vk_dispatch_table_helper.h"
30 #include "vulkan/vk_layer.h"
31 #include "vk_layer_table.h"
32 static device_table_map tableMap;
33 static instance_table_map tableInstanceMap;
34 
35 #define DISPATCH_MAP_DEBUG 0
36 
37 // Map lookup must be thread safe
device_dispatch_table(void * object)38 VkLayerDispatchTable *device_dispatch_table(void *object) {
39     dispatch_key key = get_dispatch_key(object);
40     device_table_map::const_iterator it = tableMap.find((void *)key);
41     assert(it != tableMap.end() && "Not able to find device dispatch entry");
42     return it->second;
43 }
44 
instance_dispatch_table(void * object)45 VkLayerInstanceDispatchTable *instance_dispatch_table(void *object) {
46     dispatch_key key = get_dispatch_key(object);
47     instance_table_map::const_iterator it = tableInstanceMap.find((void *)key);
48 #if DISPATCH_MAP_DEBUG
49     if (it != tableInstanceMap.end()) {
50         fprintf(stderr, "instance_dispatch_table: map: %p, object: %p, key: %p, table: %p\n", &tableInstanceMap, object, key,
51                 it->second);
52     } else {
53         fprintf(stderr, "instance_dispatch_table: map: %p, object: %p, key: %p, table: UNKNOWN\n", &tableInstanceMap, object, key);
54     }
55 #endif
56     assert(it != tableInstanceMap.end() && "Not able to find instance dispatch entry");
57     return it->second;
58 }
59 
destroy_dispatch_table(device_table_map & map,dispatch_key key)60 void destroy_dispatch_table(device_table_map &map, dispatch_key key) {
61 #if DISPATCH_MAP_DEBUG
62     device_table_map::const_iterator it = map.find((void *)key);
63     if (it != map.end()) {
64         fprintf(stderr, "destroy device dispatch_table: map: %p, key: %p, table: %p\n", &map, key, it->second);
65     } else {
66         fprintf(stderr, "destroy device dispatch table: map: %p, key: %p, table: UNKNOWN\n", &map, key);
67         assert(it != map.end());
68     }
69 #endif
70     map.erase(key);
71 }
72 
destroy_dispatch_table(instance_table_map & map,dispatch_key key)73 void destroy_dispatch_table(instance_table_map &map, dispatch_key key) {
74 #if DISPATCH_MAP_DEBUG
75     instance_table_map::const_iterator it = map.find((void *)key);
76     if (it != map.end()) {
77         fprintf(stderr, "destroy instance dispatch_table: map: %p, key: %p, table: %p\n", &map, key, it->second);
78     } else {
79         fprintf(stderr, "destroy instance dispatch table: map: %p, key: %p, table: UNKNOWN\n", &map, key);
80         assert(it != map.end());
81     }
82 #endif
83     map.erase(key);
84 }
85 
destroy_device_dispatch_table(dispatch_key key)86 void destroy_device_dispatch_table(dispatch_key key) { destroy_dispatch_table(tableMap, key); }
87 
destroy_instance_dispatch_table(dispatch_key key)88 void destroy_instance_dispatch_table(dispatch_key key) { destroy_dispatch_table(tableInstanceMap, key); }
89 
get_dispatch_table(device_table_map & map,void * object)90 VkLayerDispatchTable *get_dispatch_table(device_table_map &map, void *object) {
91     dispatch_key key = get_dispatch_key(object);
92     device_table_map::const_iterator it = map.find((void *)key);
93 #if DISPATCH_MAP_DEBUG
94     if (it != map.end()) {
95         fprintf(stderr, "device_dispatch_table: map: %p, object: %p, key: %p, table: %p\n", &tableInstanceMap, object, key,
96                 it->second);
97     } else {
98         fprintf(stderr, "device_dispatch_table: map: %p, object: %p, key: %p, table: UNKNOWN\n", &tableInstanceMap, object, key);
99     }
100 #endif
101     assert(it != map.end() && "Not able to find device dispatch entry");
102     return it->second;
103 }
104 
get_dispatch_table(instance_table_map & map,void * object)105 VkLayerInstanceDispatchTable *get_dispatch_table(instance_table_map &map, void *object) {
106     //    VkLayerInstanceDispatchTable *pDisp = *(VkLayerInstanceDispatchTable **) object;
107     dispatch_key key = get_dispatch_key(object);
108     instance_table_map::const_iterator it = map.find((void *)key);
109 #if DISPATCH_MAP_DEBUG
110     if (it != map.end()) {
111         fprintf(stderr, "instance_dispatch_table: map: %p, object: %p, key: %p, table: %p\n", &tableInstanceMap, object, key,
112                 it->second);
113     } else {
114         fprintf(stderr, "instance_dispatch_table: map: %p, object: %p, key: %p, table: UNKNOWN\n", &tableInstanceMap, object, key);
115     }
116 #endif
117     assert(it != map.end() && "Not able to find instance dispatch entry");
118     return it->second;
119 }
120 
get_chain_info(const VkInstanceCreateInfo * pCreateInfo,VkLayerFunction func)121 VkLayerInstanceCreateInfo *get_chain_info(const VkInstanceCreateInfo *pCreateInfo, VkLayerFunction func) {
122     VkLayerInstanceCreateInfo *chain_info = (VkLayerInstanceCreateInfo *)pCreateInfo->pNext;
123     while (chain_info && !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && chain_info->function == func)) {
124         chain_info = (VkLayerInstanceCreateInfo *)chain_info->pNext;
125     }
126     assert(chain_info != NULL);
127     return chain_info;
128 }
129 
get_chain_info(const VkDeviceCreateInfo * pCreateInfo,VkLayerFunction func)130 VkLayerDeviceCreateInfo *get_chain_info(const VkDeviceCreateInfo *pCreateInfo, VkLayerFunction func) {
131     VkLayerDeviceCreateInfo *chain_info = (VkLayerDeviceCreateInfo *)pCreateInfo->pNext;
132     while (chain_info && !(chain_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO && chain_info->function == func)) {
133         chain_info = (VkLayerDeviceCreateInfo *)chain_info->pNext;
134     }
135     assert(chain_info != NULL);
136     return chain_info;
137 }
138 
139 /* Various dispatchable objects will use the same underlying dispatch table if they
140  * are created from that "parent" object. Thus use pointer to dispatch table
141  * as the key to these table maps.
142  *    Instance -> PhysicalDevice
143  *    Device -> CommandBuffer or Queue
144  * If use the object themselves as key to map then implies Create entrypoints have to be intercepted
145  * and a new key inserted into map */
initInstanceTable(VkInstance instance,const PFN_vkGetInstanceProcAddr gpa,instance_table_map & map)146 VkLayerInstanceDispatchTable *initInstanceTable(VkInstance instance, const PFN_vkGetInstanceProcAddr gpa, instance_table_map &map) {
147     VkLayerInstanceDispatchTable *pTable;
148     dispatch_key key = get_dispatch_key(instance);
149     instance_table_map::const_iterator it = map.find((void *)key);
150 
151     if (it == map.end()) {
152         pTable = new VkLayerInstanceDispatchTable;
153         map[(void *)key] = pTable;
154 #if DISPATCH_MAP_DEBUG
155         fprintf(stderr, "New, Instance: map: %p, key: %p, table: %p\n", &map, key, pTable);
156 #endif
157     } else {
158 #if DISPATCH_MAP_DEBUG
159         fprintf(stderr, "Instance: map: %p, key: %p, table: %p\n", &map, key, it->second);
160 #endif
161         return it->second;
162     }
163 
164     layer_init_instance_dispatch_table(instance, pTable, gpa);
165 
166     return pTable;
167 }
168 
initInstanceTable(VkInstance instance,const PFN_vkGetInstanceProcAddr gpa)169 VkLayerInstanceDispatchTable *initInstanceTable(VkInstance instance, const PFN_vkGetInstanceProcAddr gpa) {
170     return initInstanceTable(instance, gpa, tableInstanceMap);
171 }
172 
initDeviceTable(VkDevice device,const PFN_vkGetDeviceProcAddr gpa,device_table_map & map)173 VkLayerDispatchTable *initDeviceTable(VkDevice device, const PFN_vkGetDeviceProcAddr gpa, device_table_map &map) {
174     VkLayerDispatchTable *pTable;
175     dispatch_key key = get_dispatch_key(device);
176     device_table_map::const_iterator it = map.find((void *)key);
177 
178     if (it == map.end()) {
179         pTable = new VkLayerDispatchTable;
180         map[(void *)key] = pTable;
181 #if DISPATCH_MAP_DEBUG
182         fprintf(stderr, "New, Device: map: %p, key: %p, table: %p\n", &map, key, pTable);
183 #endif
184     } else {
185 #if DISPATCH_MAP_DEBUG
186         fprintf(stderr, "Device: map: %p, key: %p, table: %p\n", &map, key, it->second);
187 #endif
188         return it->second;
189     }
190 
191     layer_init_device_dispatch_table(device, pTable, gpa);
192 
193     return pTable;
194 }
195 
initDeviceTable(VkDevice device,const PFN_vkGetDeviceProcAddr gpa)196 VkLayerDispatchTable *initDeviceTable(VkDevice device, const PFN_vkGetDeviceProcAddr gpa) {
197     return initDeviceTable(device, gpa, tableMap);
198 }
199