blob: 6a8e25c6372da6686626d5cf8a8387cb905a32dc [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
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060067/* TODO: do we need to lock around access to linked lists and such? */
Jon Ashburn27cd5842015-05-12 17:26:48 -060068struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080069
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060070enum loader_debug {
71 LOADER_INFO_BIT = VK_BIT(0),
72 LOADER_WARN_BIT = VK_BIT(1),
73 LOADER_PERF_BIT = VK_BIT(2),
74 LOADER_ERROR_BIT = VK_BIT(3),
75 LOADER_DEBUG_BIT = VK_BIT(4),
76};
77
78uint32_t g_loader_debug = 0;
79uint32_t g_loader_log_msgs = 0;
80
Jon Ashburn27cd5842015-05-12 17:26:48 -060081VkLayerInstanceDispatchTable instance_disp = {
82 .GetInstanceProcAddr = vkGetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060083 .CreateInstance = loader_CreateInstance,
84 .DestroyInstance = loader_DestroyInstance,
85 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060086 .GetPhysicalDeviceInfo = loader_GetPhysicalDeviceInfo,
87 .CreateDevice = loader_CreateDevice,
Jon Ashburneceb13e2015-05-18 15:28:32 -060088 .GetGlobalExtensionInfo = vkGetGlobalExtensionInfo,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -060089 .GetPhysicalDeviceExtensionInfo = vkGetPhysicalDeviceExtensionInfo,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060090 .GetMultiDeviceCompatibility = loader_GetMultiDeviceCompatibility,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060091 .GetDisplayInfoWSI = loader_GetDisplayInfoWSI,
92 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
93 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -060094};
95
96LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
97LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
98LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070099
Ian Elliott4470a302015-02-17 10:33:47 -0700100#if defined(WIN32)
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600101char *loader_get_registry_string(const HKEY hive,
102 const LPCTSTR sub_key,
103 const char *value)
104{
105 DWORD access_flags = KEY_QUERY_VALUE;
106 DWORD value_type;
107 HKEY key;
Ian Elliottf851ddf2015-04-28 15:57:32 -0600108 VkResult rtn_value;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600109 char *rtn_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600110 DWORD rtn_len = 0;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600111 size_t allocated_len = 0;
112
113 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
114 if (rtn_value != ERROR_SUCCESS) {
115 // We didn't find the key. Try the 32-bit hive (where we've seen the
116 // key end up on some people's systems):
117 access_flags |= KEY_WOW64_32KEY;
118 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
119 if (rtn_value != ERROR_SUCCESS) {
120 // We still couldn't find the key, so give up:
121 return NULL;
122 }
123 }
124
125 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600126 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600127 if (rtn_value == ERROR_SUCCESS) {
128 // If we get to here, we found the key, and need to allocate memory
129 // large enough for rtn_str, and query again:
130 allocated_len = rtn_len + 4;
131 rtn_str = malloc(allocated_len);
132 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600133 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600134 if (rtn_value == ERROR_SUCCESS) {
135 // We added 4 extra bytes to rtn_str, so that we can ensure that
136 // the string is NULL-terminated (albeit, in a brute-force manner):
137 rtn_str[allocated_len-1] = '\0';
138 } else {
139 // This should never occur, but in case it does, clean up:
140 free(rtn_str);
141 rtn_str = NULL;
142 }
143 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
144
145 // Close the registry key that was opened:
146 RegCloseKey(key);
147
148 return rtn_str;
149}
150
151
Ian Elliott4470a302015-02-17 10:33:47 -0700152// For ICD developers, look in the registry, and look for an environment
153// variable for a path(s) where to find the ICD(s):
154static char *loader_get_registry_and_env(const char *env_var,
155 const char *registry_value)
156{
157 char *env_str = getenv(env_var);
158 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600159 char *registry_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600160 size_t registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700161 char *rtn_str = NULL;
162 size_t rtn_len;
163
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600164 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600165 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600166 registry_value);
Ian Elliottf851ddf2015-04-28 15:57:32 -0600167 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700168
169 rtn_len = env_len + registry_len + 1;
170 if (rtn_len <= 2) {
171 // We found neither the desired registry value, nor the environment
172 // variable; return NULL:
173 return NULL;
174 } else {
175 // We found something, and so we need to allocate memory for the string
176 // to return:
177 rtn_str = malloc(rtn_len);
178 }
179
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600180 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700181 // We didn't find the desired registry value, and so we must have found
182 // only the environment variable:
183 _snprintf(rtn_str, rtn_len, "%s", env_str);
184 } else if (env_str != NULL) {
185 // We found both the desired registry value and the environment
186 // variable, so concatenate them both:
187 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
188 } else {
189 // We must have only found the desired registry value:
190 _snprintf(rtn_str, rtn_len, "%s", registry_str);
191 }
192
Ian Elliott2de26bc2015-04-03 13:13:01 -0600193 if (registry_str) {
194 free(registry_str);
195 }
Ian Elliott4470a302015-02-17 10:33:47 -0700196
197 return(rtn_str);
198}
199#endif // WIN32
200
201
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600202static void loader_log(VkFlags msg_type, int32_t msg_code,
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800203 const char *format, ...)
204{
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800205 char msg[256];
206 va_list ap;
207 int ret;
208
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600209 if (!(msg_code & g_loader_log_msgs)) {
210 return;
211 }
212
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800213 va_start(ap, format);
214 ret = vsnprintf(msg, sizeof(msg), format, ap);
Ian Elliott42045842015-02-13 14:29:21 -0700215 if ((ret >= (int) sizeof(msg)) || ret < 0) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800216 msg[sizeof(msg) - 1] = '\0';
217 }
218 va_end(ap);
219
Jon Ashburnae053e92015-04-24 14:10:50 -0700220#if defined(WIN32)
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600221 OutputDebugString(msg);
Jon Ashburn1de39402015-05-05 16:20:46 -0600222#endif
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -0600223 fputs(msg, stderr);
224 fputc('\n', stderr);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800225}
226
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600227bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
228{
229 return memcmp(op1, op2, sizeof(VkExtensionProperties)) == 0 ? true : false;
230}
231
232/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600233 * Search the given ext_list for an extension
234 * matching the given vk_ext_prop
235 */
236bool has_vk_extension_property(
237 const VkExtensionProperties *vk_ext_prop,
238 const struct loader_extension_list *ext_list)
239{
240 for (uint32_t i = 0; i < ext_list->count; i++) {
241 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
242 return true;
243 }
244 return false;
245}
246
247/*
248 * Search the given ext_list for an extension
249 * matching the given vk_ext_prop
250 */
251static struct loader_extension_property *get_extension_property_from_vkext(
252 const VkExtensionProperties *vk_ext_prop,
253 const struct loader_extension_list *ext_list)
254{
255 for (uint32_t i = 0; i < ext_list->count; i++) {
256 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
257 return &ext_list->list[i];
258 }
259 return NULL;
260}
261
262static void get_global_extensions(
263 const PFN_vkGetGlobalExtensionInfo fp_get,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600264 const char *get_extension_info_name,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600265 const char *lib_name,
266 const enum extension_origin origin,
267 struct loader_extension_list *ext_list)
268{
269 uint32_t i, count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600270 size_t siz = sizeof(count);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600271 struct loader_extension_property ext_props;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600272 VkResult res;
273
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600274 res = fp_get(VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
275 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600276 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from ICD");
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600277 return;
278 }
279 siz = sizeof(VkExtensionProperties);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600280 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600281 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600282 res = fp_get(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600283 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600284 ext_props.hosted = false;
285 ext_props.origin = origin;
286 ext_props.lib_name = lib_name;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600287 strncpy(ext_props.get_extension_info_name, get_extension_info_name, MAX_EXTENSION_NAME_SIZE);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600288 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600289 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600290 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600291
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600292 return;
293}
294
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600295static void get_physical_device_layer_extensions(
296 struct loader_instance *ptr_instance,
297 VkPhysicalDevice physical_device,
298 const uint32_t layer_index,
299 struct loader_extension_list *ext_list)
300{
301 uint32_t i, count;
302 size_t siz = sizeof(count);
303 VkResult res;
304 loader_platform_dl_handle lib_handle;
305 PFN_vkGetPhysicalDeviceExtensionInfo fp_get;
306 struct loader_extension_property ext_props;
307
308 if (!loader.scanned_layers[layer_index].physical_device_extensions_supported) {
309 return;
310 }
311
312 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
313 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -0600314 char funcStr[MAX_EXTENSION_NAME_SIZE+1]; // add one character for 0 termination
315 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetPhysicalDeviceExtensionInfo", ext_props.info.name);
316 funcStr[MAX_EXTENSION_NAME_SIZE] = 0; // make sure string is 0 terminated
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600317 lib_handle = loader_add_layer_lib("device", &ext_props);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600318
319 /* first try extension specific function, then generic */
320 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
321 if (!fp_get) {
Jon Ashburn128f9422015-05-28 19:16:58 -0600322 sprintf(funcStr, "vkGetPhysicalDeviceExtensionInfo");
323 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600324 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600325 if (fp_get) {
326 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
327 if (res == VK_SUCCESS) {
328 siz = sizeof(VkExtensionProperties);
329 for (i = 0; i < count; i++) {
330 memset(&ext_props, 0, sizeof(ext_props));
331 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
332 if (res == VK_SUCCESS && (ext_props.info.sType == VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES)) {
333 ext_props.hosted = false;
334 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
Jon Ashburn128f9422015-05-28 19:16:58 -0600335 strcpy(ext_props.get_extension_info_name, funcStr);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600336 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
337 loader_add_to_ext_list(ext_list, 1, &ext_props);
338 }
339 }
340 } else {
341 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
342 }
343 }
344
345 loader_remove_layer_lib(ptr_instance, &ext_props);
346 return;
347}
348
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600349static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600350{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600351 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
352 ext_info->list = malloc(ext_info->capacity);
353 if (ext_info->list == NULL) {
354 return false;
355 }
356 memset(ext_info->list, 0, ext_info->capacity);
357 ext_info->count = 0;
358 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600359}
360
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600361void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600362{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600363 free(ext_info->list);
364 ext_info->count = 0;
365 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600366}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600367
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600368static void loader_add_vk_ext_to_ext_list(
369 struct loader_extension_list *ext_list,
370 uint32_t prop_list_count,
371 const VkExtensionProperties *props,
372 const struct loader_extension_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600373{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600374 struct loader_extension_property *ext_prop;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600375
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600376 for (uint32_t i = 0; i < prop_list_count; i++) {
377 // look for duplicates
378 if (has_vk_extension_property(&props[i], ext_list)) {
379 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600380 }
381
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600382 ext_prop = get_extension_property_from_vkext(&props[i], search_list);
383 if (!ext_prop) {
384 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", props[i].name);
385 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600386 }
387
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600388 loader_add_to_ext_list(ext_list, 1, ext_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600389 }
390}
391
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600392/*
393 * Append non-duplicate extension properties defined in prop_list
394 * to the given ext_info list
395 */
396void loader_add_to_ext_list(
397 struct loader_extension_list *ext_list,
398 uint32_t prop_list_count,
399 const struct loader_extension_property *props)
400{
401 uint32_t i;
402 struct loader_extension_property *cur_ext;
403
404 if (ext_list->list == NULL || ext_list->capacity == 0) {
405 loader_init_ext_list(ext_list);
406 }
407
408 if (ext_list->list == NULL)
409 return;
410
411 for (i = 0; i < prop_list_count; i++) {
412 cur_ext = (struct loader_extension_property *) &props[i];
413
414 // look for duplicates
415 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
416 continue;
417 }
418
419 // add to list at end
420 // check for enough capacity
421 if (ext_list->count * sizeof(struct loader_extension_property)
422 >= ext_list->capacity) {
423 // double capacity
424 ext_list->capacity *= 2;
425 ext_list->list = realloc(ext_list->list, ext_list->capacity);
426 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600427
428 /*
429 * Check if any extensions already on the list come from the same
430 * library and use the same Get*ExtensionInfo. If so, link this
431 * extension to the previous as an alias. That way when we activate
432 * extensions we only activiate the associated layer once no
433 * matter how many extensions are used.
434 */
435 for (uint32_t j = 0; j < ext_list->count; j++) {
436 struct loader_extension_property *active_property = &ext_list->list[j];
437 if (cur_ext->lib_name &&
438 cur_ext->origin == VK_EXTENSION_ORIGIN_LAYER &&
439 active_property->origin == VK_EXTENSION_ORIGIN_LAYER &&
440 strcmp(cur_ext->lib_name, active_property->lib_name) == 0 &&
441 strcmp(cur_ext->get_extension_info_name, active_property->get_extension_info_name) == 0 &&
442 active_property->alias == NULL) {
443 cur_ext->alias = active_property;
444 break;
445 }
446 }
447
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600448 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
449 ext_list->count++;
450 }
451}
452
453/*
454 * Search the search_list for any extension with
455 * a name that matches the given ext_name.
456 * Add all matching extensions to the found_list
457 * Do not add if found VkExtensionProperties is already
458 * on the found_list
459 */
460static void loader_search_ext_list_for_name(
461 const char *ext_name,
462 const struct loader_extension_list *search_list,
463 struct loader_extension_list *found_list)
464{
465 for (uint32_t i = 0; i < search_list->count; i++) {
466 struct loader_extension_property *ext_prop = &search_list->list[i];
467 if (0 == strcmp(ext_prop->info.name, ext_name)) {
468 /* Found an extension with the same name, add to found_list */
469 loader_add_to_ext_list(found_list, 1, &search_list->list[i]);
470 }
471 }
472}
473
474bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600475{
476 uint32_t i;
477
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600478 for (i = 0; i < loader.global_extensions.count; i++) {
479 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600480 return true;
481 }
482 return false;
483}
484
Jon Ashburn27cd5842015-05-12 17:26:48 -0600485void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600486{
487 uint32_t i;
488 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
489
490 // traverse scanned icd list adding non-duplicate extensions to the list
491 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600492 loader_add_to_ext_list(&loader.global_extensions,
493 icd_list->global_extension_list.count,
494 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600495 icd_list = icd_list->next;
496 };
497
498 //Traverse layers list adding non-duplicate extensions to the list
499 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600500 loader_add_to_ext_list(&loader.global_extensions,
501 loader.scanned_layers[i].global_extension_list.count,
502 loader.scanned_layers[i].global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600503 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600504
505 // Traverse loader's extensions, adding non-duplicate extensions to the list
506 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn0c5d4ab2015-05-26 13:57:35 -0600507 wsi_lunarg_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600508}
509
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600510static void loader_icd_destroy(
511 struct loader_instance *ptr_inst,
512 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800513{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600514 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600515 free(icd->gpus);
516 free(icd->loader_dispatch);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800517 free(icd);
518}
519
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600520static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800521{
522 struct loader_icd *icd;
523
524 icd = malloc(sizeof(*icd));
525 if (!icd)
526 return NULL;
527
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600528 memset(icd, 0, sizeof(*icd));
529
Jon Ashburn46d1f582015-01-28 11:01:35 -0700530 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800531
532 return icd;
533}
534
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600535static struct loader_icd *loader_icd_add(
536 struct loader_instance *ptr_inst,
537 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800538{
539 struct loader_icd *icd;
540
Jon Ashburn46d1f582015-01-28 11:01:35 -0700541 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800542 if (!icd)
543 return NULL;
544
Chia-I Wu13a61a52014-08-04 11:18:20 +0800545 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700546 icd->next = ptr_inst->icds;
547 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600548 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800549
550 return icd;
551}
552
Jon Ashburn46d1f582015-01-28 11:01:35 -0700553static void loader_scanned_icd_add(const char *filename)
554{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700555 loader_platform_dl_handle handle;
Jon Ashburn3da71f22015-05-14 12:43:38 -0600556 void *fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600557 void *fp_get_global_ext_info;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600558 void *fp_get_device_ext_info;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700559 struct loader_scanned_icds *new_node;
560
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700561 // Used to call: dlopen(filename, RTLD_LAZY);
562 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700563 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600564 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700565 return;
566 }
567
568#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600569 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700570 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600571 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700572 return; \
573 } \
574} while (0)
575
Jon Ashburn46888392015-01-29 15:45:51 -0700576 LOOKUP(fp_create_inst, CreateInstance);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600577 LOOKUP(fp_get_global_ext_info, GetGlobalExtensionInfo);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600578 LOOKUP(fp_get_device_ext_info, GetPhysicalDeviceExtensionInfo);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700579#undef LOOKUP
580
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600581 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
582 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700583 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600584 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700585 return;
586 }
587
588 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -0700589 new_node->CreateInstance = fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600590 new_node->GetGlobalExtensionInfo = fp_get_global_ext_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600591 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600592 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700593 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700594
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600595 new_node->lib_name = (char *) (new_node + 1);
596 if (!new_node->lib_name) {
597 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
598 return;
599 }
600 strcpy(new_node->lib_name, filename);
601
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600602 loader.scanned_icd_list = new_node;
603
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600604 get_global_extensions(
605 (PFN_vkGetGlobalExtensionInfo) fp_get_global_ext_info,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600606 "vkGetGlobalExtensionInfo",
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600607 new_node->lib_name,
608 VK_EXTENSION_ORIGIN_ICD,
609 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600610}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700611
Jon Ashburn3da71f22015-05-14 12:43:38 -0600612static void loader_icd_init_entrys(struct loader_icd *icd,
613 struct loader_scanned_icds *scanned_icds)
614{
615 /* initialize entrypoint function pointers */
616
617 #define LOOKUP(func) do { \
618 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
619 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600620 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -0600621 return; \
622 } \
623 } while (0)
624
Jon Ashburn8d1b0b52015-05-18 13:20:15 -0600625 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
626 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600627 LOOKUP(DestroyInstance);
628 LOOKUP(EnumeratePhysicalDevices);
629 LOOKUP(GetPhysicalDeviceInfo);
630 LOOKUP(CreateDevice);
631 LOOKUP(GetPhysicalDeviceExtensionInfo);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600632 LOOKUP(GetMultiDeviceCompatibility);
Jon Ashburn95a77ba2015-05-15 15:09:35 -0600633 LOOKUP(GetDisplayInfoWSI);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600634 LOOKUP(DbgCreateMsgCallback);
635 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600636#undef LOOKUP
637
638 return;
639}
640
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600641static void loader_debug_init(void)
642{
643 const char *env;
644
645 if (g_loader_debug > 0)
646 return;
647
648 g_loader_debug = 0;
649
650 /* parse comma-separated debug options */
651 env = getenv("LOADER_DEBUG");
652 while (env) {
653 const char *p = strchr(env, ',');
654 size_t len;
655
656 if (p)
657 len = p - env;
658 else
659 len = strlen(env);
660
661 if (len > 0) {
662 if (strncmp(env, "warn", len) == 0) {
663 g_loader_debug |= LOADER_WARN_BIT;
664 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
665 } else if (strncmp(env, "info", len) == 0) {
666 g_loader_debug |= LOADER_INFO_BIT;
667 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
668 } else if (strncmp(env, "perf", len) == 0) {
669 g_loader_debug |= LOADER_PERF_BIT;
670 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
671 } else if (strncmp(env, "error", len) == 0) {
672 g_loader_debug |= LOADER_ERROR_BIT;
673 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
674 } else if (strncmp(env, "debug", len) == 0) {
675 g_loader_debug |= LOADER_DEBUG_BIT;
676 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
677 }
678 }
679
680 if (!p)
681 break;
682
683 env = p + 1;
684 }
685}
686
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600687/**
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600688 * Try to \c loader_icd_scan VK driver(s).
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600689 *
690 * This function scans the default system path or path
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600691 * specified by the \c LIBVK_DRIVERS_PATH environment variable in
692 * order to find loadable VK ICDs with the name of libVK_*.
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600693 *
694 * \returns
695 * void; but side effect is to set loader_icd_scanned to true
696 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600697void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800698{
Ian Elliott4470a302015-02-17 10:33:47 -0700699 const char *p, *next;
700 char *libPaths = NULL;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600701 DIR *sysdir;
702 struct dirent *dent;
703 char icd_library[1024];
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600704 char path[1024];
Ian Elliott19628802015-02-04 12:06:46 -0700705 uint32_t len;
Ian Elliott4470a302015-02-17 10:33:47 -0700706#if defined(WIN32)
707 bool must_free_libPaths;
708 libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV,
709 DRIVER_PATH_REGISTRY_VALUE);
710 if (libPaths != NULL) {
711 must_free_libPaths = true;
712 } else {
713 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600714 libPaths = DEFAULT_VK_DRIVERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700715 }
716#else // WIN32
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600717 if (geteuid() == getuid()) {
Ian Elliott4470a302015-02-17 10:33:47 -0700718 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
719 libPaths = getenv(DRIVER_PATH_ENV);
720 }
721 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600722 libPaths = DEFAULT_VK_DRIVERS_PATH;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600723 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700724#endif // WIN32
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800725
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600726 loader_debug_init();
727
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600728 for (p = libPaths; *p; p = next) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700729 next = strchr(p, PATH_SEPERATOR);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600730 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -0700731 len = (uint32_t) strlen(p);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600732 next = p + len;
733 }
734 else {
Ian Elliott19628802015-02-04 12:06:46 -0700735 len = (uint32_t) (next - p);
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600736 sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
737 p = path;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600738 next++;
739 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800740
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700741 // TODO/TBD: Do we want to do this on Windows, or just let Windows take
742 // care of its own search path (which it apparently has)?
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600743 sysdir = opendir(p);
744 if (sysdir) {
745 dent = readdir(sysdir);
746 while (dent) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600747 /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and
748 * ending with VK_LIBRARY_SUFFIX
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700749 */
750 if (!strncmp(dent->d_name,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600751 VK_DRIVER_LIBRARY_PREFIX,
752 VK_DRIVER_LIBRARY_PREFIX_LEN)) {
Ian Elliott19628802015-02-04 12:06:46 -0700753 uint32_t nlen = (uint32_t) strlen(dent->d_name);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600754 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
755 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700756 !strncmp(suf,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600757 VK_LIBRARY_SUFFIX,
758 VK_LIBRARY_SUFFIX_LEN)) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700759 snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
760 loader_scanned_icd_add(icd_library);
761 }
762 }
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600763
764 dent = readdir(sysdir);
765 }
766 closedir(sysdir);
767 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800768 }
769
Ian Elliott4470a302015-02-17 10:33:47 -0700770#if defined(WIN32)
771 // Free any allocated memory:
772 if (must_free_libPaths) {
773 free(libPaths);
774 }
775#endif // WIN32
776
777 // Note that we've scanned for ICDs:
Jon Ashburn46d1f582015-01-28 11:01:35 -0700778 loader.icds_scanned = true;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800779}
780
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600781
Jon Ashburn27cd5842015-05-12 17:26:48 -0600782void layer_lib_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600783{
784 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -0700785 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600786 DIR *curdir;
787 struct dirent *dent;
Ian Elliott4470a302015-02-17 10:33:47 -0700788 size_t len, i;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600789 char temp_str[1024];
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600790 uint32_t count;
791 PFN_vkGetGlobalExtensionInfo fp_get_ext;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600792
Ian Elliott4470a302015-02-17 10:33:47 -0700793#if defined(WIN32)
794 bool must_free_libPaths;
795 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
796 LAYERS_PATH_REGISTRY_VALUE);
797 if (libPaths != NULL) {
798 must_free_libPaths = true;
799 } else {
800 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600801 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600802 }
Ian Elliott4470a302015-02-17 10:33:47 -0700803#else // WIN32
804 if (geteuid() == getuid()) {
805 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -0700806 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -0700807 }
808 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600809 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700810 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700811#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600812
Ian Elliott4470a302015-02-17 10:33:47 -0700813 if (libPaths == NULL) {
814 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700815 return;
816 }
Ian Elliott4470a302015-02-17 10:33:47 -0700817 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700818 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -0700819 if (loader.layer_dirs == NULL) {
820 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -0700821 return;
Ian Elliott4470a302015-02-17 10:33:47 -0700822 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600823 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott4470a302015-02-17 10:33:47 -0700824 strcpy(loader.layer_dirs, libPaths);
825#if defined(WIN32)
826 // Free any allocated memory:
827 if (must_free_libPaths) {
828 free(libPaths);
829 must_free_libPaths = false;
830 }
831#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700832 libPaths = loader.layer_dirs;
833
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600834 /* cleanup any previously scanned libraries */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600835 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600836 if (loader.scanned_layers[i].lib_name != NULL)
837 free(loader.scanned_layers[i].lib_name);
838 loader_destroy_ext_list(&loader.scanned_layers[i].global_extension_list);
839 loader.scanned_layers[i].lib_name = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600840 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600841 loader.scanned_layer_count = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600842 count = 0;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600843
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600844 for (p = libPaths; *p; p = next) {
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600845 next = strchr(p, PATH_SEPERATOR);
846 if (next == NULL) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600847 len = (uint32_t) strlen(p);
848 next = p + len;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600849 }
850 else {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600851 len = (uint32_t) (next - p);
852 *(char *) next = '\0';
853 next++;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600854 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600855
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600856 curdir = opendir(p);
857 if (curdir) {
858 dent = readdir(curdir);
859 while (dent) {
860 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
861 * ending with VK_LIBRARY_SUFFIX
862 */
863 if (!strncmp(dent->d_name,
864 VK_LAYER_LIBRARY_PREFIX,
865 VK_LAYER_LIBRARY_PREFIX_LEN)) {
866 uint32_t nlen = (uint32_t) strlen(dent->d_name);
867 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
868 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
869 !strncmp(suf,
870 VK_LIBRARY_SUFFIX,
871 VK_LIBRARY_SUFFIX_LEN)) {
872 loader_platform_dl_handle handle;
873 snprintf(temp_str, sizeof(temp_str),
874 "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
875 // Used to call: dlopen(temp_str, RTLD_LAZY)
876 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
877 "Attempt to open library: %s\n", temp_str);
878 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
Courtney Goeltzenleuchter57fb1572015-06-08 15:13:50 -0600879 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed\n");
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600880 dent = readdir(curdir);
881 continue;
882 }
883 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
884 "Opened library: %s\n", temp_str);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -0600885
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600886 /* TODO: Remove fixed count */
887 if (count == MAX_LAYER_LIBRARIES) {
888 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
889 "%s ignored: max layer libraries exceed",
890 temp_str);
891 break;
892 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600893
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600894 fp_get_ext = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionInfo");
895 if (!fp_get_ext) {
896 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
897 "Couldn't dlsym vkGetGlobalExtensionInfo from library %s",
898 temp_str);
899 dent = readdir(curdir);
900 loader_platform_close_library(handle);
901 continue;
902 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600903
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600904 loader.scanned_layers[count].lib_name =
905 malloc(strlen(temp_str) + 1);
906 if (loader.scanned_layers[count].lib_name == NULL) {
907 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "%s ignored: out of memory", temp_str);
908 break;
909 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600910
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600911 strcpy(loader.scanned_layers[count].lib_name, temp_str);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600912
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -0600913 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for %s\n", temp_str);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600914 get_global_extensions(
915 fp_get_ext,
916 "vkGetGlobalExtensionInfo",
917 loader.scanned_layers[count].lib_name,
918 VK_EXTENSION_ORIGIN_LAYER,
919 &loader.scanned_layers[count].global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600920
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600921 fp_get_ext = loader_platform_get_proc_address(handle,
922 "vkGetPhysicalDeviceExtensionInfo");
923 if (fp_get_ext) {
924 loader.scanned_layers[count].physical_device_extensions_supported = true;
925 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600926
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600927 count++;
928 loader_platform_close_library(handle);
929 }
930 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600931
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600932 dent = readdir(curdir);
933 } // while (dir_entry)
934 if (count == MAX_LAYER_LIBRARIES)
935 break;
936 closedir(curdir);
937 } // if (curdir))
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600938 } // for (libpaths)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600939
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600940 loader.scanned_layer_count = count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600941 loader.layers_scanned = true;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600942}
943
Jon Ashburn27cd5842015-05-12 17:26:48 -0600944static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
945{
946 // inst is not wrapped
947 if (inst == VK_NULL_HANDLE) {
948 return NULL;
949 }
950 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
951 void *addr;
952
Jon Ashburn8fd08252015-05-28 16:25:02 -0600953 if (!strcmp(pName, "vkGetInstanceProcAddr"))
954 return (void *) loader_gpa_instance_internal;
955
Jon Ashburn27cd5842015-05-12 17:26:48 -0600956 if (disp_table == NULL)
957 return NULL;
958
959 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600960 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -0600961 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600962 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600963
964 if (disp_table->GetInstanceProcAddr == NULL) {
965 return NULL;
966 }
967 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600968}
969
Jon Ashburn128f9422015-05-28 19:16:58 -0600970struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600971{
Jon Ashburn128f9422015-05-28 19:16:58 -0600972
Jon Ashburn98bd4542015-01-29 16:44:24 -0700973 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
974 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
975 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -0600976 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -0700977 *gpu_index = i;
978 return icd;
979 }
980 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600981 }
982 return NULL;
983}
984
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600985static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600986{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600987 if (icd->layer_count[gpu_index])
988 return true;
989 else
990 return false;
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600991}
992
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600993static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -0600994 const char *chain_type,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600995 struct loader_extension_property *ext_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600996{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600997 struct loader_lib_info *new_layer_lib_list, *my_lib;
998
999 /* Only loader layer libraries here */
1000 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1001 return NULL;
1002 }
1003
1004 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1005 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1006 /* Have already loaded this library, just increment ref count */
1007 loader.loaded_layer_lib_list[i].ref_count++;
Jon Ashburne68a9ff2015-05-25 14:11:37 -06001008 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001009 "%s Chain: Increment layer reference count for layer library %s",
1010 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001011 return loader.loaded_layer_lib_list[i].lib_handle;
1012 }
1013 }
1014
1015 /* Haven't seen this library so load it */
1016 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1017 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1018 if (!new_layer_lib_list) {
1019 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1020 return NULL;
1021 }
1022
1023 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1024
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001025 /* NOTE: We require that the extension property be immutable */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001026 my_lib->lib_name = ext_prop->lib_name;
1027 my_lib->ref_count = 0;
1028 my_lib->lib_handle = NULL;
1029
1030 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1031 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1032 loader_platform_open_library_error(my_lib->lib_name));
1033 return NULL;
1034 } else {
1035 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001036 "Chain: %s: Loading layer library %s",
1037 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001038 }
1039 loader.loaded_layer_lib_count++;
1040 loader.loaded_layer_lib_list = new_layer_lib_list;
1041 my_lib->ref_count++;
1042
1043 return my_lib->lib_handle;
1044}
1045
1046static void loader_remove_layer_lib(
1047 struct loader_instance *inst,
1048 struct loader_extension_property *ext_prop)
1049{
1050 uint32_t idx;
1051 struct loader_lib_info *new_layer_lib_list, *my_lib;
1052
1053 /* Only loader layer libraries here */
1054 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001055 return;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001056 }
Jon Ashburndf7d5842014-10-16 15:48:50 -06001057
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001058 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1059 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1060 /* found matching library */
1061 idx = i;
1062 my_lib = &loader.loaded_layer_lib_list[i];
1063 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001064 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001065 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001066
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001067 my_lib->ref_count--;
1068 inst->layer_count--;
1069 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001070 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1071 "Decrement reference count for layer library %s", ext_prop->lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001072 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001073 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001074
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001075 loader_platform_close_library(my_lib->lib_handle);
1076 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1077 "Unloading layer library %s", ext_prop->lib_name);
1078
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001079 /* Need to remove unused library from list */
1080 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1081 if (!new_layer_lib_list) {
1082 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1083 return;
1084 }
1085
1086 if (idx > 0) {
1087 /* Copy records before idx */
1088 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1089 sizeof(struct loader_lib_info) * idx);
1090 }
1091 if (idx < (loader.loaded_layer_lib_count - 1)) {
1092 /* Copy records after idx */
1093 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1094 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1095 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001096
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001097 free(loader.loaded_layer_lib_list);
1098 loader.loaded_layer_lib_count--;
1099 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001100}
1101
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001102static void loader_add_layer_env(
1103 struct loader_extension_list *ext_list,
1104 const struct loader_extension_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001105{
Ian Elliott4470a302015-02-17 10:33:47 -07001106 char *layerEnv;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001107 uint32_t len;
Jon Ashburnd09bd102014-10-22 21:15:26 -06001108 char *p, *pOrig, *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001109
Ian Elliott4470a302015-02-17 10:33:47 -07001110#if defined(WIN32)
1111 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
1112 LAYER_NAMES_REGISTRY_VALUE);
1113#else // WIN32
1114 layerEnv = getenv(LAYER_NAMES_ENV);
1115#endif // WIN32
1116 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001117 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001118 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001119 p = malloc(strlen(layerEnv) + 1);
Ian Elliott4470a302015-02-17 10:33:47 -07001120 if (p == NULL) {
1121#if defined(WIN32)
1122 free(layerEnv);
1123#endif // WIN32
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001124 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001125 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001126 strcpy(p, layerEnv);
Ian Elliott4470a302015-02-17 10:33:47 -07001127#if defined(WIN32)
1128 free(layerEnv);
1129#endif // WIN32
Jon Ashburnd09bd102014-10-22 21:15:26 -06001130 pOrig = p;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001131
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001132 while (p && *p ) {
Jon Ashburn19c25022015-04-14 14:14:48 -06001133 //memset(&lib_name[0], 0, sizeof(const char *) * MAX_LAYER_LIBRARIES);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001134 next = strchr(p, PATH_SEPERATOR);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001135 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -07001136 len = (uint32_t) strlen(p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001137 next = p + len;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001138 } else {
Ian Elliott19628802015-02-04 12:06:46 -07001139 len = (uint32_t) (next - p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001140 *(char *) next = '\0';
1141 next++;
1142 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001143 name = basename(p);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001144 loader_search_ext_list_for_name(name, search_list, ext_list);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001145 p = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001146 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001147
Jon Ashburnd09bd102014-10-22 21:15:26 -06001148 free(pOrig);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001149 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001150}
1151
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001152
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001153void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001154{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001155 if (!instance->layer_count) {
1156 return;
1157 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001158
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001159 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001160 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
1161 struct loader_extension_property *ext_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001162
1163 loader_remove_layer_lib(instance, ext_prop);
1164
1165 instance->layer_count--;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001166 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001167
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001168}
1169
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001170void loader_enable_instance_layers(struct loader_instance *inst)
1171{
1172 if (inst == NULL)
1173 return;
1174
1175 /* Add any layers specified in the environment first */
1176 loader_add_layer_env(&inst->enabled_instance_extensions, &loader.global_extensions);
1177
1178 /* Add layers / extensions specified by the application */
1179 loader_add_vk_ext_to_ext_list(
1180 &inst->enabled_instance_extensions,
1181 inst->app_extension_count,
1182 inst->app_extension_props,
1183 &loader.global_extensions);
1184}
1185
Jon Ashburn27cd5842015-05-12 17:26:48 -06001186uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1187{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001188 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06001189 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001190
Jon Ashburn27cd5842015-05-12 17:26:48 -06001191 if (inst == NULL)
1192 return 0;
1193
1194 // NOTE inst is unwrapped at this point in time
1195 VkObject baseObj = (VkObject) inst;
1196 VkObject nextObj = (VkObject) inst;
1197 VkBaseLayerObject *nextInstObj;
1198 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1199
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001200 /*
1201 * Figure out how many actual layers will need to be wrapped.
1202 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001203 for (uint32_t i = 0; i < inst->enabled_instance_extensions.count; i++) {
1204 struct loader_extension_property *ext_prop = &inst->enabled_instance_extensions.list[i];
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001205 if (ext_prop->alias) {
1206 ext_prop = ext_prop->alias;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001207 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001208 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1209 continue;
1210 }
1211 loader_add_to_ext_list(&inst->activated_layer_list, 1, ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001212 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001213
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001214 inst->layer_count = inst->activated_layer_list.count;
1215
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001216 if (!inst->layer_count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001217 return 0;
1218 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001219
Jon Ashburn128f9422015-05-28 19:16:58 -06001220 wrappedInstance = malloc(sizeof(VkBaseLayerObject)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001221 * inst->layer_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001222 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001223 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1224 return 0;
1225 }
1226
1227 /* Create instance chain of enabled layers */
1228 layer_idx = inst->layer_count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001229 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
1230 struct loader_extension_property *ext_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001231 loader_platform_dl_handle lib_handle;
1232
1233 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001234 * For global exenstions implemented within the loader (i.e. WSI, DEBUG_REPORT
1235 * the extension must provide two entry points for the loader to use:
1236 * - "trampoline" entry point - this is the address returned by GetProcAddr
1237 * and will always do what's necessary to support a global call.
1238 * - "terminator" function - this function will be put at the end of the
1239 * instance chain and will contain the necessary logica to call / process
1240 * the extension for the appropriate ICDs that are available.
1241 * There is no generic mechanism for including these functions, the references
1242 * must be placed into the appropriate loader entry points.
1243 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
1244 * loader_coalesce_extensions(void) - add extension records to the list of global
1245 * extension available to the app.
1246 * instance_disp - add function pointer for terminator function to this array.
1247 * The extension itself should be in a separate file that will be
1248 * linked directly with the loader.
1249 * Note: An extension's Get*ProcAddr should not return a function pointer for
1250 * any extension entry points until the extension has been enabled.
1251 * To do this requires a different behavior from Get*ProcAddr functions implemented
1252 * in layers.
1253 * The very first call to a layer will be it's Get*ProcAddr function requesting
1254 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1255 * with the wrapped object given (either Instance or Device) and return the layer's
1256 * Get*ProcAddr function. The layer should also use this opportunity to record the
1257 * baseObject so that it can find the correct local dispatch table on future calls.
1258 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1259 * will not use a wrapped object and must look up their local dispatch table from
1260 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001261 */
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001262 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001263
Jon Ashburn128f9422015-05-28 19:16:58 -06001264 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001265 nextInstObj->pGPA = nextGPA;
1266 nextInstObj->baseObject = baseObj;
1267 nextInstObj->nextObject = nextObj;
1268 nextObj = (VkObject) nextInstObj;
1269
1270 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001271 snprintf(funcStr, 256, "%sGetInstanceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001272 lib_handle = loader_add_layer_lib("instance", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001273 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1274 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001275 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001276 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 -06001277
1278 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001279 continue;
1280 }
1281
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001282 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1283 "Insert instance layer library %s for extension: %s",
1284 ext_prop->lib_name, ext_prop->info.name);
1285
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001286 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001287 }
1288
Jon Ashburn8fd08252015-05-28 16:25:02 -06001289 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001290
Jon Ashburn128f9422015-05-28 19:16:58 -06001291 free(wrappedInstance);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001292 return inst->layer_count;
1293}
1294
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001295void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1296{
1297
1298 loader_init_instance_extension_dispatch_table(inst->disp,
1299 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06001300 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001301}
1302
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001303void loader_enable_device_layers(struct loader_icd *icd, uint32_t gpu_index)
1304{
1305 if (icd == NULL)
1306 return;
1307
1308 /* Add any layers specified in the environment first */
1309 loader_add_layer_env(&icd->enabled_device_extensions[gpu_index], &loader.global_extensions);
1310
1311 /* Add layers / extensions specified by the application */
1312 loader_add_vk_ext_to_ext_list(
1313 &icd->enabled_device_extensions[gpu_index],
1314 icd->app_extension_count[gpu_index],
1315 icd->app_extension_props[gpu_index],
1316 &loader.global_extensions);
1317}
1318
1319extern uint32_t loader_activate_device_layers(
1320 VkDevice device,
1321 struct loader_icd *icd,
1322 uint32_t gpu_index,
1323 uint32_t ext_count,
1324 const VkExtensionProperties *ext_props)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001325{
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001326 uint32_t count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001327 uint32_t layer_idx;
1328
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001329 if (!icd)
1330 return 0;
Jon Ashburn83a64252015-04-15 11:31:12 -06001331 assert(gpu_index < MAX_GPUS_FOR_LAYER);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001332
1333 /* activate any layer libraries */
1334 if (!loader_layers_activated(icd, gpu_index)) {
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001335 VkObject nextObj = (VkObject) device;
1336 VkObject baseObj = nextObj;
1337 VkBaseLayerObject *nextGpuObj;
Jon Ashburn7c096122015-05-22 09:19:49 -06001338 PFN_vkGetDeviceProcAddr nextGPA = icd->GetDeviceProcAddr;
Jon Ashburnce94f312015-05-28 19:25:20 -06001339 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001340 count = 0;
1341 for (uint32_t i = 0; i < icd->enabled_device_extensions[gpu_index].count; i++) {
1342 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1343 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER) {
1344 count++;
1345 }
1346 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001347 if (!count)
1348 return 0;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001349
1350 icd->layer_count[gpu_index] = count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001351
Jon Ashburnce94f312015-05-28 19:25:20 -06001352 wrappedGpus = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]);
1353 if (! wrappedGpus) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001354 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001355 return 0;
1356 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001357 layer_idx = count - 1;
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001358 for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001359 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1360 loader_platform_dl_handle lib_handle;
1361
1362 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1363 continue;
1364 }
1365
Jon Ashburnce94f312015-05-28 19:25:20 -06001366 nextGpuObj = (wrappedGpus + i);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001367 nextGpuObj->pGPA = nextGPA;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001368 nextGpuObj->baseObject = baseObj;
1369 nextGpuObj->nextObject = nextObj;
1370 nextObj = (VkObject) nextGpuObj;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001371
Jon Ashburn79113cc2014-12-01 14:22:40 -07001372 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001373 snprintf(funcStr, 256, "%sGetDeviceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001374 lib_handle = loader_add_layer_lib("device", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001375 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1376 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001377 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001378 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 -06001379 continue;
1380 }
1381
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001382 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1383 "Insert device layer library %s for extension: %s",
1384 ext_prop->lib_name, ext_prop->info.name);
1385
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001386 layer_idx--;
1387 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001388
Jon Ashburn8fd08252015-05-28 16:25:02 -06001389 loader_init_device_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA,
1390 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
Jon Ashburnce94f312015-05-28 19:25:20 -06001391 free(wrappedGpus);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001392 } else {
1393 // TODO: Check that active layers match requested?
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001394 }
1395 return icd->layer_count[gpu_index];
1396}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001397
Jon Ashburn27cd5842015-05-12 17:26:48 -06001398VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001399 const VkInstanceCreateInfo* pCreateInfo,
1400 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001401{
Jon Ashburneed0c002015-05-21 17:42:17 -06001402 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07001403 struct loader_scanned_icds *scanned_icds;
1404 struct loader_icd *icd;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001405 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001406
Jon Ashburn46888392015-01-29 15:45:51 -07001407 scanned_icds = loader.scanned_icd_list;
1408 while (scanned_icds) {
1409 icd = loader_icd_add(ptr_instance, scanned_icds);
1410 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -06001411 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn3da71f22015-05-14 12:43:38 -06001412 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001413 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07001414 {
1415 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001416 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001417 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001418 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07001419 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06001420 } else
1421 {
1422 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07001423 }
1424 }
1425 scanned_icds = scanned_icds->next;
1426 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001427
Ian Elliotteb450762015-02-05 15:19:15 -07001428 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001429 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -07001430 }
Jon Ashburn46888392015-01-29 15:45:51 -07001431
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001432 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001433}
1434
Jon Ashburn27cd5842015-05-12 17:26:48 -06001435VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001436 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001437{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06001438 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001439 struct loader_icd *icds = ptr_instance->icds;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001440 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001441
1442 // Remove this instance from the list of instances:
1443 struct loader_instance *prev = NULL;
1444 struct loader_instance *next = loader.instances;
1445 while (next != NULL) {
1446 if (next == ptr_instance) {
1447 // Remove this instance from the list:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001448 free(ptr_instance->app_extension_props);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001449 if (prev)
1450 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07001451 else
1452 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001453 break;
1454 }
1455 prev = next;
1456 next = next->next;
1457 }
1458 if (next == NULL) {
1459 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001460 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001461 }
1462
Jon Ashburn3da71f22015-05-14 12:43:38 -06001463 while (icds) {
1464 if (icds->instance) {
1465 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06001466 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001467 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06001468 "ICD ignored: failed to DestroyInstance on device");
1469 }
Jon Ashburn128f9422015-05-28 19:16:58 -06001470 loader_icd_destroy(ptr_instance, icds);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001471 icds->instance = VK_NULL_HANDLE;
1472 icds = icds->next;
Jon Ashburn46888392015-01-29 15:45:51 -07001473 }
1474
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001475
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001476 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001477}
1478
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001479VkResult loader_init_physical_device_info(
1480 struct loader_instance *ptr_instance)
1481{
1482 struct loader_icd *icd;
1483 uint32_t n, count = 0;
1484 VkResult res = VK_ERROR_UNKNOWN;
1485
1486 icd = ptr_instance->icds;
1487 while (icd) {
1488 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
1489 if (res != VK_SUCCESS)
1490 return res;
1491 icd->gpu_count = n;
1492 count += n;
1493 icd = icd->next;
1494 }
1495
1496 ptr_instance->total_gpu_count = count;
1497
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001498 icd = ptr_instance->icds;
1499 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001500 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
1501
1502 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001503 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
1504 if (!icd->gpus) {
1505 /* TODO: Add cleanup code here */
1506 return VK_ERROR_OUT_OF_HOST_MEMORY;
1507 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001508 res = icd->EnumeratePhysicalDevices(
1509 icd->instance,
1510 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06001511 icd->gpus);
1512 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001513
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001514 icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n *
1515 sizeof(VkLayerDispatchTable));
1516 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001517
1518 loader_init_device_dispatch_table(icd->loader_dispatch + i,
Jon Ashburn128f9422015-05-28 19:16:58 -06001519 get_proc_addr, icd->gpus[i], icd->gpus[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001520
Jon Ashburn128f9422015-05-28 19:16:58 -06001521 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001522
1523 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
1524 /* TODO: Add cleanup code here */
1525 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1526 }
1527 if (res == VK_SUCCESS && icd->GetPhysicalDeviceExtensionInfo) {
1528 size_t data_size;
1529 uint32_t extension_count;
1530
1531 data_size = sizeof(extension_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001532 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_COUNT, 0, &data_size, &extension_count);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001533 if (data_size == sizeof(extension_count) && res == VK_SUCCESS) {
1534 struct loader_extension_property ext_props;
1535
1536 /* Gather all the ICD extensions */
1537 for (uint32_t extension_id = 0; extension_id < extension_count; extension_id++) {
1538 data_size = sizeof(VkExtensionProperties);
Jon Ashburn128f9422015-05-28 19:16:58 -06001539 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_PROPERTIES,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001540 extension_id, &data_size, &ext_props.info);
1541 if (data_size == sizeof(VkExtensionProperties) && res == VK_SUCCESS) {
1542 ext_props.hosted = false;
1543 ext_props.origin = VK_EXTENSION_ORIGIN_ICD;
1544 ext_props.lib_name = icd->scanned_icds->lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -06001545 // For ICDs, this is the only option
1546 strcpy(ext_props.get_extension_info_name, "vkGetPhysicalDeviceExtensionInfo");
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001547 loader_add_to_ext_list(&icd->device_extension_cache[i], 1, &ext_props);
1548 }
1549 }
1550
1551 // Traverse layers list adding non-duplicate extensions to the list
1552 for (uint32_t l = 0; l < loader.scanned_layer_count; l++) {
Jon Ashburn128f9422015-05-28 19:16:58 -06001553 get_physical_device_layer_extensions(ptr_instance, icd->gpus[i], l, &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001554 }
1555 }
1556 }
1557
1558 if (res != VK_SUCCESS) {
1559 /* clean up any extension lists previously created before this request failed */
1560 for (uint32_t j = 0; j < i; j++) {
1561 loader_destroy_ext_list(&icd->device_extension_cache[i]);
1562 }
1563 return res;
1564 }
1565 }
1566
1567 count += n;
1568 }
1569
1570 icd = icd->next;
1571 }
1572
1573 return VK_SUCCESS;
1574}
1575
Jon Ashburn27cd5842015-05-12 17:26:48 -06001576VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06001577 VkInstance instance,
1578 uint32_t* pPhysicalDeviceCount,
1579 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001580{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001581 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001582 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001583 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001584
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001585 if (ptr_instance->total_gpu_count == 0) {
1586 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001587 }
1588
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001589 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
1590 if (!pPhysicalDevices) {
1591 return VK_SUCCESS;
1592 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001593
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001594 while (icd) {
1595 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06001596 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001597 index += icd->gpu_count;
1598 icd = icd->next;
1599 }
1600
1601 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001602}
1603
Jon Ashburn3da71f22015-05-14 12:43:38 -06001604VkResult loader_GetPhysicalDeviceInfo(
1605 VkPhysicalDevice gpu,
1606 VkPhysicalDeviceInfoType infoType,
1607 size_t* pDataSize,
1608 void* pData)
1609{
1610 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001611 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001612 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1613
1614 if (icd->GetPhysicalDeviceInfo)
1615 res = icd->GetPhysicalDeviceInfo(gpu, infoType, pDataSize, pData);
1616
1617 return res;
1618}
1619
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001620VkResult loader_CreateDevice(
1621 VkPhysicalDevice gpu,
1622 const VkDeviceCreateInfo* pCreateInfo,
1623 VkDevice* pDevice)
1624{
1625 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001626 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001627 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001628
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001629 if (icd->CreateDevice) {
1630 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001631 if (res != VK_SUCCESS) {
1632 return res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001633 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001634
1635 VkLayerDispatchTable *dev_disp = icd->loader_dispatch + gpu_index;
1636 loader_init_dispatch(*pDevice, dev_disp);
1637
1638 icd->app_extension_count[gpu_index] = pCreateInfo->extensionCount;
1639 icd->app_extension_props[gpu_index] = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1640 if (icd->app_extension_props[gpu_index] == NULL && (icd->app_extension_count[gpu_index] > 0)) {
1641 return VK_ERROR_OUT_OF_HOST_MEMORY;
1642 }
1643
1644 /* Make local copy of extension list */
1645 if (icd->app_extension_count[gpu_index] > 0 && icd->app_extension_props[gpu_index] != NULL) {
1646 memcpy(icd->app_extension_props[gpu_index], pCreateInfo->pEnabledExtensions, sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1647 }
1648
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001649 /*
1650 * Put together the complete list of extensions to enable
1651 * This includes extensions requested via environment variables.
1652 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001653 loader_enable_device_layers(icd, gpu_index);
1654
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001655 /*
1656 * Load the libraries needed by the extensions on the
1657 * enabled extension list. This will build the
1658 * device instance chain terminating with the
1659 * selected device.
1660 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001661 loader_activate_device_layers(*pDevice, icd, gpu_index,
1662 icd->app_extension_count[gpu_index],
1663 icd->app_extension_props[gpu_index]);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001664 }
1665
1666 return res;
1667}
1668
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001669LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
1670{
Jon Ashburn07daee72015-05-21 18:13:33 -06001671 if (instance == VK_NULL_HANDLE)
1672 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001673
Jon Ashburn07daee72015-05-21 18:13:33 -06001674 void *addr;
1675 /* get entrypoint addresses that are global (in the loader)*/
1676 addr = globalGetProcAddr(pName);
1677 if (addr)
1678 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001679
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001680 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
1681
1682 addr = debug_report_instance_gpa(ptr_instance, pName);
1683 if (addr) {
1684 return addr;
1685 }
1686
Jon Ashburn07daee72015-05-21 18:13:33 -06001687 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001688 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001689 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001690 return (ptr_instance->wsi_lunarg_enabled) ? addr : NULL;
Jon Ashburn07daee72015-05-21 18:13:33 -06001691
1692 /* return the instance dispatch table entrypoint for extensions */
1693 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
1694 if (disp_table == NULL)
1695 return NULL;
1696
1697 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
1698 if (addr)
1699 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001700
1701 return NULL;
1702}
1703
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001704LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001705{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001706 if (device == VK_NULL_HANDLE) {
1707 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001708 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001709
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001710 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001711
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001712 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
1713 make sure the loader entrypoint is returned */
1714 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06001715 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001716 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06001717 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001718
Jon Ashburn07daee72015-05-21 18:13:33 -06001719 /* return any extension device entrypoints the loader knows about */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001720 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001721 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001722 return addr;
Jon Ashburn07daee72015-05-21 18:13:33 -06001723
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001724 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001725 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001726 if (disp_table == NULL)
1727 return NULL;
1728
Jon Ashburn27cd5842015-05-12 17:26:48 -06001729 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001730 if (addr)
1731 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001732 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001733 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001734 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001735 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001736 }
1737}
1738
Jon Ashburneceb13e2015-05-18 15:28:32 -06001739LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001740 VkExtensionInfoType infoType,
1741 uint32_t extensionIndex,
1742 size_t* pDataSize,
1743 void* pData)
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001744{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001745 uint32_t *count;
1746 /* Scan/discover all ICD libraries in a single-threaded manner */
1747 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001748
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001749 /* get layer libraries in a single-threaded manner */
1750 loader_platform_thread_once(&once_layer, layer_lib_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001751
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001752 /* merge any duplicate extensions */
1753 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
1754
1755
1756 if (pDataSize == NULL)
1757 return VK_ERROR_INVALID_POINTER;
1758
1759 switch (infoType) {
1760 case VK_EXTENSION_INFO_TYPE_COUNT:
1761 *pDataSize = sizeof(uint32_t);
1762 if (pData == NULL)
1763 return VK_SUCCESS;
1764 count = (uint32_t *) pData;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001765 *count = loader.global_extensions.count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001766 break;
1767 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1768 *pDataSize = sizeof(VkExtensionProperties);
1769 if (pData == NULL)
1770 return VK_SUCCESS;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001771 if (extensionIndex >= loader.global_extensions.count)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001772 return VK_ERROR_INVALID_VALUE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001773 memcpy((VkExtensionProperties *) pData,
1774 &loader.global_extensions.list[extensionIndex],
1775 sizeof(VkExtensionProperties));
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001776 break;
1777 default:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001778 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Invalid infoType in vkGetGlobalExtensionInfo");
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001779 return VK_ERROR_INVALID_VALUE;
1780 };
1781
1782 return VK_SUCCESS;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001783}
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001784
1785LOADER_EXPORT VkResult VKAPI vkGetPhysicalDeviceExtensionInfo(
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001786 VkPhysicalDevice gpu,
1787 VkExtensionInfoType infoType,
1788 uint32_t extensionIndex,
1789 size_t* pDataSize,
1790 void* pData)
1791{
1792 uint32_t gpu_index;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001793 uint32_t *count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001794 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001795
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001796 if (pDataSize == NULL)
1797 return VK_ERROR_INVALID_POINTER;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001798
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001799 switch (infoType) {
1800 case VK_EXTENSION_INFO_TYPE_COUNT:
1801 *pDataSize = sizeof(uint32_t);
1802 if (pData == NULL)
1803 return VK_SUCCESS;
1804 count = (uint32_t *) pData;
1805 *count = icd->device_extension_cache[gpu_index].count;
1806 break;
1807 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1808 *pDataSize = sizeof(VkExtensionProperties);
1809 if (pData == NULL)
1810 return VK_SUCCESS;
1811 if (extensionIndex >= icd->device_extension_cache[gpu_index].count)
1812 return VK_ERROR_INVALID_VALUE;
1813 memcpy((VkExtensionProperties *) pData,
1814 &icd->device_extension_cache[gpu_index].list[extensionIndex],
1815 sizeof(VkExtensionProperties));
1816 break;
1817 default:
1818 return VK_ERROR_INVALID_VALUE;
1819 };
1820
1821 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001822}
1823
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001824VkResult loader_GetMultiDeviceCompatibility(
1825 VkPhysicalDevice gpu0,
1826 VkPhysicalDevice gpu1,
1827 VkPhysicalDeviceCompatibilityInfo* pInfo)
1828{
1829 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001830 struct loader_icd *icd = loader_get_icd(gpu0, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001831 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1832
1833 if (icd->GetMultiDeviceCompatibility)
1834 res = icd->GetMultiDeviceCompatibility(gpu0, gpu1, pInfo);
1835
1836 return res;
1837}