blob: f3e8559f2f8d826b3f373b14bcf7e9da8b119123 [file] [log] [blame]
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001/*
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002 * Vulkan
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Chia-I Wu701f3f62014-09-02 08:32:09 +080023 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
Jon Ashburn01e2d662014-11-14 09:52:42 -070026 * Jon Ashburn <jon@lunarg.com>
Chia-I Wu701f3f62014-09-02 08:32:09 +080027 * Courtney Goeltzenleuchter <courtney@lunarg.com>
Ian Elliott5aa4ea22015-03-31 15:32:41 -060028 * Ian Elliott <ian@lunarg.com>
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080029 */
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060030#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080031#include <stdio.h>
32#include <stdlib.h>
33#include <stdarg.h>
34#include <stdbool.h>
35#include <string.h>
36
Chia-I Wu13a61a52014-08-04 11:18:20 +080037#include <sys/types.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070038#if defined(WIN32)
39#include "dirent_on_windows.h"
40#else // WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080041#include <dirent.h>
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070042#endif // WIN32
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060043#include "vk_loader_platform.h"
Chia-I Wu19300602014-08-04 08:03:57 +080044#include "loader.h"
Jon Ashburn07daee72015-05-21 18:13:33 -060045#include "wsi_lunarg.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060046#include "gpa_helper.h"
47#include "table_ops.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060048#include "debug_report.h"
Tobin Ehlis0c6f9ee2015-07-03 09:42:57 -060049#include "vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060050#include "cJSON.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080051
Courtney Goeltzenleuchterf579fa62015-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 Goeltzenleuchtered488302015-06-01 14:09:34 -060057static loader_platform_dl_handle loader_add_layer_lib(
58 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060059 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060060
61static void loader_remove_layer_lib(
62 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060063 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchtered488302015-06-01 14:09:34 -060064
Jon Ashburn27cd5842015-05-12 17:26:48 -060065struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080066
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060067static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -060068static bool loader_init_ext_list(struct loader_extension_list *ext_info);
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060069
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060070enum loader_debug {
71 LOADER_INFO_BIT = VK_BIT(0),
72 LOADER_WARN_BIT = VK_BIT(1),
73 LOADER_PERF_BIT = VK_BIT(2),
74 LOADER_ERROR_BIT = VK_BIT(3),
75 LOADER_DEBUG_BIT = VK_BIT(4),
76};
77
78uint32_t g_loader_debug = 0;
79uint32_t g_loader_log_msgs = 0;
80
Jon Ashburn6301a0f2015-05-29 13:15:39 -060081//thread safety lock for accessing global data structures such as "loader"
82// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060083// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060084loader_platform_thread_mutex loader_lock;
85
86const VkLayerInstanceDispatchTable instance_disp = {
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -060087 .GetInstanceProcAddr = loader_GetInstanceProcAddr,
Jon Ashburn27cd5842015-05-12 17:26:48 -060088 .CreateInstance = loader_CreateInstance,
89 .DestroyInstance = loader_DestroyInstance,
90 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Chris Forbesbc0bb772015-06-21 22:55:02 +120091 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
92 .GetPhysicalDeviceFormatInfo = loader_GetPhysicalDeviceFormatInfo,
93 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
Tony Barbour59a47322015-06-24 16:06:58 -060094 .GetPhysicalDeviceProperties = loader_GetPhysicalDeviceProperties,
95 .GetPhysicalDevicePerformance = loader_GetPhysicalDevicePerformance,
96 .GetPhysicalDeviceQueueCount = loader_GetPhysicalDeviceQueueCount,
97 .GetPhysicalDeviceQueueProperties = loader_GetPhysicalDeviceQueueProperties,
98 .GetPhysicalDeviceMemoryProperties = loader_GetPhysicalDeviceMemoryProperties,
Tony Barbour59a47322015-06-24 16:06:58 -060099 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600100 .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600101 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
102 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburn27cd5842015-05-12 17:26:48 -0600103};
104
105LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
106LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
107LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700108
Jon Ashburnffad94d2015-06-30 14:46:22 -0700109static void loader_log(VkFlags msg_type, int32_t msg_code,
110 const char *format, ...)
111{
112 char msg[256];
113 va_list ap;
114 int ret;
115
116 if (!(msg_type & g_loader_log_msgs)) {
117 return;
118 }
119
120 va_start(ap, format);
121 ret = vsnprintf(msg, sizeof(msg), format, ap);
122 if ((ret >= (int) sizeof(msg)) || ret < 0) {
123 msg[sizeof(msg)-1] = '\0';
124 }
125 va_end(ap);
126
Ian Elliott4470a302015-02-17 10:33:47 -0700127#if defined(WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700128 OutputDebugString(msg);
129#endif
130 fputs(msg, stderr);
131 fputc('\n', stderr);
132}
133
134#if defined(WIN32)
135/**
136* Find the list of registry files (names within a key) in key "location".
137*
138* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
139* for a list or name/values which are added to a returned list (function return value).
140* The DWORD values within the key must be 0 or they are skipped.
141* Function return is a string with a ';' seperated list of filenames.
142* Function return is NULL if no valid name/value pairs are found in the key,
143* or the key is not found.
144*
145* \returns
146* A string list of filenames as pointer.
147* When done using the returned string list, pointer should be freed.
148*/
149static char *loader_get_registry_files(const char *location)
150{
151 LONG rtn_value;
152 HKEY hive, key;
153 DWORD access_flags = KEY_QUERY_VALUE;
154 char name[2048];
155 char *out = NULL;
156
157 hive = DEFAULT_VK_REGISTRY_HIVE;
158 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
159 if (rtn_value != ERROR_SUCCESS) {
160 // We didn't find the key. Try the 32-bit hive (where we've seen the
161 // key end up on some people's systems):
162 access_flags |= KEY_WOW64_32KEY;
163 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
164 if (rtn_value != ERROR_SUCCESS) {
165 // We still couldn't find the key, so give up:
166 return NULL;
167 }
168 }
169
170 DWORD idx = 0;
171 DWORD name_size = sizeof(name);
172 DWORD value;
173 DWORD total_size = 4096;
174 DWORD value_size = sizeof(value);
175 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
176 if (value_size == sizeof(value) && value == 0) {
177 if (out == NULL) {
178 out = malloc(total_size);
179 out[0] = '\0';
180 }
181 else if (strlen(out) + name_size + 1 > total_size) {
182 out = realloc(out, total_size * 2);
183 total_size *= 2;
184 }
185 if (out == NULL) {
186 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
187 return NULL;
188 }
189 if (strlen(out) == 0)
190 snprintf(out, name_size + 1, "%s", name);
191 else
192 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name);
193 }
194 }
195 return out;
196}
197
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600198char *loader_get_registry_string(const HKEY hive,
199 const LPCTSTR sub_key,
200 const char *value)
201{
202 DWORD access_flags = KEY_QUERY_VALUE;
203 DWORD value_type;
204 HKEY key;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700205 LONG rtn_value;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600206 char *rtn_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600207 DWORD rtn_len = 0;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600208 size_t allocated_len = 0;
209
210 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
211 if (rtn_value != ERROR_SUCCESS) {
212 // We didn't find the key. Try the 32-bit hive (where we've seen the
213 // key end up on some people's systems):
214 access_flags |= KEY_WOW64_32KEY;
215 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
216 if (rtn_value != ERROR_SUCCESS) {
217 // We still couldn't find the key, so give up:
218 return NULL;
219 }
220 }
221
222 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600223 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600224 if (rtn_value == ERROR_SUCCESS) {
225 // If we get to here, we found the key, and need to allocate memory
226 // large enough for rtn_str, and query again:
227 allocated_len = rtn_len + 4;
228 rtn_str = malloc(allocated_len);
229 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600230 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600231 if (rtn_value == ERROR_SUCCESS) {
232 // We added 4 extra bytes to rtn_str, so that we can ensure that
233 // the string is NULL-terminated (albeit, in a brute-force manner):
234 rtn_str[allocated_len-1] = '\0';
235 } else {
236 // This should never occur, but in case it does, clean up:
237 free(rtn_str);
238 rtn_str = NULL;
239 }
240 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
241
242 // Close the registry key that was opened:
243 RegCloseKey(key);
244
245 return rtn_str;
246}
247
248
Ian Elliott4470a302015-02-17 10:33:47 -0700249// For ICD developers, look in the registry, and look for an environment
250// variable for a path(s) where to find the ICD(s):
251static char *loader_get_registry_and_env(const char *env_var,
252 const char *registry_value)
253{
254 char *env_str = getenv(env_var);
255 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600256 char *registry_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600257 size_t registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700258 char *rtn_str = NULL;
259 size_t rtn_len;
260
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600261 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600262 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600263 registry_value);
Ian Elliottf851ddf2015-04-28 15:57:32 -0600264 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700265
266 rtn_len = env_len + registry_len + 1;
267 if (rtn_len <= 2) {
268 // We found neither the desired registry value, nor the environment
269 // variable; return NULL:
270 return NULL;
271 } else {
272 // We found something, and so we need to allocate memory for the string
273 // to return:
274 rtn_str = malloc(rtn_len);
275 }
276
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600277 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700278 // We didn't find the desired registry value, and so we must have found
279 // only the environment variable:
280 _snprintf(rtn_str, rtn_len, "%s", env_str);
281 } else if (env_str != NULL) {
282 // We found both the desired registry value and the environment
283 // variable, so concatenate them both:
284 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
285 } else {
286 // We must have only found the desired registry value:
287 _snprintf(rtn_str, rtn_len, "%s", registry_str);
288 }
289
Ian Elliott2de26bc2015-04-03 13:13:01 -0600290 if (registry_str) {
291 free(registry_str);
292 }
Ian Elliott4470a302015-02-17 10:33:47 -0700293
294 return(rtn_str);
295}
296#endif // WIN32
297
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600298bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
299{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600300 return strcmp(op1->extName, op2->extName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600301}
302
303/*
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600304 * Search the given ext_array for an extension
305 * matching the given vk_ext_prop
306 */
307bool has_vk_extension_property_array(
308 const VkExtensionProperties *vk_ext_prop,
309 const uint32_t count,
310 const VkExtensionProperties *ext_array)
311{
312 for (uint32_t i = 0; i < count; i++) {
313 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
314 return true;
315 }
316 return false;
317}
318
319/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600320 * Search the given ext_list for an extension
321 * matching the given vk_ext_prop
322 */
323bool has_vk_extension_property(
324 const VkExtensionProperties *vk_ext_prop,
325 const struct loader_extension_list *ext_list)
326{
327 for (uint32_t i = 0; i < ext_list->count; i++) {
328 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
329 return true;
330 }
331 return false;
332}
333
334/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600335 * Search the given layer list for a layer
336 * matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600337 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600338static struct loader_layer_properties *get_layer_property(
339 const char *name,
340 const struct loader_layer_list *layer_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600341{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600342 for (uint32_t i = 0; i < layer_list->count; i++) {
343 const VkLayerProperties *item = &layer_list->list[i].info;
344 if (strcmp(name, item->layerName) == 0)
345 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600346 }
347 return NULL;
348}
349
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600350static void loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -0600351 const PFN_vkGetGlobalExtensionProperties fp_get_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600352 const char *lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600353 const loader_platform_dl_handle lib_handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600354 const enum extension_origin origin,
355 struct loader_extension_list *ext_list)
356{
357 uint32_t i, count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600358 struct loader_extension_property ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600359 VkExtensionProperties *extension_properties;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600360 VkResult res;
361
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600362 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600363 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600364 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600365 return;
366 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600367
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600368#ifdef WIN32
369 extension_properties = _alloca(count * sizeof(VkExtensionProperties));
370#else
371 extension_properties = alloca(count * sizeof(VkExtensionProperties));
372#endif
373
374 res = fp_get_props(NULL, &count, extension_properties);
375 if (res != VK_SUCCESS) {
376 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
377 return;
378 }
Tony Barbour59a47322015-06-24 16:06:58 -0600379
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600380 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600381 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600382 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
383 //TODO eventually get this from the layer config file
384 ext_props.origin = origin;
385 ext_props.lib_name = lib_name;
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600386
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600387 char spec_version[64], version[64];
388
389 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
390 VK_MAJOR(ext_props.info.specVersion),
391 VK_MINOR(ext_props.info.specVersion),
392 VK_PATCH(ext_props.info.specVersion));
393 snprintf(version, sizeof(version), "%d.%d.%d",
394 VK_MAJOR(ext_props.info.version),
395 VK_MINOR(ext_props.info.version),
396 VK_PATCH(ext_props.info.version));
397
398 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
399 "Global Extension: %s (%s) version %s, Vulkan version %s",
400 ext_props.info.extName, lib_name, version, spec_version);
401 loader_add_to_ext_list(ext_list, 1, &ext_props);
402 }
403
404 return;
405}
406
407static void loader_add_global_layer_properties(
408 const char *lib_name,
409 const loader_platform_dl_handle lib_handle,
410 struct loader_layer_list *layer_list)
411{
412 uint32_t i, count;
413 VkLayerProperties *layer_properties;
414 PFN_vkGetGlobalExtensionProperties fp_get_ext_props;
415 PFN_vkGetGlobalLayerProperties fp_get_layer_props;
416 VkResult res;
417
418 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalExtensionProperties");
419 if (!fp_get_ext_props) {
420 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
421 "Couldn't dlsym vkGetGlobalExtensionProperties from library %s",
422 lib_name);
423 return;
424 }
425
426 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
427 if (!fp_get_layer_props) {
428 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
429 "Couldn't dlsym vkGetGlobalLayerProperties from library %s",
430 lib_name);
431 return;
432 }
433
434 res = fp_get_layer_props(&count, NULL);
435 if (res != VK_SUCCESS) {
436 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global layer count from %s", lib_name);
437 return;
438 }
439
440 if (count == 0) {
441 return;
442 }
443
444#ifdef WIN32
445 layer_properties = _alloca(count * sizeof(VkLayerProperties));
446#else
447 layer_properties = alloca(count * sizeof(VkLayerProperties));
448#endif
449
450 res = fp_get_layer_props(&count, layer_properties);
451 if (res != VK_SUCCESS) {
452 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting %d global layer properties from %s",
453 count, lib_name);
454 return;
455 }
456
457 for (i = 0; i < count; i++) {
458 struct loader_layer_properties *layer = &layer_list->list[layer_list->count];
459 layer->lib_info.lib_name = malloc(strlen(lib_name) + 1);
460 if (layer->lib_info.lib_name == NULL) {
461 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "layer library %s ignored: out of memory", lib_name);
462 return;
463 }
464
465 strcpy(layer->lib_info.lib_name, lib_name);
466 memcpy(&layer->info, &layer_properties[i], sizeof(VkLayerProperties));
467 loader_init_ext_list(&layer->instance_extension_list);
468 loader_init_ext_list(&layer->device_extension_list);
469 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for layer %s (%s)",
470 layer->info.layerName, layer->info.description);
471
472 loader_add_to_layer_list(layer_list, 1, layer);
473
474 loader_add_global_extensions(
475 fp_get_ext_props,
476 lib_name,
477 lib_handle,
478 VK_EXTENSION_ORIGIN_LAYER,
479 &layer->instance_extension_list);
480 }
481
482 return;
483}
484
485static void loader_add_physical_device_extensions(
486 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
487 VkPhysicalDevice physical_device,
488 const enum extension_origin origin,
489 const char *lib_name,
490 struct loader_extension_list *ext_list)
491{
492 uint32_t i, count;
493 VkResult res;
494 struct loader_extension_property ext_props;
495 VkExtensionProperties *extension_properties;
496
497 memset(&ext_props, 0, sizeof(ext_props));
498 ext_props.origin = origin;
499 ext_props.lib_name = lib_name;
500
501 if (get_phys_dev_ext_props) {
502 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
503 if (res == VK_SUCCESS && count > 0) {
504#ifdef WIN32
505 extension_properties = _alloca(count * sizeof(VkExtensionProperties));
506#else
507 extension_properties = alloca(count * sizeof(VkExtensionProperties));
508#endif
509 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties);
510 for (i = 0; i < count; i++) {
511 char spec_version[64], version[64];
512
513 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
514
515 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
516 VK_MAJOR(ext_props.info.specVersion),
517 VK_MINOR(ext_props.info.specVersion),
518 VK_PATCH(ext_props.info.specVersion));
519 snprintf(version, sizeof(version), "%d.%d.%d",
520 VK_MAJOR(ext_props.info.version),
521 VK_MINOR(ext_props.info.version),
522 VK_PATCH(ext_props.info.version));
523
524 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
525 "PhysicalDevice Extension: %s (%s) version %s, Vulkan version %s",
526 ext_props.info.extName, lib_name, version, spec_version);
527 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600528 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600529 } else {
530 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600531 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600532 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600533
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600534 return;
535}
536
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600537static void loader_add_physical_device_layer_properties(
538 struct loader_icd *icd,
539 char *lib_name,
540 const loader_platform_dl_handle lib_handle)
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600541{
542 uint32_t i, count;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600543 VkLayerProperties *layer_properties;
544 PFN_vkGetPhysicalDeviceExtensionProperties fp_get_ext_props;
545 PFN_vkGetPhysicalDeviceLayerProperties fp_get_layer_props;
546 VkPhysicalDevice gpu = icd->gpus[0];
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600547 VkResult res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600548
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600549 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties");
550 if (!fp_get_ext_props) {
551 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
552 "Couldn't dlsym vkGetPhysicalDeviceExtensionProperties from library %s",
553 lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600554 return;
555 }
556
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600557 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
558 if (!fp_get_layer_props) {
559 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
560 "Couldn't dlsym vkGetPhysicalDeviceLayerProperties from library %s",
561 lib_name);
562 return;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600563 }
564
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600565 /*
566 * NOTE: We assume that all GPUs of an ICD support the same PhysicalDevice
567 * layers and extensions. Thus only ask for info about the first gpu.
568 */
569 res = fp_get_layer_props(gpu, &count, NULL);
570 if (res != VK_SUCCESS) {
571 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting PhysicalDevice layer count from %s", lib_name);
572 return;
573 }
574
575 if (count == 0) {
576 return;
577 }
578
579#ifdef WIN32
580 layer_properties = _alloca(count * sizeof(VkLayerProperties));
581#else
582 layer_properties = alloca(count * sizeof(VkLayerProperties));
583#endif
584
585 res = fp_get_layer_props(gpu, &count, layer_properties);
586 if (res != VK_SUCCESS) {
587 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d PhysicalDevice layer properties from %s",
588 count, lib_name);
589 return;
590 }
591
592 for (i = 0; i < count; i++) {
593 struct loader_layer_properties layer;
594 memset(&layer, 0, sizeof(struct loader_layer_properties));
595 layer.lib_info.lib_name = lib_name;
596 memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
597 loader_init_ext_list(&layer.instance_extension_list);
598 loader_init_ext_list(&layer.device_extension_list);
599 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting PhysicalDevice extensions for layer %s (%s)",
600 layer.info.layerName, layer.info.description);
601 loader_add_to_layer_list(&icd->layer_properties_cache, 1, &layer);
602 loader_add_physical_device_extensions(
603 fp_get_ext_props,
604 icd->gpus[i],
605 VK_EXTENSION_ORIGIN_LAYER,
606 lib_name,
607 &layer.device_extension_list);
608 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600609 return;
610}
611
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600612static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600613{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600614 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
615 ext_info->list = malloc(ext_info->capacity);
616 if (ext_info->list == NULL) {
617 return false;
618 }
619 memset(ext_info->list, 0, ext_info->capacity);
620 ext_info->count = 0;
621 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600622}
623
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600624void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600625{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600626 free(ext_info->list);
627 ext_info->count = 0;
628 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600629}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600630
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600631/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600632 * Search the given search_list for any layers in the props list.
633 * Add these to the output layer_list. Don't add duplicates to the output layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600634 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600635static void loader_add_layer_names_to_list(
636 struct loader_layer_list *output_list,
637 uint32_t name_count,
638 const char * const *names,
639 const struct loader_layer_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600640{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600641 struct loader_layer_properties *layer_prop;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600642
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600643 for (uint32_t i = 0; i < name_count; i++) {
644 const char *search_target = names[i];
645 layer_prop = get_layer_property(search_target, search_list);
646 if (!layer_prop) {
647 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", search_target);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600648 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600649 }
650
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600651 loader_add_to_layer_list(output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600652 }
653}
654
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600655/*
656 * Append non-duplicate extension properties defined in prop_list
657 * to the given ext_info list
658 */
659void loader_add_to_ext_list(
660 struct loader_extension_list *ext_list,
661 uint32_t prop_list_count,
662 const struct loader_extension_property *props)
663{
664 uint32_t i;
665 struct loader_extension_property *cur_ext;
666
667 if (ext_list->list == NULL || ext_list->capacity == 0) {
668 loader_init_ext_list(ext_list);
669 }
670
671 if (ext_list->list == NULL)
672 return;
673
674 for (i = 0; i < prop_list_count; i++) {
675 cur_ext = (struct loader_extension_property *) &props[i];
676
677 // look for duplicates
678 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
679 continue;
680 }
681
682 // add to list at end
683 // check for enough capacity
684 if (ext_list->count * sizeof(struct loader_extension_property)
685 >= ext_list->capacity) {
686 // double capacity
687 ext_list->capacity *= 2;
688 ext_list->list = realloc(ext_list->list, ext_list->capacity);
689 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600690
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600691 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
692 ext_list->count++;
693 }
694}
695
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600696static bool loader_init_layer_list(struct loader_layer_list *list)
697{
698 list->capacity = 32 * sizeof(struct loader_layer_properties);
699 list->list = malloc(list->capacity);
700 if (list->list == NULL) {
701 return false;
702 }
703 memset(list->list, 0, list->capacity);
704 list->count = 0;
705 return true;
706}
707
708void loader_destroy_layer_list(struct loader_layer_list *layer_list)
709{
710 free(layer_list->list);
711 layer_list->count = 0;
712 layer_list->capacity = 0;
713}
714
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600715/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600716 * Search the given layer list for a list
717 * matching the given VkLayerProperties
718 */
719bool has_vk_layer_property(
720 const VkLayerProperties *vk_layer_prop,
721 const struct loader_layer_list *list)
722{
723 for (uint32_t i = 0; i < list->count; i++) {
724 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
725 return true;
726 }
727 return false;
728}
729
730/*
731 * Search the given layer list for a layer
732 * matching the given name
733 */
734bool has_layer_name(
735 const char *name,
736 const struct loader_layer_list *list)
737{
738 for (uint32_t i = 0; i < list->count; i++) {
739 if (strcmp(name, list->list[i].info.layerName) == 0)
740 return true;
741 }
742 return false;
743}
744
745/*
746 * Append non-duplicate layer properties defined in prop_list
747 * to the given layer_info list
748 */
749void loader_add_to_layer_list(
750 struct loader_layer_list *list,
751 uint32_t prop_list_count,
752 const struct loader_layer_properties *props)
753{
754 uint32_t i;
755 struct loader_layer_properties *layer;
756
757 if (list->list == NULL || list->capacity == 0) {
758 loader_init_layer_list(list);
759 }
760
761 if (list->list == NULL)
762 return;
763
764 for (i = 0; i < prop_list_count; i++) {
765 layer = (struct loader_layer_properties *) &props[i];
766
767 // look for duplicates
768 if (has_vk_layer_property(&layer->info, list)) {
769 continue;
770 }
771
772 // add to list at end
773 // check for enough capacity
774 if (list->count * sizeof(struct loader_layer_properties)
775 >= list->capacity) {
776 // double capacity
777 list->capacity *= 2;
778 list->list = realloc(list->list, list->capacity);
779 }
780
781 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
782 list->count++;
783 }
784}
785
786/*
787 * Search the search_list for any layer with
788 * a name that matches the given layer_name.
789 * Add all matching layers to the found_list
790 * Do not add if found VkLayerProperties is already
791 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600792 */
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600793static void loader_find_layer_name_add_list(
794 const char *name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600795 const struct loader_layer_list *search_list,
796 struct loader_layer_list *found_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600797{
798 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600799 struct loader_layer_properties *layer_prop = &search_list->list[i];
800 if (0 == strcmp(layer_prop->info.layerName, name)) {
801 /* Found a layer with the same name, add to found_list */
802 loader_add_to_layer_list(found_list, 1, layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600803 }
804 }
805}
806
807bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600808{
809 uint32_t i;
810
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600811 for (i = 0; i < loader.global_extensions.count; i++) {
812 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600813 return true;
814 }
815 return false;
816}
817
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600818/*
819 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
820 * the extension must provide two entry points for the loader to use:
821 * - "trampoline" entry point - this is the address returned by GetProcAddr
822 * and will always do what's necessary to support a global call.
823 * - "terminator" function - this function will be put at the end of the
824 * instance chain and will contain the necessary logica to call / process
825 * the extension for the appropriate ICDs that are available.
826 * There is no generic mechanism for including these functions, the references
827 * must be placed into the appropriate loader entry points.
828 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
829 * loader_coalesce_extensions(void) - add extension records to the list of global
830 * extension available to the app.
831 * instance_disp - add function pointer for terminator function to this array.
832 * The extension itself should be in a separate file that will be
833 * linked directly with the loader.
834 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600835void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600836{
837 uint32_t i;
838 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
839
840 // traverse scanned icd list adding non-duplicate extensions to the list
841 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600842 loader_add_to_ext_list(&loader.global_extensions,
843 icd_list->global_extension_list.count,
844 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600845 icd_list = icd_list->next;
846 };
847
848 //Traverse layers list adding non-duplicate extensions to the list
Jon Ashburn5ef20602015-07-02 09:40:15 -0600849 for (i = 0; i < loader.scanned_layers.count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600850 loader_add_to_ext_list(&loader.global_extensions,
Jon Ashburn5ef20602015-07-02 09:40:15 -0600851 loader.scanned_layers.list[i].instance_extension_list.count,
852 loader.scanned_layers.list[i].instance_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600853 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600854
855 // Traverse loader's extensions, adding non-duplicate extensions to the list
856 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600857}
858
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600859static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
860 struct loader_device **found_dev)
861{
862 *found_dev = NULL;
863 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
864 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
865 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
866 if (dev->device == device) {
867 *found_dev = dev;
868 return icd;
869 }
870 }
871 }
872 return NULL;
873}
874
875static void loader_destroy_logical_device(struct loader_device *dev)
876{
877 free(dev->app_extension_props);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600878 if (dev->activated_layer_list.count)
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600879 loader_destroy_layer_list(&dev->activated_layer_list);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600880 free(dev);
881}
882
883static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
884{
885 struct loader_device *new_dev;
886
887 new_dev = malloc(sizeof(struct loader_device));
888 if (!new_dev) {
889 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
890 return NULL;
891 }
892
893 memset(new_dev, 0, sizeof(struct loader_device));
894
895 new_dev->next = *device_list;
896 new_dev->device = dev;
897 *device_list = new_dev;
898 return new_dev;
899}
900
901void loader_remove_logical_device(VkDevice device)
902{
903 struct loader_device *found_dev, *dev, *prev_dev;
904 struct loader_icd *icd;
905 icd = loader_get_icd_and_device(device, &found_dev);
906
907 if (!icd || !found_dev)
908 return;
909
910 prev_dev = NULL;
911 dev = icd->logical_device_list;
912 while (dev && dev != found_dev) {
913 prev_dev = dev;
914 dev = dev->next;
915 }
916
917 if (prev_dev)
918 prev_dev->next = found_dev->next;
919 else
920 icd->logical_device_list = found_dev->next;
921 loader_destroy_logical_device(found_dev);
922}
923
924
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600925static void loader_icd_destroy(
926 struct loader_instance *ptr_inst,
927 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800928{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600929 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600930 free(icd->gpus);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600931 for (struct loader_device *dev = icd->logical_device_list; dev; ) {
932 struct loader_device *next_dev = dev->next;
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600933 loader_destroy_logical_device(dev);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600934 dev = next_dev;
935 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600936
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800937 free(icd);
938}
939
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600940static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800941{
942 struct loader_icd *icd;
943
944 icd = malloc(sizeof(*icd));
945 if (!icd)
946 return NULL;
947
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600948 memset(icd, 0, sizeof(*icd));
949
Jon Ashburn46d1f582015-01-28 11:01:35 -0700950 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800951
952 return icd;
953}
954
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600955static struct loader_icd *loader_icd_add(
956 struct loader_instance *ptr_inst,
957 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800958{
959 struct loader_icd *icd;
960
Jon Ashburn46d1f582015-01-28 11:01:35 -0700961 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800962 if (!icd)
963 return NULL;
964
Chia-I Wu13a61a52014-08-04 11:18:20 +0800965 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700966 icd->next = ptr_inst->icds;
967 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600968 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800969
970 return icd;
971}
972
Jon Ashburn46d1f582015-01-28 11:01:35 -0700973static void loader_scanned_icd_add(const char *filename)
974{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700975 loader_platform_dl_handle handle;
Jon Ashburn3da71f22015-05-14 12:43:38 -0600976 void *fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -0600977 void *fp_get_global_ext_props;
Tony Barbour59a47322015-06-24 16:06:58 -0600978 void *fp_get_device_ext_props;
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600979 PFN_vkGPA fp_get_proc_addr;
Jon Ashburn46d1f582015-01-28 11:01:35 -0700980 struct loader_scanned_icds *new_node;
981
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700982 // Used to call: dlopen(filename, RTLD_LAZY);
983 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -0700984 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600985 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -0700986 return;
987 }
988
989#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -0600990 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700991 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600992 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -0700993 return; \
994 } \
995} while (0)
996
Jon Ashburn46888392015-01-29 15:45:51 -0700997 LOOKUP(fp_create_inst, CreateInstance);
Tony Barbour59a47322015-06-24 16:06:58 -0600998 LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
Tony Barbour59a47322015-06-24 16:06:58 -0600999 LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001000 LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001001#undef LOOKUP
1002
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001003 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
1004 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001005 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001006 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -07001007 return;
1008 }
1009
1010 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -07001011 new_node->CreateInstance = fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -06001012 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001013 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001014 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001015 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001016
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001017 new_node->lib_name = (char *) (new_node + 1);
1018 if (!new_node->lib_name) {
1019 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
1020 return;
1021 }
1022 strcpy(new_node->lib_name, filename);
1023
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001024 loader.scanned_icd_list = new_node;
1025
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001026 loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -06001027 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001028 new_node->lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001029 handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001030 VK_EXTENSION_ORIGIN_ICD,
1031 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001032}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001033
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001034static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
1035{
1036 if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
1037 return &loader.global_extensions;
1038 }
1039
1040 /* TODO: Add code to query global extensions from layer */
1041 for (uint32_t i = 0; i < loader.scanned_layers.count; i++) {
1042 struct loader_layer_properties *work_layer = &loader.scanned_layers.list[i];
1043 if (strcmp(work_layer->info.layerName, pLayerName) == 0) {
1044 return &work_layer->instance_extension_list;
1045 }
1046 }
1047
1048 return NULL;
1049}
1050
1051static struct loader_layer_list *loader_global_layers()
1052{
1053 return &loader.scanned_layers;
1054}
1055
1056static void loader_physical_device_layers(
1057 struct loader_icd *icd,
1058 uint32_t *count,
1059 struct loader_layer_list **list)
1060{
1061 *count = icd->layer_properties_cache.count;
1062 *list = &icd->layer_properties_cache;
1063}
1064
1065static void loader_physical_device_extensions(
1066 struct loader_icd *icd,
1067 uint32_t gpu_idx,
1068 const char *layer_name,
1069 uint32_t *count,
1070 struct loader_extension_list **list)
1071{
1072 if (layer_name == NULL || (strlen(layer_name) == 0)) {
1073 *count = icd->device_extension_cache[gpu_idx].count;
1074 *list = &icd->device_extension_cache[gpu_idx];
1075 return;
1076 }
1077 for (uint32_t i = 0; i < icd->layer_properties_cache.count; i++) {
1078 if (strcmp(layer_name, icd->layer_properties_cache.list[i].info.layerName) == 0) {
1079 *count = icd->layer_properties_cache.list[i].device_extension_list.count;
1080 *list = &icd->layer_properties_cache.list[i].device_extension_list;
1081 }
1082 }
1083}
1084
Jon Ashburn3da71f22015-05-14 12:43:38 -06001085static void loader_icd_init_entrys(struct loader_icd *icd,
1086 struct loader_scanned_icds *scanned_icds)
1087{
1088 /* initialize entrypoint function pointers */
1089
1090 #define LOOKUP(func) do { \
1091 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
1092 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001093 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001094 return; \
1095 } \
1096 } while (0)
1097
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001098 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
1099 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001100 LOOKUP(DestroyInstance);
1101 LOOKUP(EnumeratePhysicalDevices);
Chris Forbesbc0bb772015-06-21 22:55:02 +12001102 LOOKUP(GetPhysicalDeviceFeatures);
1103 LOOKUP(GetPhysicalDeviceFormatInfo);
1104 LOOKUP(GetPhysicalDeviceLimits);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001105 LOOKUP(CreateDevice);
Tony Barbour59a47322015-06-24 16:06:58 -06001106 LOOKUP(GetPhysicalDeviceProperties);
1107 LOOKUP(GetPhysicalDeviceMemoryProperties);
1108 LOOKUP(GetPhysicalDevicePerformance);
1109 LOOKUP(GetPhysicalDeviceQueueCount);
1110 LOOKUP(GetPhysicalDeviceQueueProperties);
1111 LOOKUP(GetPhysicalDeviceExtensionProperties);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001112 LOOKUP(DbgCreateMsgCallback);
1113 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001114#undef LOOKUP
1115
1116 return;
1117}
1118
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001119static void loader_debug_init(void)
1120{
1121 const char *env;
1122
1123 if (g_loader_debug > 0)
1124 return;
1125
1126 g_loader_debug = 0;
1127
1128 /* parse comma-separated debug options */
1129 env = getenv("LOADER_DEBUG");
1130 while (env) {
1131 const char *p = strchr(env, ',');
1132 size_t len;
1133
1134 if (p)
1135 len = p - env;
1136 else
1137 len = strlen(env);
1138
1139 if (len > 0) {
1140 if (strncmp(env, "warn", len) == 0) {
1141 g_loader_debug |= LOADER_WARN_BIT;
1142 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1143 } else if (strncmp(env, "info", len) == 0) {
1144 g_loader_debug |= LOADER_INFO_BIT;
1145 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1146 } else if (strncmp(env, "perf", len) == 0) {
1147 g_loader_debug |= LOADER_PERF_BIT;
1148 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1149 } else if (strncmp(env, "error", len) == 0) {
1150 g_loader_debug |= LOADER_ERROR_BIT;
1151 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1152 } else if (strncmp(env, "debug", len) == 0) {
1153 g_loader_debug |= LOADER_DEBUG_BIT;
1154 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1155 }
1156 }
1157
1158 if (!p)
1159 break;
1160
1161 env = p + 1;
1162 }
1163}
1164
Jon Ashburn2077e382015-06-29 11:25:34 -06001165struct loader_manifest_files {
1166 uint32_t count;
1167 char **filename_list;
1168};
1169
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001170/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001171 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001172 *
1173 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001174 * A pointer to first char in the next path.
1175 * The next path (or NULL) in the list is returned in next_path.
1176 * Note: input string is modified in some cases. PASS IN A COPY!
1177 */
Jon Ashburn2077e382015-06-29 11:25:34 -06001178static char *loader_get_next_path(char *path)
1179{
1180 uint32_t len;
1181 char *next;
1182
1183 if (path == NULL)
1184 return NULL;
1185 next = strchr(path, PATH_SEPERATOR);
1186 if (next == NULL) {
1187 len = (uint32_t) strlen(path);
1188 next = path + len;
1189 }
1190 else {
1191 *next = '\0';
1192 next++;
1193 }
1194
1195 return next;
1196}
1197
1198/**
1199 * Given a filename (file) and a list of paths (dir), try to find an existing
1200 * file in the paths. If filename already is a path then no
1201 * searching in the given paths.
1202 *
1203 * \returns
1204 * A string in out_fullpath of either the full path or file.
1205 * Side effect is that dir string maybe modified.
1206 */
1207static void loader_get_fullpath(const char *file,
1208 char *dir,
1209 size_t out_size,
1210 char *out_fullpath)
1211{
1212 char *next_dir;
1213 if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1214 //find file exists with prepending given path
1215 while (*dir) {
1216 next_dir = loader_get_next_path(dir);
1217 snprintf(out_fullpath, out_size, "%s%c%s",
1218 dir, DIRECTORY_SYMBOL, file);
1219 if (loader_platform_file_exists(out_fullpath)) {
1220 return;
1221 }
1222 dir = next_dir;
1223 }
1224 }
1225 snprintf(out_fullpath, out_size, "%s", file);
1226}
1227
1228/**
1229 * Read a JSON file into a buffer.
1230 *
1231 * \returns
1232 * A pointer to a cJSON object representing the JSON parse tree.
1233 * This returned buffer should be freed by caller.
1234 */
1235static cJSON *loader_get_json(const char *filename)
1236{
1237 FILE *file;
1238 char *json_buf;
1239 cJSON *json;
1240 uint64_t len;
1241 file = fopen(filename,"rb");
1242 fseek(file, 0, SEEK_END);
1243 len = ftell(file);
1244 fseek(file, 0, SEEK_SET);
1245 json_buf = (char*) alloca(len+1);
1246 if (json_buf == NULL) {
1247 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1248 fclose(file);
1249 return NULL;
1250 }
1251 if (fread(json_buf, sizeof(char), len, file) != len) {
1252 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1253 fclose(file);
1254 return NULL;
1255 }
1256 fclose(file);
1257 json_buf[len] = '\0';
1258
1259 //parse text from file
1260 json = cJSON_Parse(json_buf);
1261 if (json == NULL)
1262 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1263 return json;
1264}
1265
1266/**
1267 * Find the Vulkan library manifest files.
1268 *
1269 * This function scans the location or env_override directories/files
1270 * for a list of JSON manifest files. If env_override is non-NULL
1271 * and has a valid value. Then the location is ignored. Otherwise
1272 * location is used to look for manifest files. The location
1273 * is interpreted as Registry path on Windows and a directory path(s)
1274 * on Linux.
1275 *
1276 * \returns
1277 * A string list of manifest files to be opened in out_files param.
1278 * List has a pointer to string for each manifest filename.
1279 * When done using the list in out_files, pointers should be freed.
Jon Ashburnffad94d2015-06-30 14:46:22 -07001280 * Location or override string lists can be either files or directories as follows:
1281 * | location | override
1282 * --------------------------------
1283 * Win ICD | files | files
1284 * Win Layer | files | dirs
1285 * Linux ICD | dirs | files
1286 * Linux Layer| dirs | dirs
Jon Ashburn2077e382015-06-29 11:25:34 -06001287 */
1288static void loader_get_manifest_files(const char *env_override,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001289 bool is_layer,
1290 const char *location,
1291 struct loader_manifest_files *out_files)
Jon Ashburn2077e382015-06-29 11:25:34 -06001292{
1293 char *override = NULL;
1294 char *loc;
1295 char *file, *next_file, *name;
1296 size_t alloced_count = 64;
1297 char full_path[2048];
1298 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001299 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06001300 struct dirent *dent;
1301
1302 out_files->count = 0;
1303 out_files->filename_list = NULL;
1304
Jon Ashburn2077e382015-06-29 11:25:34 -06001305 if (env_override != NULL && (override = getenv(env_override))) {
1306#if defined(__linux__)
1307 if (geteuid() != getuid()) {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001308 /* Don't allow setuid apps to use the env var: */
Jon Ashburn2077e382015-06-29 11:25:34 -06001309 override = NULL;
1310 }
1311#endif
1312 }
1313
1314 if (location == NULL) {
1315 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001316 "Can't get manifest files with NULL location, env_override=%s",
1317 env_override);
Jon Ashburn2077e382015-06-29 11:25:34 -06001318 return;
1319 }
1320
Jon Ashburnffad94d2015-06-30 14:46:22 -07001321#if defined(__linux__)
1322 list_is_dirs = (override == NULL || is_layer) ? true : false;
1323#else //WIN32
1324 list_is_dirs = (is_layer && override != NULL) ? true : false;
1325#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001326 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07001327 // Also handle getting the location(s) from registry on Windows
1328 if (override == NULL) {
1329#if defined (_WIN32)
1330 loc = loader_get_registry_files(location);
1331 if (loc == NULL) {
1332 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1333 return;
1334 }
1335#else
Jon Ashburn2077e382015-06-29 11:25:34 -06001336 loc = alloca(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001337 if (loc == NULL) {
1338 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1339 return;
1340 }
1341 strcpy(loc, location);
1342#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001343 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001344 else {
1345 loc = alloca(strlen(override) + 1);
1346 if (loc == NULL) {
1347 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1348 return;
1349 }
1350 strcpy(loc, override);
1351 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001352
1353 file = loc;
1354 while (*file) {
1355 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001356 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001357 sysdir = opendir(file);
1358 name = NULL;
1359 if (sysdir) {
1360 dent = readdir(sysdir);
1361 if (dent == NULL)
1362 break;
1363 name = &(dent->d_name[0]);
1364 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1365 name = full_path;
1366 }
1367 }
1368 else {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001369#if defined(__linux__)
1370 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06001371 char *dir;
1372 // make a copy of location so it isn't modified
1373 dir = alloca(strlen(location) + 1);
1374 if (dir == NULL) {
1375 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1376 return;
1377 }
1378 strcpy(dir, location);
1379
1380 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1381
1382 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001383#else // WIN32
1384 name = file;
1385#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001386 }
1387 while (name) {
1388 /* Look for files ending with ".json" suffix */
1389 uint32_t nlen = (uint32_t) strlen(name);
1390 const char *suf = name + nlen - 5;
1391 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1392 if (out_files->count == 0) {
1393 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1394 }
1395 else if (out_files->count == alloced_count) {
1396 out_files->filename_list = realloc(out_files->filename_list,
1397 alloced_count * sizeof(char *) * 2);
1398 alloced_count *= 2;
1399 }
1400 if (out_files->filename_list == NULL) {
1401 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1402 return;
1403 }
1404 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1405 if (out_files->filename_list[out_files->count] == NULL) {
1406 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1407 return;
1408 }
1409 strcpy(out_files->filename_list[out_files->count], name);
1410 out_files->count++;
Jon Ashburnf70f3612015-07-02 10:08:47 -06001411 } else if (!list_is_dirs) {
1412 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name);
Jon Ashburn2077e382015-06-29 11:25:34 -06001413 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001414 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001415 dent = readdir(sysdir);
1416 if (dent == NULL)
1417 break;
1418 name = &(dent->d_name[0]);
1419 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1420 name = full_path;
1421 }
1422 else {
1423 break;
1424 }
1425 }
1426 if (sysdir)
1427 closedir(sysdir);
1428 file = next_file;
1429 }
1430 return;
1431}
1432
1433/**
1434 * Try to find the Vulkan ICD driver(s).
1435 *
1436 * This function scans the default system loader path(s) or path
1437 * specified by the \c VK_ICD_FILENAMES environment variable in
1438 * order to find loadable VK ICDs manifest files. From these
1439 * manifest files it finds the ICD libraries.
1440 *
1441 * \returns
Jon Ashburn3a37aee2015-06-30 16:44:28 -06001442 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001443 */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001444void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001445{
Jon Ashburn2077e382015-06-29 11:25:34 -06001446 char *file_str;
1447 struct loader_manifest_files manifest_files;
1448
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001449
1450 // convenient place to initialize a mutex
1451 loader_platform_thread_create_mutex(&loader_lock);
1452
Jon Ashburn2077e382015-06-29 11:25:34 -06001453 // convenient place to initialize logging
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001454 loader_debug_init();
1455
Jon Ashburn2077e382015-06-29 11:25:34 -06001456 // Get a list of manifest files for ICDs
1457 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1458 &manifest_files);
1459 for (uint32_t i = 0; i < manifest_files.count; i++) {
1460 file_str = manifest_files.filename_list[i];
1461 if (file_str == NULL)
1462 continue;
1463
1464 cJSON *json, *icd_json;
1465 json = loader_get_json(file_str);
1466 icd_json = cJSON_GetObjectItem(json, "ICD");
1467 if (icd_json != NULL) {
1468 icd_json = cJSON_GetObjectItem(icd_json, "library_path");
1469 if (icd_json != NULL) {
1470 char *icd_filename = cJSON_PrintUnformatted(icd_json);
1471 char *icd_file = icd_filename;
1472 if (icd_filename != NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001473 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1474 char *dir = def_dir;
1475 // strip off extra quotes
1476 if (icd_filename[strlen(icd_filename) - 1] == '"')
1477 icd_filename[strlen(icd_filename) - 1] = '\0';
1478 if (icd_filename[0] == '"')
1479 icd_filename++;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001480#if defined(__linux__)
1481 char full_path[2048];
Jon Ashburn2077e382015-06-29 11:25:34 -06001482 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1483 loader_scanned_icd_add(full_path);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001484#else // WIN32
1485 loader_scanned_icd_add(icd_filename);
1486#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001487 free(icd_file);
1488 }
1489 }
1490 else
1491 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1492 }
1493 else
1494 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1495
1496 free(file_str);
1497 cJSON_Delete(json);
1498 }
1499 free(manifest_files.filename_list);
1500
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001501}
1502
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001503
Jon Ashburn5ef20602015-07-02 09:40:15 -06001504void loader_layer_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001505{
1506 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -07001507 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001508 DIR *curdir;
1509 struct dirent *dent;
Ian Elliott4470a302015-02-17 10:33:47 -07001510 size_t len, i;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001511 char temp_str[1024];
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001512
Ian Elliott4470a302015-02-17 10:33:47 -07001513#if defined(WIN32)
1514 bool must_free_libPaths;
1515 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
1516 LAYERS_PATH_REGISTRY_VALUE);
1517 if (libPaths != NULL) {
1518 must_free_libPaths = true;
1519 } else {
1520 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001521 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001522 }
Ian Elliott4470a302015-02-17 10:33:47 -07001523#else // WIN32
1524 if (geteuid() == getuid()) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001525 /* Don't allow setuid apps to use the LAYERS_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -07001526 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -07001527 }
1528 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001529 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -07001530 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001531#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001532
Ian Elliott4470a302015-02-17 10:33:47 -07001533 if (libPaths == NULL) {
1534 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001535 return;
1536 }
Ian Elliott4470a302015-02-17 10:33:47 -07001537 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001538 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -07001539 if (loader.layer_dirs == NULL) {
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06001540 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
1541
Ian Elliott4470a302015-02-17 10:33:47 -07001542 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -07001543 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001544 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001545 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott4470a302015-02-17 10:33:47 -07001546 strcpy(loader.layer_dirs, libPaths);
1547#if defined(WIN32)
1548 // Free any allocated memory:
1549 if (must_free_libPaths) {
1550 free(libPaths);
1551 must_free_libPaths = false;
1552 }
1553#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001554 libPaths = loader.layer_dirs;
1555
Jon Ashburn5ef20602015-07-02 09:40:15 -06001556 if (loader.scanned_layers.capacity == 0) {
1557 loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1558 if (loader.scanned_layers.list == NULL) {
1559 //TODO ERR log
1560 return;
1561 }
1562 memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1563 loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001564 }
Jon Ashburn5ef20602015-07-02 09:40:15 -06001565 else {
1566 /* cleanup any previously scanned libraries */
1567 //TODO make sure everything is cleaned up properly
1568 for (i = 0; i < loader.scanned_layers.count; i++) {
1569 if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
1570 free(loader.scanned_layers.list[i].lib_info.lib_name);
Jon Ashburn5ef20602015-07-02 09:40:15 -06001571 loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
1572 loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
1573 loader.scanned_layers.list[i].lib_info.lib_name = NULL;
1574 }
1575 loader.scanned_layers.count = 0;
1576 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001577
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001578 for (p = libPaths; *p; p = next) {
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001579 next = strchr(p, PATH_SEPERATOR);
1580 if (next == NULL) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001581 len = (uint32_t) strlen(p);
1582 next = p + len;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001583 }
1584 else {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001585 len = (uint32_t) (next - p);
1586 *(char *) next = '\0';
1587 next++;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001588 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001589
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001590 curdir = opendir(p);
1591 if (curdir) {
1592 dent = readdir(curdir);
1593 while (dent) {
1594 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
1595 * ending with VK_LIBRARY_SUFFIX
1596 */
1597 if (!strncmp(dent->d_name,
1598 VK_LAYER_LIBRARY_PREFIX,
1599 VK_LAYER_LIBRARY_PREFIX_LEN)) {
1600 uint32_t nlen = (uint32_t) strlen(dent->d_name);
1601 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
1602 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
1603 !strncmp(suf,
1604 VK_LIBRARY_SUFFIX,
1605 VK_LIBRARY_SUFFIX_LEN)) {
1606 loader_platform_dl_handle handle;
1607 snprintf(temp_str, sizeof(temp_str),
Jon Ashburn2077e382015-06-29 11:25:34 -06001608 "%s%c%s",p, DIRECTORY_SYMBOL, dent->d_name);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001609 // Used to call: dlopen(temp_str, RTLD_LAZY)
1610 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001611 "Attempt to open library: %s", temp_str);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001612 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001613 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed");
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001614 dent = readdir(curdir);
1615 continue;
1616 }
1617 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001618 "Opened library: %s", temp_str);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001619
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001620 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for %s", temp_str);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001621
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001622 loader_add_global_layer_properties(temp_str, handle, &loader.scanned_layers);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001623
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001624 loader_platform_close_library(handle);
1625 }
1626 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001627
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001628 dent = readdir(curdir);
1629 } // while (dir_entry)
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001630 closedir(curdir);
1631 } // if (curdir))
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001632 } // for (libpaths)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001633}
1634
Jon Ashburn27cd5842015-05-12 17:26:48 -06001635static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1636{
1637 // inst is not wrapped
1638 if (inst == VK_NULL_HANDLE) {
1639 return NULL;
1640 }
1641 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1642 void *addr;
1643
Jon Ashburn8fd08252015-05-28 16:25:02 -06001644 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1645 return (void *) loader_gpa_instance_internal;
1646
Jon Ashburn27cd5842015-05-12 17:26:48 -06001647 if (disp_table == NULL)
1648 return NULL;
1649
1650 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001651 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001652 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001653 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001654
1655 if (disp_table->GetInstanceProcAddr == NULL) {
1656 return NULL;
1657 }
1658 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001659}
1660
Jon Ashburn128f9422015-05-28 19:16:58 -06001661struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001662{
Jon Ashburn128f9422015-05-28 19:16:58 -06001663
Jon Ashburn98bd4542015-01-29 16:44:24 -07001664 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1665 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1666 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -06001667 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -07001668 *gpu_index = i;
1669 return icd;
1670 }
1671 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001672 }
1673 return NULL;
1674}
1675
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001676static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -06001677 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001678 struct loader_layer_properties *layer_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001679{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001680 struct loader_lib_info *new_layer_lib_list, *my_lib;
1681
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001682 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001683 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001684 /* Have already loaded this library, just increment ref count */
1685 loader.loaded_layer_lib_list[i].ref_count++;
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001686 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001687 "%s Chain: Increment layer reference count for layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001688 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001689 return loader.loaded_layer_lib_list[i].lib_handle;
1690 }
1691 }
1692
1693 /* Haven't seen this library so load it */
1694 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1695 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1696 if (!new_layer_lib_list) {
1697 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1698 return NULL;
1699 }
1700
1701 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1702
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001703 /* NOTE: We require that the layer property be immutable */
1704 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001705 my_lib->ref_count = 0;
1706 my_lib->lib_handle = NULL;
1707
1708 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1709 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1710 loader_platform_open_library_error(my_lib->lib_name));
1711 return NULL;
1712 } else {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001713 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001714 "Chain: %s: Loading layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001715 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001716 }
1717 loader.loaded_layer_lib_count++;
1718 loader.loaded_layer_lib_list = new_layer_lib_list;
1719 my_lib->ref_count++;
1720
1721 return my_lib->lib_handle;
1722}
1723
1724static void loader_remove_layer_lib(
1725 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001726 struct loader_layer_properties *layer_prop)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001727{
1728 uint32_t idx;
1729 struct loader_lib_info *new_layer_lib_list, *my_lib;
1730
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001731 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001732 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001733 /* found matching library */
1734 idx = i;
1735 my_lib = &loader.loaded_layer_lib_list[i];
1736 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001737 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001738 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001739
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001740 my_lib->ref_count--;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001741 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001742 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001743 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001744 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001745 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001746
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001747 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001748 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001749 "Unloading layer library %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001750
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001751 /* Need to remove unused library from list */
1752 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1753 if (!new_layer_lib_list) {
1754 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1755 return;
1756 }
1757
1758 if (idx > 0) {
1759 /* Copy records before idx */
1760 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1761 sizeof(struct loader_lib_info) * idx);
1762 }
1763 if (idx < (loader.loaded_layer_lib_count - 1)) {
1764 /* Copy records after idx */
1765 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1766 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1767 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001768
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001769 free(loader.loaded_layer_lib_list);
1770 loader.loaded_layer_lib_count--;
1771 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001772}
1773
Jon Ashburn0c26e712015-07-02 16:10:32 -06001774static void loader_add_layer_implicit(
1775 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001776 struct loader_layer_list *list,
1777 struct loader_layer_list *search_list)
Jon Ashburn0c26e712015-07-02 16:10:32 -06001778{
1779 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001780 for (i = 0; i < search_list->count; i++) {
1781 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06001782 if (prop->type & type) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001783 /* Found an layer with the same type, add to layer_list */
1784 loader_add_to_layer_list(list, 1, prop);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001785 }
1786 }
1787
1788}
1789
1790/**
1791 * Get the layer name(s) from the env_name environment variable. If layer
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001792 * is found in search_list then add it to layer_list.
Jon Ashburn0c26e712015-07-02 16:10:32 -06001793 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001794static void loader_add_layer_env(
Jon Ashburneb6d5682015-07-02 14:10:53 -06001795 const char *env_name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001796 struct loader_layer_list *layer_list,
1797 const struct loader_layer_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001798{
Ian Elliott4470a302015-02-17 10:33:47 -07001799 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06001800 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001801
Jon Ashburneb6d5682015-07-02 14:10:53 -06001802 layerEnv = getenv(env_name);
Ian Elliott4470a302015-02-17 10:33:47 -07001803 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001804 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001805 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06001806 name = alloca(strlen(layerEnv) + 1);
1807 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001808 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001809 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06001810 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001811
Jon Ashburneb6d5682015-07-02 14:10:53 -06001812 while (name && *name ) {
1813 next = loader_get_next_path(name);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001814 loader_find_layer_name_add_list(name, search_list, layer_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001815 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001816 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001817
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001818 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001819}
1820
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001821void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001822{
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001823 if (!instance->activated_layer_list.count) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001824 return;
1825 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001826
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001827 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001828 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001829 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001830
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001831 loader_remove_layer_lib(instance, layer_prop);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001832 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001833 loader_destroy_layer_list(&instance->activated_layer_list);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001834}
1835
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001836void loader_enable_instance_layers(
1837 struct loader_instance *inst,
1838 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001839{
1840 if (inst == NULL)
1841 return;
1842
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001843 if (!loader_init_layer_list(&inst->activated_layer_list)) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001844 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
1845 return;
1846 }
1847
Jon Ashburn0c26e712015-07-02 16:10:32 -06001848 /* Add any implicit layers first */
1849 loader_add_layer_implicit(
1850 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
1851 &inst->activated_layer_list,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001852 &loader.scanned_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001853
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001854 /* Add any layers specified via environment variable first */
Jon Ashburneb6d5682015-07-02 14:10:53 -06001855 loader_add_layer_env(
1856 "VK_INSTANCE_LAYERS",
1857 &inst->activated_layer_list,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001858 &loader.scanned_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001859
1860 /* Add layers specified by the application */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001861 loader_add_layer_names_to_list(
1862 &inst->activated_layer_list,
1863 pCreateInfo->layerCount,
1864 pCreateInfo->ppEnabledLayerNames,
1865 &loader.scanned_layers);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001866}
1867
Jon Ashburn27cd5842015-05-12 17:26:48 -06001868uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1869{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001870 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06001871 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001872
David Pinedoa0a8a242015-06-24 15:29:18 -06001873 if (inst == NULL) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001874 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06001875 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001876
1877 // NOTE inst is unwrapped at this point in time
1878 VkObject baseObj = (VkObject) inst;
1879 VkObject nextObj = (VkObject) inst;
1880 VkBaseLayerObject *nextInstObj;
1881 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1882
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001883 if (!inst->activated_layer_list.count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001884 return 0;
1885 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001886
Jon Ashburn128f9422015-05-28 19:16:58 -06001887 wrappedInstance = malloc(sizeof(VkBaseLayerObject)
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001888 * inst->activated_layer_list.count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001889 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001890 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1891 return 0;
1892 }
1893
1894 /* Create instance chain of enabled layers */
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001895 layer_idx = inst->activated_layer_list.count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001896 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001897 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001898 loader_platform_dl_handle lib_handle;
1899
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001900 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001901 * Note: An extension's Get*ProcAddr should not return a function pointer for
1902 * any extension entry points until the extension has been enabled.
1903 * To do this requires a different behavior from Get*ProcAddr functions implemented
1904 * in layers.
1905 * The very first call to a layer will be it's Get*ProcAddr function requesting
1906 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1907 * with the wrapped object given (either Instance or Device) and return the layer's
1908 * Get*ProcAddr function. The layer should also use this opportunity to record the
1909 * baseObject so that it can find the correct local dispatch table on future calls.
1910 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1911 * will not use a wrapped object and must look up their local dispatch table from
1912 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001913 */
Jon Ashburn128f9422015-05-28 19:16:58 -06001914 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001915 nextInstObj->pGPA = nextGPA;
1916 nextInstObj->baseObject = baseObj;
1917 nextInstObj->nextObject = nextObj;
1918 nextObj = (VkObject) nextInstObj;
1919
1920 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001921 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
1922 lib_handle = loader_add_layer_lib("instance", layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001923 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1924 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001925 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001926 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001927
1928 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001929 continue;
1930 }
1931
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001932 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001933 "Insert instance layer %s (%s)",
1934 layer_prop->info.layerName,
1935 layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001936
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001937 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001938 }
1939
Jon Ashburn8fd08252015-05-28 16:25:02 -06001940 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001941
Jon Ashburn128f9422015-05-28 19:16:58 -06001942 free(wrappedInstance);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001943 return inst->activated_layer_list.count;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001944}
1945
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001946void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1947{
1948
1949 loader_init_instance_extension_dispatch_table(inst->disp,
1950 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06001951 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001952}
1953
Courtney Goeltzenleuchtera6628c22015-06-25 16:27:24 -06001954static void loader_enable_device_layers(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001955 struct loader_device *dev,
1956 const VkDeviceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001957{
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001958 if (dev == NULL)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001959 return;
1960
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001961 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001962 loader_init_layer_list(&dev->activated_layer_list);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001963 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001964
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001965 if (dev->activated_layer_list.list == NULL) {
1966 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
1967 return;
1968 }
1969
Jon Ashburn0c26e712015-07-02 16:10:32 -06001970 /* Add any implicit layers first */
1971 loader_add_layer_implicit(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001972 VK_LAYER_TYPE_DEVICE_IMPLICIT,
1973 &dev->activated_layer_list,
1974 &loader.scanned_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001975
1976 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06001977 loader_add_layer_env(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001978 "VK_DEVICE_LAYERS",
1979 &dev->activated_layer_list,
1980 &loader.scanned_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001981
1982 /* Add layers specified by the application */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001983 loader_add_layer_names_to_list(
1984 &dev->activated_layer_list,
1985 pCreateInfo->layerCount,
1986 pCreateInfo->ppEnabledLayerNames,
1987 &loader.scanned_layers);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001988}
1989
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001990/*
1991 * This function terminates the device chain fro CreateDevice.
1992 * CreateDevice is a special case and so the loader call's
1993 * the ICD's CreateDevice before creating the chain. Since
1994 * we can't call CreateDevice twice we must terminate the
1995 * device chain with something else.
1996 */
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06001997static VkResult scratch_vkCreateDevice(
1998 VkPhysicalDevice gpu,
1999 const VkDeviceCreateInfo *pCreateInfo,
2000 VkDevice *pDevice)
2001{
2002 return VK_SUCCESS;
2003}
2004
2005static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2006{
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002007 if (!strcmp(name, "vkGetDeviceProcAddr"))
2008 return (void *) loader_GetDeviceChainProcAddr;
2009 if (!strcmp(name, "vkCreateDevice"))
2010 return (void *) scratch_vkCreateDevice;
2011
Courtney Goeltzenleuchter3e029d12015-06-29 16:09:23 -06002012 struct loader_device *found_dev;
2013 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2014 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002015}
2016
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002017static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002018 VkPhysicalDevice gpu,
2019 VkDevice device,
2020 struct loader_device *dev,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002021 struct loader_icd *icd)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002022{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002023 if (!icd)
2024 return 0;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002025
David Pinedoa0a8a242015-06-24 15:29:18 -06002026 if (!dev) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002027 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002028 }
Jon Ashburn94e70492015-06-10 10:13:10 -06002029
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002030 /* activate any layer libraries */
Jon Ashburn94e70492015-06-10 10:13:10 -06002031 VkObject nextObj = (VkObject) device;
2032 VkObject baseObj = nextObj;
2033 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002034 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn94e70492015-06-10 10:13:10 -06002035 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002036
Jon Ashburn94e70492015-06-10 10:13:10 -06002037 if (!dev->activated_layer_list.count)
2038 return 0;
2039
2040 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2041 if (!wrappedGpus) {
2042 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2043 return 0;
2044 }
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002045
Jon Ashburn94e70492015-06-10 10:13:10 -06002046 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2047
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002048 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
Jon Ashburn94e70492015-06-10 10:13:10 -06002049 loader_platform_dl_handle lib_handle;
2050
Jon Ashburn94e70492015-06-10 10:13:10 -06002051 nextGpuObj = (wrappedGpus + i);
2052 nextGpuObj->pGPA = nextGPA;
2053 nextGpuObj->baseObject = baseObj;
2054 nextGpuObj->nextObject = nextObj;
2055 nextObj = (VkObject) nextGpuObj;
2056
2057 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002058 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2059 lib_handle = loader_add_layer_lib("device", layer_prop);
Jon Ashburn94e70492015-06-10 10:13:10 -06002060 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2061 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2062 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002063 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->info.layerName);
Jon Ashburn94e70492015-06-10 10:13:10 -06002064 continue;
2065 }
2066
2067 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002068 "Insert device layer library %s (%s)",
2069 layer_prop->info.layerName,
2070 layer_prop->lib_info.lib_name);
Jon Ashburn94e70492015-06-10 10:13:10 -06002071
2072 }
2073
2074 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2075 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
2076 free(wrappedGpus);
2077
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002078 return dev->activated_layer_list.count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002079}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002080
Jon Ashburn27cd5842015-05-12 17:26:48 -06002081VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002082 const VkInstanceCreateInfo* pCreateInfo,
2083 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002084{
Jon Ashburneed0c002015-05-21 17:42:17 -06002085 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07002086 struct loader_scanned_icds *scanned_icds;
2087 struct loader_icd *icd;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002088 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002089
Jon Ashburn46888392015-01-29 15:45:51 -07002090 scanned_icds = loader.scanned_icd_list;
2091 while (scanned_icds) {
2092 icd = loader_icd_add(ptr_instance, scanned_icds);
2093 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -06002094 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn3da71f22015-05-14 12:43:38 -06002095 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002096 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07002097 {
2098 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002099 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002100 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002101 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07002102 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06002103 } else
2104 {
2105 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07002106 }
2107 }
2108 scanned_icds = scanned_icds->next;
2109 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002110
Ian Elliotteb450762015-02-05 15:19:15 -07002111 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002112 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -07002113 }
Jon Ashburn46888392015-01-29 15:45:51 -07002114
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002115 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002116}
2117
Jon Ashburn27cd5842015-05-12 17:26:48 -06002118VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002119 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002120{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06002121 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002122 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002123 struct loader_icd *next_icd;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002124 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002125
2126 // Remove this instance from the list of instances:
2127 struct loader_instance *prev = NULL;
2128 struct loader_instance *next = loader.instances;
2129 while (next != NULL) {
2130 if (next == ptr_instance) {
2131 // Remove this instance from the list:
2132 if (prev)
2133 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07002134 else
2135 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002136 break;
2137 }
2138 prev = next;
2139 next = next->next;
2140 }
2141 if (next == NULL) {
2142 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002143 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002144 }
2145
Jon Ashburn3da71f22015-05-14 12:43:38 -06002146 while (icds) {
2147 if (icds->instance) {
2148 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06002149 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002150 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06002151 "ICD ignored: failed to DestroyInstance on device");
2152 }
Jon Ashburna6fd2612015-06-16 14:43:19 -06002153 next_icd = icds->next;
Jon Ashburn3da71f22015-05-14 12:43:38 -06002154 icds->instance = VK_NULL_HANDLE;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002155 loader_icd_destroy(ptr_instance, icds);
2156
2157 icds = next_icd;
Jon Ashburn46888392015-01-29 15:45:51 -07002158 }
2159
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002160
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002161 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002162}
2163
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002164VkResult loader_init_physical_device_info(
2165 struct loader_instance *ptr_instance)
2166{
2167 struct loader_icd *icd;
2168 uint32_t n, count = 0;
2169 VkResult res = VK_ERROR_UNKNOWN;
2170
2171 icd = ptr_instance->icds;
2172 while (icd) {
2173 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2174 if (res != VK_SUCCESS)
2175 return res;
2176 icd->gpu_count = n;
2177 count += n;
2178 icd = icd->next;
2179 }
2180
2181 ptr_instance->total_gpu_count = count;
2182
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002183 icd = ptr_instance->icds;
2184 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002185
2186 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06002187 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2188 if (!icd->gpus) {
2189 /* TODO: Add cleanup code here */
2190 return VK_ERROR_OUT_OF_HOST_MEMORY;
2191 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002192 res = icd->EnumeratePhysicalDevices(
2193 icd->instance,
2194 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06002195 icd->gpus);
2196 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002197
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002198 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002199
Jon Ashburn128f9422015-05-28 19:16:58 -06002200 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002201
2202 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2203 /* TODO: Add cleanup code here */
2204 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2205 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002206 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002207
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002208 loader_add_physical_device_extensions(
2209 icd->GetPhysicalDeviceExtensionProperties,
2210 icd->gpus[0],
2211 VK_EXTENSION_ORIGIN_ICD,
2212 icd->scanned_icds->lib_name,
2213 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002214
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002215 for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
2216 loader_platform_dl_handle lib_handle;
2217 char *lib_name = loader.scanned_layers.list[i].lib_info.lib_name;
2218
2219 lib_handle = loader_platform_open_library(lib_name);
2220 if (lib_handle == NULL) {
2221 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed: %s", lib_name);
2222 continue;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002223 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002224 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2225 "library: %s", lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002226
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002227 loader_add_physical_device_layer_properties(
2228 icd, lib_name, lib_handle);
2229
2230 loader_platform_close_library(lib_handle);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002231 }
2232 }
2233
2234 if (res != VK_SUCCESS) {
2235 /* clean up any extension lists previously created before this request failed */
2236 for (uint32_t j = 0; j < i; j++) {
2237 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2238 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002239
2240 loader_destroy_layer_list(&icd->layer_properties_cache);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002241 return res;
2242 }
2243 }
2244
2245 count += n;
2246 }
2247
2248 icd = icd->next;
2249 }
2250
2251 return VK_SUCCESS;
2252}
2253
Jon Ashburn27cd5842015-05-12 17:26:48 -06002254VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06002255 VkInstance instance,
2256 uint32_t* pPhysicalDeviceCount,
2257 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002258{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002259 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002260 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002261 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002262
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002263 if (ptr_instance->total_gpu_count == 0) {
2264 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002265 }
2266
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002267 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2268 if (!pPhysicalDevices) {
2269 return VK_SUCCESS;
2270 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002271
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002272 while (icd) {
2273 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06002274 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002275 index += icd->gpu_count;
2276 icd = icd->next;
2277 }
2278
2279 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002280}
2281
Tony Barbour59a47322015-06-24 16:06:58 -06002282VkResult loader_GetPhysicalDeviceProperties(
Jon Ashburn3da71f22015-05-14 12:43:38 -06002283 VkPhysicalDevice gpu,
Tony Barbour59a47322015-06-24 16:06:58 -06002284 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn3da71f22015-05-14 12:43:38 -06002285{
2286 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002287 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002288 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2289
Tony Barbour59a47322015-06-24 16:06:58 -06002290 if (icd->GetPhysicalDeviceProperties)
2291 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2292
2293 return res;
2294}
2295
2296VkResult loader_GetPhysicalDevicePerformance(
2297 VkPhysicalDevice gpu,
2298 VkPhysicalDevicePerformance* pPerformance)
2299{
2300 uint32_t gpu_index;
2301 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2302 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2303
2304 if (icd->GetPhysicalDevicePerformance)
2305 res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2306
2307 return res;
2308}
2309
2310VkResult loader_GetPhysicalDeviceQueueCount(
2311 VkPhysicalDevice gpu,
2312 uint32_t* pCount)
2313{
2314 uint32_t gpu_index;
2315 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2316 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2317
2318 if (icd->GetPhysicalDeviceQueueCount)
2319 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2320
2321 return res;
2322}
2323
2324VkResult loader_GetPhysicalDeviceQueueProperties (
2325 VkPhysicalDevice gpu,
2326 uint32_t count,
2327 VkPhysicalDeviceQueueProperties * pProperties)
2328{
2329 uint32_t gpu_index;
2330 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2331 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2332
2333 if (icd->GetPhysicalDeviceQueueProperties)
2334 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2335
2336 return res;
2337}
2338
2339VkResult loader_GetPhysicalDeviceMemoryProperties (
2340 VkPhysicalDevice gpu,
2341 VkPhysicalDeviceMemoryProperties* pProperties)
2342{
2343 uint32_t gpu_index;
2344 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2345 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2346
2347 if (icd->GetPhysicalDeviceMemoryProperties)
2348 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002349
2350 return res;
2351}
2352
Chris Forbesbc0bb772015-06-21 22:55:02 +12002353VkResult loader_GetPhysicalDeviceFeatures(
2354 VkPhysicalDevice physicalDevice,
2355 VkPhysicalDeviceFeatures* pFeatures)
2356{
2357 uint32_t gpu_index;
2358 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2359 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2360
2361 if (icd->GetPhysicalDeviceFeatures)
2362 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2363
2364 return res;
2365}
2366
2367VkResult loader_GetPhysicalDeviceFormatInfo(
2368 VkPhysicalDevice physicalDevice,
2369 VkFormat format,
2370 VkFormatProperties* pFormatInfo)
2371{
2372 uint32_t gpu_index;
2373 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2374 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2375
2376 if (icd->GetPhysicalDeviceFormatInfo)
2377 res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2378
2379 return res;
2380}
2381
2382VkResult loader_GetPhysicalDeviceLimits(
2383 VkPhysicalDevice physicalDevice,
2384 VkPhysicalDeviceLimits* pLimits)
2385{
2386 uint32_t gpu_index;
2387 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2388 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2389
2390 if (icd->GetPhysicalDeviceLimits)
2391 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2392
2393 return res;
2394}
2395
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002396VkResult loader_CreateDevice(
2397 VkPhysicalDevice gpu,
2398 const VkDeviceCreateInfo* pCreateInfo,
2399 VkDevice* pDevice)
2400{
2401 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002402 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002403 struct loader_device *dev;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002404 VkResult res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002405
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002406 if (!icd->CreateDevice) {
2407 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002408 }
2409
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002410 /*
2411 * TODO: Must filter CreateInfo extension list to only
2412 * those extensions supported by the ICD.
2413 * TODO: Probably should verify that every extension is
2414 * covered by either the ICD or some layer.
2415 */
2416
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002417 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2418 if (res != VK_SUCCESS) {
2419 return res;
2420 }
2421
2422 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2423 if (dev == NULL) {
2424 return VK_ERROR_OUT_OF_HOST_MEMORY;
2425 }
2426 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2427 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2428 icd->gpus[gpu_index], icd->gpus[gpu_index]);
2429
2430 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2431 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2432
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002433 /*
2434 * Put together the complete list of extensions to enable
2435 * This includes extensions requested via environment variables.
2436 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002437 loader_enable_device_layers(dev, pCreateInfo);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002438
2439 /*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002440 * Load the libraries and build the device chain
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002441 * terminating with the selected device.
2442 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002443 loader_activate_device_layers(gpu, *pDevice, dev, icd);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002444
2445 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2446
2447 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2448
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002449 return res;
2450}
2451
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002452static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002453{
Jon Ashburn07daee72015-05-21 18:13:33 -06002454 if (instance == VK_NULL_HANDLE)
2455 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002456
Jon Ashburn07daee72015-05-21 18:13:33 -06002457 void *addr;
2458 /* get entrypoint addresses that are global (in the loader)*/
2459 addr = globalGetProcAddr(pName);
2460 if (addr)
2461 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002462
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002463 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2464
Jon Ashburn922c8f62015-06-18 09:05:37 -06002465 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002466 addr = debug_report_instance_gpa(ptr_instance, pName);
2467 if (addr) {
2468 return addr;
2469 }
2470
Jon Ashburn922c8f62015-06-18 09:05:37 -06002471 /* TODO Remove this once WSI has no loader special code */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002472 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002473 if (addr) {
Jon Ashburn922c8f62015-06-18 09:05:37 -06002474 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002475 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002476
2477 /* return the instance dispatch table entrypoint for extensions */
2478 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2479 if (disp_table == NULL)
2480 return NULL;
2481
2482 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2483 if (addr)
2484 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002485
2486 return NULL;
2487}
2488
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002489LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2490{
2491 return loader_GetInstanceProcAddr(instance, pName);
2492}
2493
2494static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002495{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002496 if (device == VK_NULL_HANDLE) {
2497 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07002498 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002499
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002500 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002501
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002502 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2503 make sure the loader entrypoint is returned */
2504 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06002505 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002506 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06002507 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002508
Jon Ashburn07daee72015-05-21 18:13:33 -06002509 /* return any extension device entrypoints the loader knows about */
Jon Ashburn922c8f62015-06-18 09:05:37 -06002510 /* TODO once WSI has no loader special code remove this */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002511 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002512 if (addr) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002513 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002514 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002515
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002516 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002517 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002518 if (disp_table == NULL)
2519 return NULL;
2520
Jon Ashburn27cd5842015-05-12 17:26:48 -06002521 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002522 if (addr)
2523 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002524 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002525 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002526 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002527 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002528 }
2529}
2530
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002531LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2532{
2533 return loader_GetDeviceProcAddr(device, pName);
2534}
2535
Tony Barbour59a47322015-06-24 16:06:58 -06002536LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002537 const char* pLayerName,
2538 uint32_t* pCount,
2539 VkExtensionProperties* pProperties)
2540{
2541 struct loader_extension_list *global_extension_list;
2542
2543 /* Scan/discover all ICD libraries in a single-threaded manner */
2544 loader_platform_thread_once(&once_icd, loader_icd_scan);
2545
2546 /* get layer libraries in a single-threaded manner */
2547 loader_platform_thread_once(&once_layer, loader_layer_scan);
2548
2549 /* merge any duplicate extensions */
2550 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2551
2552 uint32_t copy_size;
2553
2554 if (pCount == NULL) {
2555 return VK_ERROR_INVALID_POINTER;
2556 }
2557
2558 loader_platform_thread_lock_mutex(&loader_lock);
2559
2560 global_extension_list = loader_global_extensions(pLayerName);
2561 if (global_extension_list == NULL) {
2562 loader_platform_thread_unlock_mutex(&loader_lock);
2563 return VK_ERROR_INVALID_LAYER;
2564 }
2565
2566 if (pProperties == NULL) {
2567 *pCount = global_extension_list->count;
2568 loader_platform_thread_unlock_mutex(&loader_lock);
2569 return VK_SUCCESS;
2570 }
2571
2572 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2573 for (uint32_t i = 0; i < copy_size; i++) {
2574 memcpy(&pProperties[i],
2575 &global_extension_list->list[i].info,
2576 sizeof(VkExtensionProperties));
2577 }
2578 *pCount = copy_size;
2579
2580 loader_platform_thread_unlock_mutex(&loader_lock);
2581
2582 if (copy_size < global_extension_list->count) {
2583 return VK_INCOMPLETE;
2584 }
2585
2586 return VK_SUCCESS;
2587}
2588
2589LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2590 uint32_t* pCount,
2591 VkLayerProperties* pProperties)
Tony Barbour59a47322015-06-24 16:06:58 -06002592{
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002593
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002594 /* Scan/discover all ICD libraries in a single-threaded manner */
2595 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002596
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002597 /* get layer libraries in a single-threaded manner */
Jon Ashburn5ef20602015-07-02 09:40:15 -06002598 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002599
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002600 /* merge any duplicate extensions */
2601 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2602
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002603 uint32_t copy_size;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002604
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002605 if (pCount == NULL) {
2606 return VK_ERROR_INVALID_POINTER;
2607 }
2608
2609 /* TODO: do we still need to lock */
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002610 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002611
2612 struct loader_layer_list *layer_list;
2613 layer_list = loader_global_layers();
2614
2615 if (pProperties == NULL) {
2616 *pCount = layer_list->count;
2617 loader_platform_thread_unlock_mutex(&loader_lock);
2618 return VK_SUCCESS;
2619 }
2620
2621 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
2622 for (uint32_t i = 0; i < copy_size; i++) {
2623 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
2624 }
2625 *pCount = copy_size;
Tony Barbour59a47322015-06-24 16:06:58 -06002626
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002627 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002628
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002629 if (copy_size < layer_list->count) {
2630 return VK_INCOMPLETE;
2631 }
Tony Barbour59a47322015-06-24 16:06:58 -06002632
2633 return VK_SUCCESS;
2634}
2635
2636VkResult loader_GetPhysicalDeviceExtensionProperties(
2637 VkPhysicalDevice gpu,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002638 const char* pLayerName,
2639 uint32_t* pCount,
Tony Barbour59a47322015-06-24 16:06:58 -06002640 VkExtensionProperties* pProperties)
2641{
2642 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002643 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002644 uint32_t copy_size;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002645
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002646 if (pCount == NULL) {
2647 return VK_ERROR_INVALID_POINTER;
2648 }
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002649
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002650 uint32_t count;
2651 struct loader_extension_list *list;
2652 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
2653
2654 if (pProperties == NULL) {
2655 *pCount = count;
2656 return VK_SUCCESS;
2657 }
2658
2659 copy_size = *pCount < count ? *pCount : count;
2660 for (uint32_t i = 0; i < copy_size; i++) {
2661 memcpy(&pProperties[i],
2662 &list->list[i].info,
2663 sizeof(VkExtensionProperties));
2664 }
2665 *pCount = copy_size;
2666
2667 if (copy_size < count) {
2668 return VK_INCOMPLETE;
2669 }
2670
2671 return VK_SUCCESS;
2672}
2673
2674VkResult loader_GetPhysicalDeviceLayerProperties(
2675 VkPhysicalDevice gpu,
2676 uint32_t* pCount,
2677 VkLayerProperties* pProperties)
2678{
2679 uint32_t gpu_index;
2680 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2681 uint32_t copy_size;
2682
2683 if (pCount == NULL) {
2684 return VK_ERROR_INVALID_POINTER;
2685 }
2686
2687 uint32_t count;
2688 struct loader_layer_list *layer_list;
2689 loader_physical_device_layers(icd, &count, &layer_list);
2690
2691 if (pProperties == NULL) {
2692 *pCount = count;
2693 return VK_SUCCESS;
2694 }
2695
2696 copy_size = *pCount < count ? *pCount : count;
2697 for (uint32_t i = 0; i < copy_size; i++) {
2698 memcpy(&pProperties[i],
2699 &layer_list->list[i].info,
2700 sizeof(VkLayerProperties));
2701 }
2702 *pCount = copy_size;
2703
2704 if (copy_size < count) {
2705 return VK_INCOMPLETE;
2706 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002707
2708 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002709}