blob: dd38aa3f796df896e0f280461e17ffda30a90a9d [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 -060067static void loader_deactivate_instance_layers(struct loader_instance *instance);
68
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060069/* TODO: do we need to lock around access to linked lists and such? */
Jon Ashburn27cd5842015-05-12 17:26:48 -060070struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080071
Jon Ashburn27cd5842015-05-12 17:26:48 -060072VkLayerInstanceDispatchTable instance_disp = {
73 .GetInstanceProcAddr = vkGetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060074 .CreateInstance = loader_CreateInstance,
75 .DestroyInstance = loader_DestroyInstance,
76 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060077 .GetPhysicalDeviceInfo = loader_GetPhysicalDeviceInfo,
78 .CreateDevice = loader_CreateDevice,
Jon Ashburneceb13e2015-05-18 15:28:32 -060079 .GetGlobalExtensionInfo = vkGetGlobalExtensionInfo,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -060080 .GetPhysicalDeviceExtensionInfo = vkGetPhysicalDeviceExtensionInfo,
Jon Ashburn95a77ba2015-05-15 15:09:35 -060081 .GetMultiDeviceCompatibility = loader_GetMultiDeviceCompatibility,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060082 .GetDisplayInfoWSI = loader_GetDisplayInfoWSI,
83 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
84 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -060085};
86
87LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
88LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
89LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070090
Ian Elliott4470a302015-02-17 10:33:47 -070091#if defined(WIN32)
Ian Elliott5aa4ea22015-03-31 15:32:41 -060092char *loader_get_registry_string(const HKEY hive,
93 const LPCTSTR sub_key,
94 const char *value)
95{
96 DWORD access_flags = KEY_QUERY_VALUE;
97 DWORD value_type;
98 HKEY key;
Ian Elliottf851ddf2015-04-28 15:57:32 -060099 VkResult rtn_value;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600100 char *rtn_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600101 DWORD rtn_len = 0;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600102 size_t allocated_len = 0;
103
104 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
105 if (rtn_value != ERROR_SUCCESS) {
106 // We didn't find the key. Try the 32-bit hive (where we've seen the
107 // key end up on some people's systems):
108 access_flags |= KEY_WOW64_32KEY;
109 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
110 if (rtn_value != ERROR_SUCCESS) {
111 // We still couldn't find the key, so give up:
112 return NULL;
113 }
114 }
115
116 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600117 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600118 if (rtn_value == ERROR_SUCCESS) {
119 // If we get to here, we found the key, and need to allocate memory
120 // large enough for rtn_str, and query again:
121 allocated_len = rtn_len + 4;
122 rtn_str = malloc(allocated_len);
123 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600124 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600125 if (rtn_value == ERROR_SUCCESS) {
126 // We added 4 extra bytes to rtn_str, so that we can ensure that
127 // the string is NULL-terminated (albeit, in a brute-force manner):
128 rtn_str[allocated_len-1] = '\0';
129 } else {
130 // This should never occur, but in case it does, clean up:
131 free(rtn_str);
132 rtn_str = NULL;
133 }
134 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
135
136 // Close the registry key that was opened:
137 RegCloseKey(key);
138
139 return rtn_str;
140}
141
142
Ian Elliott4470a302015-02-17 10:33:47 -0700143// For ICD developers, look in the registry, and look for an environment
144// variable for a path(s) where to find the ICD(s):
145static char *loader_get_registry_and_env(const char *env_var,
146 const char *registry_value)
147{
148 char *env_str = getenv(env_var);
149 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600150 char *registry_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600151 size_t registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700152 char *rtn_str = NULL;
153 size_t rtn_len;
154
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600155 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600156 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600157 registry_value);
Ian Elliottf851ddf2015-04-28 15:57:32 -0600158 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700159
160 rtn_len = env_len + registry_len + 1;
161 if (rtn_len <= 2) {
162 // We found neither the desired registry value, nor the environment
163 // variable; return NULL:
164 return NULL;
165 } else {
166 // We found something, and so we need to allocate memory for the string
167 // to return:
168 rtn_str = malloc(rtn_len);
169 }
170
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600171 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700172 // We didn't find the desired registry value, and so we must have found
173 // only the environment variable:
174 _snprintf(rtn_str, rtn_len, "%s", env_str);
175 } else if (env_str != NULL) {
176 // We found both the desired registry value and the environment
177 // variable, so concatenate them both:
178 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
179 } else {
180 // We must have only found the desired registry value:
181 _snprintf(rtn_str, rtn_len, "%s", registry_str);
182 }
183
Ian Elliott2de26bc2015-04-03 13:13:01 -0600184 if (registry_str) {
185 free(registry_str);
186 }
Ian Elliott4470a302015-02-17 10:33:47 -0700187
188 return(rtn_str);
189}
190#endif // WIN32
191
192
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600193static void loader_log(VkFlags msg_type, int32_t msg_code,
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800194 const char *format, ...)
195{
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800196 char msg[256];
197 va_list ap;
198 int ret;
199
200 va_start(ap, format);
201 ret = vsnprintf(msg, sizeof(msg), format, ap);
Ian Elliott42045842015-02-13 14:29:21 -0700202 if ((ret >= (int) sizeof(msg)) || ret < 0) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800203 msg[sizeof(msg) - 1] = '\0';
204 }
205 va_end(ap);
206
Jon Ashburnae053e92015-04-24 14:10:50 -0700207#if defined(WIN32)
208 OutputDebugString(msg);
Jon Ashburn1de39402015-05-05 16:20:46 -0600209#endif
Courtney Goeltzenleuchterc80a5572015-04-13 14:10:06 -0600210 fputs(msg, stderr);
211 fputc('\n', stderr);
Jon Ashburn1de39402015-05-05 16:20:46 -0600212
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800213}
214
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600215bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
216{
217 return memcmp(op1, op2, sizeof(VkExtensionProperties)) == 0 ? true : false;
218}
219
220/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600221 * Search the given ext_list for an extension
222 * matching the given vk_ext_prop
223 */
224bool has_vk_extension_property(
225 const VkExtensionProperties *vk_ext_prop,
226 const struct loader_extension_list *ext_list)
227{
228 for (uint32_t i = 0; i < ext_list->count; i++) {
229 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
230 return true;
231 }
232 return false;
233}
234
235/*
236 * Search the given ext_list for an extension
237 * matching the given vk_ext_prop
238 */
239static struct loader_extension_property *get_extension_property_from_vkext(
240 const VkExtensionProperties *vk_ext_prop,
241 const struct loader_extension_list *ext_list)
242{
243 for (uint32_t i = 0; i < ext_list->count; i++) {
244 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
245 return &ext_list->list[i];
246 }
247 return NULL;
248}
249
250static void get_global_extensions(
251 const PFN_vkGetGlobalExtensionInfo fp_get,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600252 const char *get_extension_info_name,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600253 const char *lib_name,
254 const enum extension_origin origin,
255 struct loader_extension_list *ext_list)
256{
257 uint32_t i, count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600258 size_t siz = sizeof(count);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600259 struct loader_extension_property ext_props;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600260 VkResult res;
261
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600262 res = fp_get(VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
263 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600264 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from ICD");
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600265 return;
266 }
267 siz = sizeof(VkExtensionProperties);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600268 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600269 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600270 res = fp_get(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600271 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600272 ext_props.hosted = false;
273 ext_props.origin = origin;
274 ext_props.lib_name = lib_name;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600275 strncpy(ext_props.get_extension_info_name, get_extension_info_name, MAX_EXTENSION_NAME_SIZE);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600276 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600277 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600278 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600279
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600280 return;
281}
282
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600283static void get_physical_device_layer_extensions(
284 struct loader_instance *ptr_instance,
285 VkPhysicalDevice physical_device,
286 const uint32_t layer_index,
287 struct loader_extension_list *ext_list)
288{
289 uint32_t i, count;
290 size_t siz = sizeof(count);
291 VkResult res;
292 loader_platform_dl_handle lib_handle;
293 PFN_vkGetPhysicalDeviceExtensionInfo fp_get;
294 struct loader_extension_property ext_props;
295
296 if (!loader.scanned_layers[layer_index].physical_device_extensions_supported) {
297 return;
298 }
299
300 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
301 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -0600302 char funcStr[MAX_EXTENSION_NAME_SIZE+1]; // add one character for 0 termination
303 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetPhysicalDeviceExtensionInfo", ext_props.info.name);
304 funcStr[MAX_EXTENSION_NAME_SIZE] = 0; // make sure string is 0 terminated
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600305 lib_handle = loader_add_layer_lib("device", &ext_props);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600306
307 /* first try extension specific function, then generic */
308 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
309 if (!fp_get) {
Jon Ashburn128f9422015-05-28 19:16:58 -0600310 sprintf(funcStr, "vkGetPhysicalDeviceExtensionInfo");
311 fp_get = (PFN_vkGetPhysicalDeviceExtensionInfo) loader_platform_get_proc_address(lib_handle, funcStr);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600312 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600313 if (fp_get) {
314 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_COUNT, 0, &siz, &count);
315 if (res == VK_SUCCESS) {
316 siz = sizeof(VkExtensionProperties);
317 for (i = 0; i < count; i++) {
318 memset(&ext_props, 0, sizeof(ext_props));
319 res = fp_get(physical_device, VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &siz, &ext_props.info);
320 if (res == VK_SUCCESS && (ext_props.info.sType == VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES)) {
321 ext_props.hosted = false;
322 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
Jon Ashburn128f9422015-05-28 19:16:58 -0600323 strcpy(ext_props.get_extension_info_name, funcStr);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600324 ext_props.lib_name = loader.scanned_layers[layer_index].lib_name;
325 loader_add_to_ext_list(ext_list, 1, &ext_props);
326 }
327 }
328 } else {
329 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
330 }
331 }
332
333 loader_remove_layer_lib(ptr_instance, &ext_props);
334 return;
335}
336
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600337static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600338{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600339 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
340 ext_info->list = malloc(ext_info->capacity);
341 if (ext_info->list == NULL) {
342 return false;
343 }
344 memset(ext_info->list, 0, ext_info->capacity);
345 ext_info->count = 0;
346 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600347}
348
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600349static void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600350{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600351 free(ext_info->list);
352 ext_info->count = 0;
353 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600354}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600355
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600356static void loader_add_vk_ext_to_ext_list(
357 struct loader_extension_list *ext_list,
358 uint32_t prop_list_count,
359 const VkExtensionProperties *props,
360 const struct loader_extension_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600361{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600362 struct loader_extension_property *ext_prop;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600363
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600364 for (uint32_t i = 0; i < prop_list_count; i++) {
365 // look for duplicates
366 if (has_vk_extension_property(&props[i], ext_list)) {
367 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600368 }
369
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600370 ext_prop = get_extension_property_from_vkext(&props[i], search_list);
371 if (!ext_prop) {
372 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", props[i].name);
373 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600374 }
375
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600376 loader_add_to_ext_list(ext_list, 1, ext_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600377 }
378}
379
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600380/*
381 * Append non-duplicate extension properties defined in prop_list
382 * to the given ext_info list
383 */
384void loader_add_to_ext_list(
385 struct loader_extension_list *ext_list,
386 uint32_t prop_list_count,
387 const struct loader_extension_property *props)
388{
389 uint32_t i;
390 struct loader_extension_property *cur_ext;
391
392 if (ext_list->list == NULL || ext_list->capacity == 0) {
393 loader_init_ext_list(ext_list);
394 }
395
396 if (ext_list->list == NULL)
397 return;
398
399 for (i = 0; i < prop_list_count; i++) {
400 cur_ext = (struct loader_extension_property *) &props[i];
401
402 // look for duplicates
403 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
404 continue;
405 }
406
407 // add to list at end
408 // check for enough capacity
409 if (ext_list->count * sizeof(struct loader_extension_property)
410 >= ext_list->capacity) {
411 // double capacity
412 ext_list->capacity *= 2;
413 ext_list->list = realloc(ext_list->list, ext_list->capacity);
414 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600415
416 /*
417 * Check if any extensions already on the list come from the same
418 * library and use the same Get*ExtensionInfo. If so, link this
419 * extension to the previous as an alias. That way when we activate
420 * extensions we only activiate the associated layer once no
421 * matter how many extensions are used.
422 */
423 for (uint32_t j = 0; j < ext_list->count; j++) {
424 struct loader_extension_property *active_property = &ext_list->list[j];
425 if (cur_ext->lib_name &&
426 cur_ext->origin == VK_EXTENSION_ORIGIN_LAYER &&
427 active_property->origin == VK_EXTENSION_ORIGIN_LAYER &&
428 strcmp(cur_ext->lib_name, active_property->lib_name) == 0 &&
429 strcmp(cur_ext->get_extension_info_name, active_property->get_extension_info_name) == 0 &&
430 active_property->alias == NULL) {
431 cur_ext->alias = active_property;
432 break;
433 }
434 }
435
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600436 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
437 ext_list->count++;
438 }
439}
440
441/*
442 * Search the search_list for any extension with
443 * a name that matches the given ext_name.
444 * Add all matching extensions to the found_list
445 * Do not add if found VkExtensionProperties is already
446 * on the found_list
447 */
448static void loader_search_ext_list_for_name(
449 const char *ext_name,
450 const struct loader_extension_list *search_list,
451 struct loader_extension_list *found_list)
452{
453 for (uint32_t i = 0; i < search_list->count; i++) {
454 struct loader_extension_property *ext_prop = &search_list->list[i];
455 if (0 == strcmp(ext_prop->info.name, ext_name)) {
456 /* Found an extension with the same name, add to found_list */
457 loader_add_to_ext_list(found_list, 1, &search_list->list[i]);
458 }
459 }
460}
461
462bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600463{
464 uint32_t i;
465
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600466 for (i = 0; i < loader.global_extensions.count; i++) {
467 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600468 return true;
469 }
470 return false;
471}
472
Jon Ashburn27cd5842015-05-12 17:26:48 -0600473void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600474{
475 uint32_t i;
476 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
477
478 // traverse scanned icd list adding non-duplicate extensions to the list
479 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600480 loader_add_to_ext_list(&loader.global_extensions,
481 icd_list->global_extension_list.count,
482 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600483 icd_list = icd_list->next;
484 };
485
486 //Traverse layers list adding non-duplicate extensions to the list
487 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600488 loader_add_to_ext_list(&loader.global_extensions,
489 loader.scanned_layers[i].global_extension_list.count,
490 loader.scanned_layers[i].global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600491 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600492
493 // Traverse loader's extensions, adding non-duplicate extensions to the list
494 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn0c5d4ab2015-05-26 13:57:35 -0600495 wsi_lunarg_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600496}
497
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600498static void loader_icd_destroy(
499 struct loader_instance *ptr_inst,
500 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800501{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700502 loader_platform_close_library(icd->scanned_icds->handle);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600503 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600504 free(icd->gpus);
505 free(icd->loader_dispatch);
506 //TODO free wrappedGpus or remove them
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800507 free(icd);
508}
509
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600510static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800511{
512 struct loader_icd *icd;
513
514 icd = malloc(sizeof(*icd));
515 if (!icd)
516 return NULL;
517
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600518 memset(icd, 0, sizeof(*icd));
519
Jon Ashburn46d1f582015-01-28 11:01:35 -0700520 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800521
522 return icd;
523}
524
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600525static struct loader_icd *loader_icd_add(
526 struct loader_instance *ptr_inst,
527 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800528{
529 struct loader_icd *icd;
530
Jon Ashburn46d1f582015-01-28 11:01:35 -0700531 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800532 if (!icd)
533 return NULL;
534
Chia-I Wu13a61a52014-08-04 11:18:20 +0800535 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700536 icd->next = ptr_inst->icds;
537 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600538 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800539
540 return icd;
541}
542
Jon Ashburn46d1f582015-01-28 11:01:35 -0700543static void loader_scanned_icd_add(const char *filename)
544{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700545 loader_platform_dl_handle handle;
Jon Ashburn3da71f22015-05-14 12:43:38 -0600546 void *fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600547 void *fp_get_global_ext_info;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600548 void *fp_get_device_ext_info;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700549 struct loader_scanned_icds *new_node;
550
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700551 // Used to call: dlopen(filename, RTLD_LAZY);
552 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700553 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600554 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700555 return;
556 }
557
558#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600559 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700560 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600561 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700562 return; \
563 } \
564} while (0)
565
Jon Ashburn46888392015-01-29 15:45:51 -0700566 LOOKUP(fp_create_inst, CreateInstance);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600567 LOOKUP(fp_get_global_ext_info, GetGlobalExtensionInfo);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600568 LOOKUP(fp_get_device_ext_info, GetPhysicalDeviceExtensionInfo);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700569#undef LOOKUP
570
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600571 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
572 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700573 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600574 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -0700575 return;
576 }
577
578 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -0700579 new_node->CreateInstance = fp_create_inst;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600580 new_node->GetGlobalExtensionInfo = fp_get_global_ext_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600581 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600582 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700583 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700584
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600585 new_node->lib_name = (char *) (new_node + 1);
586 if (!new_node->lib_name) {
587 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
588 return;
589 }
590 strcpy(new_node->lib_name, filename);
591
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600592 loader.scanned_icd_list = new_node;
593
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600594 get_global_extensions(
595 (PFN_vkGetGlobalExtensionInfo) fp_get_global_ext_info,
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600596 "vkGetGlobalExtensionInfo",
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600597 new_node->lib_name,
598 VK_EXTENSION_ORIGIN_ICD,
599 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600600}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700601
Jon Ashburn3da71f22015-05-14 12:43:38 -0600602static void loader_icd_init_entrys(struct loader_icd *icd,
603 struct loader_scanned_icds *scanned_icds)
604{
605 /* initialize entrypoint function pointers */
606
607 #define LOOKUP(func) do { \
608 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
609 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600610 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -0600611 return; \
612 } \
613 } while (0)
614
Jon Ashburn8d1b0b52015-05-18 13:20:15 -0600615 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
616 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600617 LOOKUP(DestroyInstance);
618 LOOKUP(EnumeratePhysicalDevices);
619 LOOKUP(GetPhysicalDeviceInfo);
620 LOOKUP(CreateDevice);
621 LOOKUP(GetPhysicalDeviceExtensionInfo);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600622 LOOKUP(GetMultiDeviceCompatibility);
Jon Ashburn95a77ba2015-05-15 15:09:35 -0600623 LOOKUP(GetDisplayInfoWSI);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600624 LOOKUP(DbgCreateMsgCallback);
625 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -0600626#undef LOOKUP
627
628 return;
629}
630
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600631/**
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600632 * Try to \c loader_icd_scan VK driver(s).
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600633 *
634 * This function scans the default system path or path
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600635 * specified by the \c LIBVK_DRIVERS_PATH environment variable in
636 * order to find loadable VK ICDs with the name of libVK_*.
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600637 *
638 * \returns
639 * void; but side effect is to set loader_icd_scanned to true
640 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600641void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800642{
Ian Elliott4470a302015-02-17 10:33:47 -0700643 const char *p, *next;
644 char *libPaths = NULL;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600645 DIR *sysdir;
646 struct dirent *dent;
647 char icd_library[1024];
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600648 char path[1024];
Ian Elliott19628802015-02-04 12:06:46 -0700649 uint32_t len;
Ian Elliott4470a302015-02-17 10:33:47 -0700650#if defined(WIN32)
651 bool must_free_libPaths;
652 libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV,
653 DRIVER_PATH_REGISTRY_VALUE);
654 if (libPaths != NULL) {
655 must_free_libPaths = true;
656 } else {
657 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600658 libPaths = DEFAULT_VK_DRIVERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700659 }
660#else // WIN32
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600661 if (geteuid() == getuid()) {
Ian Elliott4470a302015-02-17 10:33:47 -0700662 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
663 libPaths = getenv(DRIVER_PATH_ENV);
664 }
665 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600666 libPaths = DEFAULT_VK_DRIVERS_PATH;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600667 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700668#endif // WIN32
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800669
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600670 for (p = libPaths; *p; p = next) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700671 next = strchr(p, PATH_SEPERATOR);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600672 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -0700673 len = (uint32_t) strlen(p);
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600674 next = p + len;
675 }
676 else {
Ian Elliott19628802015-02-04 12:06:46 -0700677 len = (uint32_t) (next - p);
Jon Ashburn5cda59c2014-10-03 16:31:35 -0600678 sprintf(path, "%.*s", (len > sizeof(path) - 1) ? (int) sizeof(path) - 1 : len, p);
679 p = path;
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600680 next++;
681 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800682
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700683 // TODO/TBD: Do we want to do this on Windows, or just let Windows take
684 // care of its own search path (which it apparently has)?
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600685 sysdir = opendir(p);
686 if (sysdir) {
687 dent = readdir(sysdir);
688 while (dent) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600689 /* Look for ICDs starting with VK_DRIVER_LIBRARY_PREFIX and
690 * ending with VK_LIBRARY_SUFFIX
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700691 */
692 if (!strncmp(dent->d_name,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600693 VK_DRIVER_LIBRARY_PREFIX,
694 VK_DRIVER_LIBRARY_PREFIX_LEN)) {
Ian Elliott19628802015-02-04 12:06:46 -0700695 uint32_t nlen = (uint32_t) strlen(dent->d_name);
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600696 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
697 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700698 !strncmp(suf,
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600699 VK_LIBRARY_SUFFIX,
700 VK_LIBRARY_SUFFIX_LEN)) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700701 snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
702 loader_scanned_icd_add(icd_library);
703 }
704 }
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600705
706 dent = readdir(sysdir);
707 }
708 closedir(sysdir);
709 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800710 }
711
Ian Elliott4470a302015-02-17 10:33:47 -0700712#if defined(WIN32)
713 // Free any allocated memory:
714 if (must_free_libPaths) {
715 free(libPaths);
716 }
717#endif // WIN32
718
719 // Note that we've scanned for ICDs:
Jon Ashburn46d1f582015-01-28 11:01:35 -0700720 loader.icds_scanned = true;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800721}
722
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600723
Jon Ashburn27cd5842015-05-12 17:26:48 -0600724void layer_lib_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600725{
726 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -0700727 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600728 DIR *curdir;
729 struct dirent *dent;
Ian Elliott4470a302015-02-17 10:33:47 -0700730 size_t len, i;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600731 char temp_str[1024];
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600732 uint32_t count;
733 PFN_vkGetGlobalExtensionInfo fp_get_ext;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600734
Ian Elliott4470a302015-02-17 10:33:47 -0700735#if defined(WIN32)
736 bool must_free_libPaths;
737 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
738 LAYERS_PATH_REGISTRY_VALUE);
739 if (libPaths != NULL) {
740 must_free_libPaths = true;
741 } else {
742 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600743 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600744 }
Ian Elliott4470a302015-02-17 10:33:47 -0700745#else // WIN32
746 if (geteuid() == getuid()) {
747 /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -0700748 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -0700749 }
750 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -0600751 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -0700752 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700753#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600754
Ian Elliott4470a302015-02-17 10:33:47 -0700755 if (libPaths == NULL) {
756 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700757 return;
758 }
Ian Elliott4470a302015-02-17 10:33:47 -0700759 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700760 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -0700761 if (loader.layer_dirs == NULL) {
762 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -0700763 return;
Ian Elliott4470a302015-02-17 10:33:47 -0700764 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600765 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott4470a302015-02-17 10:33:47 -0700766 strcpy(loader.layer_dirs, libPaths);
767#if defined(WIN32)
768 // Free any allocated memory:
769 if (must_free_libPaths) {
770 free(libPaths);
771 must_free_libPaths = false;
772 }
773#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -0700774 libPaths = loader.layer_dirs;
775
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600776 /* cleanup any previously scanned libraries */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600777 for (i = 0; i < loader.scanned_layer_count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600778 if (loader.scanned_layers[i].lib_name != NULL)
779 free(loader.scanned_layers[i].lib_name);
780 loader_destroy_ext_list(&loader.scanned_layers[i].global_extension_list);
781 loader.scanned_layers[i].lib_name = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600782 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600783 loader.scanned_layer_count = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600784 count = 0;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600785
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600786 for (p = libPaths; *p; p = next) {
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600787 next = strchr(p, PATH_SEPERATOR);
788 if (next == NULL) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600789 len = (uint32_t) strlen(p);
790 next = p + len;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600791 }
792 else {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600793 len = (uint32_t) (next - p);
794 *(char *) next = '\0';
795 next++;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600796 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600797
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600798 curdir = opendir(p);
799 if (curdir) {
800 dent = readdir(curdir);
801 while (dent) {
802 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
803 * ending with VK_LIBRARY_SUFFIX
804 */
805 if (!strncmp(dent->d_name,
806 VK_LAYER_LIBRARY_PREFIX,
807 VK_LAYER_LIBRARY_PREFIX_LEN)) {
808 uint32_t nlen = (uint32_t) strlen(dent->d_name);
809 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
810 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
811 !strncmp(suf,
812 VK_LIBRARY_SUFFIX,
813 VK_LIBRARY_SUFFIX_LEN)) {
814 loader_platform_dl_handle handle;
815 snprintf(temp_str, sizeof(temp_str),
816 "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
817 // Used to call: dlopen(temp_str, RTLD_LAZY)
818 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
819 "Attempt to open library: %s\n", temp_str);
820 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
821 dent = readdir(curdir);
822 continue;
823 }
824 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
825 "Opened library: %s\n", temp_str);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -0600826
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600827 /* TODO: Remove fixed count */
828 if (count == MAX_LAYER_LIBRARIES) {
829 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
830 "%s ignored: max layer libraries exceed",
831 temp_str);
832 break;
833 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600834
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600835 fp_get_ext = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionInfo");
836 if (!fp_get_ext) {
837 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
838 "Couldn't dlsym vkGetGlobalExtensionInfo from library %s",
839 temp_str);
840 dent = readdir(curdir);
841 loader_platform_close_library(handle);
842 continue;
843 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600844
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600845 loader.scanned_layers[count].lib_name =
846 malloc(strlen(temp_str) + 1);
847 if (loader.scanned_layers[count].lib_name == NULL) {
848 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "%s ignored: out of memory", temp_str);
849 break;
850 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600851
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600852 strcpy(loader.scanned_layers[count].lib_name, temp_str);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600853
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600854 fprintf(stderr, "Collecting global extensions for %s\n", temp_str);
855 get_global_extensions(
856 fp_get_ext,
857 "vkGetGlobalExtensionInfo",
858 loader.scanned_layers[count].lib_name,
859 VK_EXTENSION_ORIGIN_LAYER,
860 &loader.scanned_layers[count].global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600861
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600862 fp_get_ext = loader_platform_get_proc_address(handle,
863 "vkGetPhysicalDeviceExtensionInfo");
864 if (fp_get_ext) {
865 loader.scanned_layers[count].physical_device_extensions_supported = true;
866 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600867
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600868 count++;
869 loader_platform_close_library(handle);
870 }
871 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600872
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600873 dent = readdir(curdir);
874 } // while (dir_entry)
875 if (count == MAX_LAYER_LIBRARIES)
876 break;
877 closedir(curdir);
878 } // if (curdir))
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600879 } // for (libpaths)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600880
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600881 loader.scanned_layer_count = count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600882 loader.layers_scanned = true;
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600883}
884
Jon Ashburn27cd5842015-05-12 17:26:48 -0600885static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
886{
887 // inst is not wrapped
888 if (inst == VK_NULL_HANDLE) {
889 return NULL;
890 }
891 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
892 void *addr;
893
Jon Ashburn8fd08252015-05-28 16:25:02 -0600894 if (!strcmp(pName, "vkGetInstanceProcAddr"))
895 return (void *) loader_gpa_instance_internal;
896
Jon Ashburn27cd5842015-05-12 17:26:48 -0600897 if (disp_table == NULL)
898 return NULL;
899
900 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600901 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -0600902 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600903 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600904
905 if (disp_table->GetInstanceProcAddr == NULL) {
906 return NULL;
907 }
908 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -0600909}
910
Jon Ashburn128f9422015-05-28 19:16:58 -0600911struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600912{
Jon Ashburn128f9422015-05-28 19:16:58 -0600913
Jon Ashburn98bd4542015-01-29 16:44:24 -0700914 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
915 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
916 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -0600917 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -0700918 *gpu_index = i;
919 return icd;
920 }
921 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600922 }
923 return NULL;
924}
925
Mark Lobodzinski17caf572015-01-29 08:55:56 -0600926static bool loader_layers_activated(const struct loader_icd *icd, const uint32_t gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600927{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600928 if (icd->layer_count[gpu_index])
929 return true;
930 else
931 return false;
Jon Ashburn876b1ac2014-10-17 15:09:07 -0600932}
933
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600934static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -0600935 const char *chain_type,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600936 struct loader_extension_property *ext_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -0600937{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600938 struct loader_lib_info *new_layer_lib_list, *my_lib;
939
940 /* Only loader layer libraries here */
941 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
942 return NULL;
943 }
944
945 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
946 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
947 /* Have already loaded this library, just increment ref count */
948 loader.loaded_layer_lib_list[i].ref_count++;
Jon Ashburne68a9ff2015-05-25 14:11:37 -0600949 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600950 "%s Chain: Increment layer reference count for layer library %s",
951 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600952 return loader.loaded_layer_lib_list[i].lib_handle;
953 }
954 }
955
956 /* Haven't seen this library so load it */
957 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
958 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
959 if (!new_layer_lib_list) {
960 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
961 return NULL;
962 }
963
964 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
965
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600966 /* NOTE: We require that the extension property be immutable */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600967 my_lib->lib_name = ext_prop->lib_name;
968 my_lib->ref_count = 0;
969 my_lib->lib_handle = NULL;
970
971 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
972 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
973 loader_platform_open_library_error(my_lib->lib_name));
974 return NULL;
975 } else {
976 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600977 "Chain: %s: Loading layer library %s",
978 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600979 }
980 loader.loaded_layer_lib_count++;
981 loader.loaded_layer_lib_list = new_layer_lib_list;
982 my_lib->ref_count++;
983
984 return my_lib->lib_handle;
985}
986
987static void loader_remove_layer_lib(
988 struct loader_instance *inst,
989 struct loader_extension_property *ext_prop)
990{
991 uint32_t idx;
992 struct loader_lib_info *new_layer_lib_list, *my_lib;
993
994 /* Only loader layer libraries here */
995 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
Jon Ashburn6b4d70c2014-10-22 18:13:16 -0600996 return;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600997 }
Jon Ashburndf7d5842014-10-16 15:48:50 -0600998
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600999 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1000 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1001 /* found matching library */
1002 idx = i;
1003 my_lib = &loader.loaded_layer_lib_list[i];
1004 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001005 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001006 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001007
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001008 my_lib->ref_count--;
1009 inst->layer_count--;
1010 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001011 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1012 "Decrement reference count for layer library %s", ext_prop->lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001013 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001014 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001015
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001016 loader_platform_close_library(my_lib->lib_handle);
1017 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1018 "Unloading layer library %s", ext_prop->lib_name);
1019
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001020 /* Need to remove unused library from list */
1021 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1022 if (!new_layer_lib_list) {
1023 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1024 return;
1025 }
1026
1027 if (idx > 0) {
1028 /* Copy records before idx */
1029 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1030 sizeof(struct loader_lib_info) * idx);
1031 }
1032 if (idx < (loader.loaded_layer_lib_count - 1)) {
1033 /* Copy records after idx */
1034 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1035 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1036 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001037
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001038 free(loader.loaded_layer_lib_list);
1039 loader.loaded_layer_lib_count--;
1040 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001041}
1042
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001043static void loader_add_layer_env(
1044 struct loader_extension_list *ext_list,
1045 const struct loader_extension_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001046{
Ian Elliott4470a302015-02-17 10:33:47 -07001047 char *layerEnv;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001048 uint32_t len;
Jon Ashburnd09bd102014-10-22 21:15:26 -06001049 char *p, *pOrig, *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001050
Ian Elliott4470a302015-02-17 10:33:47 -07001051#if defined(WIN32)
1052 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
1053 LAYER_NAMES_REGISTRY_VALUE);
1054#else // WIN32
1055 layerEnv = getenv(LAYER_NAMES_ENV);
1056#endif // WIN32
1057 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001058 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001059 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001060 p = malloc(strlen(layerEnv) + 1);
Ian Elliott4470a302015-02-17 10:33:47 -07001061 if (p == NULL) {
1062#if defined(WIN32)
1063 free(layerEnv);
1064#endif // WIN32
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001065 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001066 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001067 strcpy(p, layerEnv);
Ian Elliott4470a302015-02-17 10:33:47 -07001068#if defined(WIN32)
1069 free(layerEnv);
1070#endif // WIN32
Jon Ashburnd09bd102014-10-22 21:15:26 -06001071 pOrig = p;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001072
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001073 while (p && *p ) {
Jon Ashburn19c25022015-04-14 14:14:48 -06001074 //memset(&lib_name[0], 0, sizeof(const char *) * MAX_LAYER_LIBRARIES);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001075 next = strchr(p, PATH_SEPERATOR);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001076 if (next == NULL) {
Ian Elliott19628802015-02-04 12:06:46 -07001077 len = (uint32_t) strlen(p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001078 next = p + len;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001079 } else {
Ian Elliott19628802015-02-04 12:06:46 -07001080 len = (uint32_t) (next - p);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001081 *(char *) next = '\0';
1082 next++;
1083 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001084 name = basename(p);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001085 loader_search_ext_list_for_name(name, search_list, ext_list);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001086 p = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001087 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001088
Jon Ashburnd09bd102014-10-22 21:15:26 -06001089 free(pOrig);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001090 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001091}
1092
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001093
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001094static void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001095{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001096 if (!instance->layer_count) {
1097 return;
1098 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001099
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001100 /* Create instance chain of enabled layers */
1101 for (uint32_t i = 0; i < instance->enabled_instance_extensions.count; i++) {
1102 struct loader_extension_property *ext_prop = &instance->enabled_instance_extensions.list[i];
1103
1104 if (ext_prop->origin == VK_EXTENSION_ORIGIN_ICD) {
1105 continue;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001106 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001107
1108 loader_remove_layer_lib(instance, ext_prop);
1109
1110 instance->layer_count--;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001111 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001112
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001113}
1114
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001115void loader_enable_instance_layers(struct loader_instance *inst)
1116{
1117 if (inst == NULL)
1118 return;
1119
1120 /* Add any layers specified in the environment first */
1121 loader_add_layer_env(&inst->enabled_instance_extensions, &loader.global_extensions);
1122
1123 /* Add layers / extensions specified by the application */
1124 loader_add_vk_ext_to_ext_list(
1125 &inst->enabled_instance_extensions,
1126 inst->app_extension_count,
1127 inst->app_extension_props,
1128 &loader.global_extensions);
1129}
1130
Jon Ashburn27cd5842015-05-12 17:26:48 -06001131uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1132{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001133 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06001134 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001135
Jon Ashburn27cd5842015-05-12 17:26:48 -06001136 if (inst == NULL)
1137 return 0;
1138
1139 // NOTE inst is unwrapped at this point in time
1140 VkObject baseObj = (VkObject) inst;
1141 VkObject nextObj = (VkObject) inst;
1142 VkBaseLayerObject *nextInstObj;
1143 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1144
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001145 /*
1146 * Figure out how many actual layers will need to be wrapped.
1147 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001148 for (uint32_t i = 0; i < inst->enabled_instance_extensions.count; i++) {
1149 struct loader_extension_property *ext_prop = &inst->enabled_instance_extensions.list[i];
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001150 if (ext_prop->alias) {
1151 ext_prop = ext_prop->alias;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001152 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001153 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1154 continue;
1155 }
1156 loader_add_to_ext_list(&inst->activated_layer_list, 1, ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001157 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001158
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001159 inst->layer_count = inst->activated_layer_list.count;
1160
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001161 if (!inst->layer_count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001162 return 0;
1163 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001164
Jon Ashburn128f9422015-05-28 19:16:58 -06001165 wrappedInstance = malloc(sizeof(VkBaseLayerObject)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001166 * inst->layer_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001167 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001168 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1169 return 0;
1170 }
1171
1172 /* Create instance chain of enabled layers */
1173 layer_idx = inst->layer_count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001174 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
1175 struct loader_extension_property *ext_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001176 loader_platform_dl_handle lib_handle;
1177
1178 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001179 * For global exenstions implemented within the loader (i.e. WSI, DEBUG_REPORT
1180 * the extension must provide two entry points for the loader to use:
1181 * - "trampoline" entry point - this is the address returned by GetProcAddr
1182 * and will always do what's necessary to support a global call.
1183 * - "terminator" function - this function will be put at the end of the
1184 * instance chain and will contain the necessary logica to call / process
1185 * the extension for the appropriate ICDs that are available.
1186 * There is no generic mechanism for including these functions, the references
1187 * must be placed into the appropriate loader entry points.
1188 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
1189 * loader_coalesce_extensions(void) - add extension records to the list of global
1190 * extension available to the app.
1191 * instance_disp - add function pointer for terminator function to this array.
1192 * The extension itself should be in a separate file that will be
1193 * linked directly with the loader.
1194 * Note: An extension's Get*ProcAddr should not return a function pointer for
1195 * any extension entry points until the extension has been enabled.
1196 * To do this requires a different behavior from Get*ProcAddr functions implemented
1197 * in layers.
1198 * The very first call to a layer will be it's Get*ProcAddr function requesting
1199 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1200 * with the wrapped object given (either Instance or Device) and return the layer's
1201 * Get*ProcAddr function. The layer should also use this opportunity to record the
1202 * baseObject so that it can find the correct local dispatch table on future calls.
1203 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1204 * will not use a wrapped object and must look up their local dispatch table from
1205 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001206 */
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001207 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001208
Jon Ashburn128f9422015-05-28 19:16:58 -06001209 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001210 nextInstObj->pGPA = nextGPA;
1211 nextInstObj->baseObject = baseObj;
1212 nextInstObj->nextObject = nextObj;
1213 nextObj = (VkObject) nextInstObj;
1214
1215 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001216 snprintf(funcStr, 256, "%sGetInstanceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001217 lib_handle = loader_add_layer_lib("instance", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001218 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1219 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001220 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001221 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 -06001222
1223 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001224 continue;
1225 }
1226
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001227 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1228 "Insert instance layer library %s for extension: %s",
1229 ext_prop->lib_name, ext_prop->info.name);
1230
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001231 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001232 }
1233
Jon Ashburn8fd08252015-05-28 16:25:02 -06001234 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001235
Jon Ashburn128f9422015-05-28 19:16:58 -06001236 free(wrappedInstance);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001237 return inst->layer_count;
1238}
1239
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001240void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1241{
1242
1243 loader_init_instance_extension_dispatch_table(inst->disp,
1244 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06001245 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001246}
1247
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001248void loader_enable_device_layers(struct loader_icd *icd, uint32_t gpu_index)
1249{
1250 if (icd == NULL)
1251 return;
1252
1253 /* Add any layers specified in the environment first */
1254 loader_add_layer_env(&icd->enabled_device_extensions[gpu_index], &loader.global_extensions);
1255
1256 /* Add layers / extensions specified by the application */
1257 loader_add_vk_ext_to_ext_list(
1258 &icd->enabled_device_extensions[gpu_index],
1259 icd->app_extension_count[gpu_index],
1260 icd->app_extension_props[gpu_index],
1261 &loader.global_extensions);
1262}
1263
1264extern uint32_t loader_activate_device_layers(
1265 VkDevice device,
1266 struct loader_icd *icd,
1267 uint32_t gpu_index,
1268 uint32_t ext_count,
1269 const VkExtensionProperties *ext_props)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001270{
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001271 uint32_t count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001272 uint32_t layer_idx;
1273
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001274 if (!icd)
1275 return 0;
Jon Ashburn83a64252015-04-15 11:31:12 -06001276 assert(gpu_index < MAX_GPUS_FOR_LAYER);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001277
1278 /* activate any layer libraries */
1279 if (!loader_layers_activated(icd, gpu_index)) {
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001280 VkObject nextObj = (VkObject) device;
1281 VkObject baseObj = nextObj;
1282 VkBaseLayerObject *nextGpuObj;
Jon Ashburn7c096122015-05-22 09:19:49 -06001283 PFN_vkGetDeviceProcAddr nextGPA = icd->GetDeviceProcAddr;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001284
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001285 count = 0;
1286 for (uint32_t i = 0; i < icd->enabled_device_extensions[gpu_index].count; i++) {
1287 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1288 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER) {
1289 count++;
1290 }
1291 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001292 if (!count)
1293 return 0;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001294
1295 icd->layer_count[gpu_index] = count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001296
Jon Ashburnbacb0f52015-04-06 10:58:22 -06001297 icd->wrappedGpus[gpu_index] = malloc(sizeof(VkBaseLayerObject) * icd->layer_count[gpu_index]);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001298 if (! icd->wrappedGpus[gpu_index]) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001299 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001300 return 0;
1301 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001302 layer_idx = count - 1;
Mark Lobodzinski17caf572015-01-29 08:55:56 -06001303 for (int32_t i = icd->layer_count[gpu_index] - 1; i >= 0; i--) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001304 struct loader_extension_property *ext_prop = &icd->enabled_device_extensions[gpu_index].list[i];
1305 loader_platform_dl_handle lib_handle;
1306
1307 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1308 continue;
1309 }
1310
Jon Ashburnd09bd102014-10-22 21:15:26 -06001311 nextGpuObj = (icd->wrappedGpus[gpu_index] + i);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001312 nextGpuObj->pGPA = nextGPA;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001313 nextGpuObj->baseObject = baseObj;
1314 nextGpuObj->nextObject = nextObj;
1315 nextObj = (VkObject) nextGpuObj;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001316
Jon Ashburn79113cc2014-12-01 14:22:40 -07001317 char funcStr[256];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001318 snprintf(funcStr, 256, "%sGetDeviceProcAddr", ext_prop->info.name);
Jon Ashburn4f67d742015-05-27 13:19:22 -06001319 lib_handle = loader_add_layer_lib("device", ext_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001320 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1321 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001322 if (!nextGPA) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001323 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 -06001324 continue;
1325 }
1326
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001327 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1328 "Insert device layer library %s for extension: %s",
1329 ext_prop->lib_name, ext_prop->info.name);
1330
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001331 layer_idx--;
1332 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001333
Jon Ashburn8fd08252015-05-28 16:25:02 -06001334 loader_init_device_dispatch_table(icd->loader_dispatch + gpu_index, nextGPA,
1335 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001336 } else {
1337 // TODO: Check that active layers match requested?
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001338 }
1339 return icd->layer_count[gpu_index];
1340}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001341
Jon Ashburn27cd5842015-05-12 17:26:48 -06001342VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001343 const VkInstanceCreateInfo* pCreateInfo,
1344 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001345{
Jon Ashburneed0c002015-05-21 17:42:17 -06001346 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07001347 struct loader_scanned_icds *scanned_icds;
1348 struct loader_icd *icd;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001349 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001350
Jon Ashburn46888392015-01-29 15:45:51 -07001351 scanned_icds = loader.scanned_icd_list;
1352 while (scanned_icds) {
1353 icd = loader_icd_add(ptr_instance, scanned_icds);
1354 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -06001355 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn3da71f22015-05-14 12:43:38 -06001356 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001357 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07001358 {
1359 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001360 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001361 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001362 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07001363 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06001364 } else
1365 {
1366 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07001367 }
1368 }
1369 scanned_icds = scanned_icds->next;
1370 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001371
Ian Elliotteb450762015-02-05 15:19:15 -07001372 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001373 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -07001374 }
Jon Ashburn46888392015-01-29 15:45:51 -07001375
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001376 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001377}
1378
Jon Ashburn27cd5842015-05-12 17:26:48 -06001379VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001380 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001381{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06001382 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001383 struct loader_icd *icds = ptr_instance->icds;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001384 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001385
1386 // Remove this instance from the list of instances:
1387 struct loader_instance *prev = NULL;
1388 struct loader_instance *next = loader.instances;
1389 while (next != NULL) {
1390 if (next == ptr_instance) {
1391 // Remove this instance from the list:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001392 free(ptr_instance->app_extension_props);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001393 if (prev)
1394 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07001395 else
1396 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001397 break;
1398 }
1399 prev = next;
1400 next = next->next;
1401 }
1402 if (next == NULL) {
1403 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001404 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001405 }
1406
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001407 loader_deactivate_instance_layers(ptr_instance);
1408 loader_destroy_ext_list(&ptr_instance->enabled_instance_extensions);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001409
Jon Ashburn3da71f22015-05-14 12:43:38 -06001410 while (icds) {
1411 if (icds->instance) {
1412 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06001413 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001414 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06001415 "ICD ignored: failed to DestroyInstance on device");
1416 }
Jon Ashburn128f9422015-05-28 19:16:58 -06001417 loader_icd_destroy(ptr_instance, icds);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001418 icds->instance = VK_NULL_HANDLE;
1419 icds = icds->next;
Jon Ashburn46888392015-01-29 15:45:51 -07001420 }
1421
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001422 free(ptr_instance);
1423
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001424 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001425}
1426
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001427VkResult loader_init_physical_device_info(
1428 struct loader_instance *ptr_instance)
1429{
1430 struct loader_icd *icd;
1431 uint32_t n, count = 0;
1432 VkResult res = VK_ERROR_UNKNOWN;
1433
1434 icd = ptr_instance->icds;
1435 while (icd) {
1436 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
1437 if (res != VK_SUCCESS)
1438 return res;
1439 icd->gpu_count = n;
1440 count += n;
1441 icd = icd->next;
1442 }
1443
1444 ptr_instance->total_gpu_count = count;
1445
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001446 icd = ptr_instance->icds;
1447 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001448 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
1449
1450 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001451 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
1452 if (!icd->gpus) {
1453 /* TODO: Add cleanup code here */
1454 return VK_ERROR_OUT_OF_HOST_MEMORY;
1455 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001456 res = icd->EnumeratePhysicalDevices(
1457 icd->instance,
1458 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06001459 icd->gpus);
1460 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001461
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001462 icd->loader_dispatch = (VkLayerDispatchTable *) malloc(n *
1463 sizeof(VkLayerDispatchTable));
1464 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001465
1466 loader_init_device_dispatch_table(icd->loader_dispatch + i,
Jon Ashburn128f9422015-05-28 19:16:58 -06001467 get_proc_addr, icd->gpus[i], icd->gpus[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001468
Jon Ashburn128f9422015-05-28 19:16:58 -06001469 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001470
1471 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
1472 /* TODO: Add cleanup code here */
1473 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1474 }
1475 if (res == VK_SUCCESS && icd->GetPhysicalDeviceExtensionInfo) {
1476 size_t data_size;
1477 uint32_t extension_count;
1478
1479 data_size = sizeof(extension_count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001480 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_COUNT, 0, &data_size, &extension_count);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001481 if (data_size == sizeof(extension_count) && res == VK_SUCCESS) {
1482 struct loader_extension_property ext_props;
1483
1484 /* Gather all the ICD extensions */
1485 for (uint32_t extension_id = 0; extension_id < extension_count; extension_id++) {
1486 data_size = sizeof(VkExtensionProperties);
Jon Ashburn128f9422015-05-28 19:16:58 -06001487 res = icd->GetPhysicalDeviceExtensionInfo(icd->gpus[i], VK_EXTENSION_INFO_TYPE_PROPERTIES,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001488 extension_id, &data_size, &ext_props.info);
1489 if (data_size == sizeof(VkExtensionProperties) && res == VK_SUCCESS) {
1490 ext_props.hosted = false;
1491 ext_props.origin = VK_EXTENSION_ORIGIN_ICD;
1492 ext_props.lib_name = icd->scanned_icds->lib_name;
Jon Ashburn128f9422015-05-28 19:16:58 -06001493 // For ICDs, this is the only option
1494 strcpy(ext_props.get_extension_info_name, "vkGetPhysicalDeviceExtensionInfo");
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001495 loader_add_to_ext_list(&icd->device_extension_cache[i], 1, &ext_props);
1496 }
1497 }
1498
1499 // Traverse layers list adding non-duplicate extensions to the list
1500 for (uint32_t l = 0; l < loader.scanned_layer_count; l++) {
Jon Ashburn128f9422015-05-28 19:16:58 -06001501 get_physical_device_layer_extensions(ptr_instance, icd->gpus[i], l, &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001502 }
1503 }
1504 }
1505
1506 if (res != VK_SUCCESS) {
1507 /* clean up any extension lists previously created before this request failed */
1508 for (uint32_t j = 0; j < i; j++) {
1509 loader_destroy_ext_list(&icd->device_extension_cache[i]);
1510 }
1511 return res;
1512 }
1513 }
1514
1515 count += n;
1516 }
1517
1518 icd = icd->next;
1519 }
1520
1521 return VK_SUCCESS;
1522}
1523
Jon Ashburn27cd5842015-05-12 17:26:48 -06001524VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06001525 VkInstance instance,
1526 uint32_t* pPhysicalDeviceCount,
1527 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001528{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001529 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001530 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001531 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001532
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001533 if (ptr_instance->total_gpu_count == 0) {
1534 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001535 }
1536
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001537 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
1538 if (!pPhysicalDevices) {
1539 return VK_SUCCESS;
1540 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07001541
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001542 while (icd) {
1543 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06001544 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001545 index += icd->gpu_count;
1546 icd = icd->next;
1547 }
1548
1549 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001550}
1551
Jon Ashburn3da71f22015-05-14 12:43:38 -06001552VkResult loader_GetPhysicalDeviceInfo(
1553 VkPhysicalDevice gpu,
1554 VkPhysicalDeviceInfoType infoType,
1555 size_t* pDataSize,
1556 void* pData)
1557{
1558 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001559 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001560 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1561
1562 if (icd->GetPhysicalDeviceInfo)
1563 res = icd->GetPhysicalDeviceInfo(gpu, infoType, pDataSize, pData);
1564
1565 return res;
1566}
1567
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001568VkResult loader_CreateDevice(
1569 VkPhysicalDevice gpu,
1570 const VkDeviceCreateInfo* pCreateInfo,
1571 VkDevice* pDevice)
1572{
1573 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001574 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001575 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001576
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001577 if (icd->CreateDevice) {
1578 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001579 if (res != VK_SUCCESS) {
1580 return res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001581 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001582
1583 VkLayerDispatchTable *dev_disp = icd->loader_dispatch + gpu_index;
1584 loader_init_dispatch(*pDevice, dev_disp);
1585
1586 icd->app_extension_count[gpu_index] = pCreateInfo->extensionCount;
1587 icd->app_extension_props[gpu_index] = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1588 if (icd->app_extension_props[gpu_index] == NULL && (icd->app_extension_count[gpu_index] > 0)) {
1589 return VK_ERROR_OUT_OF_HOST_MEMORY;
1590 }
1591
1592 /* Make local copy of extension list */
1593 if (icd->app_extension_count[gpu_index] > 0 && icd->app_extension_props[gpu_index] != NULL) {
1594 memcpy(icd->app_extension_props[gpu_index], pCreateInfo->pEnabledExtensions, sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
1595 }
1596
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001597 /*
1598 * Put together the complete list of extensions to enable
1599 * This includes extensions requested via environment variables.
1600 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001601 loader_enable_device_layers(icd, gpu_index);
1602
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001603 /*
1604 * Load the libraries needed by the extensions on the
1605 * enabled extension list. This will build the
1606 * device instance chain terminating with the
1607 * selected device.
1608 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001609 loader_activate_device_layers(*pDevice, icd, gpu_index,
1610 icd->app_extension_count[gpu_index],
1611 icd->app_extension_props[gpu_index]);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001612 }
1613
1614 return res;
1615}
1616
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001617LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
1618{
Jon Ashburn07daee72015-05-21 18:13:33 -06001619 if (instance == VK_NULL_HANDLE)
1620 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001621
Jon Ashburn07daee72015-05-21 18:13:33 -06001622 void *addr;
1623 /* get entrypoint addresses that are global (in the loader)*/
1624 addr = globalGetProcAddr(pName);
1625 if (addr)
1626 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001627
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001628 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
1629
1630 addr = debug_report_instance_gpa(ptr_instance, pName);
1631 if (addr) {
1632 return addr;
1633 }
1634
Jon Ashburn07daee72015-05-21 18:13:33 -06001635 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001636 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001637 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001638 return (ptr_instance->wsi_lunarg_enabled) ? addr : NULL;
Jon Ashburn07daee72015-05-21 18:13:33 -06001639
1640 /* return the instance dispatch table entrypoint for extensions */
1641 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
1642 if (disp_table == NULL)
1643 return NULL;
1644
1645 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
1646 if (addr)
1647 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06001648
1649 return NULL;
1650}
1651
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001652LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07001653{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001654 if (device == VK_NULL_HANDLE) {
1655 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001656 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001657
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001658 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001659
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001660 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
1661 make sure the loader entrypoint is returned */
1662 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06001663 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001664 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06001665 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001666
Jon Ashburn07daee72015-05-21 18:13:33 -06001667 /* return any extension device entrypoints the loader knows about */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001668 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
Jon Ashburn07daee72015-05-21 18:13:33 -06001669 if (addr)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001670 return addr;
Jon Ashburn07daee72015-05-21 18:13:33 -06001671
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001672 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001673 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001674 if (disp_table == NULL)
1675 return NULL;
1676
Jon Ashburn27cd5842015-05-12 17:26:48 -06001677 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08001678 if (addr)
1679 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001680 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001681 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001682 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001683 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001684 }
1685}
1686
Jon Ashburneceb13e2015-05-18 15:28:32 -06001687LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001688 VkExtensionInfoType infoType,
1689 uint32_t extensionIndex,
1690 size_t* pDataSize,
1691 void* pData)
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001692{
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001693 uint32_t *count;
1694 /* Scan/discover all ICD libraries in a single-threaded manner */
1695 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001696
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001697 /* get layer libraries in a single-threaded manner */
1698 loader_platform_thread_once(&once_layer, layer_lib_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001699
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001700 /* merge any duplicate extensions */
1701 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
1702
1703
1704 if (pDataSize == NULL)
1705 return VK_ERROR_INVALID_POINTER;
1706
1707 switch (infoType) {
1708 case VK_EXTENSION_INFO_TYPE_COUNT:
1709 *pDataSize = sizeof(uint32_t);
1710 if (pData == NULL)
1711 return VK_SUCCESS;
1712 count = (uint32_t *) pData;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001713 *count = loader.global_extensions.count;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001714 break;
1715 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1716 *pDataSize = sizeof(VkExtensionProperties);
1717 if (pData == NULL)
1718 return VK_SUCCESS;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001719 if (extensionIndex >= loader.global_extensions.count)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001720 return VK_ERROR_INVALID_VALUE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001721 memcpy((VkExtensionProperties *) pData,
1722 &loader.global_extensions.list[extensionIndex],
1723 sizeof(VkExtensionProperties));
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001724 break;
1725 default:
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001726 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Invalid infoType in vkGetGlobalExtensionInfo");
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001727 return VK_ERROR_INVALID_VALUE;
1728 };
1729
1730 return VK_SUCCESS;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001731}
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001732
1733LOADER_EXPORT VkResult VKAPI vkGetPhysicalDeviceExtensionInfo(
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001734 VkPhysicalDevice gpu,
1735 VkExtensionInfoType infoType,
1736 uint32_t extensionIndex,
1737 size_t* pDataSize,
1738 void* pData)
1739{
1740 uint32_t gpu_index;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001741 uint32_t *count;
Jon Ashburn128f9422015-05-28 19:16:58 -06001742 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001743
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001744 if (pDataSize == NULL)
1745 return VK_ERROR_INVALID_POINTER;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001746
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001747 switch (infoType) {
1748 case VK_EXTENSION_INFO_TYPE_COUNT:
1749 *pDataSize = sizeof(uint32_t);
1750 if (pData == NULL)
1751 return VK_SUCCESS;
1752 count = (uint32_t *) pData;
1753 *count = icd->device_extension_cache[gpu_index].count;
1754 break;
1755 case VK_EXTENSION_INFO_TYPE_PROPERTIES:
1756 *pDataSize = sizeof(VkExtensionProperties);
1757 if (pData == NULL)
1758 return VK_SUCCESS;
1759 if (extensionIndex >= icd->device_extension_cache[gpu_index].count)
1760 return VK_ERROR_INVALID_VALUE;
1761 memcpy((VkExtensionProperties *) pData,
1762 &icd->device_extension_cache[gpu_index].list[extensionIndex],
1763 sizeof(VkExtensionProperties));
1764 break;
1765 default:
1766 return VK_ERROR_INVALID_VALUE;
1767 };
1768
1769 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001770}
1771
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001772VkResult loader_GetMultiDeviceCompatibility(
1773 VkPhysicalDevice gpu0,
1774 VkPhysicalDevice gpu1,
1775 VkPhysicalDeviceCompatibilityInfo* pInfo)
1776{
1777 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06001778 struct loader_icd *icd = loader_get_icd(gpu0, &gpu_index);
Jon Ashburn95a77ba2015-05-15 15:09:35 -06001779 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
1780
1781 if (icd->GetMultiDeviceCompatibility)
1782 res = icd->GetMultiDeviceCompatibility(gpu0, gpu1, pInfo);
1783
1784 return res;
1785}