blob: b82b6ca9ff75868c499ded2ba7f3f3bf197972b0 [file] [log] [blame]
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001/*
Courtney Goeltzenleuchter9cc421e2015-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 Wu44e42362014-09-02 08:32:09 +080023 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
Jon Ashburn406a0fe2014-11-14 09:52:42 -070026 * Jon Ashburn <jon@lunarg.com>
Chia-I Wu44e42362014-09-02 08:32:09 +080027 * Courtney Goeltzenleuchter <courtney@lunarg.com>
Ian Elliott76005132015-03-31 15:32:41 -060028 * Ian Elliott <ian@lunarg.com>
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080029 */
Jon Ashburn183dfd02014-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 Wu894a1172014-08-04 11:18:20 +080037#include <sys/types.h>
Ian Elliott81ac44c2015-01-13 17:52:38 -070038#if defined(WIN32)
39#include "dirent_on_windows.h"
40#else // WIN32
Chia-I Wu894a1172014-08-04 11:18:20 +080041#include <dirent.h>
Ian Elliott81ac44c2015-01-13 17:52:38 -070042#endif // WIN32
Tobin Ehlis7a51d902015-07-03 10:34:49 -060043#include "vk_loader_platform.h"
Chia-I Wu468e3c32014-08-04 08:03:57 +080044#include "loader.h"
Jon Ashburncedc15f2015-05-21 18:13:33 -060045#include "wsi_lunarg.h"
Jon Ashburnfce93d92015-05-12 17:26:48 -060046#include "gpa_helper.h"
47#include "table_ops.h"
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060048#include "debug_report.h"
Tobin Ehlis2d1d9702015-07-03 09:42:57 -060049#include "vk_icd.h"
Jon Ashburnffd5d672015-06-29 11:25:34 -060050#include "cJSON.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080051
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060052void loader_add_to_ext_list(
53 struct loader_extension_list *ext_list,
54 uint32_t prop_list_count,
55 const struct loader_extension_property *prop_list);
56
Courtney Goeltzenleuchter71cd74d2015-06-01 14:09:34 -060057static loader_platform_dl_handle loader_add_layer_lib(
58 const char *chain_type,
59 struct loader_extension_property *ext_prop);
60
61static void loader_remove_layer_lib(
62 struct loader_instance *inst,
63 struct loader_extension_property *ext_prop);
64
Jon Ashburnfce93d92015-05-12 17:26:48 -060065struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080066
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -060067static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
68
Courtney Goeltzenleuchter8b253f92015-06-08 15:11:18 -060069enum loader_debug {
70 LOADER_INFO_BIT = VK_BIT(0),
71 LOADER_WARN_BIT = VK_BIT(1),
72 LOADER_PERF_BIT = VK_BIT(2),
73 LOADER_ERROR_BIT = VK_BIT(3),
74 LOADER_DEBUG_BIT = VK_BIT(4),
75};
76
77uint32_t g_loader_debug = 0;
78uint32_t g_loader_log_msgs = 0;
79
Jon Ashburnb40f2562015-05-29 13:15:39 -060080//thread safety lock for accessing global data structures such as "loader"
81// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburnffd5d672015-06-29 11:25:34 -060082// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburnb40f2562015-05-29 13:15:39 -060083loader_platform_thread_mutex loader_lock;
84
85const VkLayerInstanceDispatchTable instance_disp = {
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -060086 .GetInstanceProcAddr = loader_GetInstanceProcAddr,
Jon Ashburnfce93d92015-05-12 17:26:48 -060087 .CreateInstance = loader_CreateInstance,
88 .DestroyInstance = loader_DestroyInstance,
89 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Chris Forbesd7576302015-06-21 22:55:02 +120090 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
91 .GetPhysicalDeviceFormatInfo = loader_GetPhysicalDeviceFormatInfo,
92 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
Tony Barbour426b9052015-06-24 16:06:58 -060093 .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
94 .GetPhysicalDevicePerformance = loader_GetPhysicalDevicePerformance,
95 .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount,
96 .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties,
97 .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
98 .GetPhysicalDeviceExtensionCount = loader_GetPhysicalDeviceExtensionCount,
99 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600100 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
101 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburnfce93d92015-05-12 17:26:48 -0600102};
103
104LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
105LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
106LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott81ac44c2015-01-13 17:52:38 -0700107
Jon Ashburnee33ae72015-06-30 14:46:22 -0700108static void loader_log(VkFlags msg_type, int32_t msg_code,
109 const char *format, ...)
110{
111 char msg[256];
112 va_list ap;
113 int ret;
114
115 if (!(msg_type & g_loader_log_msgs)) {
116 return;
117 }
118
119 va_start(ap, format);
120 ret = vsnprintf(msg, sizeof(msg), format, ap);
121 if ((ret >= (int) sizeof(msg)) || ret < 0) {
122 msg[sizeof(msg)-1] = '\0';
123 }
124 va_end(ap);
125
Ian Elliott225188f2015-02-17 10:33:47 -0700126#if defined(WIN32)
Jon Ashburnee33ae72015-06-30 14:46:22 -0700127 OutputDebugString(msg);
128#endif
129 fputs(msg, stderr);
130 fputc('\n', stderr);
131}
132
133#if defined(WIN32)
134/**
135* Find the list of registry files (names within a key) in key "location".
136*
137* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
138* for a list or name/values which are added to a returned list (function return value).
139* The DWORD values within the key must be 0 or they are skipped.
140* Function return is a string with a ';' seperated list of filenames.
141* Function return is NULL if no valid name/value pairs are found in the key,
142* or the key is not found.
143*
144* \returns
145* A string list of filenames as pointer.
146* When done using the returned string list, pointer should be freed.
147*/
148static char *loader_get_registry_files(const char *location)
149{
150 LONG rtn_value;
151 HKEY hive, key;
152 DWORD access_flags = KEY_QUERY_VALUE;
153 char name[2048];
154 char *out = NULL;
155
156 hive = DEFAULT_VK_REGISTRY_HIVE;
157 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
158 if (rtn_value != ERROR_SUCCESS) {
159 // We didn't find the key. Try the 32-bit hive (where we've seen the
160 // key end up on some people's systems):
161 access_flags |= KEY_WOW64_32KEY;
162 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
163 if (rtn_value != ERROR_SUCCESS) {
164 // We still couldn't find the key, so give up:
165 return NULL;
166 }
167 }
168
169 DWORD idx = 0;
170 DWORD name_size = sizeof(name);
171 DWORD value;
172 DWORD total_size = 4096;
173 DWORD value_size = sizeof(value);
174 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
175 if (value_size == sizeof(value) && value == 0) {
176 if (out == NULL) {
177 out = malloc(total_size);
178 out[0] = '\0';
179 }
180 else if (strlen(out) + name_size + 1 > total_size) {
181 out = realloc(out, total_size * 2);
182 total_size *= 2;
183 }
184 if (out == NULL) {
185 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
186 return NULL;
187 }
188 if (strlen(out) == 0)
189 snprintf(out, name_size + 1, "%s", name);
190 else
191 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name);
192 }
193 }
194 return out;
195}
196
Ian Elliott76005132015-03-31 15:32:41 -0600197char *loader_get_registry_string(const HKEY hive,
198 const LPCTSTR sub_key,
199 const char *value)
200{
201 DWORD access_flags = KEY_QUERY_VALUE;
202 DWORD value_type;
203 HKEY key;
Jon Ashburnee33ae72015-06-30 14:46:22 -0700204 LONG rtn_value;
Ian Elliott76005132015-03-31 15:32:41 -0600205 char *rtn_str = NULL;
Tony Barboura938abb2015-04-22 11:36:22 -0600206 DWORD rtn_len = 0;
Ian Elliott76005132015-03-31 15:32:41 -0600207 size_t allocated_len = 0;
208
209 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
210 if (rtn_value != ERROR_SUCCESS) {
211 // We didn't find the key. Try the 32-bit hive (where we've seen the
212 // key end up on some people's systems):
213 access_flags |= KEY_WOW64_32KEY;
214 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
215 if (rtn_value != ERROR_SUCCESS) {
216 // We still couldn't find the key, so give up:
217 return NULL;
218 }
219 }
220
221 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliott464711a2015-04-28 15:57:32 -0600222 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott76005132015-03-31 15:32:41 -0600223 if (rtn_value == ERROR_SUCCESS) {
224 // If we get to here, we found the key, and need to allocate memory
225 // large enough for rtn_str, and query again:
226 allocated_len = rtn_len + 4;
227 rtn_str = malloc(allocated_len);
228 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliott464711a2015-04-28 15:57:32 -0600229 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott76005132015-03-31 15:32:41 -0600230 if (rtn_value == ERROR_SUCCESS) {
231 // We added 4 extra bytes to rtn_str, so that we can ensure that
232 // the string is NULL-terminated (albeit, in a brute-force manner):
233 rtn_str[allocated_len-1] = '\0';
234 } else {
235 // This should never occur, but in case it does, clean up:
236 free(rtn_str);
237 rtn_str = NULL;
238 }
239 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
240
241 // Close the registry key that was opened:
242 RegCloseKey(key);
243
244 return rtn_str;
245}
246
247
Ian Elliott225188f2015-02-17 10:33:47 -0700248// For ICD developers, look in the registry, and look for an environment
249// variable for a path(s) where to find the ICD(s):
250static char *loader_get_registry_and_env(const char *env_var,
251 const char *registry_value)
252{
253 char *env_str = getenv(env_var);
254 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott76005132015-03-31 15:32:41 -0600255 char *registry_str = NULL;
Tony Barboura938abb2015-04-22 11:36:22 -0600256 size_t registry_len = 0;
Ian Elliott225188f2015-02-17 10:33:47 -0700257 char *rtn_str = NULL;
258 size_t rtn_len;
259
Ian Elliott76005132015-03-31 15:32:41 -0600260 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott10ec9622015-04-09 18:07:15 -0600261 "Software\\Vulkan",
Ian Elliott76005132015-03-31 15:32:41 -0600262 registry_value);
Ian Elliott464711a2015-04-28 15:57:32 -0600263 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott225188f2015-02-17 10:33:47 -0700264
265 rtn_len = env_len + registry_len + 1;
266 if (rtn_len <= 2) {
267 // We found neither the desired registry value, nor the environment
268 // variable; return NULL:
269 return NULL;
270 } else {
271 // We found something, and so we need to allocate memory for the string
272 // to return:
273 rtn_str = malloc(rtn_len);
274 }
275
Ian Elliott76005132015-03-31 15:32:41 -0600276 if (registry_len == 0) {
Ian Elliott225188f2015-02-17 10:33:47 -0700277 // We didn't find the desired registry value, and so we must have found
278 // only the environment variable:
279 _snprintf(rtn_str, rtn_len, "%s", env_str);
280 } else if (env_str != NULL) {
281 // We found both the desired registry value and the environment
282 // variable, so concatenate them both:
283 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
284 } else {
285 // We must have only found the desired registry value:
286 _snprintf(rtn_str, rtn_len, "%s", registry_str);
287 }
288
Ian Elliott7518ecd2015-04-03 13:13:01 -0600289 if (registry_str) {
290 free(registry_str);
291 }
Ian Elliott225188f2015-02-17 10:33:47 -0700292
293 return(rtn_str);
294}
295#endif // WIN32
296
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600297bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
298{
299 return memcmp(op1, op2, sizeof(VkExtensionProperties)) == 0 ? true : false;
300}
301
302/*
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600303 * Search the given ext_list for an extension
304 * matching the given vk_ext_prop
305 */
306bool has_vk_extension_property(
307 const VkExtensionProperties *vk_ext_prop,
308 const struct loader_extension_list *ext_list)
309{
310 for (uint32_t i = 0; i < ext_list->count; i++) {
311 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
312 return true;
313 }
314 return false;
315}
316
317/*
318 * Search the given ext_list for an extension
319 * matching the given vk_ext_prop
320 */
321static struct loader_extension_property *get_extension_property_from_vkext(
322 const VkExtensionProperties *vk_ext_prop,
323 const struct loader_extension_list *ext_list)
324{
325 for (uint32_t i = 0; i < ext_list->count; i++) {
Courtney Goeltzenleuchter296bf842015-06-25 16:26:55 -0600326 const VkExtensionProperties *item = &ext_list->list[i].info;
327 if (compare_vk_extension_properties(item, vk_ext_prop))
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600328 return &ext_list->list[i];
329 }
330 return NULL;
331}
332
Jon Ashburn60699262015-06-10 16:11:42 -0600333static void loader_get_global_extensions(
Tony Barbour426b9052015-06-24 16:06:58 -0600334 const PFN_vkGetGlobalExtensionCount fp_get_count,
335 const PFN_vkGetGlobalExtensionProperties fp_get_props,
Jon Ashburn60699262015-06-10 16:11:42 -0600336 const PFN_vkGPA get_proc_addr,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600337 const char *lib_name,
Jon Ashburn60699262015-06-10 16:11:42 -0600338 const loader_platform_dl_handle lib_handle,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600339 const enum extension_origin origin,
340 struct loader_extension_list *ext_list)
341{
342 uint32_t i, count;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600343 struct loader_extension_property ext_props;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600344 VkResult res;
Jon Ashburn60699262015-06-10 16:11:42 -0600345 PFN_vkGPA ext_get_proc_addr;
346 PFN_vkGetInstanceProcAddr get_instance_proc_addr;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600347
Tony Barbour426b9052015-06-24 16:06:58 -0600348 res = fp_get_count(&count);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600349 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600350 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from ICD");
Jon Ashburneb2728b2015-04-10 14:33:07 -0600351 return;
352 }
Jon Ashburn60699262015-06-10 16:11:42 -0600353
354 if (get_proc_addr == NULL)
355 get_instance_proc_addr = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Tony Barbour426b9052015-06-24 16:06:58 -0600356
Jon Ashburneb2728b2015-04-10 14:33:07 -0600357 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -0600358 memset(&ext_props, 0, sizeof(ext_props));
Tony Barbour426b9052015-06-24 16:06:58 -0600359 res = fp_get_props(i, &ext_props.info);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600360 if (res == VK_SUCCESS) {
Jon Ashburn60699262015-06-10 16:11:42 -0600361 //TODO eventually get this from the layer config file
362 if (get_proc_addr == NULL) {
363 char funcStr[MAX_EXTENSION_NAME_SIZE+1];
364 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetInstanceProcAddr", ext_props.info.name);
365
366 if ((ext_get_proc_addr = (PFN_vkGPA) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
367 ext_get_proc_addr = get_instance_proc_addr;
368 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600369 ext_props.origin = origin;
370 ext_props.lib_name = lib_name;
Courtney Goeltzenleuchter296bf842015-06-25 16:26:55 -0600371 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
372 "Global Extension: %s: %s", ext_props.info.name, ext_props.info.description);
Jon Ashburn60699262015-06-10 16:11:42 -0600373 ext_props.get_proc_addr = (get_proc_addr == NULL) ? ext_get_proc_addr : get_proc_addr;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600374 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600375 }
Jon Ashburneb2728b2015-04-10 14:33:07 -0600376 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600377
Jon Ashburneb2728b2015-04-10 14:33:07 -0600378 return;
379}
380
Jon Ashburn60699262015-06-10 16:11:42 -0600381static void loader_get_physical_device_layer_extensions(
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600382 struct loader_instance *ptr_instance,
383 VkPhysicalDevice physical_device,
Jon Ashburn68a63922015-07-02 09:40:15 -0600384 const struct loader_layer_properties *layer_props,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600385 struct loader_extension_list *ext_list)
386{
387 uint32_t i, count;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600388 VkResult res;
389 loader_platform_dl_handle lib_handle;
Tony Barbour426b9052015-06-24 16:06:58 -0600390 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props;
391 PFN_vkGetPhysicalDeviceExtensionCount get_phys_dev_ext_count;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600392 struct loader_extension_property ext_props;
Jon Ashburn60699262015-06-10 16:11:42 -0600393 PFN_vkGPA ext_get_proc_addr;
394 PFN_vkGetDeviceProcAddr get_device_proc_addr;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600395
Jon Ashburn68a63922015-07-02 09:40:15 -0600396 if (layer_props->device_extension_list.count == 0) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600397 return;
398 }
399
400 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
Jon Ashburn68a63922015-07-02 09:40:15 -0600401 ext_props.lib_name = layer_props->lib_info.lib_name;
Jon Ashburnd5df54d2015-05-28 19:16:58 -0600402 char funcStr[MAX_EXTENSION_NAME_SIZE+1]; // add one character for 0 termination
Jon Ashburn60699262015-06-10 16:11:42 -0600403
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600404 lib_handle = loader_add_layer_lib("device", &ext_props);
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -0600405
Tony Barbour426b9052015-06-24 16:06:58 -0600406 get_phys_dev_ext_props = (PFN_vkGetPhysicalDeviceExtensionProperties) loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties");
407 get_phys_dev_ext_count = (PFN_vkGetPhysicalDeviceExtensionCount) loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionCount");
Jon Ashburn60699262015-06-10 16:11:42 -0600408 get_device_proc_addr = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Tony Barbour426b9052015-06-24 16:06:58 -0600409 if (get_phys_dev_ext_count) {
410 res = get_phys_dev_ext_count(physical_device, &count);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600411 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600412 for (i = 0; i < count; i++) {
413 memset(&ext_props, 0, sizeof(ext_props));
Tony Barbour426b9052015-06-24 16:06:58 -0600414 res = get_phys_dev_ext_props(physical_device, i, &ext_props.info);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600415 if (res == VK_SUCCESS && (ext_props.info.sType == VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES)) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600416 ext_props.origin = VK_EXTENSION_ORIGIN_LAYER;
Jon Ashburn60699262015-06-10 16:11:42 -0600417 //TODO eventually get this from the layer config file
418 snprintf(funcStr, MAX_EXTENSION_NAME_SIZE, "%sGetDeviceProcAddr", ext_props.info.name);
419
420 if ((ext_get_proc_addr = (PFN_vkGPA) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
421 ext_get_proc_addr = get_device_proc_addr;
422 ext_props.get_proc_addr = ext_get_proc_addr;
Jon Ashburn68a63922015-07-02 09:40:15 -0600423 ext_props.lib_name = layer_props->lib_info.lib_name;
Courtney Goeltzenleuchter296bf842015-06-25 16:26:55 -0600424 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
425 "PhysicalDevice Extension: %s: %s", ext_props.info.name, ext_props.info.description);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600426 loader_add_to_ext_list(ext_list, 1, &ext_props);
427 }
428 }
429 } else {
430 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
431 }
432 }
433
434 loader_remove_layer_lib(ptr_instance, &ext_props);
435 return;
436}
437
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600438static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburneb2728b2015-04-10 14:33:07 -0600439{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600440 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
441 ext_info->list = malloc(ext_info->capacity);
442 if (ext_info->list == NULL) {
443 return false;
444 }
445 memset(ext_info->list, 0, ext_info->capacity);
446 ext_info->count = 0;
447 return true;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600448}
449
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600450void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburneb2728b2015-04-10 14:33:07 -0600451{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600452 free(ext_info->list);
453 ext_info->count = 0;
454 ext_info->capacity = 0;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600455}
Jon Ashburneb2728b2015-04-10 14:33:07 -0600456
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600457static void loader_add_vk_ext_to_ext_list(
458 struct loader_extension_list *ext_list,
459 uint32_t prop_list_count,
460 const VkExtensionProperties *props,
461 const struct loader_extension_list *search_list)
Jon Ashburneb2728b2015-04-10 14:33:07 -0600462{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600463 struct loader_extension_property *ext_prop;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600464
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600465 for (uint32_t i = 0; i < prop_list_count; i++) {
Courtney Goeltzenleuchter296bf842015-06-25 16:26:55 -0600466 const VkExtensionProperties *search_target = &props[i];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600467 // look for duplicates
Courtney Goeltzenleuchter296bf842015-06-25 16:26:55 -0600468 if (has_vk_extension_property(search_target, ext_list)) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600469 continue;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600470 }
471
Courtney Goeltzenleuchter296bf842015-06-25 16:26:55 -0600472 ext_prop = get_extension_property_from_vkext(search_target, search_list);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600473 if (!ext_prop) {
Courtney Goeltzenleuchter296bf842015-06-25 16:26:55 -0600474 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", search_target->name);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600475 continue;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600476 }
477
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600478 loader_add_to_ext_list(ext_list, 1, ext_prop);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600479 }
480}
481
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600482/*
483 * Append non-duplicate extension properties defined in prop_list
484 * to the given ext_info list
485 */
486void loader_add_to_ext_list(
487 struct loader_extension_list *ext_list,
488 uint32_t prop_list_count,
489 const struct loader_extension_property *props)
490{
491 uint32_t i;
492 struct loader_extension_property *cur_ext;
493
494 if (ext_list->list == NULL || ext_list->capacity == 0) {
495 loader_init_ext_list(ext_list);
496 }
497
498 if (ext_list->list == NULL)
499 return;
500
501 for (i = 0; i < prop_list_count; i++) {
502 cur_ext = (struct loader_extension_property *) &props[i];
503
504 // look for duplicates
505 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
506 continue;
507 }
508
509 // add to list at end
510 // check for enough capacity
511 if (ext_list->count * sizeof(struct loader_extension_property)
512 >= ext_list->capacity) {
513 // double capacity
514 ext_list->capacity *= 2;
515 ext_list->list = realloc(ext_list->list, ext_list->capacity);
516 }
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -0600517
518 /*
519 * Check if any extensions already on the list come from the same
Jon Ashburn60699262015-06-10 16:11:42 -0600520 * library and use the same Get*ProcAddr. If so, link this
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -0600521 * extension to the previous as an alias. That way when we activate
522 * extensions we only activiate the associated layer once no
523 * matter how many extensions are used.
524 */
525 for (uint32_t j = 0; j < ext_list->count; j++) {
526 struct loader_extension_property *active_property = &ext_list->list[j];
527 if (cur_ext->lib_name &&
528 cur_ext->origin == VK_EXTENSION_ORIGIN_LAYER &&
529 active_property->origin == VK_EXTENSION_ORIGIN_LAYER &&
530 strcmp(cur_ext->lib_name, active_property->lib_name) == 0 &&
Jon Ashburn60699262015-06-10 16:11:42 -0600531 (cur_ext->get_proc_addr == active_property->get_proc_addr) &&
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -0600532 active_property->alias == NULL) {
533 cur_ext->alias = active_property;
534 break;
535 }
536 }
537
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600538 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
539 ext_list->count++;
540 }
541}
542
543/*
544 * Search the search_list for any extension with
545 * a name that matches the given ext_name.
546 * Add all matching extensions to the found_list
547 * Do not add if found VkExtensionProperties is already
548 * on the found_list
549 */
550static void loader_search_ext_list_for_name(
551 const char *ext_name,
552 const struct loader_extension_list *search_list,
553 struct loader_extension_list *found_list)
554{
555 for (uint32_t i = 0; i < search_list->count; i++) {
556 struct loader_extension_property *ext_prop = &search_list->list[i];
Courtney Goeltzenleuchterd8ec21d2015-06-09 09:14:48 -0600557 if (ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER &&
558 0 == strcmp(ext_prop->info.name, ext_name)) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600559 /* Found an extension with the same name, add to found_list */
560 loader_add_to_ext_list(found_list, 1, &search_list->list[i]);
561 }
562 }
563}
564
565bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburn42e41032015-04-14 09:15:32 -0600566{
567 uint32_t i;
568
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600569 for (i = 0; i < loader.global_extensions.count; i++) {
570 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburn42e41032015-04-14 09:15:32 -0600571 return true;
572 }
573 return false;
574}
575
Jon Ashburnfce93d92015-05-12 17:26:48 -0600576void loader_coalesce_extensions(void)
Jon Ashburneb2728b2015-04-10 14:33:07 -0600577{
578 uint32_t i;
579 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
580
581 // traverse scanned icd list adding non-duplicate extensions to the list
582 while (icd_list != NULL) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600583 loader_add_to_ext_list(&loader.global_extensions,
584 icd_list->global_extension_list.count,
585 icd_list->global_extension_list.list);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600586 icd_list = icd_list->next;
587 };
588
589 //Traverse layers list adding non-duplicate extensions to the list
Jon Ashburn68a63922015-07-02 09:40:15 -0600590 for (i = 0; i < loader.scanned_layers.count; i++) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600591 loader_add_to_ext_list(&loader.global_extensions,
Jon Ashburn68a63922015-07-02 09:40:15 -0600592 loader.scanned_layers.list[i].instance_extension_list.count,
593 loader.scanned_layers.list[i].instance_extension_list.list);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600594 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600595
596 // Traverse loader's extensions, adding non-duplicate extensions to the list
597 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600598}
599
Jon Ashburncb5a5ac2015-06-10 10:06:06 -0600600static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
601 struct loader_device **found_dev)
602{
603 *found_dev = NULL;
604 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
605 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
606 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
607 if (dev->device == device) {
608 *found_dev = dev;
609 return icd;
610 }
611 }
612 }
613 return NULL;
614}
615
616static void loader_destroy_logical_device(struct loader_device *dev)
617{
618 free(dev->app_extension_props);
619 if (dev->enabled_device_extensions.count)
620 loader_destroy_ext_list(&dev->enabled_device_extensions);
621 if (dev->activated_layer_list.count)
622 loader_destroy_ext_list(&dev->activated_layer_list);
623 free(dev);
624}
625
626static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
627{
628 struct loader_device *new_dev;
629
630 new_dev = malloc(sizeof(struct loader_device));
631 if (!new_dev) {
632 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
633 return NULL;
634 }
635
636 memset(new_dev, 0, sizeof(struct loader_device));
637
638 new_dev->next = *device_list;
639 new_dev->device = dev;
640 *device_list = new_dev;
641 return new_dev;
642}
643
644void loader_remove_logical_device(VkDevice device)
645{
646 struct loader_device *found_dev, *dev, *prev_dev;
647 struct loader_icd *icd;
648 icd = loader_get_icd_and_device(device, &found_dev);
649
650 if (!icd || !found_dev)
651 return;
652
653 prev_dev = NULL;
654 dev = icd->logical_device_list;
655 while (dev && dev != found_dev) {
656 prev_dev = dev;
657 dev = dev->next;
658 }
659
660 if (prev_dev)
661 prev_dev->next = found_dev->next;
662 else
663 icd->logical_device_list = found_dev->next;
664 loader_destroy_logical_device(found_dev);
665}
666
667
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600668static void loader_icd_destroy(
669 struct loader_instance *ptr_inst,
670 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800671{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600672 ptr_inst->total_icd_count--;
Jon Ashburnd5df54d2015-05-28 19:16:58 -0600673 free(icd->gpus);
Courtney Goeltzenleuchter6b70e362015-06-14 19:57:15 -0600674 for (struct loader_device *dev = icd->logical_device_list; dev; ) {
675 struct loader_device *next_dev = dev->next;
Jon Ashburncb5a5ac2015-06-10 10:06:06 -0600676 loader_destroy_logical_device(dev);
Courtney Goeltzenleuchter6b70e362015-06-14 19:57:15 -0600677 dev = next_dev;
678 }
Jon Ashburncb5a5ac2015-06-10 10:06:06 -0600679
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800680 free(icd);
681}
682
Jon Ashburneb2728b2015-04-10 14:33:07 -0600683static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800684{
685 struct loader_icd *icd;
686
687 icd = malloc(sizeof(*icd));
688 if (!icd)
689 return NULL;
690
Courtney Goeltzenleuchter6f928162014-10-28 10:29:27 -0600691 memset(icd, 0, sizeof(*icd));
692
Jon Ashburn14275da2015-01-28 11:01:35 -0700693 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800694
695 return icd;
696}
697
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600698static struct loader_icd *loader_icd_add(
699 struct loader_instance *ptr_inst,
700 const struct loader_scanned_icds *scanned)
Chia-I Wu894a1172014-08-04 11:18:20 +0800701{
702 struct loader_icd *icd;
703
Jon Ashburn14275da2015-01-28 11:01:35 -0700704 icd = loader_icd_create(scanned);
Chia-I Wu894a1172014-08-04 11:18:20 +0800705 if (!icd)
706 return NULL;
707
Chia-I Wu894a1172014-08-04 11:18:20 +0800708 /* prepend to the list */
Jon Ashburn3336df82015-01-29 15:45:51 -0700709 icd->next = ptr_inst->icds;
710 ptr_inst->icds = icd;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600711 ptr_inst->total_icd_count++;
Chia-I Wu894a1172014-08-04 11:18:20 +0800712
713 return icd;
714}
715
Jon Ashburn14275da2015-01-28 11:01:35 -0700716static void loader_scanned_icd_add(const char *filename)
717{
Ian Elliott81ac44c2015-01-13 17:52:38 -0700718 loader_platform_dl_handle handle;
Jon Ashburn0dd356d2015-05-14 12:43:38 -0600719 void *fp_create_inst;
Tony Barbour426b9052015-06-24 16:06:58 -0600720 void *fp_get_global_ext_props;
721 void *fp_get_global_ext_count;
722 void *fp_get_device_ext_props;
723 void *fp_get_device_ext_count;
Jon Ashburn60699262015-06-10 16:11:42 -0600724 PFN_vkGPA fp_get_proc_addr;
Jon Ashburn14275da2015-01-28 11:01:35 -0700725 struct loader_scanned_icds *new_node;
726
Ian Elliott81ac44c2015-01-13 17:52:38 -0700727 // Used to call: dlopen(filename, RTLD_LAZY);
728 handle = loader_platform_open_library(filename);
Jon Ashburn14275da2015-01-28 11:01:35 -0700729 if (!handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600730 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn14275da2015-01-28 11:01:35 -0700731 return;
732 }
733
734#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600735 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn14275da2015-01-28 11:01:35 -0700736 if (!func_ptr) { \
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600737 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn14275da2015-01-28 11:01:35 -0700738 return; \
739 } \
740} while (0)
741
Jon Ashburn3336df82015-01-29 15:45:51 -0700742 LOOKUP(fp_create_inst, CreateInstance);
Tony Barbour426b9052015-06-24 16:06:58 -0600743 LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
744 LOOKUP(fp_get_global_ext_count, GetGlobalExtensionCount);
745 LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
746 LOOKUP(fp_get_device_ext_count, GetPhysicalDeviceExtensionCount);
Jon Ashburn60699262015-06-10 16:11:42 -0600747 LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
Jon Ashburn14275da2015-01-28 11:01:35 -0700748#undef LOOKUP
749
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600750 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
751 + strlen(filename) + 1);
Jon Ashburn14275da2015-01-28 11:01:35 -0700752 if (!new_node) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600753 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn14275da2015-01-28 11:01:35 -0700754 return;
755 }
756
757 new_node->handle = handle;
Jon Ashburn3336df82015-01-29 15:45:51 -0700758 new_node->CreateInstance = fp_create_inst;
Tony Barbour426b9052015-06-24 16:06:58 -0600759 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
760 new_node->GetGlobalExtensionCount = fp_get_global_ext_count;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600761 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600762 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn14275da2015-01-28 11:01:35 -0700763 new_node->next = loader.scanned_icd_list;
Jon Ashburn14275da2015-01-28 11:01:35 -0700764
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600765 new_node->lib_name = (char *) (new_node + 1);
766 if (!new_node->lib_name) {
767 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
768 return;
769 }
770 strcpy(new_node->lib_name, filename);
771
Jon Ashburneb2728b2015-04-10 14:33:07 -0600772 loader.scanned_icd_list = new_node;
773
Jon Ashburn60699262015-06-10 16:11:42 -0600774 loader_get_global_extensions(
Tony Barbour426b9052015-06-24 16:06:58 -0600775 (PFN_vkGetGlobalExtensionCount) fp_get_global_ext_count,
776 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
Jon Ashburn60699262015-06-10 16:11:42 -0600777 fp_get_proc_addr,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600778 new_node->lib_name,
Jon Ashburn60699262015-06-10 16:11:42 -0600779 handle,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600780 VK_EXTENSION_ORIGIN_ICD,
781 &new_node->global_extension_list);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600782}
Ian Elliott81ac44c2015-01-13 17:52:38 -0700783
Jon Ashburn0dd356d2015-05-14 12:43:38 -0600784static void loader_icd_init_entrys(struct loader_icd *icd,
785 struct loader_scanned_icds *scanned_icds)
786{
787 /* initialize entrypoint function pointers */
788
789 #define LOOKUP(func) do { \
790 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
791 if (!icd->func) { \
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600792 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn0dd356d2015-05-14 12:43:38 -0600793 return; \
794 } \
795 } while (0)
796
Jon Ashburn1245cec2015-05-18 13:20:15 -0600797 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
798 LOOKUP(GetDeviceProcAddr);
Jon Ashburn0dd356d2015-05-14 12:43:38 -0600799 LOOKUP(DestroyInstance);
800 LOOKUP(EnumeratePhysicalDevices);
Chris Forbesd7576302015-06-21 22:55:02 +1200801 LOOKUP(GetPhysicalDeviceFeatures);
802 LOOKUP(GetPhysicalDeviceFormatInfo);
803 LOOKUP(GetPhysicalDeviceLimits);
Jon Ashburn0dd356d2015-05-14 12:43:38 -0600804 LOOKUP(CreateDevice);
Tony Barbour426b9052015-06-24 16:06:58 -0600805 LOOKUP(GetPhysicalDeviceProperties);
806 LOOKUP(GetPhysicalDeviceMemoryProperties);
807 LOOKUP(GetPhysicalDevicePerformance);
808 LOOKUP(GetPhysicalDeviceQueueCount);
809 LOOKUP(GetPhysicalDeviceQueueProperties);
810 LOOKUP(GetPhysicalDeviceExtensionProperties);
811 LOOKUP(GetPhysicalDeviceExtensionCount);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600812 LOOKUP(DbgCreateMsgCallback);
813 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn0dd356d2015-05-14 12:43:38 -0600814#undef LOOKUP
815
816 return;
817}
818
Courtney Goeltzenleuchter8b253f92015-06-08 15:11:18 -0600819static void loader_debug_init(void)
820{
821 const char *env;
822
823 if (g_loader_debug > 0)
824 return;
825
826 g_loader_debug = 0;
827
828 /* parse comma-separated debug options */
829 env = getenv("LOADER_DEBUG");
830 while (env) {
831 const char *p = strchr(env, ',');
832 size_t len;
833
834 if (p)
835 len = p - env;
836 else
837 len = strlen(env);
838
839 if (len > 0) {
840 if (strncmp(env, "warn", len) == 0) {
841 g_loader_debug |= LOADER_WARN_BIT;
842 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
843 } else if (strncmp(env, "info", len) == 0) {
844 g_loader_debug |= LOADER_INFO_BIT;
845 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
846 } else if (strncmp(env, "perf", len) == 0) {
847 g_loader_debug |= LOADER_PERF_BIT;
848 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
849 } else if (strncmp(env, "error", len) == 0) {
850 g_loader_debug |= LOADER_ERROR_BIT;
851 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
852 } else if (strncmp(env, "debug", len) == 0) {
853 g_loader_debug |= LOADER_DEBUG_BIT;
854 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
855 }
856 }
857
858 if (!p)
859 break;
860
861 env = p + 1;
862 }
863}
864
Jon Ashburnffd5d672015-06-29 11:25:34 -0600865struct loader_manifest_files {
866 uint32_t count;
867 char **filename_list;
868};
869
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600870/**
Jon Ashburnffd5d672015-06-29 11:25:34 -0600871 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -0600872 *
873 * \returns
Jon Ashburnffd5d672015-06-29 11:25:34 -0600874 * A pointer to first char in the next path.
875 * The next path (or NULL) in the list is returned in next_path.
876 * Note: input string is modified in some cases. PASS IN A COPY!
877 */
878//TODO registry keys
879static char *loader_get_next_path(char *path)
880{
881 uint32_t len;
882 char *next;
883
884 if (path == NULL)
885 return NULL;
886 next = strchr(path, PATH_SEPERATOR);
887 if (next == NULL) {
888 len = (uint32_t) strlen(path);
889 next = path + len;
890 }
891 else {
892 *next = '\0';
893 next++;
894 }
895
896 return next;
897}
898
899/**
900 * Given a filename (file) and a list of paths (dir), try to find an existing
901 * file in the paths. If filename already is a path then no
902 * searching in the given paths.
903 *
904 * \returns
905 * A string in out_fullpath of either the full path or file.
906 * Side effect is that dir string maybe modified.
907 */
908static void loader_get_fullpath(const char *file,
909 char *dir,
910 size_t out_size,
911 char *out_fullpath)
912{
913 char *next_dir;
914 if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
915 //find file exists with prepending given path
916 while (*dir) {
917 next_dir = loader_get_next_path(dir);
918 snprintf(out_fullpath, out_size, "%s%c%s",
919 dir, DIRECTORY_SYMBOL, file);
920 if (loader_platform_file_exists(out_fullpath)) {
921 return;
922 }
923 dir = next_dir;
924 }
925 }
926 snprintf(out_fullpath, out_size, "%s", file);
927}
928
929/**
930 * Read a JSON file into a buffer.
931 *
932 * \returns
933 * A pointer to a cJSON object representing the JSON parse tree.
934 * This returned buffer should be freed by caller.
935 */
936static cJSON *loader_get_json(const char *filename)
937{
938 FILE *file;
939 char *json_buf;
940 cJSON *json;
941 uint64_t len;
942 file = fopen(filename,"rb");
943 fseek(file, 0, SEEK_END);
944 len = ftell(file);
945 fseek(file, 0, SEEK_SET);
946 json_buf = (char*) alloca(len+1);
947 if (json_buf == NULL) {
948 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
949 fclose(file);
950 return NULL;
951 }
952 if (fread(json_buf, sizeof(char), len, file) != len) {
953 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
954 fclose(file);
955 return NULL;
956 }
957 fclose(file);
958 json_buf[len] = '\0';
959
960 //parse text from file
961 json = cJSON_Parse(json_buf);
962 if (json == NULL)
963 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
964 return json;
965}
966
967/**
968 * Find the Vulkan library manifest files.
969 *
970 * This function scans the location or env_override directories/files
971 * for a list of JSON manifest files. If env_override is non-NULL
972 * and has a valid value. Then the location is ignored. Otherwise
973 * location is used to look for manifest files. The location
974 * is interpreted as Registry path on Windows and a directory path(s)
975 * on Linux.
976 *
977 * \returns
978 * A string list of manifest files to be opened in out_files param.
979 * List has a pointer to string for each manifest filename.
980 * When done using the list in out_files, pointers should be freed.
Jon Ashburnee33ae72015-06-30 14:46:22 -0700981 * Location or override string lists can be either files or directories as follows:
982 * | location | override
983 * --------------------------------
984 * Win ICD | files | files
985 * Win Layer | files | dirs
986 * Linux ICD | dirs | files
987 * Linux Layer| dirs | dirs
Jon Ashburnffd5d672015-06-29 11:25:34 -0600988 */
989static void loader_get_manifest_files(const char *env_override,
Jon Ashburnee33ae72015-06-30 14:46:22 -0700990 bool is_layer,
991 const char *location,
992 struct loader_manifest_files *out_files)
Jon Ashburnffd5d672015-06-29 11:25:34 -0600993{
994 char *override = NULL;
995 char *loc;
996 char *file, *next_file, *name;
997 size_t alloced_count = 64;
998 char full_path[2048];
999 DIR *sysdir = NULL;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001000 bool list_is_dirs = false;
Jon Ashburnffd5d672015-06-29 11:25:34 -06001001 struct dirent *dent;
1002
1003 out_files->count = 0;
1004 out_files->filename_list = NULL;
1005
Jon Ashburnffd5d672015-06-29 11:25:34 -06001006 if (env_override != NULL && (override = getenv(env_override))) {
1007#if defined(__linux__)
1008 if (geteuid() != getuid()) {
Jon Ashburnee33ae72015-06-30 14:46:22 -07001009 /* Don't allow setuid apps to use the env var: */
Jon Ashburnffd5d672015-06-29 11:25:34 -06001010 override = NULL;
1011 }
1012#endif
1013 }
1014
1015 if (location == NULL) {
1016 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
Jon Ashburnee33ae72015-06-30 14:46:22 -07001017 "Can't get manifest files with NULL location, env_override=%s",
1018 env_override);
Jon Ashburnffd5d672015-06-29 11:25:34 -06001019 return;
1020 }
1021
Jon Ashburnee33ae72015-06-30 14:46:22 -07001022#if defined(__linux__)
1023 list_is_dirs = (override == NULL || is_layer) ? true : false;
1024#else //WIN32
1025 list_is_dirs = (is_layer && override != NULL) ? true : false;
1026#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001027 // Make a copy of the input we are using so it is not modified
Jon Ashburnee33ae72015-06-30 14:46:22 -07001028 // Also handle getting the location(s) from registry on Windows
1029 if (override == NULL) {
1030#if defined (_WIN32)
1031 loc = loader_get_registry_files(location);
1032 if (loc == NULL) {
1033 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1034 return;
1035 }
1036#else
Jon Ashburnffd5d672015-06-29 11:25:34 -06001037 loc = alloca(strlen(location) + 1);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001038 if (loc == NULL) {
1039 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1040 return;
1041 }
1042 strcpy(loc, location);
1043#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001044 }
Jon Ashburnee33ae72015-06-30 14:46:22 -07001045 else {
1046 loc = alloca(strlen(override) + 1);
1047 if (loc == NULL) {
1048 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1049 return;
1050 }
1051 strcpy(loc, override);
1052 }
Jon Ashburnffd5d672015-06-29 11:25:34 -06001053
1054 file = loc;
1055 while (*file) {
1056 next_file = loader_get_next_path(file);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001057 if (list_is_dirs) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001058 sysdir = opendir(file);
1059 name = NULL;
1060 if (sysdir) {
1061 dent = readdir(sysdir);
1062 if (dent == NULL)
1063 break;
1064 name = &(dent->d_name[0]);
1065 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1066 name = full_path;
1067 }
1068 }
1069 else {
Jon Ashburnee33ae72015-06-30 14:46:22 -07001070#if defined(__linux__)
1071 // only Linux has relative paths
Jon Ashburnffd5d672015-06-29 11:25:34 -06001072 char *dir;
1073 // make a copy of location so it isn't modified
1074 dir = alloca(strlen(location) + 1);
1075 if (dir == NULL) {
1076 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1077 return;
1078 }
1079 strcpy(dir, location);
1080
1081 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1082
1083 name = full_path;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001084#else // WIN32
1085 name = file;
1086#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001087 }
1088 while (name) {
1089 /* Look for files ending with ".json" suffix */
1090 uint32_t nlen = (uint32_t) strlen(name);
1091 const char *suf = name + nlen - 5;
1092 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1093 if (out_files->count == 0) {
1094 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1095 }
1096 else if (out_files->count == alloced_count) {
1097 out_files->filename_list = realloc(out_files->filename_list,
1098 alloced_count * sizeof(char *) * 2);
1099 alloced_count *= 2;
1100 }
1101 if (out_files->filename_list == NULL) {
1102 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1103 return;
1104 }
1105 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1106 if (out_files->filename_list[out_files->count] == NULL) {
1107 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1108 return;
1109 }
1110 strcpy(out_files->filename_list[out_files->count], name);
1111 out_files->count++;
Jon Ashburnc5662f62015-07-02 10:08:47 -06001112 } else if (!list_is_dirs) {
1113 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name);
Jon Ashburnffd5d672015-06-29 11:25:34 -06001114 }
Jon Ashburnee33ae72015-06-30 14:46:22 -07001115 if (list_is_dirs) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001116 dent = readdir(sysdir);
1117 if (dent == NULL)
1118 break;
1119 name = &(dent->d_name[0]);
1120 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1121 name = full_path;
1122 }
1123 else {
1124 break;
1125 }
1126 }
1127 if (sysdir)
1128 closedir(sysdir);
1129 file = next_file;
1130 }
1131 return;
1132}
1133
1134/**
1135 * Try to find the Vulkan ICD driver(s).
1136 *
1137 * This function scans the default system loader path(s) or path
1138 * specified by the \c VK_ICD_FILENAMES environment variable in
1139 * order to find loadable VK ICDs manifest files. From these
1140 * manifest files it finds the ICD libraries.
1141 *
1142 * \returns
Jon Ashburn622ca2f2015-06-30 16:44:28 -06001143 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001144 */
Jon Ashburnfce93d92015-05-12 17:26:48 -06001145void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001146{
Jon Ashburnffd5d672015-06-29 11:25:34 -06001147 char *file_str;
1148 struct loader_manifest_files manifest_files;
1149
Jon Ashburnb40f2562015-05-29 13:15:39 -06001150
1151 // convenient place to initialize a mutex
1152 loader_platform_thread_create_mutex(&loader_lock);
1153
Jon Ashburnffd5d672015-06-29 11:25:34 -06001154 // convenient place to initialize logging
Courtney Goeltzenleuchter8b253f92015-06-08 15:11:18 -06001155 loader_debug_init();
1156
Jon Ashburnffd5d672015-06-29 11:25:34 -06001157 // Get a list of manifest files for ICDs
1158 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1159 &manifest_files);
1160 for (uint32_t i = 0; i < manifest_files.count; i++) {
1161 file_str = manifest_files.filename_list[i];
1162 if (file_str == NULL)
1163 continue;
1164
1165 cJSON *json, *icd_json;
1166 json = loader_get_json(file_str);
1167 icd_json = cJSON_GetObjectItem(json, "ICD");
1168 if (icd_json != NULL) {
1169 icd_json = cJSON_GetObjectItem(icd_json, "library_path");
1170 if (icd_json != NULL) {
1171 char *icd_filename = cJSON_PrintUnformatted(icd_json);
1172 char *icd_file = icd_filename;
1173 if (icd_filename != NULL) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001174 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1175 char *dir = def_dir;
1176 // strip off extra quotes
1177 if (icd_filename[strlen(icd_filename) - 1] == '"')
1178 icd_filename[strlen(icd_filename) - 1] = '\0';
1179 if (icd_filename[0] == '"')
1180 icd_filename++;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001181#if defined(__linux__)
1182 char full_path[2048];
Jon Ashburnffd5d672015-06-29 11:25:34 -06001183 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1184 loader_scanned_icd_add(full_path);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001185#else // WIN32
1186 loader_scanned_icd_add(icd_filename);
1187#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001188 free(icd_file);
1189 }
1190 }
1191 else
1192 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1193 }
1194 else
1195 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1196
1197 free(file_str);
1198 cJSON_Delete(json);
1199 }
1200 free(manifest_files.filename_list);
1201
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001202}
1203
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001204
Jon Ashburn68a63922015-07-02 09:40:15 -06001205void loader_layer_scan(void)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001206{
1207 const char *p, *next;
Ian Elliott225188f2015-02-17 10:33:47 -07001208 char *libPaths = NULL;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001209 DIR *curdir;
1210 struct dirent *dent;
Ian Elliott225188f2015-02-17 10:33:47 -07001211 size_t len, i;
Jon Ashburn183dfd02014-10-22 18:13:16 -06001212 char temp_str[1024];
Jon Ashburneb2728b2015-04-10 14:33:07 -06001213 uint32_t count;
Tony Barbour426b9052015-06-24 16:06:58 -06001214 PFN_vkGetGlobalExtensionProperties fp_get_props;
1215 PFN_vkGetGlobalExtensionCount fp_get_count;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001216
Ian Elliott225188f2015-02-17 10:33:47 -07001217#if defined(WIN32)
1218 bool must_free_libPaths;
1219 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
1220 LAYERS_PATH_REGISTRY_VALUE);
1221 if (libPaths != NULL) {
1222 must_free_libPaths = true;
1223 } else {
1224 must_free_libPaths = false;
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06001225 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001226 }
Ian Elliott225188f2015-02-17 10:33:47 -07001227#else // WIN32
1228 if (geteuid() == getuid()) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001229 /* Don't allow setuid apps to use the LAYERS_PATH_ENV env var: */
Courtney Goeltzenleuchter4ee01712015-02-18 20:03:02 -07001230 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott225188f2015-02-17 10:33:47 -07001231 }
1232 if (libPaths == NULL) {
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06001233 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott225188f2015-02-17 10:33:47 -07001234 }
Ian Elliott81ac44c2015-01-13 17:52:38 -07001235#endif // WIN32
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001236
Ian Elliott225188f2015-02-17 10:33:47 -07001237 if (libPaths == NULL) {
1238 // Have no paths to search:
Courtney Goeltzenleuchterbce445a2014-12-01 09:29:42 -07001239 return;
1240 }
Ian Elliott225188f2015-02-17 10:33:47 -07001241 len = strlen(libPaths);
Courtney Goeltzenleuchterbce445a2014-12-01 09:29:42 -07001242 loader.layer_dirs = malloc(len+1);
Ian Elliott225188f2015-02-17 10:33:47 -07001243 if (loader.layer_dirs == NULL) {
Jon Ashburn0dcd6192015-06-04 15:30:58 -06001244 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
1245
Ian Elliott225188f2015-02-17 10:33:47 -07001246 free(libPaths);
Courtney Goeltzenleuchter688c74b2014-12-02 18:12:51 -07001247 return;
Ian Elliott225188f2015-02-17 10:33:47 -07001248 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001249 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott225188f2015-02-17 10:33:47 -07001250 strcpy(loader.layer_dirs, libPaths);
1251#if defined(WIN32)
1252 // Free any allocated memory:
1253 if (must_free_libPaths) {
1254 free(libPaths);
1255 must_free_libPaths = false;
1256 }
1257#endif // WIN32
Courtney Goeltzenleuchterbce445a2014-12-01 09:29:42 -07001258 libPaths = loader.layer_dirs;
1259
Jon Ashburn68a63922015-07-02 09:40:15 -06001260 if (loader.scanned_layers.capacity == 0) {
1261 loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1262 if (loader.scanned_layers.list == NULL) {
1263 //TODO ERR log
1264 return;
1265 }
1266 memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1267 loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001268 }
Jon Ashburn68a63922015-07-02 09:40:15 -06001269 else {
1270 /* cleanup any previously scanned libraries */
1271 //TODO make sure everything is cleaned up properly
1272 for (i = 0; i < loader.scanned_layers.count; i++) {
1273 if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
1274 free(loader.scanned_layers.list[i].lib_info.lib_name);
1275 free(loader.scanned_layers.list[i].name);
1276 loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
1277 loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
1278 loader.scanned_layers.list[i].lib_info.lib_name = NULL;
1279 }
1280 loader.scanned_layers.count = 0;
1281 }
Jon Ashburneb2728b2015-04-10 14:33:07 -06001282 count = 0;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001283
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001284 for (p = libPaths; *p; p = next) {
Jon Ashburneb2728b2015-04-10 14:33:07 -06001285 next = strchr(p, PATH_SEPERATOR);
1286 if (next == NULL) {
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001287 len = (uint32_t) strlen(p);
1288 next = p + len;
Jon Ashburneb2728b2015-04-10 14:33:07 -06001289 }
1290 else {
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001291 len = (uint32_t) (next - p);
1292 *(char *) next = '\0';
1293 next++;
Jon Ashburneb2728b2015-04-10 14:33:07 -06001294 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001295
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001296 curdir = opendir(p);
1297 if (curdir) {
1298 dent = readdir(curdir);
1299 while (dent) {
1300 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
1301 * ending with VK_LIBRARY_SUFFIX
1302 */
1303 if (!strncmp(dent->d_name,
1304 VK_LAYER_LIBRARY_PREFIX,
1305 VK_LAYER_LIBRARY_PREFIX_LEN)) {
1306 uint32_t nlen = (uint32_t) strlen(dent->d_name);
1307 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
1308 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
1309 !strncmp(suf,
1310 VK_LIBRARY_SUFFIX,
1311 VK_LIBRARY_SUFFIX_LEN)) {
1312 loader_platform_dl_handle handle;
1313 snprintf(temp_str, sizeof(temp_str),
Jon Ashburnffd5d672015-06-29 11:25:34 -06001314 "%s%c%s",p, DIRECTORY_SYMBOL, dent->d_name);
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001315 // Used to call: dlopen(temp_str, RTLD_LAZY)
1316 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter5d2abff2015-06-09 09:44:13 -06001317 "Attempt to open library: %s", temp_str);
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001318 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
Courtney Goeltzenleuchter5d2abff2015-06-09 09:44:13 -06001319 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed");
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001320 dent = readdir(curdir);
1321 continue;
1322 }
1323 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter5d2abff2015-06-09 09:44:13 -06001324 "Opened library: %s", temp_str);
Courtney Goeltzenleuchteraa685052015-06-01 14:49:17 -06001325
Jon Ashburn68a63922015-07-02 09:40:15 -06001326 if (count * sizeof(struct loader_layer_properties) >= loader.scanned_layers.capacity) {
1327 loader.scanned_layers.list = realloc(loader.scanned_layers.list,
1328 loader.scanned_layers.capacity * 2);
1329 if (loader.scanned_layers.list == NULL) {
1330 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1331 "realloc failed for scanned layers");
1332 break;
1333 }
1334 loader.scanned_layers.capacity *= 2;
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001335 }
Jon Ashburneb2728b2015-04-10 14:33:07 -06001336
Tony Barbour426b9052015-06-24 16:06:58 -06001337 fp_get_count = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionCount");
1338 fp_get_props = loader_platform_get_proc_address(handle, "vkGetGlobalExtensionProperties");
1339 if (!fp_get_props || !fp_get_count) {
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001340 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbour426b9052015-06-24 16:06:58 -06001341 "Couldn't dlsym vkGetGlobalExtensionCount and/or vkGetGlobalExtensionProperties from library %s",
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001342 temp_str);
1343 dent = readdir(curdir);
1344 loader_platform_close_library(handle);
1345 continue;
1346 }
Jon Ashburneb2728b2015-04-10 14:33:07 -06001347
Jon Ashburn68a63922015-07-02 09:40:15 -06001348 loader.scanned_layers.list[count].lib_info.lib_name =
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001349 malloc(strlen(temp_str) + 1);
Jon Ashburn68a63922015-07-02 09:40:15 -06001350 if (loader.scanned_layers.list[count].lib_info.lib_name == NULL) {
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001351 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "%s ignored: out of memory", temp_str);
1352 break;
1353 }
Jon Ashburneb2728b2015-04-10 14:33:07 -06001354
Jon Ashburn68a63922015-07-02 09:40:15 -06001355 strcpy(loader.scanned_layers.list[count].lib_info.lib_name, temp_str);
Jon Ashburneb2728b2015-04-10 14:33:07 -06001356
Courtney Goeltzenleuchter5d2abff2015-06-09 09:44:13 -06001357 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for %s", temp_str);
Jon Ashburn60699262015-06-10 16:11:42 -06001358 loader_get_global_extensions(
Tony Barbour426b9052015-06-24 16:06:58 -06001359 fp_get_count,
1360 fp_get_props,
Jon Ashburn60699262015-06-10 16:11:42 -06001361 NULL,
Jon Ashburn68a63922015-07-02 09:40:15 -06001362 loader.scanned_layers.list[count].lib_info.lib_name,
Jon Ashburn60699262015-06-10 16:11:42 -06001363 handle,
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001364 VK_EXTENSION_ORIGIN_LAYER,
Jon Ashburn68a63922015-07-02 09:40:15 -06001365 &loader.scanned_layers.list[count].instance_extension_list);
Jon Ashburneb2728b2015-04-10 14:33:07 -06001366
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001367
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001368 count++;
1369 loader_platform_close_library(handle);
1370 }
1371 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001372
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001373 dent = readdir(curdir);
1374 } // while (dir_entry)
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001375 closedir(curdir);
1376 } // if (curdir))
Jon Ashburneb2728b2015-04-10 14:33:07 -06001377 } // for (libpaths)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001378
Jon Ashburn68a63922015-07-02 09:40:15 -06001379 loader.scanned_layers.count = count;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001380}
1381
Jon Ashburnfce93d92015-05-12 17:26:48 -06001382static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1383{
1384 // inst is not wrapped
1385 if (inst == VK_NULL_HANDLE) {
1386 return NULL;
1387 }
1388 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1389 void *addr;
1390
Jon Ashburn4f2575f2015-05-28 16:25:02 -06001391 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1392 return (void *) loader_gpa_instance_internal;
1393
Jon Ashburnfce93d92015-05-12 17:26:48 -06001394 if (disp_table == NULL)
1395 return NULL;
1396
1397 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001398 if (addr) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06001399 return addr;
Jon Ashburne18431b2015-04-13 18:10:06 -06001400 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001401
1402 if (disp_table->GetInstanceProcAddr == NULL) {
1403 return NULL;
1404 }
1405 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburne18431b2015-04-13 18:10:06 -06001406}
1407
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001408struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburnb55278a2014-10-17 15:09:07 -06001409{
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001410
Jon Ashburndc67ef52015-01-29 16:44:24 -07001411 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1412 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1413 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001414 if (icd->gpus[i] == gpu) {
Jon Ashburndc67ef52015-01-29 16:44:24 -07001415 *gpu_index = i;
1416 return icd;
1417 }
1418 }
Jon Ashburnb55278a2014-10-17 15:09:07 -06001419 }
1420 return NULL;
1421}
1422
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001423static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn9a9de1f2015-05-27 13:19:22 -06001424 const char *chain_type,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001425 struct loader_extension_property *ext_prop)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001426{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001427 struct loader_lib_info *new_layer_lib_list, *my_lib;
1428
1429 /* Only loader layer libraries here */
1430 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1431 return NULL;
1432 }
1433
1434 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1435 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1436 /* Have already loaded this library, just increment ref count */
1437 loader.loaded_layer_lib_list[i].ref_count++;
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001438 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001439 "%s Chain: Increment layer reference count for layer library %s",
1440 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001441 return loader.loaded_layer_lib_list[i].lib_handle;
1442 }
1443 }
1444
1445 /* Haven't seen this library so load it */
1446 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1447 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1448 if (!new_layer_lib_list) {
1449 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1450 return NULL;
1451 }
1452
1453 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1454
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001455 /* NOTE: We require that the extension property be immutable */
Jon Ashburn68a63922015-07-02 09:40:15 -06001456 my_lib->lib_name = (char *) ext_prop->lib_name;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001457 my_lib->ref_count = 0;
1458 my_lib->lib_handle = NULL;
1459
1460 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1461 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1462 loader_platform_open_library_error(my_lib->lib_name));
1463 return NULL;
1464 } else {
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001465 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001466 "Chain: %s: Loading layer library %s",
1467 chain_type, ext_prop->lib_name);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001468 }
1469 loader.loaded_layer_lib_count++;
1470 loader.loaded_layer_lib_list = new_layer_lib_list;
1471 my_lib->ref_count++;
1472
1473 return my_lib->lib_handle;
1474}
1475
1476static void loader_remove_layer_lib(
1477 struct loader_instance *inst,
1478 struct loader_extension_property *ext_prop)
1479{
1480 uint32_t idx;
1481 struct loader_lib_info *new_layer_lib_list, *my_lib;
1482
1483 /* Only loader layer libraries here */
1484 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
Jon Ashburn183dfd02014-10-22 18:13:16 -06001485 return;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001486 }
Jon Ashburn815bddd2014-10-16 15:48:50 -06001487
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001488 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
1489 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, ext_prop->lib_name) == 0) {
1490 /* found matching library */
1491 idx = i;
1492 my_lib = &loader.loaded_layer_lib_list[i];
1493 break;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001494 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001495 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001496
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001497 my_lib->ref_count--;
1498 inst->layer_count--;
1499 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001500 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001501 "Decrement reference count for layer library %s", ext_prop->lib_name);
Jon Ashburnfce93d92015-05-12 17:26:48 -06001502 return;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07001503 }
Jon Ashburn4d3b7522015-04-14 14:14:48 -06001504
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001505 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001506 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001507 "Unloading layer library %s", ext_prop->lib_name);
1508
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001509 /* Need to remove unused library from list */
1510 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1511 if (!new_layer_lib_list) {
1512 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1513 return;
1514 }
1515
1516 if (idx > 0) {
1517 /* Copy records before idx */
1518 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1519 sizeof(struct loader_lib_info) * idx);
1520 }
1521 if (idx < (loader.loaded_layer_lib_count - 1)) {
1522 /* Copy records after idx */
1523 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1524 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1525 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001526
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001527 free(loader.loaded_layer_lib_list);
1528 loader.loaded_layer_lib_count--;
1529 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnead95c52014-11-18 09:06:04 -07001530}
1531
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001532static void loader_add_layer_env(
1533 struct loader_extension_list *ext_list,
1534 const struct loader_extension_list *search_list)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001535{
Ian Elliott225188f2015-02-17 10:33:47 -07001536 char *layerEnv;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001537 uint32_t len;
Jon Ashburnb4d00532014-10-22 21:15:26 -06001538 char *p, *pOrig, *next, *name;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001539
Ian Elliott225188f2015-02-17 10:33:47 -07001540#if defined(WIN32)
1541 layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV,
1542 LAYER_NAMES_REGISTRY_VALUE);
1543#else // WIN32
1544 layerEnv = getenv(LAYER_NAMES_ENV);
1545#endif // WIN32
1546 if (layerEnv == NULL) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001547 return;
Ian Elliott225188f2015-02-17 10:33:47 -07001548 }
Jon Ashburn183dfd02014-10-22 18:13:16 -06001549 p = malloc(strlen(layerEnv) + 1);
Ian Elliott225188f2015-02-17 10:33:47 -07001550 if (p == NULL) {
1551#if defined(WIN32)
1552 free(layerEnv);
1553#endif // WIN32
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001554 return;
Ian Elliott225188f2015-02-17 10:33:47 -07001555 }
Jon Ashburn183dfd02014-10-22 18:13:16 -06001556 strcpy(p, layerEnv);
Ian Elliott225188f2015-02-17 10:33:47 -07001557#if defined(WIN32)
1558 free(layerEnv);
1559#endif // WIN32
Jon Ashburnb4d00532014-10-22 21:15:26 -06001560 pOrig = p;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001561
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001562 while (p && *p ) {
Ian Elliott81ac44c2015-01-13 17:52:38 -07001563 next = strchr(p, PATH_SEPERATOR);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001564 if (next == NULL) {
Ian Elliott64f74a82015-02-04 12:06:46 -07001565 len = (uint32_t) strlen(p);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001566 next = p + len;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07001567 } else {
Ian Elliott64f74a82015-02-04 12:06:46 -07001568 len = (uint32_t) (next - p);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001569 *(char *) next = '\0';
1570 next++;
1571 }
Jon Ashburn183dfd02014-10-22 18:13:16 -06001572 name = basename(p);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001573 loader_search_ext_list_for_name(name, search_list, ext_list);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001574 p = next;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07001575 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001576
Jon Ashburnb4d00532014-10-22 21:15:26 -06001577 free(pOrig);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001578 return;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001579}
1580
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -06001581void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn183dfd02014-10-22 18:13:16 -06001582{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001583 if (!instance->layer_count) {
1584 return;
1585 }
Jon Ashburn183dfd02014-10-22 18:13:16 -06001586
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001587 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -06001588 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
1589 struct loader_extension_property *ext_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001590
1591 loader_remove_layer_lib(instance, ext_prop);
1592
1593 instance->layer_count--;
Jon Ashburn183dfd02014-10-22 18:13:16 -06001594 }
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06001595 loader_destroy_ext_list(&instance->activated_layer_list);
Jon Ashburnfce93d92015-05-12 17:26:48 -06001596
Jon Ashburn183dfd02014-10-22 18:13:16 -06001597}
1598
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001599void loader_enable_instance_layers(struct loader_instance *inst)
1600{
1601 if (inst == NULL)
1602 return;
1603
1604 /* Add any layers specified in the environment first */
1605 loader_add_layer_env(&inst->enabled_instance_extensions, &loader.global_extensions);
1606
1607 /* Add layers / extensions specified by the application */
1608 loader_add_vk_ext_to_ext_list(
1609 &inst->enabled_instance_extensions,
1610 inst->app_extension_count,
1611 inst->app_extension_props,
1612 &loader.global_extensions);
1613}
1614
Jon Ashburnfce93d92015-05-12 17:26:48 -06001615uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1616{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001617 uint32_t layer_idx;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001618 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001619
David Pinedo0fab78b2015-06-24 15:29:18 -06001620 if (inst == NULL) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06001621 return 0;
David Pinedo0fab78b2015-06-24 15:29:18 -06001622 }
Jon Ashburnfce93d92015-05-12 17:26:48 -06001623
1624 // NOTE inst is unwrapped at this point in time
1625 VkObject baseObj = (VkObject) inst;
1626 VkObject nextObj = (VkObject) inst;
1627 VkBaseLayerObject *nextInstObj;
1628 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1629
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001630 /*
1631 * Figure out how many actual layers will need to be wrapped.
1632 */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001633 for (uint32_t i = 0; i < inst->enabled_instance_extensions.count; i++) {
1634 struct loader_extension_property *ext_prop = &inst->enabled_instance_extensions.list[i];
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001635 if (ext_prop->alias) {
1636 ext_prop = ext_prop->alias;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001637 }
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001638 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1639 continue;
1640 }
1641 loader_add_to_ext_list(&inst->activated_layer_list, 1, ext_prop);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001642 }
Jon Ashburnfce93d92015-05-12 17:26:48 -06001643
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001644 inst->layer_count = inst->activated_layer_list.count;
1645
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001646 if (!inst->layer_count) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06001647 return 0;
1648 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001649
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001650 wrappedInstance = malloc(sizeof(VkBaseLayerObject)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001651 * inst->layer_count);
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001652 if (!wrappedInstance) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001653 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1654 return 0;
1655 }
1656
1657 /* Create instance chain of enabled layers */
1658 layer_idx = inst->layer_count - 1;
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001659 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
1660 struct loader_extension_property *ext_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001661 loader_platform_dl_handle lib_handle;
1662
1663 /*
Jon Ashburn4ebc0962015-06-18 09:05:37 -06001664 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
Courtney Goeltzenleuchterc27292a2015-06-01 14:12:42 -06001665 * the extension must provide two entry points for the loader to use:
1666 * - "trampoline" entry point - this is the address returned by GetProcAddr
1667 * and will always do what's necessary to support a global call.
1668 * - "terminator" function - this function will be put at the end of the
1669 * instance chain and will contain the necessary logica to call / process
1670 * the extension for the appropriate ICDs that are available.
1671 * There is no generic mechanism for including these functions, the references
1672 * must be placed into the appropriate loader entry points.
1673 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
1674 * loader_coalesce_extensions(void) - add extension records to the list of global
1675 * extension available to the app.
1676 * instance_disp - add function pointer for terminator function to this array.
1677 * The extension itself should be in a separate file that will be
1678 * linked directly with the loader.
1679 * Note: An extension's Get*ProcAddr should not return a function pointer for
1680 * any extension entry points until the extension has been enabled.
1681 * To do this requires a different behavior from Get*ProcAddr functions implemented
1682 * in layers.
1683 * The very first call to a layer will be it's Get*ProcAddr function requesting
1684 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1685 * with the wrapped object given (either Instance or Device) and return the layer's
1686 * Get*ProcAddr function. The layer should also use this opportunity to record the
1687 * baseObject so that it can find the correct local dispatch table on future calls.
1688 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1689 * will not use a wrapped object and must look up their local dispatch table from
1690 * the given baseObject.
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001691 */
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06001692 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001693
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001694 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburnfce93d92015-05-12 17:26:48 -06001695 nextInstObj->pGPA = nextGPA;
1696 nextInstObj->baseObject = baseObj;
1697 nextInstObj->nextObject = nextObj;
1698 nextObj = (VkObject) nextInstObj;
1699
1700 char funcStr[256];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001701 snprintf(funcStr, 256, "%sGetInstanceProcAddr", ext_prop->info.name);
Jon Ashburn9a9de1f2015-05-27 13:19:22 -06001702 lib_handle = loader_add_layer_lib("instance", ext_prop);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001703 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1704 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburnfce93d92015-05-12 17:26:48 -06001705 if (!nextGPA) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001706 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", ext_prop->lib_name);
Courtney Goeltzenleuchteraa685052015-06-01 14:49:17 -06001707
1708 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburnfce93d92015-05-12 17:26:48 -06001709 continue;
1710 }
1711
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001712 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1713 "Insert instance layer library %s for extension: %s",
1714 ext_prop->lib_name, ext_prop->info.name);
1715
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001716 layer_idx--;
Jon Ashburnfce93d92015-05-12 17:26:48 -06001717 }
1718
Jon Ashburn4f2575f2015-05-28 16:25:02 -06001719 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001720
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001721 free(wrappedInstance);
Jon Ashburnfce93d92015-05-12 17:26:48 -06001722 return inst->layer_count;
1723}
1724
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001725void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1726{
1727
1728 loader_init_instance_extension_dispatch_table(inst->disp,
1729 inst->disp->GetInstanceProcAddr,
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001730 (VkInstance) inst);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001731}
1732
Courtney Goeltzenleuchtera34c6342015-06-25 16:27:24 -06001733static void loader_enable_device_layers(
1734 struct loader_device *dev,
1735 struct loader_extension_list *ext_list)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001736{
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06001737 if (dev == NULL)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001738 return;
1739
1740 /* Add any layers specified in the environment first */
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06001741 loader_add_layer_env(&dev->enabled_device_extensions, &loader.global_extensions);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001742
1743 /* Add layers / extensions specified by the application */
1744 loader_add_vk_ext_to_ext_list(
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06001745 &dev->enabled_device_extensions,
1746 dev->app_extension_count,
1747 dev->app_extension_props,
Courtney Goeltzenleuchtera34c6342015-06-25 16:27:24 -06001748 ext_list);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001749}
1750
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06001751static VkResult scratch_vkCreateDevice(
1752 VkPhysicalDevice gpu,
1753 const VkDeviceCreateInfo *pCreateInfo,
1754 VkDevice *pDevice)
1755{
1756 return VK_SUCCESS;
1757}
1758
1759static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
1760{
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06001761 /* CreateDevice workaround: Make the terminator be a scratch function
1762 * that does nothing since we have already called the ICD's create device.
1763 * We can then call down the device chain and have all the layers get set up.
1764 */
1765 if (!strcmp(name, "vkGetDeviceProcAddr"))
1766 return (void *) loader_GetDeviceChainProcAddr;
1767 if (!strcmp(name, "vkCreateDevice"))
1768 return (void *) scratch_vkCreateDevice;
1769
Courtney Goeltzenleuchtere76db422015-06-29 16:09:23 -06001770 struct loader_device *found_dev;
1771 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
1772 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06001773}
1774
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06001775static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06001776 VkPhysicalDevice gpu,
1777 VkDevice device,
1778 struct loader_device *dev,
1779 struct loader_icd *icd,
1780 uint32_t ext_count,
1781 const VkExtensionProperties *ext_props)
Jon Ashburn183dfd02014-10-22 18:13:16 -06001782{
Jon Ashburn183dfd02014-10-22 18:13:16 -06001783 if (!icd)
1784 return 0;
Jon Ashburn183dfd02014-10-22 18:13:16 -06001785
David Pinedo0fab78b2015-06-24 15:29:18 -06001786 if (!dev) {
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06001787 return 0;
David Pinedo0fab78b2015-06-24 15:29:18 -06001788 }
Jon Ashburn612539f2015-06-10 10:13:10 -06001789
Jon Ashburn183dfd02014-10-22 18:13:16 -06001790 /* activate any layer libraries */
Jon Ashburn612539f2015-06-10 10:13:10 -06001791 VkObject nextObj = (VkObject) device;
1792 VkObject baseObj = nextObj;
1793 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06001794 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn612539f2015-06-10 10:13:10 -06001795 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06001796
Jon Ashburn612539f2015-06-10 10:13:10 -06001797 /*
1798 * Figure out how many actual layers will need to be wrapped.
1799 */
1800 for (uint32_t i = 0; i < dev->enabled_device_extensions.count; i++) {
1801 struct loader_extension_property *ext_prop = &dev->enabled_device_extensions.list[i];
1802 if (ext_prop->alias) {
1803 ext_prop = ext_prop->alias;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001804 }
Jon Ashburn612539f2015-06-10 10:13:10 -06001805 if (ext_prop->origin != VK_EXTENSION_ORIGIN_LAYER) {
1806 continue;
Jon Ashburnfce93d92015-05-12 17:26:48 -06001807 }
Jon Ashburn612539f2015-06-10 10:13:10 -06001808 loader_add_to_ext_list(&dev->activated_layer_list, 1, ext_prop);
Jon Ashburn183dfd02014-10-22 18:13:16 -06001809 }
Jon Ashburn612539f2015-06-10 10:13:10 -06001810
1811 if (!dev->activated_layer_list.count)
1812 return 0;
1813
1814 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
1815 if (!wrappedGpus) {
1816 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
1817 return 0;
1818 }
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06001819
Jon Ashburn612539f2015-06-10 10:13:10 -06001820 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
1821
1822 struct loader_extension_property *ext_prop = &dev->activated_layer_list.list[i];
1823 loader_platform_dl_handle lib_handle;
1824
1825 assert(ext_prop->origin == VK_EXTENSION_ORIGIN_LAYER);
1826
1827 nextGpuObj = (wrappedGpus + i);
1828 nextGpuObj->pGPA = nextGPA;
1829 nextGpuObj->baseObject = baseObj;
1830 nextGpuObj->nextObject = nextObj;
1831 nextObj = (VkObject) nextGpuObj;
1832
1833 char funcStr[256];
1834 snprintf(funcStr, 256, "%sGetDeviceProcAddr", ext_prop->info.name);
1835 lib_handle = loader_add_layer_lib("device", ext_prop);
1836 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1837 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
1838 if (!nextGPA) {
1839 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", ext_prop->info.name);
1840 continue;
1841 }
1842
1843 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
1844 "Insert device layer library %s for extension: %s",
1845 ext_prop->lib_name, ext_prop->info.name);
1846
1847 }
1848
1849 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
1850 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
1851 free(wrappedGpus);
1852
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06001853 return dev->activated_layer_list.count;
Jon Ashburn183dfd02014-10-22 18:13:16 -06001854}
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001855
Jon Ashburnfce93d92015-05-12 17:26:48 -06001856VkResult loader_CreateInstance(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001857 const VkInstanceCreateInfo* pCreateInfo,
1858 VkInstance* pInstance)
Jon Ashburn349508d2015-01-26 14:51:40 -07001859{
Jon Ashburna179dcf2015-05-21 17:42:17 -06001860 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn3336df82015-01-29 15:45:51 -07001861 struct loader_scanned_icds *scanned_icds;
1862 struct loader_icd *icd;
Jon Ashburnfce93d92015-05-12 17:26:48 -06001863 VkResult res;
Jon Ashburn349508d2015-01-26 14:51:40 -07001864
Jon Ashburn3336df82015-01-29 15:45:51 -07001865 scanned_icds = loader.scanned_icd_list;
1866 while (scanned_icds) {
1867 icd = loader_icd_add(ptr_instance, scanned_icds);
1868 if (icd) {
Jon Ashburn29669a42015-04-04 14:52:07 -06001869 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001870 &(icd->instance));
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06001871 if (res != VK_SUCCESS)
Jon Ashburn3336df82015-01-29 15:45:51 -07001872 {
1873 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001874 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001875 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001876 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn3336df82015-01-29 15:45:51 -07001877 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001878 } else
1879 {
1880 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn3336df82015-01-29 15:45:51 -07001881 }
1882 }
1883 scanned_icds = scanned_icds->next;
1884 }
Jon Ashburn349508d2015-01-26 14:51:40 -07001885
Ian Elliott617fdec2015-02-05 15:19:15 -07001886 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06001887 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliott617fdec2015-02-05 15:19:15 -07001888 }
Jon Ashburn3336df82015-01-29 15:45:51 -07001889
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001890 return res;
Jon Ashburn349508d2015-01-26 14:51:40 -07001891}
1892
Jon Ashburnfce93d92015-05-12 17:26:48 -06001893VkResult loader_DestroyInstance(
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -06001894 VkInstance instance)
Jon Ashburn349508d2015-01-26 14:51:40 -07001895{
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -06001896 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001897 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburn16a16d62015-06-16 14:43:19 -06001898 struct loader_icd *next_icd;
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -06001899 VkResult res;
Jon Ashburn349508d2015-01-26 14:51:40 -07001900
1901 // Remove this instance from the list of instances:
1902 struct loader_instance *prev = NULL;
1903 struct loader_instance *next = loader.instances;
1904 while (next != NULL) {
1905 if (next == ptr_instance) {
1906 // Remove this instance from the list:
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001907 free(ptr_instance->app_extension_props);
Jon Ashburn349508d2015-01-26 14:51:40 -07001908 if (prev)
1909 prev->next = next->next;
Jon Ashburn2cabd252015-02-03 09:26:59 -07001910 else
1911 loader.instances = next->next;
Jon Ashburn349508d2015-01-26 14:51:40 -07001912 break;
1913 }
1914 prev = next;
1915 next = next->next;
1916 }
1917 if (next == NULL) {
1918 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06001919 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn349508d2015-01-26 14:51:40 -07001920 }
1921
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001922 while (icds) {
1923 if (icds->instance) {
1924 res = icds->DestroyInstance(icds->instance);
Tony Barbour22a30862015-04-22 09:02:32 -06001925 if (res != VK_SUCCESS)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001926 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbour22a30862015-04-22 09:02:32 -06001927 "ICD ignored: failed to DestroyInstance on device");
1928 }
Jon Ashburn16a16d62015-06-16 14:43:19 -06001929 next_icd = icds->next;
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001930 icds->instance = VK_NULL_HANDLE;
Jon Ashburn16a16d62015-06-16 14:43:19 -06001931 loader_icd_destroy(ptr_instance, icds);
1932
1933 icds = next_icd;
Jon Ashburn3336df82015-01-29 15:45:51 -07001934 }
1935
Jon Ashburn349508d2015-01-26 14:51:40 -07001936
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06001937 return VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07001938}
1939
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001940VkResult loader_init_physical_device_info(
1941 struct loader_instance *ptr_instance)
1942{
1943 struct loader_icd *icd;
1944 uint32_t n, count = 0;
1945 VkResult res = VK_ERROR_UNKNOWN;
1946
1947 icd = ptr_instance->icds;
1948 while (icd) {
1949 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
1950 if (res != VK_SUCCESS)
1951 return res;
1952 icd->gpu_count = n;
1953 count += n;
1954 icd = icd->next;
1955 }
1956
1957 ptr_instance->total_gpu_count = count;
1958
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001959 icd = ptr_instance->icds;
1960 while (icd) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001961
1962 n = icd->gpu_count;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001963 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
1964 if (!icd->gpus) {
1965 /* TODO: Add cleanup code here */
1966 return VK_ERROR_OUT_OF_HOST_MEMORY;
1967 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001968 res = icd->EnumeratePhysicalDevices(
1969 icd->instance,
1970 &n,
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001971 icd->gpus);
1972 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001973
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001974 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001975
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001976 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001977
1978 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
1979 /* TODO: Add cleanup code here */
1980 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1981 }
Tony Barbour426b9052015-06-24 16:06:58 -06001982 if (res == VK_SUCCESS && icd->GetPhysicalDeviceExtensionProperties && icd->GetPhysicalDeviceExtensionCount) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001983 uint32_t extension_count;
1984
Tony Barbour426b9052015-06-24 16:06:58 -06001985 res = icd->GetPhysicalDeviceExtensionCount(icd->gpus[i], &extension_count);
1986 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001987 struct loader_extension_property ext_props;
1988
1989 /* Gather all the ICD extensions */
1990 for (uint32_t extension_id = 0; extension_id < extension_count; extension_id++) {
Tony Barbour426b9052015-06-24 16:06:58 -06001991 res = icd->GetPhysicalDeviceExtensionProperties(icd->gpus[i],
1992 extension_id, &ext_props.info);
1993 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001994 ext_props.origin = VK_EXTENSION_ORIGIN_ICD;
1995 ext_props.lib_name = icd->scanned_icds->lib_name;
Jon Ashburn60699262015-06-10 16:11:42 -06001996 ext_props.get_proc_addr = icd->GetDeviceProcAddr;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001997 loader_add_to_ext_list(&icd->device_extension_cache[i], 1, &ext_props);
1998 }
1999 }
2000
2001 // Traverse layers list adding non-duplicate extensions to the list
Jon Ashburn68a63922015-07-02 09:40:15 -06002002 for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
2003 loader_get_physical_device_layer_extensions(
2004 ptr_instance,
2005 icd->gpus[i],
2006 &loader.scanned_layers.list[i],
2007 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002008 }
2009 }
2010 }
2011
2012 if (res != VK_SUCCESS) {
2013 /* clean up any extension lists previously created before this request failed */
2014 for (uint32_t j = 0; j < i; j++) {
2015 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2016 }
2017 return res;
2018 }
2019 }
2020
2021 count += n;
2022 }
2023
2024 icd = icd->next;
2025 }
2026
2027 return VK_SUCCESS;
2028}
2029
Jon Ashburnfce93d92015-05-12 17:26:48 -06002030VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter9f530cb2015-04-20 12:48:54 -06002031 VkInstance instance,
2032 uint32_t* pPhysicalDeviceCount,
2033 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn349508d2015-01-26 14:51:40 -07002034{
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002035 uint32_t index = 0;
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002036 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002037 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002038
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002039 if (ptr_instance->total_gpu_count == 0) {
2040 loader_init_physical_device_info(ptr_instance);
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002041 }
2042
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002043 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2044 if (!pPhysicalDevices) {
2045 return VK_SUCCESS;
2046 }
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002047
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002048 while (icd) {
2049 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002050 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002051 index += icd->gpu_count;
2052 icd = icd->next;
2053 }
2054
2055 return VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002056}
2057
Tony Barbour426b9052015-06-24 16:06:58 -06002058VkResult loader_GetPhysicalDeviceProperties(
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002059 VkPhysicalDevice gpu,
Tony Barbour426b9052015-06-24 16:06:58 -06002060 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002061{
2062 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002063 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002064 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2065
Tony Barbour426b9052015-06-24 16:06:58 -06002066 if (icd->GetPhysicalDeviceProperties)
2067 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2068
2069 return res;
2070}
2071
2072VkResult loader_GetPhysicalDevicePerformance(
2073 VkPhysicalDevice gpu,
2074 VkPhysicalDevicePerformance* pPerformance)
2075{
2076 uint32_t gpu_index;
2077 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2078 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2079
2080 if (icd->GetPhysicalDevicePerformance)
2081 res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2082
2083 return res;
2084}
2085
2086VkResult loader_GetPhysicalDeviceQueueCount(
2087 VkPhysicalDevice gpu,
2088 uint32_t* pCount)
2089{
2090 uint32_t gpu_index;
2091 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2092 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2093
2094 if (icd->GetPhysicalDeviceQueueCount)
2095 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2096
2097 return res;
2098}
2099
2100VkResult loader_GetPhysicalDeviceQueueProperties (
2101 VkPhysicalDevice gpu,
2102 uint32_t count,
2103 VkPhysicalDeviceQueueProperties * pProperties)
2104{
2105 uint32_t gpu_index;
2106 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2107 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2108
2109 if (icd->GetPhysicalDeviceQueueProperties)
2110 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2111
2112 return res;
2113}
2114
2115VkResult loader_GetPhysicalDeviceMemoryProperties (
2116 VkPhysicalDevice gpu,
2117 VkPhysicalDeviceMemoryProperties* pProperties)
2118{
2119 uint32_t gpu_index;
2120 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2121 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2122
2123 if (icd->GetPhysicalDeviceMemoryProperties)
2124 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002125
2126 return res;
2127}
2128
Chris Forbesd7576302015-06-21 22:55:02 +12002129VkResult loader_GetPhysicalDeviceFeatures(
2130 VkPhysicalDevice physicalDevice,
2131 VkPhysicalDeviceFeatures* pFeatures)
2132{
2133 uint32_t gpu_index;
2134 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2135 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2136
2137 if (icd->GetPhysicalDeviceFeatures)
2138 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2139
2140 return res;
2141}
2142
2143VkResult loader_GetPhysicalDeviceFormatInfo(
2144 VkPhysicalDevice physicalDevice,
2145 VkFormat format,
2146 VkFormatProperties* pFormatInfo)
2147{
2148 uint32_t gpu_index;
2149 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2150 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2151
2152 if (icd->GetPhysicalDeviceFormatInfo)
2153 res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2154
2155 return res;
2156}
2157
2158VkResult loader_GetPhysicalDeviceLimits(
2159 VkPhysicalDevice physicalDevice,
2160 VkPhysicalDeviceLimits* pLimits)
2161{
2162 uint32_t gpu_index;
2163 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2164 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2165
2166 if (icd->GetPhysicalDeviceLimits)
2167 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2168
2169 return res;
2170}
2171
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002172VkResult loader_CreateDevice(
2173 VkPhysicalDevice gpu,
2174 const VkDeviceCreateInfo* pCreateInfo,
2175 VkDevice* pDevice)
2176{
2177 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002178 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002179 struct loader_device *dev;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002180 VkResult res;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002181
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002182 if (!icd->CreateDevice) {
2183 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002184 }
2185
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002186 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2187 if (res != VK_SUCCESS) {
2188 return res;
2189 }
2190
2191 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2192 if (dev == NULL) {
2193 return VK_ERROR_OUT_OF_HOST_MEMORY;
2194 }
2195 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2196 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2197 icd->gpus[gpu_index], icd->gpus[gpu_index]);
2198
2199 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2200 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2201
2202 dev->app_extension_count = pCreateInfo->extensionCount;
2203 dev->app_extension_props = (VkExtensionProperties *) malloc(sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
2204 if (dev->app_extension_props == NULL && (dev->app_extension_count > 0)) {
2205 return VK_ERROR_OUT_OF_HOST_MEMORY;
2206 }
2207
2208 /* Make local copy of extension list */
2209 if (dev->app_extension_count > 0 && dev->app_extension_props != NULL) {
2210 memcpy(dev->app_extension_props, pCreateInfo->pEnabledExtensions, sizeof(VkExtensionProperties) * pCreateInfo->extensionCount);
2211 }
2212
2213 /*
2214 * Put together the complete list of extensions to enable
2215 * This includes extensions requested via environment variables.
2216 */
2217 loader_enable_device_layers(dev, &icd->device_extension_cache[gpu_index]);
2218
2219 /*
2220 * Load the libraries needed by the extensions on the
2221 * enabled extension list. This will build the device chain
2222 * terminating with the selected device.
2223 */
2224 loader_activate_device_layers(gpu, *pDevice, dev, icd,
2225 dev->app_extension_count,
2226 dev->app_extension_props);
2227
2228 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2229
2230 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2231
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002232 return res;
2233}
2234
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002235static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburn53c16772015-05-06 10:15:07 -06002236{
Jon Ashburncedc15f2015-05-21 18:13:33 -06002237 if (instance == VK_NULL_HANDLE)
2238 return NULL;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002239
Jon Ashburncedc15f2015-05-21 18:13:33 -06002240 void *addr;
2241 /* get entrypoint addresses that are global (in the loader)*/
2242 addr = globalGetProcAddr(pName);
2243 if (addr)
2244 return addr;
Jon Ashburn53c16772015-05-06 10:15:07 -06002245
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002246 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2247
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002248 /* return any extension global entrypoints */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002249 addr = debug_report_instance_gpa(ptr_instance, pName);
2250 if (addr) {
2251 return addr;
2252 }
2253
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002254 /* TODO Remove this once WSI has no loader special code */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002255 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
David Pinedo0fab78b2015-06-24 15:29:18 -06002256 if (addr) {
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002257 return addr;
David Pinedo0fab78b2015-06-24 15:29:18 -06002258 }
Jon Ashburncedc15f2015-05-21 18:13:33 -06002259
2260 /* return the instance dispatch table entrypoint for extensions */
2261 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2262 if (disp_table == NULL)
2263 return NULL;
2264
2265 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2266 if (addr)
2267 return addr;
Jon Ashburn53c16772015-05-06 10:15:07 -06002268
2269 return NULL;
2270}
2271
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002272LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2273{
2274 return loader_GetInstanceProcAddr(instance, pName);
2275}
2276
2277static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn349508d2015-01-26 14:51:40 -07002278{
Jon Ashburn1245cec2015-05-18 13:20:15 -06002279 if (device == VK_NULL_HANDLE) {
2280 return NULL;
Ian Elliott81ac44c2015-01-13 17:52:38 -07002281 }
Jon Ashburne18431b2015-04-13 18:10:06 -06002282
Chia-I Wu38e5a2c2015-01-04 11:12:47 +08002283 void *addr;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002284
Jon Ashburne18431b2015-04-13 18:10:06 -06002285 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2286 make sure the loader entrypoint is returned */
2287 addr = loader_non_passthrough_gpa(pName);
Ian Elliottfdf00b62015-04-15 12:53:19 -06002288 if (addr) {
Jon Ashburne18431b2015-04-13 18:10:06 -06002289 return addr;
Ian Elliottfdf00b62015-04-15 12:53:19 -06002290 }
Jon Ashburne18431b2015-04-13 18:10:06 -06002291
Jon Ashburncedc15f2015-05-21 18:13:33 -06002292 /* return any extension device entrypoints the loader knows about */
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002293 /* TODO once WSI has no loader special code remove this */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002294 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
David Pinedo0fab78b2015-06-24 15:29:18 -06002295 if (addr) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002296 return addr;
David Pinedo0fab78b2015-06-24 15:29:18 -06002297 }
Jon Ashburncedc15f2015-05-21 18:13:33 -06002298
Jon Ashburne18431b2015-04-13 18:10:06 -06002299 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn1245cec2015-05-18 13:20:15 -06002300 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002301 if (disp_table == NULL)
2302 return NULL;
2303
Jon Ashburnfce93d92015-05-12 17:26:48 -06002304 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wu38e5a2c2015-01-04 11:12:47 +08002305 if (addr)
2306 return addr;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002307 else {
Jon Ashburn1245cec2015-05-18 13:20:15 -06002308 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002309 return NULL;
Jon Ashburn1245cec2015-05-18 13:20:15 -06002310 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002311 }
2312}
2313
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002314LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2315{
2316 return loader_GetDeviceProcAddr(device, pName);
2317}
2318
Tony Barbour426b9052015-06-24 16:06:58 -06002319LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionCount(
2320 uint32_t* pCount)
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002321{
Tony Barbour426b9052015-06-24 16:06:58 -06002322 /* Scan/discover all ICD libraries in a single-threaded manner */
2323 loader_platform_thread_once(&once_icd, loader_icd_scan);
2324
2325 /* get layer libraries in a single-threaded manner */
Jon Ashburn68a63922015-07-02 09:40:15 -06002326 loader_platform_thread_once(&once_layer, loader_layer_scan);
Tony Barbour426b9052015-06-24 16:06:58 -06002327
2328 /* merge any duplicate extensions */
2329 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2330
2331 loader_platform_thread_lock_mutex(&loader_lock);
2332 *pCount = loader.global_extensions.count;
2333 loader_platform_thread_unlock_mutex(&loader_lock);
2334 return VK_SUCCESS;
2335}
2336
2337LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
2338 uint32_t extensionIndex,
2339 VkExtensionProperties* pProperties)
2340{
Jon Ashburnb40f2562015-05-29 13:15:39 -06002341
Jon Ashburneb2728b2015-04-10 14:33:07 -06002342 /* Scan/discover all ICD libraries in a single-threaded manner */
2343 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002344
Jon Ashburneb2728b2015-04-10 14:33:07 -06002345 /* get layer libraries in a single-threaded manner */
Jon Ashburn68a63922015-07-02 09:40:15 -06002346 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002347
Jon Ashburneb2728b2015-04-10 14:33:07 -06002348 /* merge any duplicate extensions */
2349 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2350
Tony Barbour426b9052015-06-24 16:06:58 -06002351 if (extensionIndex >= loader.global_extensions.count)
2352 return VK_ERROR_INVALID_VALUE;
Jon Ashburneb2728b2015-04-10 14:33:07 -06002353
Jon Ashburnb40f2562015-05-29 13:15:39 -06002354 loader_platform_thread_lock_mutex(&loader_lock);
Tony Barbour426b9052015-06-24 16:06:58 -06002355 memcpy(pProperties,
2356 &loader.global_extensions.list[extensionIndex],
2357 sizeof(VkExtensionProperties));
2358
Jon Ashburnb40f2562015-05-29 13:15:39 -06002359 loader_platform_thread_unlock_mutex(&loader_lock);
Tony Barbour426b9052015-06-24 16:06:58 -06002360 return VK_SUCCESS;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002361}
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002362
Tony Barbour426b9052015-06-24 16:06:58 -06002363VkResult loader_GetPhysicalDeviceExtensionCount(
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002364 VkPhysicalDevice gpu,
Tony Barbour426b9052015-06-24 16:06:58 -06002365 uint32_t* pCount)
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002366{
2367 uint32_t gpu_index;
Tony Barbour426b9052015-06-24 16:06:58 -06002368 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2369 *pCount = icd->device_extension_cache[gpu_index].count;
2370
2371 return VK_SUCCESS;
2372}
2373
2374VkResult loader_GetPhysicalDeviceExtensionProperties(
2375 VkPhysicalDevice gpu,
2376 uint32_t extensionIndex,
2377 VkExtensionProperties* pProperties)
2378{
2379 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002380 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002381
Tony Barbour426b9052015-06-24 16:06:58 -06002382 if (extensionIndex >= icd->device_extension_cache[gpu_index].count)
2383 return VK_ERROR_INVALID_VALUE;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002384
Tony Barbour426b9052015-06-24 16:06:58 -06002385 memcpy( pProperties,
2386 &icd->device_extension_cache[gpu_index].list[extensionIndex],
2387 sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002388
2389 return VK_SUCCESS;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002390}