blob: 315b8580bc7235d18661ac4b0402f75d1b5103e6 [file] [log] [blame]
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001/*
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002 * Vulkan
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS 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. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Chia-I Wu701f3f62014-09-02 08:32:09 +080023 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
Jon Ashburn01e2d662014-11-14 09:52:42 -070026 * Jon Ashburn <jon@lunarg.com>
Chia-I Wu701f3f62014-09-02 08:32:09 +080027 * Courtney Goeltzenleuchter <courtney@lunarg.com>
Ian Elliott5aa4ea22015-03-31 15:32:41 -060028 * Ian Elliott <ian@lunarg.com>
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080029 */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060030#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080031#include <stdio.h>
32#include <stdlib.h>
33#include <stdarg.h>
34#include <stdbool.h>
35#include <string.h>
36
Chia-I Wu13a61a52014-08-04 11:18:20 +080037#include <sys/types.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070038#if defined(WIN32)
39#include "dirent_on_windows.h"
40#else // WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080041#include <dirent.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070042#endif // WIN32
43#include "loader_platform.h"
Chia-I Wu19300602014-08-04 08:03:57 +080044#include "loader.h"
Jon Ashburn07daee72015-05-21 18:13:33 -060045#include "wsi_lunarg.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060046#include "gpa_helper.h"
47#include "table_ops.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060048#include "debug_report.h"
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -060049#include "vkIcd.h"
Ian Elliott655cad72015-02-12 17:08:34 -070050// The following is #included again to catch certain OS-specific functions
51// being used:
52#include "loader_platform.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080053
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060054void loader_add_to_ext_list(
55 struct loader_extension_list *ext_list,
56 uint32_t prop_list_count,
57 const struct loader_extension_property *prop_list);
58
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060059static loader_platform_dl_handle loader_add_layer_lib(
60 const char *chain_type,
61 struct loader_extension_property *ext_prop);
62
63static void loader_remove_layer_lib(
64 struct loader_instance *inst,
65 struct loader_extension_property *ext_prop);
66
Jon Ashburn27cd5842015-05-12 17:26:48 -060067struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080068
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060069enum loader_debug {
70 LOADER_INFO_BIT = VK_BIT(0),
71 LOADER_WARN_BIT = VK_BIT(1),
72 LOADER_PERF_BIT = VK_BIT(2),
73 LOADER_ERROR_BIT = VK_BIT(3),
74 LOADER_DEBUG_BIT = VK_BIT(4),
75};
76
77uint32_t g_loader_debug = 0;
78uint32_t g_loader_log_msgs = 0;
79
Jon Ashburn6301a0f2015-05-29 13:15:39 -060080//thread safety lock for accessing global data structures such as "loader"
81// all entrypoints on the instance chain need to be locked except GPA
82// additionally DestroyDevice needs to be locked
83loader_platform_thread_mutex loader_lock;
84
85const VkLayerInstanceDispatchTable instance_disp = {
Jon Ashburn27cd5842015-05-12 17:26:48 -060086 .GetInstanceProcAddr = vkGetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060087 .CreateInstance = loader_CreateInstance,
88 .DestroyInstance = loader_DestroyInstance,
89 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060090 .GetPhysicalDeviceInfo = loader_GetPhysicalDeviceInfo,
91 .CreateDevice = loader_CreateDevice,
Jon Ashburn6301a0f2015-05-29 13:15:39 -060092 .GetPhysicalDeviceExtensionInfo = loader_GetPhysicalDeviceExtensionInfo,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060093 .GetMultiDeviceCompatibility = loader_GetMultiDeviceCompatibility,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060094 .GetDisplayInfoWSI = loader_GetDisplayInfoWSI,
95 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
96 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -060097};
98
99LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
100LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
101LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700102
Ian Elliott4470a302015-02-17 10:33:47 -0700103#if defined(WIN32)
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600104char *loader_get_registry_string(const HKEY hive,
105 const LPCTSTR sub_key,
106 const char *value)
107{
108 DWORD access_flags = KEY_QUERY_VALUE;
109 DWORD value_type;
110 HKEY key;
Ian Elliottf851ddf2015-04-28 15:57:32 -0600111 VkResult rtn_value;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600112 char *rtn_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600113 DWORD rtn_len = 0;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600114 size_t allocated_len = 0;
115
116 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
117 if (rtn_value != ERROR_SUCCESS) {
118 // We didn't find the key. Try the 32-bit hive (where we've seen the
119 // key end up on some people's systems):
120 access_flags |= KEY_WOW64_32KEY;
121 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
122 if (rtn_value != ERROR_SUCCESS) {
123 // We still couldn't find the key, so give up:
124 return NULL;
125 }
126 }
127
128 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600129 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600130 if (rtn_value == ERROR_SUCCESS) {
131 // If we get to here, we found the key, and need to allocate memory
132 // large enough for rtn_str, and query again:
133 allocated_len = rtn_len + 4;
134 rtn_str = malloc(allocated_len);
135 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600136 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600137 if (rtn_value == ERROR_SUCCESS) {
138 // We added 4 extra bytes to rtn_str, so that we can ensure that
139 // the string is NULL-terminated (albeit, in a brute-force manner):
140 rtn_str[allocated_len-1] = '\0';
141 } else {
142 // This should never occur, but in case it does, clean up:
143 free(rtn_str);
144 rtn_str = NULL;
145 }
146 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
147
148 // Close the registry key that was opened:
149 RegCloseKey(key);
150
151 return rtn_str;
152}
153
154
Ian Elliott4470a302015-02-17 10:33:47 -0700155// For ICD developers, look in the registry, and look for an environment
156// variable for a path(s) where to find the ICD(s):
157static char *loader_get_registry_and_env(const char *env_var,
158 const char *registry_value)
159{
160 char *env_str = getenv(env_var);
161 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600162 char *registry_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600163 size_t registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700164 char *rtn_str = NULL;
165 size_t rtn_len;
166
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600167 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600168 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600169 registry_value);
Ian Elliottf851ddf2015-04-28 15:57:32 -0600170 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700171
172 rtn_len = env_len + registry_len + 1;
173 if (rtn_len <= 2) {
174 // We found neither the desired registry value, nor the environment
175 // variable; return NULL:
176 return NULL;
177 } else {
178 // We found something, and so we need to allocate memory for the string
179 // to return:
180 rtn_str = malloc(rtn_len);
181 }
182
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600183 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700184 // We didn't find the desired registry value, and so we must have found
185 // only the environment variable:
186 _snprintf(rtn_str, rtn_len, "%s", env_str);
187 } else if (env_str != NULL) {
188 // We found both the desired registry value and the environment
189 // variable, so concatenate them both:
190 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
191 } else {
192 // We must have only found the desired registry value:
193 _snprintf(rtn_str, rtn_len, "%s", registry_str);
194 }
195
Ian Elliott2de26bc2015-04-03 13:13:01 -0600196 if (registry_str) {
197 free(registry_str);
198 }
Ian Elliott4470a302015-02-17 10:33:47 -0700199
200 return(rtn_str);
201}
202#endif // WIN32
203
204
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600205static void loader_log(VkFlags msg_type, int32_t msg_code,
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800206 const char *format, ...)
207{
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800208 char msg[256];
209 va_list ap;
210 int ret;
211
Courtney Goeltzenleuchtera585ecb2015-06-09 09:42:23 -0600212 if (!(msg_type & g_loader_log_msgs)) {
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600213 return;
214 }
215
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800216 va_start(ap, format);
217 ret = vsnprintf(msg, sizeof(msg), format, ap);
Ian Elliott42045842015-02-13 14:29:21 -0700218 if ((ret >= (int) sizeof(msg)) || ret < 0) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800219 msg[sizeof(msg) - 1] = '\0';
220 }
221 va_end(ap);
222
Jon Ashburnae053e92015-04-24 14:10:50 -0700223#if defined(WIN32)
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600224 OutputDebugString(msg);
Jon Ashburn1de39402015-05-05 16:20:46 -0600225#endif
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -0600226 fputs(msg, stderr);
227 fputc('\n', stderr);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800228}
229
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600230bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
231{
232 return memcmp(op1, op2, sizeof(VkExtensionProperties)) == 0 ? true : false;
233}
234
235/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600236 * Search the given ext_list for an extension
237 * matching the given vk_ext_prop
238 */
239bool has_vk_extension_property(
240 const VkExtensionProperties *vk_ext_prop,
241 const struct loader_extension_list *ext_list)
242{
243 for (uint32_t i = 0; i < ext_list->count; i++) {
244 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
245 return true;
246 }
247 return false;
248}
249
250/*
251 * Search the given ext_list for an extension
252 * matching the given vk_ext_prop
253 */
254static struct loader_extension_property *get_extension_property_from_vkext(
255 const VkExtensionProperties *vk_ext_prop,
256 const struct loader_extension_list *ext_list)
257{
258 for (uint32_t i = 0; i < ext_list->count; i++) {
259 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
260 return &ext_list->list[i];
261 }
262 return NULL;
263}
264
265static void get_global_extensions(
266 const PFN_vkGetGlobalExtensionInfo fp_get,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600267 const char *get_extension_info_name,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600268 const char *lib_name,
269 const enum extension_origin origin,
270 struct loader_extension_list *ext_list)
271{
272 uint32_t i, count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600273 size_t siz = sizeof(count);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600274 struct loader_extension_property ext_props;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600275 VkResult res;
276
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600277 res = fp_get(VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
278 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600279 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from ICD");
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600280 return;
281 }
282 siz = sizeof(VkExtensionProperties);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600283 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600284 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600285 res = fp_get(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600286 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600287 ext_props.origin = origin;
288 ext_props.lib_name = lib_name;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600289 strncpy(ext_props.get_extension_info_name, get_extension_info_name, MAX_EXTENSION_NAME_SIZE);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600290 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600291 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600292 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600293
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600294 return;
295}
296
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600297static void get_physical_device_layer_extensions(
298 struct loader_instance *ptr_instance,
299 VkPhysicalDevice physical_device,
300 const uint32_t layer_index,
301 struct loader_extension_list *ext_list)
302{
303 uint32_t i, count;
304 size_t siz = sizeof(count);
305 VkResult res;
306 loader_platform_dl_handle lib_handle;
307 PFN_vkGetPhysicalDeviceExtensionInfo fp_get;
308 struct loader_extension_property ext_props;
309
310 if (!loader.scanned_layers[layer_index].physical_device_extensions_supported) {
311 return;
312 }
313
314 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
315 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -0600316 char funcStr[MAX_EXTENSION_NAME_SIZE+1]; // add one character for 0 termination
317 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetPhysicalDeviceExtensionInfo", ext_props.info.name);
318 funcStr[MAX_EXTENSION_NAME_SIZE] = 0; // make sure string is 0 terminated
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600319 lib_handle = loader_add_layer_lib("device", &ext_props);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600320
321 /* first try extension specific function, then generic */
322 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
323 if (!fp_get) {
Jon Ashburn128f9422015-05-28 19:16:58 -0600324 sprintf(funcStr, "vkGetPhysicalDeviceExtensionInfo");
325 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600326 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600327 if (fp_get) {
328 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
329 if (res == VK_SUCCESS) {
330 siz = sizeof(VkExtensionProperties);
331 for (i = 0; i < count; i++) {
332 memset(&ext_props, 0, sizeof(ext_props));
333 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
334 if (res == VK_SUCCESS && (ext_props.info.sType == VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600335 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
Jon Ashburn128f9422015-05-28 19:16:58 -0600336 strcpy(ext_props.get_extension_info_name, funcStr);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600337 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
338 loader_add_to_ext_list(ext_list, 1, &ext_props);
339 }
340 }
341 } else {
342 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
343 }
344 }
345
346 loader_remove_layer_lib(ptr_instance, &ext_props);
347 return;
348}
349
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600350static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600351{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600352 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
353 ext_info->list = malloc(ext_info->capacity);
354 if (ext_info->list == NULL) {
355 return false;
356 }
357 memset(ext_info->list, 0, ext_info->capacity);
358 ext_info->count = 0;
359 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600360}
361
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600362void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600363{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600364 free(ext_info->list);
365 ext_info->count = 0;
366 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600367}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600368
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600369static void loader_add_vk_ext_to_ext_list(
370 struct loader_extension_list *ext_list,
371 uint32_t prop_list_count,
372 const VkExtensionProperties *props,
373 const struct loader_extension_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600374{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600375 struct loader_extension_property *ext_prop;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600376
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600377 for (uint32_t i = 0; i < prop_list_count; i++) {
378 // look for duplicates
379 if (has_vk_extension_property(&props[i], ext_list)) {
380 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600381 }
382
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600383 ext_prop = get_extension_property_from_vkext(&props[i], search_list);
384 if (!ext_prop) {
385 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", props[i].name);
386 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600387 }
388
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600389 loader_add_to_ext_list(ext_list, 1, ext_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600390 }
391}
392
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600393/*
394 * Append non-duplicate extension properties defined in prop_list
395 * to the given ext_info list
396 */
397void loader_add_to_ext_list(
398 struct loader_extension_list *ext_list,
399 uint32_t prop_list_count,
400 const struct loader_extension_property *props)
401{
402 uint32_t i;
403 struct loader_extension_property *cur_ext;
404
405 if (ext_list->list == NULL || ext_list->capacity == 0) {
406 loader_init_ext_list(ext_list);
407 }
408
409 if (ext_list->list == NULL)
410 return;
411
412 for (i = 0; i < prop_list_count; i++) {
413 cur_ext = (struct loader_extension_property *) &props[i];
414
415 // look for duplicates
416 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
417 continue;
418 }
419
420 // add to list at end
421 // check for enough capacity
422 if (ext_list->count * sizeof(struct loader_extension_property)
423 >= ext_list->capacity) {
424 // double capacity
425 ext_list->capacity *= 2;
426 ext_list->list = realloc(ext_list->list, ext_list->capacity);
427 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600428
429 /*
430 * Check if any extensions already on the list come from the same
431 * library and use the same Get*ExtensionInfo. If so, link this
432 * extension to the previous as an alias. That way when we activate
433 * extensions we only activiate the associated layer once no
434 * matter how many extensions are used.
435 */
436 for (uint32_t j = 0; j < ext_list->count; j++) {
437 struct loader_extension_property *active_property = &ext_list->list[j];
438 if (cur_ext->lib_name &&
439 cur_ext->origin == VK_EXTENSION_ORIGIN_LAYER &&
440 active_property->origin == VK_EXTENSION_ORIGIN_LAYER &&
441 strcmp(cur_ext->lib_name, active_property->lib_name) == 0 &&
442 strcmp(cur_ext->get_extension_info_name, active_property->get_extension_info_name) == 0 &&
443 active_property->alias == NULL) {
444 cur_ext->alias = active_property;
445 break;
446 }
447 }
448
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600449 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
450 ext_list->count++;
451 }
452}
453
454/*
455 * Search the search_list for any extension with
456 * a name that matches the given ext_name.
457 * Add all matching extensions to the found_list
458 * Do not add if found VkExtensionProperties is already
459 * on the found_list
460 */
461static void loader_search_ext_list_for_name(
462 const char *ext_name,
463 const struct loader_extension_list *search_list,
464 struct loader_extension_list *found_list)
465{
466 for (uint32_t i = 0; i < search_list->count; i++) {
467 struct loader_extension_property *ext_prop = &search_list->list[i];
Courtney Goeltzenleuchtera6743522015-06-09 09:14:48 -0600468 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER &&
469 0 == strcmp(ext_prop->info.name, ext_name)) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600470 /* Found an extension with the same name, add to found_list */
471 loader_add_to_ext_list(found_list, 1, &search_list->list[i]);
472 }
473 }
474}
475
476bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600477{
478 uint32_t i;
479
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600480 for (i = 0; i < loader.global_extensions.count; i++) {
481 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600482 return true;
483 }
484 return false;
485}
486
Jon Ashburn27cd5842015-05-12 17:26:48 -0600487void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600488{
489 uint32_t i;
490 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
491
492 // traverse scanned icd list adding non-duplicate extensions to the list
493 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600494 loader_add_to_ext_list(&loader.global_extensions,
495 icd_list->global_extension_list.count,
496 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600497 icd_list = icd_list->next;
498 };
499
500 //Traverse layers list adding non-duplicate extensions to the list
501 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600502 loader_add_to_ext_list(&loader.global_extensions,
503 loader.scanned_layers[i].global_extension_list.count,
504 loader.scanned_layers[i].global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600505 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600506
507 // Traverse loader's extensions, adding non-duplicate extensions to the list
508 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn0c5d4ab2015-05-26 13:57:35 -0600509 wsi_lunarg_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600510}
511
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600512static void loader_icd_destroy(
513 struct loader_instance *ptr_inst,
514 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800515{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600516 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600517 free(icd->gpus);
518 free(icd->loader_dispatch);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800519 free(icd);
520}
521
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600522static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800523{
524 struct loader_icd *icd;
525
526 icd = malloc(sizeof(*icd));
527 if (!icd)
528 return NULL;
529
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600530 memset(icd, 0, sizeof(*icd));
531
Jon Ashburn46d1f582015-01-28 11:01:35 -0700532 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800533
534 return icd;
535}
536
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600537static struct loader_icd *loader_icd_add(
538 struct loader_instance *ptr_inst,
539 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800540{
541 struct loader_icd *icd;
542
Jon Ashburn46d1f582015-01-28 11:01:35 -0700543 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800544 if (!icd)
545 return NULL;
546
Chia-I Wu13a61a52014-08-04 11:18:20 +0800547 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700548 icd->next = ptr_inst->icds;
549 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600550 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800551
552 return icd;
553}
554
Jon Ashburn46d1f582015-01-28 11:01:35 -0700555static void loader_scanned_icd_add(const char *filename)
556{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700557 loader_platform_dl_handle handle;
Jon Ashburn3da71f22015-05-14 12:43:38 -0600558 void *fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600559 void *fp_get_global_ext_info;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600560 void *fp_get_device_ext_info;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700561 struct loader_scanned_icds *new_node;
562
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700563 // Used to call: dlopen(filename, RTLD_LAZY);
564 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700565 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600566 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700567 return;
568 }
569
570#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600571 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700572 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600573 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700574 return; \
575 } \
576} while (0)
577
Jon Ashburn46888392015-01-29 15:45:51 -0700578 LOOKUP(fp_create_inst, CreateInstance);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600579 LOOKUP(fp_get_global_ext_info, GetGlobalExtensionInfo);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600580 LOOKUP(fp_get_device_ext_info, GetPhysicalDeviceExtensionInfo);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700581#undef LOOKUP
582
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600583 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
584 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700585 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600586 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700587 return;
588 }
589
590 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -0700591 new_node->CreateInstance = fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600592 new_node->GetGlobalExtensionInfo = fp_get_global_ext_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600593 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600594 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700595 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700596
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600597 new_node->lib_name = (char *) (new_node + 1);
598 if (!new_node->lib_name) {
599 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
600 return;
601 }
602 strcpy(new_node->lib_name, filename);
603
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600604 loader.scanned_icd_list = new_node;
605
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600606 get_global_extensions(
607 (PFN_vkGetGlobalExtensionInfo) fp_get_global_ext_info,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600608 "vkGetGlobalExtensionInfo",
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600609 new_node->lib_name,
610 VK_EXTENSION_ORIGIN_ICD,
611 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600612}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700613
Jon Ashburn3da71f22015-05-14 12:43:38 -0600614static void loader_icd_init_entrys(struct loader_icd *icd,
615 struct loader_scanned_icds *scanned_icds)
616{
617 /* initialize entrypoint function pointers */
618
619 #define LOOKUP(func) do { \
620 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
621 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600622 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -0600623 return; \
624 } \
625 } while (0)
626
Jon Ashburn8d1b0b52015-05-18 13:20:15 -0600627 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
628 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600629 LOOKUP(DestroyInstance);
630 LOOKUP(EnumeratePhysicalDevices);
631 LOOKUP(GetPhysicalDeviceInfo);
632 LOOKUP(CreateDevice);
633 LOOKUP(GetPhysicalDeviceExtensionInfo);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600634 LOOKUP(GetMultiDeviceCompatibility);
Jon Ashburn95a77ba2015-05-15 15:09:35 -0600635 LOOKUP(GetDisplayInfoWSI);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600636 LOOKUP(DbgCreateMsgCallback);
637 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600638#undef LOOKUP
639
640 return;
641}
642
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600643static void loader_debug_init(void)
644{
645 const char *env;
646
647 if (g_loader_debug > 0)
648 return;
649
650 g_loader_debug = 0;
651
652 /* parse comma-separated debug options */
653 env = getenv("LOADER_DEBUG");
654 while (env) {
655 const char *p = strchr(env, ',');
656 size_t len;
657
658 if (p)
659 len = p - env;
660 else
661 len = strlen(env);
662
663 if (len > 0) {
664 if (strncmp(env, "warn", len) == 0) {
665 g_loader_debug |= LOADER_WARN_BIT;
666 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
667 } else if (strncmp(env, "info", len) == 0) {
668 g_loader_debug |= LOADER_INFO_BIT;
669 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
670 } else if (strncmp(env, "perf", len) == 0) {
671 g_loader_debug |= LOADER_PERF_BIT;
672 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
673 } else if (strncmp(env, "error", len) == 0) {
674 g_loader_debug |= LOADER_ERROR_BIT;
675 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
676 } else if (strncmp(env, "debug", len) == 0) {
677 g_loader_debug |= LOADER_DEBUG_BIT;
678 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
679 }
680 }
681
682 if (!p)
683 break;
684
685 env = p + 1;
686 }
687}
688
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600689/**
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600690 * Try to \c loader_icd_scan VK driver(s).
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600691 *
692 * This function scans the default system path or path
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600693 * specified by the \c LIBVK_DRIVERS_PATH environment variable in
694 * order to find loadable VK ICDs with the name of libVK_*.
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600695 *
696 * \returns
697 * void; but side effect is to set loader_icd_scanned to true
698 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600699void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800700{
Ian Elliott4470a302015-02-17 10:33:47 -0700701 const char *p, *next;
702 char *libPaths = NULL;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600703 DIR *sysdir;
704 struct dirent *dent;
705 char icd_library[1024];
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600706 char path[1024];
Ian Elliott19628802015-02-04 12:06:46 -0700707 uint32_t len;
Jon Ashburn6301a0f2015-05-29 13:15:39 -0600708
709 // convenient place to initialize a mutex
710 loader_platform_thread_create_mutex(&loader_lock);
711
Ian Elliott4470a302015-02-17 10:33:47 -0700712#if defined(WIN32)
713 bool must_free_libPaths;
714 libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV,
715 DRIVER_PATH_REGISTRY_VALUE);
716 if (libPaths != NULL) {
717 must_free_libPaths = true;
718 } else {
719 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600720 libPaths = DEFAULT_VK_DRIVERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700721 }
722#else // WIN32
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600723 if (geteuid() == getuid()) {
Ian Elliott4470a302015-02-17 10:33:47 -0700724 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
725 libPaths = getenv(DRIVER_PATH_ENV);
726 }
727 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600728 libPaths = DEFAULT_VK_DRIVERS_PATH;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600729 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700730#endif // WIN32
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800731
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600732 loader_debug_init();
733
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600734 for (p = libPaths; *p; p = next) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700735 next = strchr(p, PATH_SEPERATOR);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600736 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -0700737 len = (uint32_t) strlen(p);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600738 next = p + len;
739 }
740 else {
Ian Elliott19628802015-02-04 12:06:46 -0700741 len = (uint32_t) (next - p);
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600742 sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
743 p = path;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600744 next++;
745 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800746
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700747 // TODO/TBD: Do we want to do this on Windows, or just let Windows take
748 // care of its own search path (which it apparently has)?
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600749 sysdir = opendir(p);
750 if (sysdir) {
751 dent = readdir(sysdir);
752 while (dent) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600753 /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and
754 * ending with VK_LIBRARY_SUFFIX
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700755 */
756 if (!strncmp(dent->d_name,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600757 VK_DRIVER_LIBRARY_PREFIX,
758 VK_DRIVER_LIBRARY_PREFIX_LEN)) {
Ian Elliott19628802015-02-04 12:06:46 -0700759 uint32_t nlen = (uint32_t) strlen(dent->d_name);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600760 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
761 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700762 !strncmp(suf,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600763 VK_LIBRARY_SUFFIX,
764 VK_LIBRARY_SUFFIX_LEN)) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700765 snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
766 loader_scanned_icd_add(icd_library);
767 }
768 }
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600769
770 dent = readdir(sysdir);
771 }
772 closedir(sysdir);
773 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800774 }
775
Ian Elliott4470a302015-02-17 10:33:47 -0700776#if defined(WIN32)
777 // Free any allocated memory:
778 if (must_free_libPaths) {
779 free(libPaths);
780 }
781#endif // WIN32
782
783 // Note that we've scanned for ICDs:
Jon Ashburn46d1f582015-01-28 11:01:35 -0700784 loader.icds_scanned = true;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800785}
786
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600787
Jon Ashburn27cd5842015-05-12 17:26:48 -0600788void layer_lib_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600789{
790 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -0700791 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600792 DIR *curdir;
793 struct dirent *dent;
Ian Elliott4470a302015-02-17 10:33:47 -0700794 size_t len, i;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600795 char temp_str[1024];
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600796 uint32_t count;
797 PFN_vkGetGlobalExtensionInfo fp_get_ext;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600798
Ian Elliott4470a302015-02-17 10:33:47 -0700799#if defined(WIN32)
800 bool must_free_libPaths;
801 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
802 LAYERS_PATH_REGISTRY_VALUE);
803 if (libPaths != NULL) {
804 must_free_libPaths = true;
805 } else {
806 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600807 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600808 }
Ian Elliott4470a302015-02-17 10:33:47 -0700809#else // WIN32
810 if (geteuid() == getuid()) {
811 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -0700812 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -0700813 }
814 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600815 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700816 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700817#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600818
Ian Elliott4470a302015-02-17 10:33:47 -0700819 if (libPaths == NULL) {
820 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700821 return;
822 }
Ian Elliott4470a302015-02-17 10:33:47 -0700823 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700824 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -0700825 if (loader.layer_dirs == NULL) {
Jon Ashburn90c6a0e2015-06-04 15:30:58 -0600826 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
827
Ian Elliott4470a302015-02-17 10:33:47 -0700828 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -0700829 return;
Ian Elliott4470a302015-02-17 10:33:47 -0700830 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600831 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott4470a302015-02-17 10:33:47 -0700832 strcpy(loader.layer_dirs, libPaths);
833#if defined(WIN32)
834 // Free any allocated memory:
835 if (must_free_libPaths) {
836 free(libPaths);
837 must_free_libPaths = false;
838 }
839#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700840 libPaths = loader.layer_dirs;
841
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600842 /* cleanup any previously scanned libraries */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600843 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600844 if (loader.scanned_layers[i].lib_name != NULL)
845 free(loader.scanned_layers[i].lib_name);
846 loader_destroy_ext_list(&loader.scanned_layers[i].global_extension_list);
847 loader.scanned_layers[i].lib_name = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600848 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600849 loader.scanned_layer_count = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600850 count = 0;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600851
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600852 for (p = libPaths; *p; p = next) {
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600853 next = strchr(p, PATH_SEPERATOR);
854 if (next == NULL) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600855 len = (uint32_t) strlen(p);
856 next = p + len;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600857 }
858 else {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600859 len = (uint32_t) (next - p);
860 *(char *) next = '\0';
861 next++;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600862 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600863
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600864 curdir = opendir(p);
865 if (curdir) {
866 dent = readdir(curdir);
867 while (dent) {
868 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
869 * ending with VK_LIBRARY_SUFFIX
870 */
871 if (!strncmp(dent->d_name,
872 VK_LAYER_LIBRARY_PREFIX,
873 VK_LAYER_LIBRARY_PREFIX_LEN)) {
874 uint32_t nlen = (uint32_t) strlen(dent->d_name);
875 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
876 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
877 !strncmp(suf,
878 VK_LIBRARY_SUFFIX,
879 VK_LIBRARY_SUFFIX_LEN)) {
880 loader_platform_dl_handle handle;
881 snprintf(temp_str, sizeof(temp_str),
882 "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
883 // Used to call: dlopen(temp_str, RTLD_LAZY)
884 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -0600885 "Attempt to open library: %s", temp_str);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600886 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -0600887 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed");
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600888 dent = readdir(curdir);
889 continue;
890 }
891 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -0600892 "Opened library: %s", temp_str);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -0600893
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600894 /* TODO: Remove fixed count */
895 if (count == MAX_LAYER_LIBRARIES) {
896 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
897 "%s ignored: max layer libraries exceed",
898 temp_str);
899 break;
900 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600901
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600902 fp_get_ext = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionInfo");
903 if (!fp_get_ext) {
904 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
905 "Couldn't dlsym vkGetGlobalExtensionInfo from library %s",
906 temp_str);
907 dent = readdir(curdir);
908 loader_platform_close_library(handle);
909 continue;
910 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600911
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600912 loader.scanned_layers[count].lib_name =
913 malloc(strlen(temp_str) + 1);
914 if (loader.scanned_layers[count].lib_name == NULL) {
915 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "%s ignored: out of memory", temp_str);
916 break;
917 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600918
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600919 strcpy(loader.scanned_layers[count].lib_name, temp_str);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600920
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -0600921 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for %s", temp_str);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600922 get_global_extensions(
923 fp_get_ext,
924 "vkGetGlobalExtensionInfo",
925 loader.scanned_layers[count].lib_name,
926 VK_EXTENSION_ORIGIN_LAYER,
927 &loader.scanned_layers[count].global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600928
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600929 fp_get_ext = loader_platform_get_proc_address(handle,
930 "vkGetPhysicalDeviceExtensionInfo");
931 if (fp_get_ext) {
932 loader.scanned_layers[count].physical_device_extensions_supported = true;
933 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600934
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600935 count++;
936 loader_platform_close_library(handle);
937 }
938 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600939
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600940 dent = readdir(curdir);
941 } // while (dir_entry)
942 if (count == MAX_LAYER_LIBRARIES)
943 break;
944 closedir(curdir);
945 } // if (curdir))
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600946 } // for (libpaths)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600947
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600948 loader.scanned_layer_count = count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600949 loader.layers_scanned = true;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600950}
951
Jon Ashburn27cd5842015-05-12 17:26:48 -0600952static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
953{
954 // inst is not wrapped
955 if (inst == VK_NULL_HANDLE) {
956 return NULL;
957 }
958 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
959 void *addr;
960
Jon Ashburn8fd08252015-05-28 16:25:02 -0600961 if (!strcmp(pName, "vkGetInstanceProcAddr"))
962 return (void *) loader_gpa_instance_internal;
963
Jon Ashburn27cd5842015-05-12 17:26:48 -0600964 if (disp_table == NULL)
965 return NULL;
966
967 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600968 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -0600969 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600970 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600971
972 if (disp_table->GetInstanceProcAddr == NULL) {
973 return NULL;
974 }
975 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600976}
977
Jon Ashburn128f9422015-05-28 19:16:58 -0600978struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600979{
Jon Ashburn128f9422015-05-28 19:16:58 -0600980
Jon Ashburn98bd4542015-01-29 16:44:24 -0700981 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
982 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
983 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -0600984 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -0700985 *gpu_index = i;
986 return icd;
987 }
988 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600989 }
990 return NULL;
991}
992
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600993static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600994{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600995 if (icd->layer_count[gpu_index])
996 return true;
997 else
998 return false;
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600999}
1000
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001001static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -06001002 const char *chain_type,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001003 struct loader_extension_property *ext_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001004{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001005 struct loader_lib_info *new_layer_lib_list, *my_lib;
1006
1007 /* Only loader layer libraries here */
1008 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1009 return NULL;
1010 }
1011
1012 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1013 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1014 /* Have already loaded this library, just increment ref count */
1015 loader.loaded_layer_lib_list[i].ref_count++;
Jon Ashburne68a9ff2015-05-25 14:11:37 -06001016 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001017 "%s Chain: Increment layer reference count for layer library %s",
1018 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001019 return loader.loaded_layer_lib_list[i].lib_handle;
1020 }
1021 }
1022
1023 /* Haven't seen this library so load it */
1024 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1025 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1026 if (!new_layer_lib_list) {
1027 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1028 return NULL;
1029 }
1030
1031 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1032
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001033 /* NOTE: We require that the extension property be immutable */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001034 my_lib->lib_name = ext_prop->lib_name;
1035 my_lib->ref_count = 0;
1036 my_lib->lib_handle = NULL;
1037
1038 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1039 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1040 loader_platform_open_library_error(my_lib->lib_name));
1041 return NULL;
1042 } else {
1043 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001044 "Chain: %s: Loading layer library %s",
1045 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001046 }
1047 loader.loaded_layer_lib_count++;
1048 loader.loaded_layer_lib_list = new_layer_lib_list;
1049 my_lib->ref_count++;
1050
1051 return my_lib->lib_handle;
1052}
1053
1054static void loader_remove_layer_lib(
1055 struct loader_instance *inst,
1056 struct loader_extension_property *ext_prop)
1057{
1058 uint32_t idx;
1059 struct loader_lib_info *new_layer_lib_list, *my_lib;
1060
1061 /* Only loader layer libraries here */
1062 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001063 return;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001064 }
Jon Ashburndf7d5842014-10-16 15:48:50 -06001065
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001066 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1067 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1068 /* found matching library */
1069 idx = i;
1070 my_lib = &loader.loaded_layer_lib_list[i];
1071 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001072 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001073 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001074
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001075 my_lib->ref_count--;
1076 inst->layer_count--;
1077 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001078 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1079 "Decrement reference count for layer library %s", ext_prop->lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001080 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001081 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001082
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001083 loader_platform_close_library(my_lib->lib_handle);
1084 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1085 "Unloading layer library %s", ext_prop->lib_name);
1086
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001087 /* Need to remove unused library from list */
1088 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1089 if (!new_layer_lib_list) {
1090 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1091 return;
1092 }
1093
1094 if (idx > 0) {
1095 /* Copy records before idx */
1096 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1097 sizeof(struct loader_lib_info) * idx);
1098 }
1099 if (idx < (loader.loaded_layer_lib_count - 1)) {
1100 /* Copy records after idx */
1101 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1102 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1103 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001104
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001105 free(loader.loaded_layer_lib_list);
1106 loader.loaded_layer_lib_count--;
1107 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001108}
1109
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001110static void loader_add_layer_env(
1111 struct loader_extension_list *ext_list,
1112 const struct loader_extension_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001113{
Ian Elliott4470a302015-02-17 10:33:47 -07001114 char *layerEnv;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001115 uint32_t len;
Jon Ashburnd09bd102014-10-22 21:15:26 -06001116 char *p, *pOrig, *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001117
Ian Elliott4470a302015-02-17 10:33:47 -07001118#if defined(WIN32)
1119 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
1120 LAYER_NAMES_REGISTRY_VALUE);
1121#else // WIN32
1122 layerEnv = getenv(LAYER_NAMES_ENV);
1123#endif // WIN32
1124 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001125 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001126 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001127 p = malloc(strlen(layerEnv) + 1);
Ian Elliott4470a302015-02-17 10:33:47 -07001128 if (p == NULL) {
1129#if defined(WIN32)
1130 free(layerEnv);
1131#endif // WIN32
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001132 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001133 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001134 strcpy(p, layerEnv);
Ian Elliott4470a302015-02-17 10:33:47 -07001135#if defined(WIN32)
1136 free(layerEnv);
1137#endif // WIN32
Jon Ashburnd09bd102014-10-22 21:15:26 -06001138 pOrig = p;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001139
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001140 while (p && *p ) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001141 next = strchr(p, PATH_SEPERATOR);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001142 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -07001143 len = (uint32_t) strlen(p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001144 next = p + len;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001145 } else {
Ian Elliott19628802015-02-04 12:06:46 -07001146 len = (uint32_t) (next - p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001147 *(char *) next = '\0';
1148 next++;
1149 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001150 name = basename(p);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001151 loader_search_ext_list_for_name(name, search_list, ext_list);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001152 p = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001153 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001154
Jon Ashburnd09bd102014-10-22 21:15:26 -06001155 free(pOrig);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001156 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001157}
1158
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001159
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001160void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001161{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001162 if (!instance->layer_count) {
1163 return;
1164 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001165
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001166 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001167 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
1168 struct loader_extension_property *ext_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001169
1170 loader_remove_layer_lib(instance, ext_prop);
1171
1172 instance->layer_count--;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001173 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001174
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001175}
1176
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001177void loader_enable_instance_layers(struct loader_instance *inst)
1178{
1179 if (inst == NULL)
1180 return;
1181
1182 /* Add any layers specified in the environment first */
1183 loader_add_layer_env(&inst->enabled_instance_extensions, &loader.global_extensions);
1184
1185 /* Add layers / extensions specified by the application */
1186 loader_add_vk_ext_to_ext_list(
1187 &inst->enabled_instance_extensions,
1188 inst->app_extension_count,
1189 inst->app_extension_props,
1190 &loader.global_extensions);
1191}
1192
Jon Ashburn27cd5842015-05-12 17:26:48 -06001193uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1194{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001195 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06001196 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001197
Jon Ashburn27cd5842015-05-12 17:26:48 -06001198 if (inst == NULL)
1199 return 0;
1200
1201 // NOTE inst is unwrapped at this point in time
1202 VkObject baseObj = (VkObject) inst;
1203 VkObject nextObj = (VkObject) inst;
1204 VkBaseLayerObject *nextInstObj;
1205 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1206
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001207 /*
1208 * Figure out how many actual layers will need to be wrapped.
1209 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001210 for (uint32_t i = 0; i < inst->enabled_instance_extensions.count; i++) {
1211 struct loader_extension_property *ext_prop = &inst->enabled_instance_extensions.list[i];
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001212 if (ext_prop->alias) {
1213 ext_prop = ext_prop->alias;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001214 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001215 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1216 continue;
1217 }
1218 loader_add_to_ext_list(&inst->activated_layer_list, 1, ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001219 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001220
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001221 inst->layer_count = inst->activated_layer_list.count;
1222
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001223 if (!inst->layer_count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001224 return 0;
1225 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001226
Jon Ashburn128f9422015-05-28 19:16:58 -06001227 wrappedInstance = malloc(sizeof(VkBaseLayerObject)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001228 * inst->layer_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001229 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001230 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1231 return 0;
1232 }
1233
1234 /* Create instance chain of enabled layers */
1235 layer_idx = inst->layer_count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001236 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
1237 struct loader_extension_property *ext_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001238 loader_platform_dl_handle lib_handle;
1239
1240 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001241 * For global exenstions implemented within the loader (i.e. WSI, DEBUG_REPORT
1242 * the extension must provide two entry points for the loader to use:
1243 * - "trampoline" entry point - this is the address returned by GetProcAddr
1244 * and will always do what's necessary to support a global call.
1245 * - "terminator" function - this function will be put at the end of the
1246 * instance chain and will contain the necessary logica to call / process
1247 * the extension for the appropriate ICDs that are available.
1248 * There is no generic mechanism for including these functions, the references
1249 * must be placed into the appropriate loader entry points.
1250 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
1251 * loader_coalesce_extensions(void) - add extension records to the list of global
1252 * extension available to the app.
1253 * instance_disp - add function pointer for terminator function to this array.
1254 * The extension itself should be in a separate file that will be
1255 * linked directly with the loader.
1256 * Note: An extension's Get*ProcAddr should not return a function pointer for
1257 * any extension entry points until the extension has been enabled.
1258 * To do this requires a different behavior from Get*ProcAddr functions implemented
1259 * in layers.
1260 * The very first call to a layer will be it's Get*ProcAddr function requesting
1261 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1262 * with the wrapped object given (either Instance or Device) and return the layer's
1263 * Get*ProcAddr function. The layer should also use this opportunity to record the
1264 * baseObject so that it can find the correct local dispatch table on future calls.
1265 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1266 * will not use a wrapped object and must look up their local dispatch table from
1267 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001268 */
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001269 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001270
Jon Ashburn128f9422015-05-28 19:16:58 -06001271 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001272 nextInstObj->pGPA = nextGPA;
1273 nextInstObj->baseObject = baseObj;
1274 nextInstObj->nextObject = nextObj;
1275 nextObj = (VkObject) nextInstObj;
1276
1277 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001278 snprintf(funcStr, 256, "%sGetInstanceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001279 lib_handle = loader_add_layer_lib("instance", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001280 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1281 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001282 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001283 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", ext_prop->lib_name);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001284
1285 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001286 continue;
1287 }
1288
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001289 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1290 "Insert instance layer library %s for extension: %s",
1291 ext_prop->lib_name, ext_prop->info.name);
1292
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001293 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001294 }
1295
Jon Ashburn8fd08252015-05-28 16:25:02 -06001296 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001297
Jon Ashburn128f9422015-05-28 19:16:58 -06001298 free(wrappedInstance);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001299 return inst->layer_count;
1300}
1301
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001302void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1303{
1304
1305 loader_init_instance_extension_dispatch_table(inst->disp,
1306 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06001307 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001308}
1309
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001310void loader_enable_device_layers(struct loader_icd *icd, uint32_t gpu_index)
1311{
1312 if (icd == NULL)
1313 return;
1314
1315 /* Add any layers specified in the environment first */
1316 loader_add_layer_env(&icd->enabled_device_extensions[gpu_index], &loader.global_extensions);
1317
1318 /* Add layers / extensions specified by the application */
1319 loader_add_vk_ext_to_ext_list(
1320 &icd->enabled_device_extensions[gpu_index],
1321 icd->app_extension_count[gpu_index],
1322 icd->app_extension_props[gpu_index],
1323 &loader.global_extensions);
1324}
1325
1326extern uint32_t loader_activate_device_layers(
1327 VkDevice device,
1328 struct loader_icd *icd,
1329 uint32_t gpu_index,
1330 uint32_t ext_count,
1331 const VkExtensionProperties *ext_props)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001332{
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001333 uint32_t count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001334 uint32_t layer_idx;
1335
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001336 if (!icd)
1337 return 0;
Jon Ashburn83a64252015-04-15 11:31:12 -06001338 assert(gpu_index < MAX_GPUS_FOR_LAYER);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001339
1340 /* activate any layer libraries */
1341 if (!loader_layers_activated(icd, gpu_index)) {
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001342 VkObject nextObj = (VkObject) device;
1343 VkObject baseObj = nextObj;
1344 VkBaseLayerObject *nextGpuObj;
Jon Ashburn7c096122015-05-22 09:19:49 -06001345 PFN_vkGetDeviceProcAddr nextGPA = icd->GetDeviceProcAddr;
Jon Ashburnce94f312015-05-28 19:25:20 -06001346 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001347 count = 0;
1348 for (uint32_t i = 0; i < icd->enabled_device_extensions[gpu_index].count; i++) {
1349 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1350 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER) {
1351 count++;
1352 }
1353 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001354 if (!count)
1355 return 0;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001356
1357 icd->layer_count[gpu_index] = count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001358
Jon Ashburnce94f312015-05-28 19:25:20 -06001359 wrappedGpus = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]);
1360 if (! wrappedGpus) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001361 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001362 return 0;
1363 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001364 layer_idx = count - 1;
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001365 for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001366 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1367 loader_platform_dl_handle lib_handle;
1368
1369 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1370 continue;
1371 }
1372
Jon Ashburnce94f312015-05-28 19:25:20 -06001373 nextGpuObj = (wrappedGpus + i);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001374 nextGpuObj->pGPA = nextGPA;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001375 nextGpuObj->baseObject = baseObj;
1376 nextGpuObj->nextObject = nextObj;
1377 nextObj = (VkObject) nextGpuObj;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001378
Jon Ashburn79113cc2014-12-01 14:22:40 -07001379 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001380 snprintf(funcStr, 256, "%sGetDeviceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001381 lib_handle = loader_add_layer_lib("device", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001382 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1383 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001384 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001385 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", ext_prop->info.name);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001386 continue;
1387 }
1388
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001389 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1390 "Insert device layer library %s for extension: %s",
1391 ext_prop->lib_name, ext_prop->info.name);
1392
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001393 layer_idx--;
1394 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001395
Jon Ashburn8fd08252015-05-28 16:25:02 -06001396 loader_init_device_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA,
1397 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
Jon Ashburnce94f312015-05-28 19:25:20 -06001398 free(wrappedGpus);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001399 } else {
1400 // TODO: Check that active layers match requested?
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001401 }
1402 return icd->layer_count[gpu_index];
1403}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001404
Jon Ashburn27cd5842015-05-12 17:26:48 -06001405VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001406 const VkInstanceCreateInfo* pCreateInfo,
1407 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001408{
Jon Ashburneed0c002015-05-21 17:42:17 -06001409 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07001410 struct loader_scanned_icds *scanned_icds;
1411 struct loader_icd *icd;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001412 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001413
Jon Ashburn46888392015-01-29 15:45:51 -07001414 scanned_icds = loader.scanned_icd_list;
1415 while (scanned_icds) {
1416 icd = loader_icd_add(ptr_instance, scanned_icds);
1417 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -06001418 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn3da71f22015-05-14 12:43:38 -06001419 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001420 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07001421 {
1422 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001423 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001424 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001425 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07001426 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06001427 } else
1428 {
1429 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07001430 }
1431 }
1432 scanned_icds = scanned_icds->next;
1433 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001434
Ian Elliotteb450762015-02-05 15:19:15 -07001435 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001436 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -07001437 }
Jon Ashburn46888392015-01-29 15:45:51 -07001438
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001439 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001440}
1441
Jon Ashburn27cd5842015-05-12 17:26:48 -06001442VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001443 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001444{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06001445 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001446 struct loader_icd *icds = ptr_instance->icds;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001447 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001448
1449 // Remove this instance from the list of instances:
1450 struct loader_instance *prev = NULL;
1451 struct loader_instance *next = loader.instances;
1452 while (next != NULL) {
1453 if (next == ptr_instance) {
1454 // Remove this instance from the list:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001455 free(ptr_instance->app_extension_props);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001456 if (prev)
1457 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07001458 else
1459 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001460 break;
1461 }
1462 prev = next;
1463 next = next->next;
1464 }
1465 if (next == NULL) {
1466 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001467 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001468 }
1469
Jon Ashburn3da71f22015-05-14 12:43:38 -06001470 while (icds) {
1471 if (icds->instance) {
1472 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06001473 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001474 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06001475 "ICD ignored: failed to DestroyInstance on device");
1476 }
Jon Ashburn128f9422015-05-28 19:16:58 -06001477 loader_icd_destroy(ptr_instance, icds);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001478 icds->instance = VK_NULL_HANDLE;
1479 icds = icds->next;
Jon Ashburn46888392015-01-29 15:45:51 -07001480 }
1481
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001482
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001483 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001484}
1485
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001486VkResult loader_init_physical_device_info(
1487 struct loader_instance *ptr_instance)
1488{
1489 struct loader_icd *icd;
1490 uint32_t n, count = 0;
1491 VkResult res = VK_ERROR_UNKNOWN;
1492
1493 icd = ptr_instance->icds;
1494 while (icd) {
1495 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
1496 if (res != VK_SUCCESS)
1497 return res;
1498 icd->gpu_count = n;
1499 count += n;
1500 icd = icd->next;
1501 }
1502
1503 ptr_instance->total_gpu_count = count;
1504
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001505 icd = ptr_instance->icds;
1506 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001507 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
1508
1509 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001510 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
1511 if (!icd->gpus) {
1512 /* TODO: Add cleanup code here */
1513 return VK_ERROR_OUT_OF_HOST_MEMORY;
1514 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001515 res = icd->EnumeratePhysicalDevices(
1516 icd->instance,
1517 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06001518 icd->gpus);
1519 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001520
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001521 icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n *
1522 sizeof(VkLayerDispatchTable));
1523 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001524
1525 loader_init_device_dispatch_table(icd->loader_dispatch + i,
Jon Ashburn128f9422015-05-28 19:16:58 -06001526 get_proc_addr, icd->gpus[i], icd->gpus[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001527
Jon Ashburn128f9422015-05-28 19:16:58 -06001528 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001529
1530 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
1531 /* TODO: Add cleanup code here */
1532 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1533 }
1534 if (res == VK_SUCCESS && icd->GetPhysicalDeviceExtensionInfo) {
1535 size_t data_size;
1536 uint32_t extension_count;
1537
1538 data_size = sizeof(extension_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001539 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_COUNT, 0, &data_size, &extension_count);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001540 if (data_size == sizeof(extension_count) && res == VK_SUCCESS) {
1541 struct loader_extension_property ext_props;
1542
1543 /* Gather all the ICD extensions */
1544 for (uint32_t extension_id = 0; extension_id < extension_count; extension_id++) {
1545 data_size = sizeof(VkExtensionProperties);
Jon Ashburn128f9422015-05-28 19:16:58 -06001546 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_PROPERTIES,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001547 extension_id, &data_size, &ext_props.info);
1548 if (data_size == sizeof(VkExtensionProperties) && res == VK_SUCCESS) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001549 ext_props.origin = VK_EXTENSION_ORIGIN_ICD;
1550 ext_props.lib_name = icd->scanned_icds->lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -06001551 // For ICDs, this is the only option
1552 strcpy(ext_props.get_extension_info_name, "vkGetPhysicalDeviceExtensionInfo");
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001553 loader_add_to_ext_list(&icd->device_extension_cache[i], 1, &ext_props);
1554 }
1555 }
1556
1557 // Traverse layers list adding non-duplicate extensions to the list
1558 for (uint32_t l = 0; l < loader.scanned_layer_count; l++) {
Jon Ashburn128f9422015-05-28 19:16:58 -06001559 get_physical_device_layer_extensions(ptr_instance, icd->gpus[i], l, &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001560 }
1561 }
1562 }
1563
1564 if (res != VK_SUCCESS) {
1565 /* clean up any extension lists previously created before this request failed */
1566 for (uint32_t j = 0; j < i; j++) {
1567 loader_destroy_ext_list(&icd->device_extension_cache[i]);
1568 }
1569 return res;
1570 }
1571 }
1572
1573 count += n;
1574 }
1575
1576 icd = icd->next;
1577 }
1578
1579 return VK_SUCCESS;
1580}
1581
Jon Ashburn27cd5842015-05-12 17:26:48 -06001582VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06001583 VkInstance instance,
1584 uint32_t* pPhysicalDeviceCount,
1585 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001586{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001587 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001588 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001589 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001590
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001591 if (ptr_instance->total_gpu_count == 0) {
1592 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001593 }
1594
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001595 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
1596 if (!pPhysicalDevices) {
1597 return VK_SUCCESS;
1598 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001599
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001600 while (icd) {
1601 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06001602 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001603 index += icd->gpu_count;
1604 icd = icd->next;
1605 }
1606
1607 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001608}
1609
Jon Ashburn3da71f22015-05-14 12:43:38 -06001610VkResult loader_GetPhysicalDeviceInfo(
1611 VkPhysicalDevice gpu,
1612 VkPhysicalDeviceInfoType infoType,
1613 size_t* pDataSize,
1614 void* pData)
1615{
1616 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001617 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001618 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1619
1620 if (icd->GetPhysicalDeviceInfo)
1621 res = icd->GetPhysicalDeviceInfo(gpu, infoType, pDataSize, pData);
1622
1623 return res;
1624}
1625
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001626VkResult loader_CreateDevice(
1627 VkPhysicalDevice gpu,
1628 const VkDeviceCreateInfo* pCreateInfo,
1629 VkDevice* pDevice)
1630{
1631 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001632 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001633 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001634
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001635 if (icd->CreateDevice) {
1636 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001637 if (res != VK_SUCCESS) {
1638 return res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001639 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001640
1641 VkLayerDispatchTable *dev_disp = icd->loader_dispatch + gpu_index;
1642 loader_init_dispatch(*pDevice, dev_disp);
1643
1644 icd->app_extension_count[gpu_index] = pCreateInfo->extensionCount;
1645 icd->app_extension_props[gpu_index] = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1646 if (icd->app_extension_props[gpu_index] == NULL && (icd->app_extension_count[gpu_index] > 0)) {
1647 return VK_ERROR_OUT_OF_HOST_MEMORY;
1648 }
1649
1650 /* Make local copy of extension list */
1651 if (icd->app_extension_count[gpu_index] > 0 && icd->app_extension_props[gpu_index] != NULL) {
1652 memcpy(icd->app_extension_props[gpu_index], pCreateInfo->pEnabledExtensions, sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1653 }
1654
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001655 /*
1656 * Put together the complete list of extensions to enable
1657 * This includes extensions requested via environment variables.
1658 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001659 loader_enable_device_layers(icd, gpu_index);
1660
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001661 /*
1662 * Load the libraries needed by the extensions on the
1663 * enabled extension list. This will build the
1664 * device instance chain terminating with the
1665 * selected device.
1666 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001667 loader_activate_device_layers(*pDevice, icd, gpu_index,
1668 icd->app_extension_count[gpu_index],
1669 icd->app_extension_props[gpu_index]);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001670 }
1671
1672 return res;
1673}
1674
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001675LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
1676{
Jon Ashburn07daee72015-05-21 18:13:33 -06001677 if (instance == VK_NULL_HANDLE)
1678 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001679
Jon Ashburn07daee72015-05-21 18:13:33 -06001680 void *addr;
1681 /* get entrypoint addresses that are global (in the loader)*/
1682 addr = globalGetProcAddr(pName);
1683 if (addr)
1684 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001685
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001686 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
1687
1688 addr = debug_report_instance_gpa(ptr_instance, pName);
1689 if (addr) {
1690 return addr;
1691 }
1692
Jon Ashburn07daee72015-05-21 18:13:33 -06001693 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001694 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001695 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001696 return (ptr_instance->wsi_lunarg_enabled) ? addr : NULL;
Jon Ashburn07daee72015-05-21 18:13:33 -06001697
1698 /* return the instance dispatch table entrypoint for extensions */
1699 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
1700 if (disp_table == NULL)
1701 return NULL;
1702
1703 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
1704 if (addr)
1705 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001706
1707 return NULL;
1708}
1709
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001710LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001711{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001712 if (device == VK_NULL_HANDLE) {
1713 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001714 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001715
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001716 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001717
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001718 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
1719 make sure the loader entrypoint is returned */
1720 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06001721 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001722 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06001723 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001724
Jon Ashburn07daee72015-05-21 18:13:33 -06001725 /* return any extension device entrypoints the loader knows about */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001726 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001727 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001728 return addr;
Jon Ashburn07daee72015-05-21 18:13:33 -06001729
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001730 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001731 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001732 if (disp_table == NULL)
1733 return NULL;
1734
Jon Ashburn27cd5842015-05-12 17:26:48 -06001735 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001736 if (addr)
1737 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001738 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001739 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001740 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001741 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001742 }
1743}
1744
Jon Ashburneceb13e2015-05-18 15:28:32 -06001745LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001746 VkExtensionInfoType infoType,
1747 uint32_t extensionIndex,
1748 size_t* pDataSize,
1749 void* pData)
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001750{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001751 uint32_t *count;
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001752 VkResult res = VK_SUCCESS;
1753
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001754 /* Scan/discover all ICD libraries in a single-threaded manner */
1755 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001756
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001757 /* get layer libraries in a single-threaded manner */
1758 loader_platform_thread_once(&once_layer, layer_lib_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001759
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001760 /* merge any duplicate extensions */
1761 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
1762
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001763 if (pDataSize == NULL)
1764 return VK_ERROR_INVALID_POINTER;
1765
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001766 loader_platform_thread_lock_mutex(&loader_lock);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001767 switch (infoType) {
1768 case VK_EXTENSION_INFO_TYPE_COUNT:
1769 *pDataSize = sizeof(uint32_t);
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001770 if (pData == NULL) {
1771 loader_platform_thread_unlock_mutex(&loader_lock);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001772 return VK_SUCCESS;
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001773 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001774 count = (uint32_t *) pData;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001775 *count = loader.global_extensions.count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001776 break;
1777 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1778 *pDataSize = sizeof(VkExtensionProperties);
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001779 if (pData == NULL) {
1780 loader_platform_thread_unlock_mutex(&loader_lock);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001781 return VK_SUCCESS;
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001782 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001783 if (extensionIndex >= loader.global_extensions.count)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001784 return VK_ERROR_INVALID_VALUE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001785 memcpy((VkExtensionProperties *) pData,
1786 &loader.global_extensions.list[extensionIndex],
1787 sizeof(VkExtensionProperties));
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001788 break;
1789 default:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001790 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Invalid infoType in vkGetGlobalExtensionInfo");
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001791 res = VK_ERROR_INVALID_VALUE;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001792 };
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001793 loader_platform_thread_unlock_mutex(&loader_lock);
1794 return res;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001795}
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001796
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001797VkResult loader_GetPhysicalDeviceExtensionInfo(
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001798 VkPhysicalDevice gpu,
1799 VkExtensionInfoType infoType,
1800 uint32_t extensionIndex,
1801 size_t* pDataSize,
1802 void* pData)
1803{
1804 uint32_t gpu_index;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001805 uint32_t *count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001806 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001807
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001808 if (pDataSize == NULL)
1809 return VK_ERROR_INVALID_POINTER;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001810
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001811 switch (infoType) {
1812 case VK_EXTENSION_INFO_TYPE_COUNT:
1813 *pDataSize = sizeof(uint32_t);
1814 if (pData == NULL)
1815 return VK_SUCCESS;
1816 count = (uint32_t *) pData;
1817 *count = icd->device_extension_cache[gpu_index].count;
1818 break;
1819 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1820 *pDataSize = sizeof(VkExtensionProperties);
1821 if (pData == NULL)
1822 return VK_SUCCESS;
1823 if (extensionIndex >= icd->device_extension_cache[gpu_index].count)
1824 return VK_ERROR_INVALID_VALUE;
1825 memcpy((VkExtensionProperties *) pData,
1826 &icd->device_extension_cache[gpu_index].list[extensionIndex],
1827 sizeof(VkExtensionProperties));
1828 break;
1829 default:
1830 return VK_ERROR_INVALID_VALUE;
1831 };
1832
1833 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001834}
1835
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001836VkResult loader_GetMultiDeviceCompatibility(
1837 VkPhysicalDevice gpu0,
1838 VkPhysicalDevice gpu1,
1839 VkPhysicalDeviceCompatibilityInfo* pInfo)
1840{
1841 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001842 struct loader_icd *icd = loader_get_icd(gpu0, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001843 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1844
1845 if (icd->GetMultiDeviceCompatibility)
1846 res = icd->GetMultiDeviceCompatibility(gpu0, gpu1, pInfo);
1847
1848 return res;
1849}