blob: 4da023b3d792b7a1f2e2f9139a021151ef9e4ca4 [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 Ashburneceb13e2015-05-18 15:28:32 -060092 .GetGlobalExtensionInfo = vkGetGlobalExtensionInfo,
Jon Ashburn6301a0f2015-05-29 13:15:39 -060093 .GetPhysicalDeviceExtensionInfo = loader_GetPhysicalDeviceExtensionInfo,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060094 .GetMultiDeviceCompatibility = loader_GetMultiDeviceCompatibility,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060095 .GetDisplayInfoWSI = loader_GetDisplayInfoWSI,
96 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
97 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -060098};
99
100LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
101LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
102LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700103
Ian Elliott4470a302015-02-17 10:33:47 -0700104#if defined(WIN32)
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600105char *loader_get_registry_string(const HKEY hive,
106 const LPCTSTR sub_key,
107 const char *value)
108{
109 DWORD access_flags = KEY_QUERY_VALUE;
110 DWORD value_type;
111 HKEY key;
Ian Elliottf851ddf2015-04-28 15:57:32 -0600112 VkResult rtn_value;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600113 char *rtn_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600114 DWORD rtn_len = 0;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600115 size_t allocated_len = 0;
116
117 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
118 if (rtn_value != ERROR_SUCCESS) {
119 // We didn't find the key. Try the 32-bit hive (where we've seen the
120 // key end up on some people's systems):
121 access_flags |= KEY_WOW64_32KEY;
122 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
123 if (rtn_value != ERROR_SUCCESS) {
124 // We still couldn't find the key, so give up:
125 return NULL;
126 }
127 }
128
129 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600130 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600131 if (rtn_value == ERROR_SUCCESS) {
132 // If we get to here, we found the key, and need to allocate memory
133 // large enough for rtn_str, and query again:
134 allocated_len = rtn_len + 4;
135 rtn_str = malloc(allocated_len);
136 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600137 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600138 if (rtn_value == ERROR_SUCCESS) {
139 // We added 4 extra bytes to rtn_str, so that we can ensure that
140 // the string is NULL-terminated (albeit, in a brute-force manner):
141 rtn_str[allocated_len-1] = '\0';
142 } else {
143 // This should never occur, but in case it does, clean up:
144 free(rtn_str);
145 rtn_str = NULL;
146 }
147 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
148
149 // Close the registry key that was opened:
150 RegCloseKey(key);
151
152 return rtn_str;
153}
154
155
Ian Elliott4470a302015-02-17 10:33:47 -0700156// For ICD developers, look in the registry, and look for an environment
157// variable for a path(s) where to find the ICD(s):
158static char *loader_get_registry_and_env(const char *env_var,
159 const char *registry_value)
160{
161 char *env_str = getenv(env_var);
162 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600163 char *registry_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600164 size_t registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700165 char *rtn_str = NULL;
166 size_t rtn_len;
167
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600168 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600169 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600170 registry_value);
Ian Elliottf851ddf2015-04-28 15:57:32 -0600171 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700172
173 rtn_len = env_len + registry_len + 1;
174 if (rtn_len <= 2) {
175 // We found neither the desired registry value, nor the environment
176 // variable; return NULL:
177 return NULL;
178 } else {
179 // We found something, and so we need to allocate memory for the string
180 // to return:
181 rtn_str = malloc(rtn_len);
182 }
183
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600184 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700185 // We didn't find the desired registry value, and so we must have found
186 // only the environment variable:
187 _snprintf(rtn_str, rtn_len, "%s", env_str);
188 } else if (env_str != NULL) {
189 // We found both the desired registry value and the environment
190 // variable, so concatenate them both:
191 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
192 } else {
193 // We must have only found the desired registry value:
194 _snprintf(rtn_str, rtn_len, "%s", registry_str);
195 }
196
Ian Elliott2de26bc2015-04-03 13:13:01 -0600197 if (registry_str) {
198 free(registry_str);
199 }
Ian Elliott4470a302015-02-17 10:33:47 -0700200
201 return(rtn_str);
202}
203#endif // WIN32
204
205
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600206static void loader_log(VkFlags msg_type, int32_t msg_code,
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800207 const char *format, ...)
208{
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800209 char msg[256];
210 va_list ap;
211 int ret;
212
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600213 if (!(msg_code & g_loader_log_msgs)) {
214 return;
215 }
216
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800217 va_start(ap, format);
218 ret = vsnprintf(msg, sizeof(msg), format, ap);
Ian Elliott42045842015-02-13 14:29:21 -0700219 if ((ret >= (int) sizeof(msg)) || ret < 0) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800220 msg[sizeof(msg) - 1] = '\0';
221 }
222 va_end(ap);
223
Jon Ashburnae053e92015-04-24 14:10:50 -0700224#if defined(WIN32)
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600225 OutputDebugString(msg);
Jon Ashburn1de39402015-05-05 16:20:46 -0600226#endif
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -0600227 fputs(msg, stderr);
228 fputc('\n', stderr);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800229}
230
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600231bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
232{
233 return memcmp(op1, op2, sizeof(VkExtensionProperties)) == 0 ? true : false;
234}
235
236/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600237 * Search the given ext_list for an extension
238 * matching the given vk_ext_prop
239 */
240bool has_vk_extension_property(
241 const VkExtensionProperties *vk_ext_prop,
242 const struct loader_extension_list *ext_list)
243{
244 for (uint32_t i = 0; i < ext_list->count; i++) {
245 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
246 return true;
247 }
248 return false;
249}
250
251/*
252 * Search the given ext_list for an extension
253 * matching the given vk_ext_prop
254 */
255static struct loader_extension_property *get_extension_property_from_vkext(
256 const VkExtensionProperties *vk_ext_prop,
257 const struct loader_extension_list *ext_list)
258{
259 for (uint32_t i = 0; i < ext_list->count; i++) {
260 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
261 return &ext_list->list[i];
262 }
263 return NULL;
264}
265
266static void get_global_extensions(
267 const PFN_vkGetGlobalExtensionInfo fp_get,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600268 const char *get_extension_info_name,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600269 const char *lib_name,
270 const enum extension_origin origin,
271 struct loader_extension_list *ext_list)
272{
273 uint32_t i, count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600274 size_t siz = sizeof(count);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600275 struct loader_extension_property ext_props;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600276 VkResult res;
277
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600278 res = fp_get(VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
279 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600280 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from ICD");
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600281 return;
282 }
283 siz = sizeof(VkExtensionProperties);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600284 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600285 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600286 res = fp_get(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600287 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600288 ext_props.origin = origin;
289 ext_props.lib_name = lib_name;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600290 strncpy(ext_props.get_extension_info_name, get_extension_info_name, MAX_EXTENSION_NAME_SIZE);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600291 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600292 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600293 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600294
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600295 return;
296}
297
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600298static void get_physical_device_layer_extensions(
299 struct loader_instance *ptr_instance,
300 VkPhysicalDevice physical_device,
301 const uint32_t layer_index,
302 struct loader_extension_list *ext_list)
303{
304 uint32_t i, count;
305 size_t siz = sizeof(count);
306 VkResult res;
307 loader_platform_dl_handle lib_handle;
308 PFN_vkGetPhysicalDeviceExtensionInfo fp_get;
309 struct loader_extension_property ext_props;
310
311 if (!loader.scanned_layers[layer_index].physical_device_extensions_supported) {
312 return;
313 }
314
315 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
316 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -0600317 char funcStr[MAX_EXTENSION_NAME_SIZE+1]; // add one character for 0 termination
318 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetPhysicalDeviceExtensionInfo", ext_props.info.name);
319 funcStr[MAX_EXTENSION_NAME_SIZE] = 0; // make sure string is 0 terminated
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600320 lib_handle = loader_add_layer_lib("device", &ext_props);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600321
322 /* first try extension specific function, then generic */
323 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
324 if (!fp_get) {
Jon Ashburn128f9422015-05-28 19:16:58 -0600325 sprintf(funcStr, "vkGetPhysicalDeviceExtensionInfo");
326 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600327 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600328 if (fp_get) {
329 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
330 if (res == VK_SUCCESS) {
331 siz = sizeof(VkExtensionProperties);
332 for (i = 0; i < count; i++) {
333 memset(&ext_props, 0, sizeof(ext_props));
334 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
335 if (res == VK_SUCCESS && (ext_props.info.sType == VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600336 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
Jon Ashburn128f9422015-05-28 19:16:58 -0600337 strcpy(ext_props.get_extension_info_name, funcStr);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600338 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
339 loader_add_to_ext_list(ext_list, 1, &ext_props);
340 }
341 }
342 } else {
343 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
344 }
345 }
346
347 loader_remove_layer_lib(ptr_instance, &ext_props);
348 return;
349}
350
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600351static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600352{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600353 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
354 ext_info->list = malloc(ext_info->capacity);
355 if (ext_info->list == NULL) {
356 return false;
357 }
358 memset(ext_info->list, 0, ext_info->capacity);
359 ext_info->count = 0;
360 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600361}
362
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600363void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600364{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600365 free(ext_info->list);
366 ext_info->count = 0;
367 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600368}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600369
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600370static void loader_add_vk_ext_to_ext_list(
371 struct loader_extension_list *ext_list,
372 uint32_t prop_list_count,
373 const VkExtensionProperties *props,
374 const struct loader_extension_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600375{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600376 struct loader_extension_property *ext_prop;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600377
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600378 for (uint32_t i = 0; i < prop_list_count; i++) {
379 // look for duplicates
380 if (has_vk_extension_property(&props[i], ext_list)) {
381 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600382 }
383
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600384 ext_prop = get_extension_property_from_vkext(&props[i], search_list);
385 if (!ext_prop) {
386 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", props[i].name);
387 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600388 }
389
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600390 loader_add_to_ext_list(ext_list, 1, ext_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600391 }
392}
393
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600394/*
395 * Append non-duplicate extension properties defined in prop_list
396 * to the given ext_info list
397 */
398void loader_add_to_ext_list(
399 struct loader_extension_list *ext_list,
400 uint32_t prop_list_count,
401 const struct loader_extension_property *props)
402{
403 uint32_t i;
404 struct loader_extension_property *cur_ext;
405
406 if (ext_list->list == NULL || ext_list->capacity == 0) {
407 loader_init_ext_list(ext_list);
408 }
409
410 if (ext_list->list == NULL)
411 return;
412
413 for (i = 0; i < prop_list_count; i++) {
414 cur_ext = (struct loader_extension_property *) &props[i];
415
416 // look for duplicates
417 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
418 continue;
419 }
420
421 // add to list at end
422 // check for enough capacity
423 if (ext_list->count * sizeof(struct loader_extension_property)
424 >= ext_list->capacity) {
425 // double capacity
426 ext_list->capacity *= 2;
427 ext_list->list = realloc(ext_list->list, ext_list->capacity);
428 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600429
430 /*
431 * Check if any extensions already on the list come from the same
432 * library and use the same Get*ExtensionInfo. If so, link this
433 * extension to the previous as an alias. That way when we activate
434 * extensions we only activiate the associated layer once no
435 * matter how many extensions are used.
436 */
437 for (uint32_t j = 0; j < ext_list->count; j++) {
438 struct loader_extension_property *active_property = &ext_list->list[j];
439 if (cur_ext->lib_name &&
440 cur_ext->origin == VK_EXTENSION_ORIGIN_LAYER &&
441 active_property->origin == VK_EXTENSION_ORIGIN_LAYER &&
442 strcmp(cur_ext->lib_name, active_property->lib_name) == 0 &&
443 strcmp(cur_ext->get_extension_info_name, active_property->get_extension_info_name) == 0 &&
444 active_property->alias == NULL) {
445 cur_ext->alias = active_property;
446 break;
447 }
448 }
449
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600450 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
451 ext_list->count++;
452 }
453}
454
455/*
456 * Search the search_list for any extension with
457 * a name that matches the given ext_name.
458 * Add all matching extensions to the found_list
459 * Do not add if found VkExtensionProperties is already
460 * on the found_list
461 */
462static void loader_search_ext_list_for_name(
463 const char *ext_name,
464 const struct loader_extension_list *search_list,
465 struct loader_extension_list *found_list)
466{
467 for (uint32_t i = 0; i < search_list->count; i++) {
468 struct loader_extension_property *ext_prop = &search_list->list[i];
Courtney Goeltzenleuchtera6743522015-06-09 09:14:48 -0600469 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER &&
470 0 == strcmp(ext_prop->info.name, ext_name)) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600471 /* Found an extension with the same name, add to found_list */
472 loader_add_to_ext_list(found_list, 1, &search_list->list[i]);
473 }
474 }
475}
476
477bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600478{
479 uint32_t i;
480
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600481 for (i = 0; i < loader.global_extensions.count; i++) {
482 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600483 return true;
484 }
485 return false;
486}
487
Jon Ashburn27cd5842015-05-12 17:26:48 -0600488void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600489{
490 uint32_t i;
491 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
492
493 // traverse scanned icd list adding non-duplicate extensions to the list
494 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600495 loader_add_to_ext_list(&loader.global_extensions,
496 icd_list->global_extension_list.count,
497 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600498 icd_list = icd_list->next;
499 };
500
501 //Traverse layers list adding non-duplicate extensions to the list
502 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600503 loader_add_to_ext_list(&loader.global_extensions,
504 loader.scanned_layers[i].global_extension_list.count,
505 loader.scanned_layers[i].global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600506 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600507
508 // Traverse loader's extensions, adding non-duplicate extensions to the list
509 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn0c5d4ab2015-05-26 13:57:35 -0600510 wsi_lunarg_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600511}
512
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600513static void loader_icd_destroy(
514 struct loader_instance *ptr_inst,
515 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800516{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600517 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600518 free(icd->gpus);
519 free(icd->loader_dispatch);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800520 free(icd);
521}
522
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600523static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800524{
525 struct loader_icd *icd;
526
527 icd = malloc(sizeof(*icd));
528 if (!icd)
529 return NULL;
530
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600531 memset(icd, 0, sizeof(*icd));
532
Jon Ashburn46d1f582015-01-28 11:01:35 -0700533 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800534
535 return icd;
536}
537
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600538static struct loader_icd *loader_icd_add(
539 struct loader_instance *ptr_inst,
540 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800541{
542 struct loader_icd *icd;
543
Jon Ashburn46d1f582015-01-28 11:01:35 -0700544 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800545 if (!icd)
546 return NULL;
547
Chia-I Wu13a61a52014-08-04 11:18:20 +0800548 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700549 icd->next = ptr_inst->icds;
550 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600551 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800552
553 return icd;
554}
555
Jon Ashburn46d1f582015-01-28 11:01:35 -0700556static void loader_scanned_icd_add(const char *filename)
557{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700558 loader_platform_dl_handle handle;
Jon Ashburn3da71f22015-05-14 12:43:38 -0600559 void *fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600560 void *fp_get_global_ext_info;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600561 void *fp_get_device_ext_info;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700562 struct loader_scanned_icds *new_node;
563
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700564 // Used to call: dlopen(filename, RTLD_LAZY);
565 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700566 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600567 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700568 return;
569 }
570
571#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600572 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700573 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600574 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700575 return; \
576 } \
577} while (0)
578
Jon Ashburn46888392015-01-29 15:45:51 -0700579 LOOKUP(fp_create_inst, CreateInstance);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600580 LOOKUP(fp_get_global_ext_info, GetGlobalExtensionInfo);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600581 LOOKUP(fp_get_device_ext_info, GetPhysicalDeviceExtensionInfo);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700582#undef LOOKUP
583
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600584 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
585 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700586 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600587 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700588 return;
589 }
590
591 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -0700592 new_node->CreateInstance = fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600593 new_node->GetGlobalExtensionInfo = fp_get_global_ext_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600594 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600595 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700596 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700597
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600598 new_node->lib_name = (char *) (new_node + 1);
599 if (!new_node->lib_name) {
600 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
601 return;
602 }
603 strcpy(new_node->lib_name, filename);
604
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600605 loader.scanned_icd_list = new_node;
606
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600607 get_global_extensions(
608 (PFN_vkGetGlobalExtensionInfo) fp_get_global_ext_info,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600609 "vkGetGlobalExtensionInfo",
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600610 new_node->lib_name,
611 VK_EXTENSION_ORIGIN_ICD,
612 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600613}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700614
Jon Ashburn3da71f22015-05-14 12:43:38 -0600615static void loader_icd_init_entrys(struct loader_icd *icd,
616 struct loader_scanned_icds *scanned_icds)
617{
618 /* initialize entrypoint function pointers */
619
620 #define LOOKUP(func) do { \
621 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
622 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600623 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -0600624 return; \
625 } \
626 } while (0)
627
Jon Ashburn8d1b0b52015-05-18 13:20:15 -0600628 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
629 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600630 LOOKUP(DestroyInstance);
631 LOOKUP(EnumeratePhysicalDevices);
632 LOOKUP(GetPhysicalDeviceInfo);
633 LOOKUP(CreateDevice);
634 LOOKUP(GetPhysicalDeviceExtensionInfo);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600635 LOOKUP(GetMultiDeviceCompatibility);
Jon Ashburn95a77ba2015-05-15 15:09:35 -0600636 LOOKUP(GetDisplayInfoWSI);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600637 LOOKUP(DbgCreateMsgCallback);
638 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600639#undef LOOKUP
640
641 return;
642}
643
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600644static void loader_debug_init(void)
645{
646 const char *env;
647
648 if (g_loader_debug > 0)
649 return;
650
651 g_loader_debug = 0;
652
653 /* parse comma-separated debug options */
654 env = getenv("LOADER_DEBUG");
655 while (env) {
656 const char *p = strchr(env, ',');
657 size_t len;
658
659 if (p)
660 len = p - env;
661 else
662 len = strlen(env);
663
664 if (len > 0) {
665 if (strncmp(env, "warn", len) == 0) {
666 g_loader_debug |= LOADER_WARN_BIT;
667 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
668 } else if (strncmp(env, "info", len) == 0) {
669 g_loader_debug |= LOADER_INFO_BIT;
670 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
671 } else if (strncmp(env, "perf", len) == 0) {
672 g_loader_debug |= LOADER_PERF_BIT;
673 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
674 } else if (strncmp(env, "error", len) == 0) {
675 g_loader_debug |= LOADER_ERROR_BIT;
676 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
677 } else if (strncmp(env, "debug", len) == 0) {
678 g_loader_debug |= LOADER_DEBUG_BIT;
679 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
680 }
681 }
682
683 if (!p)
684 break;
685
686 env = p + 1;
687 }
688}
689
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600690/**
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600691 * Try to \c loader_icd_scan VK driver(s).
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600692 *
693 * This function scans the default system path or path
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600694 * specified by the \c LIBVK_DRIVERS_PATH environment variable in
695 * order to find loadable VK ICDs with the name of libVK_*.
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600696 *
697 * \returns
698 * void; but side effect is to set loader_icd_scanned to true
699 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600700void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800701{
Ian Elliott4470a302015-02-17 10:33:47 -0700702 const char *p, *next;
703 char *libPaths = NULL;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600704 DIR *sysdir;
705 struct dirent *dent;
706 char icd_library[1024];
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600707 char path[1024];
Ian Elliott19628802015-02-04 12:06:46 -0700708 uint32_t len;
Jon Ashburn6301a0f2015-05-29 13:15:39 -0600709
710 // convenient place to initialize a mutex
711 loader_platform_thread_create_mutex(&loader_lock);
712
Ian Elliott4470a302015-02-17 10:33:47 -0700713#if defined(WIN32)
714 bool must_free_libPaths;
715 libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV,
716 DRIVER_PATH_REGISTRY_VALUE);
717 if (libPaths != NULL) {
718 must_free_libPaths = true;
719 } else {
720 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600721 libPaths = DEFAULT_VK_DRIVERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700722 }
723#else // WIN32
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600724 if (geteuid() == getuid()) {
Ian Elliott4470a302015-02-17 10:33:47 -0700725 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
726 libPaths = getenv(DRIVER_PATH_ENV);
727 }
728 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600729 libPaths = DEFAULT_VK_DRIVERS_PATH;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600730 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700731#endif // WIN32
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800732
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600733 loader_debug_init();
734
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600735 for (p = libPaths; *p; p = next) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700736 next = strchr(p, PATH_SEPERATOR);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600737 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -0700738 len = (uint32_t) strlen(p);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600739 next = p + len;
740 }
741 else {
Ian Elliott19628802015-02-04 12:06:46 -0700742 len = (uint32_t) (next - p);
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600743 sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
744 p = path;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600745 next++;
746 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800747
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700748 // TODO/TBD: Do we want to do this on Windows, or just let Windows take
749 // care of its own search path (which it apparently has)?
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600750 sysdir = opendir(p);
751 if (sysdir) {
752 dent = readdir(sysdir);
753 while (dent) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600754 /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and
755 * ending with VK_LIBRARY_SUFFIX
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700756 */
757 if (!strncmp(dent->d_name,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600758 VK_DRIVER_LIBRARY_PREFIX,
759 VK_DRIVER_LIBRARY_PREFIX_LEN)) {
Ian Elliott19628802015-02-04 12:06:46 -0700760 uint32_t nlen = (uint32_t) strlen(dent->d_name);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600761 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
762 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700763 !strncmp(suf,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600764 VK_LIBRARY_SUFFIX,
765 VK_LIBRARY_SUFFIX_LEN)) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700766 snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
767 loader_scanned_icd_add(icd_library);
768 }
769 }
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600770
771 dent = readdir(sysdir);
772 }
773 closedir(sysdir);
774 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800775 }
776
Ian Elliott4470a302015-02-17 10:33:47 -0700777#if defined(WIN32)
778 // Free any allocated memory:
779 if (must_free_libPaths) {
780 free(libPaths);
781 }
782#endif // WIN32
783
784 // Note that we've scanned for ICDs:
Jon Ashburn46d1f582015-01-28 11:01:35 -0700785 loader.icds_scanned = true;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800786}
787
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600788
Jon Ashburn27cd5842015-05-12 17:26:48 -0600789void layer_lib_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600790{
791 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -0700792 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600793 DIR *curdir;
794 struct dirent *dent;
Ian Elliott4470a302015-02-17 10:33:47 -0700795 size_t len, i;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600796 char temp_str[1024];
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600797 uint32_t count;
798 PFN_vkGetGlobalExtensionInfo fp_get_ext;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600799
Ian Elliott4470a302015-02-17 10:33:47 -0700800#if defined(WIN32)
801 bool must_free_libPaths;
802 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
803 LAYERS_PATH_REGISTRY_VALUE);
804 if (libPaths != NULL) {
805 must_free_libPaths = true;
806 } else {
807 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600808 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600809 }
Ian Elliott4470a302015-02-17 10:33:47 -0700810#else // WIN32
811 if (geteuid() == getuid()) {
812 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -0700813 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -0700814 }
815 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600816 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700817 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700818#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600819
Ian Elliott4470a302015-02-17 10:33:47 -0700820 if (libPaths == NULL) {
821 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700822 return;
823 }
Ian Elliott4470a302015-02-17 10:33:47 -0700824 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700825 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -0700826 if (loader.layer_dirs == NULL) {
Jon Ashburn90c6a0e2015-06-04 15:30:58 -0600827 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
828
Ian Elliott4470a302015-02-17 10:33:47 -0700829 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -0700830 return;
Ian Elliott4470a302015-02-17 10:33:47 -0700831 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600832 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott4470a302015-02-17 10:33:47 -0700833 strcpy(loader.layer_dirs, libPaths);
834#if defined(WIN32)
835 // Free any allocated memory:
836 if (must_free_libPaths) {
837 free(libPaths);
838 must_free_libPaths = false;
839 }
840#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700841 libPaths = loader.layer_dirs;
842
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600843 /* cleanup any previously scanned libraries */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600844 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600845 if (loader.scanned_layers[i].lib_name != NULL)
846 free(loader.scanned_layers[i].lib_name);
847 loader_destroy_ext_list(&loader.scanned_layers[i].global_extension_list);
848 loader.scanned_layers[i].lib_name = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600849 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600850 loader.scanned_layer_count = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600851 count = 0;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600852
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600853 for (p = libPaths; *p; p = next) {
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600854 next = strchr(p, PATH_SEPERATOR);
855 if (next == NULL) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600856 len = (uint32_t) strlen(p);
857 next = p + len;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600858 }
859 else {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600860 len = (uint32_t) (next - p);
861 *(char *) next = '\0';
862 next++;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600863 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600864
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600865 curdir = opendir(p);
866 if (curdir) {
867 dent = readdir(curdir);
868 while (dent) {
869 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
870 * ending with VK_LIBRARY_SUFFIX
871 */
872 if (!strncmp(dent->d_name,
873 VK_LAYER_LIBRARY_PREFIX,
874 VK_LAYER_LIBRARY_PREFIX_LEN)) {
875 uint32_t nlen = (uint32_t) strlen(dent->d_name);
876 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
877 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
878 !strncmp(suf,
879 VK_LIBRARY_SUFFIX,
880 VK_LIBRARY_SUFFIX_LEN)) {
881 loader_platform_dl_handle handle;
882 snprintf(temp_str, sizeof(temp_str),
883 "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
884 // Used to call: dlopen(temp_str, RTLD_LAZY)
885 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
886 "Attempt to open library: %s\n", temp_str);
887 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
Courtney Goeltzenleuchter57fb1572015-06-08 15:13:50 -0600888 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed\n");
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600889 dent = readdir(curdir);
890 continue;
891 }
892 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
893 "Opened library: %s\n", temp_str);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -0600894
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600895 /* TODO: Remove fixed count */
896 if (count == MAX_LAYER_LIBRARIES) {
897 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
898 "%s ignored: max layer libraries exceed",
899 temp_str);
900 break;
901 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600902
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600903 fp_get_ext = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionInfo");
904 if (!fp_get_ext) {
905 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
906 "Couldn't dlsym vkGetGlobalExtensionInfo from library %s",
907 temp_str);
908 dent = readdir(curdir);
909 loader_platform_close_library(handle);
910 continue;
911 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600912
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600913 loader.scanned_layers[count].lib_name =
914 malloc(strlen(temp_str) + 1);
915 if (loader.scanned_layers[count].lib_name == NULL) {
916 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "%s ignored: out of memory", temp_str);
917 break;
918 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600919
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600920 strcpy(loader.scanned_layers[count].lib_name, temp_str);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600921
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600922 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for %s\n", temp_str);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600923 get_global_extensions(
924 fp_get_ext,
925 "vkGetGlobalExtensionInfo",
926 loader.scanned_layers[count].lib_name,
927 VK_EXTENSION_ORIGIN_LAYER,
928 &loader.scanned_layers[count].global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600929
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600930 fp_get_ext = loader_platform_get_proc_address(handle,
931 "vkGetPhysicalDeviceExtensionInfo");
932 if (fp_get_ext) {
933 loader.scanned_layers[count].physical_device_extensions_supported = true;
934 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600935
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600936 count++;
937 loader_platform_close_library(handle);
938 }
939 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600940
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600941 dent = readdir(curdir);
942 } // while (dir_entry)
943 if (count == MAX_LAYER_LIBRARIES)
944 break;
945 closedir(curdir);
946 } // if (curdir))
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600947 } // for (libpaths)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600948
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600949 loader.scanned_layer_count = count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600950 loader.layers_scanned = true;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600951}
952
Jon Ashburn27cd5842015-05-12 17:26:48 -0600953static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
954{
955 // inst is not wrapped
956 if (inst == VK_NULL_HANDLE) {
957 return NULL;
958 }
959 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
960 void *addr;
961
Jon Ashburn8fd08252015-05-28 16:25:02 -0600962 if (!strcmp(pName, "vkGetInstanceProcAddr"))
963 return (void *) loader_gpa_instance_internal;
964
Jon Ashburn27cd5842015-05-12 17:26:48 -0600965 if (disp_table == NULL)
966 return NULL;
967
968 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600969 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -0600970 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600971 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600972
973 if (disp_table->GetInstanceProcAddr == NULL) {
974 return NULL;
975 }
976 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600977}
978
Jon Ashburn128f9422015-05-28 19:16:58 -0600979struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600980{
Jon Ashburn128f9422015-05-28 19:16:58 -0600981
Jon Ashburn98bd4542015-01-29 16:44:24 -0700982 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
983 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
984 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -0600985 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -0700986 *gpu_index = i;
987 return icd;
988 }
989 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600990 }
991 return NULL;
992}
993
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600994static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600995{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600996 if (icd->layer_count[gpu_index])
997 return true;
998 else
999 return false;
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001000}
1001
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001002static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -06001003 const char *chain_type,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001004 struct loader_extension_property *ext_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001005{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001006 struct loader_lib_info *new_layer_lib_list, *my_lib;
1007
1008 /* Only loader layer libraries here */
1009 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1010 return NULL;
1011 }
1012
1013 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1014 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1015 /* Have already loaded this library, just increment ref count */
1016 loader.loaded_layer_lib_list[i].ref_count++;
Jon Ashburne68a9ff2015-05-25 14:11:37 -06001017 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001018 "%s Chain: Increment layer reference count for layer library %s",
1019 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001020 return loader.loaded_layer_lib_list[i].lib_handle;
1021 }
1022 }
1023
1024 /* Haven't seen this library so load it */
1025 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1026 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1027 if (!new_layer_lib_list) {
1028 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1029 return NULL;
1030 }
1031
1032 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1033
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001034 /* NOTE: We require that the extension property be immutable */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001035 my_lib->lib_name = ext_prop->lib_name;
1036 my_lib->ref_count = 0;
1037 my_lib->lib_handle = NULL;
1038
1039 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1040 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1041 loader_platform_open_library_error(my_lib->lib_name));
1042 return NULL;
1043 } else {
1044 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001045 "Chain: %s: Loading layer library %s",
1046 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001047 }
1048 loader.loaded_layer_lib_count++;
1049 loader.loaded_layer_lib_list = new_layer_lib_list;
1050 my_lib->ref_count++;
1051
1052 return my_lib->lib_handle;
1053}
1054
1055static void loader_remove_layer_lib(
1056 struct loader_instance *inst,
1057 struct loader_extension_property *ext_prop)
1058{
1059 uint32_t idx;
1060 struct loader_lib_info *new_layer_lib_list, *my_lib;
1061
1062 /* Only loader layer libraries here */
1063 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001064 return;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001065 }
Jon Ashburndf7d5842014-10-16 15:48:50 -06001066
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001067 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1068 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1069 /* found matching library */
1070 idx = i;
1071 my_lib = &loader.loaded_layer_lib_list[i];
1072 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001073 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001074 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001075
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001076 my_lib->ref_count--;
1077 inst->layer_count--;
1078 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001079 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1080 "Decrement reference count for layer library %s", ext_prop->lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001081 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001082 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001083
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001084 loader_platform_close_library(my_lib->lib_handle);
1085 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1086 "Unloading layer library %s", ext_prop->lib_name);
1087
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001088 /* Need to remove unused library from list */
1089 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1090 if (!new_layer_lib_list) {
1091 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1092 return;
1093 }
1094
1095 if (idx > 0) {
1096 /* Copy records before idx */
1097 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1098 sizeof(struct loader_lib_info) * idx);
1099 }
1100 if (idx < (loader.loaded_layer_lib_count - 1)) {
1101 /* Copy records after idx */
1102 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1103 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1104 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001105
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001106 free(loader.loaded_layer_lib_list);
1107 loader.loaded_layer_lib_count--;
1108 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001109}
1110
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001111static void loader_add_layer_env(
1112 struct loader_extension_list *ext_list,
1113 const struct loader_extension_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001114{
Ian Elliott4470a302015-02-17 10:33:47 -07001115 char *layerEnv;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001116 uint32_t len;
Jon Ashburnd09bd102014-10-22 21:15:26 -06001117 char *p, *pOrig, *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001118
Ian Elliott4470a302015-02-17 10:33:47 -07001119#if defined(WIN32)
1120 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
1121 LAYER_NAMES_REGISTRY_VALUE);
1122#else // WIN32
1123 layerEnv = getenv(LAYER_NAMES_ENV);
1124#endif // WIN32
1125 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001126 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001127 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001128 p = malloc(strlen(layerEnv) + 1);
Ian Elliott4470a302015-02-17 10:33:47 -07001129 if (p == NULL) {
1130#if defined(WIN32)
1131 free(layerEnv);
1132#endif // WIN32
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001133 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001134 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001135 strcpy(p, layerEnv);
Ian Elliott4470a302015-02-17 10:33:47 -07001136#if defined(WIN32)
1137 free(layerEnv);
1138#endif // WIN32
Jon Ashburnd09bd102014-10-22 21:15:26 -06001139 pOrig = p;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001140
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001141 while (p && *p ) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001142 next = strchr(p, PATH_SEPERATOR);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001143 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -07001144 len = (uint32_t) strlen(p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001145 next = p + len;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001146 } else {
Ian Elliott19628802015-02-04 12:06:46 -07001147 len = (uint32_t) (next - p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001148 *(char *) next = '\0';
1149 next++;
1150 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001151 name = basename(p);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001152 loader_search_ext_list_for_name(name, search_list, ext_list);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001153 p = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001154 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001155
Jon Ashburnd09bd102014-10-22 21:15:26 -06001156 free(pOrig);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001157 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001158}
1159
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001160
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001161void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001162{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001163 if (!instance->layer_count) {
1164 return;
1165 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001166
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001167 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001168 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
1169 struct loader_extension_property *ext_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001170
1171 loader_remove_layer_lib(instance, ext_prop);
1172
1173 instance->layer_count--;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001174 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001175
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001176}
1177
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001178void loader_enable_instance_layers(struct loader_instance *inst)
1179{
1180 if (inst == NULL)
1181 return;
1182
1183 /* Add any layers specified in the environment first */
1184 loader_add_layer_env(&inst->enabled_instance_extensions, &loader.global_extensions);
1185
1186 /* Add layers / extensions specified by the application */
1187 loader_add_vk_ext_to_ext_list(
1188 &inst->enabled_instance_extensions,
1189 inst->app_extension_count,
1190 inst->app_extension_props,
1191 &loader.global_extensions);
1192}
1193
Jon Ashburn27cd5842015-05-12 17:26:48 -06001194uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1195{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001196 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06001197 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001198
Jon Ashburn27cd5842015-05-12 17:26:48 -06001199 if (inst == NULL)
1200 return 0;
1201
1202 // NOTE inst is unwrapped at this point in time
1203 VkObject baseObj = (VkObject) inst;
1204 VkObject nextObj = (VkObject) inst;
1205 VkBaseLayerObject *nextInstObj;
1206 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1207
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001208 /*
1209 * Figure out how many actual layers will need to be wrapped.
1210 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001211 for (uint32_t i = 0; i < inst->enabled_instance_extensions.count; i++) {
1212 struct loader_extension_property *ext_prop = &inst->enabled_instance_extensions.list[i];
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001213 if (ext_prop->alias) {
1214 ext_prop = ext_prop->alias;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001215 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001216 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1217 continue;
1218 }
1219 loader_add_to_ext_list(&inst->activated_layer_list, 1, ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001220 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001221
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001222 inst->layer_count = inst->activated_layer_list.count;
1223
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001224 if (!inst->layer_count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001225 return 0;
1226 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001227
Jon Ashburn128f9422015-05-28 19:16:58 -06001228 wrappedInstance = malloc(sizeof(VkBaseLayerObject)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001229 * inst->layer_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001230 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001231 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1232 return 0;
1233 }
1234
1235 /* Create instance chain of enabled layers */
1236 layer_idx = inst->layer_count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001237 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
1238 struct loader_extension_property *ext_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001239 loader_platform_dl_handle lib_handle;
1240
1241 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001242 * For global exenstions implemented within the loader (i.e. WSI, DEBUG_REPORT
1243 * the extension must provide two entry points for the loader to use:
1244 * - "trampoline" entry point - this is the address returned by GetProcAddr
1245 * and will always do what's necessary to support a global call.
1246 * - "terminator" function - this function will be put at the end of the
1247 * instance chain and will contain the necessary logica to call / process
1248 * the extension for the appropriate ICDs that are available.
1249 * There is no generic mechanism for including these functions, the references
1250 * must be placed into the appropriate loader entry points.
1251 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
1252 * loader_coalesce_extensions(void) - add extension records to the list of global
1253 * extension available to the app.
1254 * instance_disp - add function pointer for terminator function to this array.
1255 * The extension itself should be in a separate file that will be
1256 * linked directly with the loader.
1257 * Note: An extension's Get*ProcAddr should not return a function pointer for
1258 * any extension entry points until the extension has been enabled.
1259 * To do this requires a different behavior from Get*ProcAddr functions implemented
1260 * in layers.
1261 * The very first call to a layer will be it's Get*ProcAddr function requesting
1262 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1263 * with the wrapped object given (either Instance or Device) and return the layer's
1264 * Get*ProcAddr function. The layer should also use this opportunity to record the
1265 * baseObject so that it can find the correct local dispatch table on future calls.
1266 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1267 * will not use a wrapped object and must look up their local dispatch table from
1268 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001269 */
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001270 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001271
Jon Ashburn128f9422015-05-28 19:16:58 -06001272 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001273 nextInstObj->pGPA = nextGPA;
1274 nextInstObj->baseObject = baseObj;
1275 nextInstObj->nextObject = nextObj;
1276 nextObj = (VkObject) nextInstObj;
1277
1278 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001279 snprintf(funcStr, 256, "%sGetInstanceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001280 lib_handle = loader_add_layer_lib("instance", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001281 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1282 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001283 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001284 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 -06001285
1286 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001287 continue;
1288 }
1289
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001290 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1291 "Insert instance layer library %s for extension: %s",
1292 ext_prop->lib_name, ext_prop->info.name);
1293
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001294 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001295 }
1296
Jon Ashburn8fd08252015-05-28 16:25:02 -06001297 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001298
Jon Ashburn128f9422015-05-28 19:16:58 -06001299 free(wrappedInstance);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001300 return inst->layer_count;
1301}
1302
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001303void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1304{
1305
1306 loader_init_instance_extension_dispatch_table(inst->disp,
1307 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06001308 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001309}
1310
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001311void loader_enable_device_layers(struct loader_icd *icd, uint32_t gpu_index)
1312{
1313 if (icd == NULL)
1314 return;
1315
1316 /* Add any layers specified in the environment first */
1317 loader_add_layer_env(&icd->enabled_device_extensions[gpu_index], &loader.global_extensions);
1318
1319 /* Add layers / extensions specified by the application */
1320 loader_add_vk_ext_to_ext_list(
1321 &icd->enabled_device_extensions[gpu_index],
1322 icd->app_extension_count[gpu_index],
1323 icd->app_extension_props[gpu_index],
1324 &loader.global_extensions);
1325}
1326
1327extern uint32_t loader_activate_device_layers(
1328 VkDevice device,
1329 struct loader_icd *icd,
1330 uint32_t gpu_index,
1331 uint32_t ext_count,
1332 const VkExtensionProperties *ext_props)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001333{
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001334 uint32_t count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001335 uint32_t layer_idx;
1336
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001337 if (!icd)
1338 return 0;
Jon Ashburn83a64252015-04-15 11:31:12 -06001339 assert(gpu_index < MAX_GPUS_FOR_LAYER);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001340
1341 /* activate any layer libraries */
1342 if (!loader_layers_activated(icd, gpu_index)) {
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001343 VkObject nextObj = (VkObject) device;
1344 VkObject baseObj = nextObj;
1345 VkBaseLayerObject *nextGpuObj;
Jon Ashburn7c096122015-05-22 09:19:49 -06001346 PFN_vkGetDeviceProcAddr nextGPA = icd->GetDeviceProcAddr;
Jon Ashburnce94f312015-05-28 19:25:20 -06001347 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001348 count = 0;
1349 for (uint32_t i = 0; i < icd->enabled_device_extensions[gpu_index].count; i++) {
1350 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1351 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER) {
1352 count++;
1353 }
1354 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001355 if (!count)
1356 return 0;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001357
1358 icd->layer_count[gpu_index] = count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001359
Jon Ashburnce94f312015-05-28 19:25:20 -06001360 wrappedGpus = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]);
1361 if (! wrappedGpus) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001362 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001363 return 0;
1364 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001365 layer_idx = count - 1;
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001366 for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001367 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1368 loader_platform_dl_handle lib_handle;
1369
1370 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1371 continue;
1372 }
1373
Jon Ashburnce94f312015-05-28 19:25:20 -06001374 nextGpuObj = (wrappedGpus + i);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001375 nextGpuObj->pGPA = nextGPA;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001376 nextGpuObj->baseObject = baseObj;
1377 nextGpuObj->nextObject = nextObj;
1378 nextObj = (VkObject) nextGpuObj;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001379
Jon Ashburn79113cc2014-12-01 14:22:40 -07001380 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001381 snprintf(funcStr, 256, "%sGetDeviceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001382 lib_handle = loader_add_layer_lib("device", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001383 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1384 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001385 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001386 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 -06001387 continue;
1388 }
1389
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001390 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1391 "Insert device layer library %s for extension: %s",
1392 ext_prop->lib_name, ext_prop->info.name);
1393
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001394 layer_idx--;
1395 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001396
Jon Ashburn8fd08252015-05-28 16:25:02 -06001397 loader_init_device_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA,
1398 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
Jon Ashburnce94f312015-05-28 19:25:20 -06001399 free(wrappedGpus);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001400 } else {
1401 // TODO: Check that active layers match requested?
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001402 }
1403 return icd->layer_count[gpu_index];
1404}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001405
Jon Ashburn27cd5842015-05-12 17:26:48 -06001406VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001407 const VkInstanceCreateInfo* pCreateInfo,
1408 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001409{
Jon Ashburneed0c002015-05-21 17:42:17 -06001410 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07001411 struct loader_scanned_icds *scanned_icds;
1412 struct loader_icd *icd;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001413 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001414
Jon Ashburn46888392015-01-29 15:45:51 -07001415 scanned_icds = loader.scanned_icd_list;
1416 while (scanned_icds) {
1417 icd = loader_icd_add(ptr_instance, scanned_icds);
1418 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -06001419 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn3da71f22015-05-14 12:43:38 -06001420 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001421 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07001422 {
1423 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001424 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001425 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001426 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07001427 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06001428 } else
1429 {
1430 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07001431 }
1432 }
1433 scanned_icds = scanned_icds->next;
1434 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001435
Ian Elliotteb450762015-02-05 15:19:15 -07001436 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001437 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -07001438 }
Jon Ashburn46888392015-01-29 15:45:51 -07001439
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001440 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001441}
1442
Jon Ashburn27cd5842015-05-12 17:26:48 -06001443VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001444 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001445{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06001446 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001447 struct loader_icd *icds = ptr_instance->icds;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001448 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001449
1450 // Remove this instance from the list of instances:
1451 struct loader_instance *prev = NULL;
1452 struct loader_instance *next = loader.instances;
1453 while (next != NULL) {
1454 if (next == ptr_instance) {
1455 // Remove this instance from the list:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001456 free(ptr_instance->app_extension_props);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001457 if (prev)
1458 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07001459 else
1460 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001461 break;
1462 }
1463 prev = next;
1464 next = next->next;
1465 }
1466 if (next == NULL) {
1467 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001468 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001469 }
1470
Jon Ashburn3da71f22015-05-14 12:43:38 -06001471 while (icds) {
1472 if (icds->instance) {
1473 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06001474 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001475 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06001476 "ICD ignored: failed to DestroyInstance on device");
1477 }
Jon Ashburn128f9422015-05-28 19:16:58 -06001478 loader_icd_destroy(ptr_instance, icds);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001479 icds->instance = VK_NULL_HANDLE;
1480 icds = icds->next;
Jon Ashburn46888392015-01-29 15:45:51 -07001481 }
1482
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001483
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001484 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001485}
1486
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001487VkResult loader_init_physical_device_info(
1488 struct loader_instance *ptr_instance)
1489{
1490 struct loader_icd *icd;
1491 uint32_t n, count = 0;
1492 VkResult res = VK_ERROR_UNKNOWN;
1493
1494 icd = ptr_instance->icds;
1495 while (icd) {
1496 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
1497 if (res != VK_SUCCESS)
1498 return res;
1499 icd->gpu_count = n;
1500 count += n;
1501 icd = icd->next;
1502 }
1503
1504 ptr_instance->total_gpu_count = count;
1505
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001506 icd = ptr_instance->icds;
1507 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001508 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
1509
1510 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001511 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
1512 if (!icd->gpus) {
1513 /* TODO: Add cleanup code here */
1514 return VK_ERROR_OUT_OF_HOST_MEMORY;
1515 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001516 res = icd->EnumeratePhysicalDevices(
1517 icd->instance,
1518 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06001519 icd->gpus);
1520 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001521
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001522 icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n *
1523 sizeof(VkLayerDispatchTable));
1524 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001525
1526 loader_init_device_dispatch_table(icd->loader_dispatch + i,
Jon Ashburn128f9422015-05-28 19:16:58 -06001527 get_proc_addr, icd->gpus[i], icd->gpus[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001528
Jon Ashburn128f9422015-05-28 19:16:58 -06001529 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001530
1531 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
1532 /* TODO: Add cleanup code here */
1533 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1534 }
1535 if (res == VK_SUCCESS && icd->GetPhysicalDeviceExtensionInfo) {
1536 size_t data_size;
1537 uint32_t extension_count;
1538
1539 data_size = sizeof(extension_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001540 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_COUNT, 0, &data_size, &extension_count);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001541 if (data_size == sizeof(extension_count) && res == VK_SUCCESS) {
1542 struct loader_extension_property ext_props;
1543
1544 /* Gather all the ICD extensions */
1545 for (uint32_t extension_id = 0; extension_id < extension_count; extension_id++) {
1546 data_size = sizeof(VkExtensionProperties);
Jon Ashburn128f9422015-05-28 19:16:58 -06001547 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_PROPERTIES,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001548 extension_id, &data_size, &ext_props.info);
1549 if (data_size == sizeof(VkExtensionProperties) && res == VK_SUCCESS) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001550 ext_props.origin = VK_EXTENSION_ORIGIN_ICD;
1551 ext_props.lib_name = icd->scanned_icds->lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -06001552 // For ICDs, this is the only option
1553 strcpy(ext_props.get_extension_info_name, "vkGetPhysicalDeviceExtensionInfo");
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001554 loader_add_to_ext_list(&icd->device_extension_cache[i], 1, &ext_props);
1555 }
1556 }
1557
1558 // Traverse layers list adding non-duplicate extensions to the list
1559 for (uint32_t l = 0; l < loader.scanned_layer_count; l++) {
Jon Ashburn128f9422015-05-28 19:16:58 -06001560 get_physical_device_layer_extensions(ptr_instance, icd->gpus[i], l, &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001561 }
1562 }
1563 }
1564
1565 if (res != VK_SUCCESS) {
1566 /* clean up any extension lists previously created before this request failed */
1567 for (uint32_t j = 0; j < i; j++) {
1568 loader_destroy_ext_list(&icd->device_extension_cache[i]);
1569 }
1570 return res;
1571 }
1572 }
1573
1574 count += n;
1575 }
1576
1577 icd = icd->next;
1578 }
1579
1580 return VK_SUCCESS;
1581}
1582
Jon Ashburn27cd5842015-05-12 17:26:48 -06001583VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06001584 VkInstance instance,
1585 uint32_t* pPhysicalDeviceCount,
1586 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001587{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001588 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001589 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001590 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001591
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001592 if (ptr_instance->total_gpu_count == 0) {
1593 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001594 }
1595
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001596 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
1597 if (!pPhysicalDevices) {
1598 return VK_SUCCESS;
1599 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001600
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001601 while (icd) {
1602 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06001603 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001604 index += icd->gpu_count;
1605 icd = icd->next;
1606 }
1607
1608 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001609}
1610
Jon Ashburn3da71f22015-05-14 12:43:38 -06001611VkResult loader_GetPhysicalDeviceInfo(
1612 VkPhysicalDevice gpu,
1613 VkPhysicalDeviceInfoType infoType,
1614 size_t* pDataSize,
1615 void* pData)
1616{
1617 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001618 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001619 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1620
1621 if (icd->GetPhysicalDeviceInfo)
1622 res = icd->GetPhysicalDeviceInfo(gpu, infoType, pDataSize, pData);
1623
1624 return res;
1625}
1626
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001627VkResult loader_CreateDevice(
1628 VkPhysicalDevice gpu,
1629 const VkDeviceCreateInfo* pCreateInfo,
1630 VkDevice* pDevice)
1631{
1632 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001633 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001634 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001635
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001636 if (icd->CreateDevice) {
1637 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001638 if (res != VK_SUCCESS) {
1639 return res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001640 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001641
1642 VkLayerDispatchTable *dev_disp = icd->loader_dispatch + gpu_index;
1643 loader_init_dispatch(*pDevice, dev_disp);
1644
1645 icd->app_extension_count[gpu_index] = pCreateInfo->extensionCount;
1646 icd->app_extension_props[gpu_index] = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1647 if (icd->app_extension_props[gpu_index] == NULL && (icd->app_extension_count[gpu_index] > 0)) {
1648 return VK_ERROR_OUT_OF_HOST_MEMORY;
1649 }
1650
1651 /* Make local copy of extension list */
1652 if (icd->app_extension_count[gpu_index] > 0 && icd->app_extension_props[gpu_index] != NULL) {
1653 memcpy(icd->app_extension_props[gpu_index], pCreateInfo->pEnabledExtensions, sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1654 }
1655
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001656 /*
1657 * Put together the complete list of extensions to enable
1658 * This includes extensions requested via environment variables.
1659 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001660 loader_enable_device_layers(icd, gpu_index);
1661
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001662 /*
1663 * Load the libraries needed by the extensions on the
1664 * enabled extension list. This will build the
1665 * device instance chain terminating with the
1666 * selected device.
1667 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001668 loader_activate_device_layers(*pDevice, icd, gpu_index,
1669 icd->app_extension_count[gpu_index],
1670 icd->app_extension_props[gpu_index]);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001671 }
1672
1673 return res;
1674}
1675
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001676LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
1677{
Jon Ashburn07daee72015-05-21 18:13:33 -06001678 if (instance == VK_NULL_HANDLE)
1679 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001680
Jon Ashburn07daee72015-05-21 18:13:33 -06001681 void *addr;
1682 /* get entrypoint addresses that are global (in the loader)*/
1683 addr = globalGetProcAddr(pName);
1684 if (addr)
1685 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001686
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001687 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
1688
1689 addr = debug_report_instance_gpa(ptr_instance, pName);
1690 if (addr) {
1691 return addr;
1692 }
1693
Jon Ashburn07daee72015-05-21 18:13:33 -06001694 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001695 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001696 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001697 return (ptr_instance->wsi_lunarg_enabled) ? addr : NULL;
Jon Ashburn07daee72015-05-21 18:13:33 -06001698
1699 /* return the instance dispatch table entrypoint for extensions */
1700 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
1701 if (disp_table == NULL)
1702 return NULL;
1703
1704 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
1705 if (addr)
1706 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001707
1708 return NULL;
1709}
1710
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001711LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001712{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001713 if (device == VK_NULL_HANDLE) {
1714 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001715 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001716
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001717 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001718
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001719 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
1720 make sure the loader entrypoint is returned */
1721 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06001722 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001723 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06001724 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001725
Jon Ashburn07daee72015-05-21 18:13:33 -06001726 /* return any extension device entrypoints the loader knows about */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001727 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001728 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001729 return addr;
Jon Ashburn07daee72015-05-21 18:13:33 -06001730
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001731 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001732 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001733 if (disp_table == NULL)
1734 return NULL;
1735
Jon Ashburn27cd5842015-05-12 17:26:48 -06001736 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001737 if (addr)
1738 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001739 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001740 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001741 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001742 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001743 }
1744}
1745
Jon Ashburneceb13e2015-05-18 15:28:32 -06001746LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001747 VkExtensionInfoType infoType,
1748 uint32_t extensionIndex,
1749 size_t* pDataSize,
1750 void* pData)
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001751{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001752 uint32_t *count;
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001753 VkResult res = VK_SUCCESS;
1754
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001755 /* Scan/discover all ICD libraries in a single-threaded manner */
1756 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001757
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001758 /* get layer libraries in a single-threaded manner */
1759 loader_platform_thread_once(&once_layer, layer_lib_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001760
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001761 /* merge any duplicate extensions */
1762 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
1763
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001764 if (pDataSize == NULL)
1765 return VK_ERROR_INVALID_POINTER;
1766
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001767 loader_platform_thread_lock_mutex(&loader_lock);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001768 switch (infoType) {
1769 case VK_EXTENSION_INFO_TYPE_COUNT:
1770 *pDataSize = sizeof(uint32_t);
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001771 if (pData == NULL) {
1772 loader_platform_thread_unlock_mutex(&loader_lock);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001773 return VK_SUCCESS;
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001774 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001775 count = (uint32_t *) pData;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001776 *count = loader.global_extensions.count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001777 break;
1778 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1779 *pDataSize = sizeof(VkExtensionProperties);
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001780 if (pData == NULL) {
1781 loader_platform_thread_unlock_mutex(&loader_lock);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001782 return VK_SUCCESS;
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001783 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001784 if (extensionIndex >= loader.global_extensions.count)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001785 return VK_ERROR_INVALID_VALUE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001786 memcpy((VkExtensionProperties *) pData,
1787 &loader.global_extensions.list[extensionIndex],
1788 sizeof(VkExtensionProperties));
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001789 break;
1790 default:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001791 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Invalid infoType in vkGetGlobalExtensionInfo");
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001792 res = VK_ERROR_INVALID_VALUE;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001793 };
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001794 loader_platform_thread_unlock_mutex(&loader_lock);
1795 return res;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001796}
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001797
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001798VkResult loader_GetPhysicalDeviceExtensionInfo(
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001799 VkPhysicalDevice gpu,
1800 VkExtensionInfoType infoType,
1801 uint32_t extensionIndex,
1802 size_t* pDataSize,
1803 void* pData)
1804{
1805 uint32_t gpu_index;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001806 uint32_t *count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001807 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001808
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001809 if (pDataSize == NULL)
1810 return VK_ERROR_INVALID_POINTER;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001811
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001812 switch (infoType) {
1813 case VK_EXTENSION_INFO_TYPE_COUNT:
1814 *pDataSize = sizeof(uint32_t);
1815 if (pData == NULL)
1816 return VK_SUCCESS;
1817 count = (uint32_t *) pData;
1818 *count = icd->device_extension_cache[gpu_index].count;
1819 break;
1820 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1821 *pDataSize = sizeof(VkExtensionProperties);
1822 if (pData == NULL)
1823 return VK_SUCCESS;
1824 if (extensionIndex >= icd->device_extension_cache[gpu_index].count)
1825 return VK_ERROR_INVALID_VALUE;
1826 memcpy((VkExtensionProperties *) pData,
1827 &icd->device_extension_cache[gpu_index].list[extensionIndex],
1828 sizeof(VkExtensionProperties));
1829 break;
1830 default:
1831 return VK_ERROR_INVALID_VALUE;
1832 };
1833
1834 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001835}
1836
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001837VkResult loader_GetMultiDeviceCompatibility(
1838 VkPhysicalDevice gpu0,
1839 VkPhysicalDevice gpu1,
1840 VkPhysicalDeviceCompatibilityInfo* pInfo)
1841{
1842 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001843 struct loader_icd *icd = loader_get_icd(gpu0, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001844 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1845
1846 if (icd->GetMultiDeviceCompatibility)
1847 res = icd->GetMultiDeviceCompatibility(gpu0, gpu1, pInfo);
1848
1849 return res;
1850}