blob: 06c7f47d235e8e486da7e3236d472a57aecd4a5b [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
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600109void* loader_heap_alloc(
110 struct loader_instance *instance,
111 size_t size,
112 VkSystemAllocType alloc_type)
113{
114 if (instance && instance->alloc_callbacks.pfnAlloc) {
115 /* TODO: What should default alignment be? 1, 4, 8, other? */
116 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type);
117 }
118 return malloc(size);
119}
120
121void* loader_aligned_heap_alloc(
122 struct loader_instance *instance,
123 size_t size,
124 size_t alignment,
125 VkSystemAllocType alloc_type)
126{
127 if (!instance && instance->alloc_callbacks.pfnAlloc) {
128 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type);
129 }
130 return aligned_alloc(size, alignment);
131}
132
133void loader_heap_free(
134 struct loader_instance *instance,
135 void *pMem)
136{
137 if (!instance && instance->alloc_callbacks.pfnFree) {
138 return instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem);
139 }
140 return free(pMem);
141}
142
Jon Ashburnffad94d2015-06-30 14:46:22 -0700143static void loader_log(VkFlags msg_type, int32_t msg_code,
144 const char *format, ...)
145{
146 char msg[256];
147 va_list ap;
148 int ret;
149
150 if (!(msg_type & g_loader_log_msgs)) {
151 return;
152 }
153
154 va_start(ap, format);
155 ret = vsnprintf(msg, sizeof(msg), format, ap);
156 if ((ret >= (int) sizeof(msg)) || ret < 0) {
157 msg[sizeof(msg)-1] = '\0';
158 }
159 va_end(ap);
160
Ian Elliott4470a302015-02-17 10:33:47 -0700161#if defined(WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700162 OutputDebugString(msg);
163#endif
164 fputs(msg, stderr);
165 fputc('\n', stderr);
166}
167
168#if defined(WIN32)
169/**
170* Find the list of registry files (names within a key) in key "location".
171*
172* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
173* for a list or name/values which are added to a returned list (function return value).
174* The DWORD values within the key must be 0 or they are skipped.
175* Function return is a string with a ';' seperated list of filenames.
176* Function return is NULL if no valid name/value pairs are found in the key,
177* or the key is not found.
178*
179* \returns
180* A string list of filenames as pointer.
181* When done using the returned string list, pointer should be freed.
182*/
183static char *loader_get_registry_files(const char *location)
184{
185 LONG rtn_value;
186 HKEY hive, key;
187 DWORD access_flags = KEY_QUERY_VALUE;
188 char name[2048];
189 char *out = NULL;
190
191 hive = DEFAULT_VK_REGISTRY_HIVE;
192 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
193 if (rtn_value != ERROR_SUCCESS) {
194 // We didn't find the key. Try the 32-bit hive (where we've seen the
195 // key end up on some people's systems):
196 access_flags |= KEY_WOW64_32KEY;
197 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
198 if (rtn_value != ERROR_SUCCESS) {
199 // We still couldn't find the key, so give up:
200 return NULL;
201 }
202 }
203
204 DWORD idx = 0;
205 DWORD name_size = sizeof(name);
206 DWORD value;
207 DWORD total_size = 4096;
208 DWORD value_size = sizeof(value);
209 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
210 if (value_size == sizeof(value) && value == 0) {
211 if (out == NULL) {
212 out = malloc(total_size);
213 out[0] = '\0';
214 }
215 else if (strlen(out) + name_size + 1 > total_size) {
216 out = realloc(out, total_size * 2);
217 total_size *= 2;
218 }
219 if (out == NULL) {
220 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
221 return NULL;
222 }
223 if (strlen(out) == 0)
224 snprintf(out, name_size + 1, "%s", name);
225 else
226 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name);
227 }
228 }
229 return out;
230}
231
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600232char *loader_get_registry_string(const HKEY hive,
233 const LPCTSTR sub_key,
234 const char *value)
235{
236 DWORD access_flags = KEY_QUERY_VALUE;
237 DWORD value_type;
238 HKEY key;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700239 LONG rtn_value;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600240 char *rtn_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600241 DWORD rtn_len = 0;
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600242 size_t allocated_len = 0;
243
244 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
245 if (rtn_value != ERROR_SUCCESS) {
246 // We didn't find the key. Try the 32-bit hive (where we've seen the
247 // key end up on some people's systems):
248 access_flags |= KEY_WOW64_32KEY;
249 rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
250 if (rtn_value != ERROR_SUCCESS) {
251 // We still couldn't find the key, so give up:
252 return NULL;
253 }
254 }
255
256 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600257 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600258 if (rtn_value == ERROR_SUCCESS) {
259 // If we get to here, we found the key, and need to allocate memory
260 // large enough for rtn_str, and query again:
261 allocated_len = rtn_len + 4;
262 rtn_str = malloc(allocated_len);
263 rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
Ian Elliottf851ddf2015-04-28 15:57:32 -0600264 (PVOID) rtn_str, (LPDWORD) &rtn_len);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600265 if (rtn_value == ERROR_SUCCESS) {
266 // We added 4 extra bytes to rtn_str, so that we can ensure that
267 // the string is NULL-terminated (albeit, in a brute-force manner):
268 rtn_str[allocated_len-1] = '\0';
269 } else {
270 // This should never occur, but in case it does, clean up:
271 free(rtn_str);
272 rtn_str = NULL;
273 }
274 } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
275
276 // Close the registry key that was opened:
277 RegCloseKey(key);
278
279 return rtn_str;
280}
281
282
Ian Elliott4470a302015-02-17 10:33:47 -0700283// For ICD developers, look in the registry, and look for an environment
284// variable for a path(s) where to find the ICD(s):
285static char *loader_get_registry_and_env(const char *env_var,
286 const char *registry_value)
287{
288 char *env_str = getenv(env_var);
289 size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600290 char *registry_str = NULL;
Tony Barbour18f71552015-04-22 11:36:22 -0600291 size_t registry_len = 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700292 char *rtn_str = NULL;
293 size_t rtn_len;
294
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600295 registry_str = loader_get_registry_string(HKEY_LOCAL_MACHINE,
Ian Elliott06ebd752015-04-09 18:07:15 -0600296 "Software\\Vulkan",
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600297 registry_value);
Ian Elliottf851ddf2015-04-28 15:57:32 -0600298 registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
Ian Elliott4470a302015-02-17 10:33:47 -0700299
300 rtn_len = env_len + registry_len + 1;
301 if (rtn_len <= 2) {
302 // We found neither the desired registry value, nor the environment
303 // variable; return NULL:
304 return NULL;
305 } else {
306 // We found something, and so we need to allocate memory for the string
307 // to return:
308 rtn_str = malloc(rtn_len);
309 }
310
Ian Elliott5aa4ea22015-03-31 15:32:41 -0600311 if (registry_len == 0) {
Ian Elliott4470a302015-02-17 10:33:47 -0700312 // We didn't find the desired registry value, and so we must have found
313 // only the environment variable:
314 _snprintf(rtn_str, rtn_len, "%s", env_str);
315 } else if (env_str != NULL) {
316 // We found both the desired registry value and the environment
317 // variable, so concatenate them both:
318 _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
319 } else {
320 // We must have only found the desired registry value:
321 _snprintf(rtn_str, rtn_len, "%s", registry_str);
322 }
323
Ian Elliott2de26bc2015-04-03 13:13:01 -0600324 if (registry_str) {
325 free(registry_str);
326 }
Ian Elliott4470a302015-02-17 10:33:47 -0700327
328 return(rtn_str);
329}
330#endif // WIN32
331
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600332bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
333{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600334 return strcmp(op1->extName, op2->extName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600335}
336
337/*
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600338 * Search the given ext_array for an extension
339 * matching the given vk_ext_prop
340 */
341bool has_vk_extension_property_array(
342 const VkExtensionProperties *vk_ext_prop,
343 const uint32_t count,
344 const VkExtensionProperties *ext_array)
345{
346 for (uint32_t i = 0; i < count; i++) {
347 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
348 return true;
349 }
350 return false;
351}
352
353/*
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600354 * Search the given ext_list for an extension
355 * matching the given vk_ext_prop
356 */
357bool has_vk_extension_property(
358 const VkExtensionProperties *vk_ext_prop,
359 const struct loader_extension_list *ext_list)
360{
361 for (uint32_t i = 0; i < ext_list->count; i++) {
362 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
363 return true;
364 }
365 return false;
366}
367
368/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600369 * Search the given layer list for a layer
370 * matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600371 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600372static struct loader_layer_properties *get_layer_property(
373 const char *name,
374 const struct loader_layer_list *layer_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600375{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600376 for (uint32_t i = 0; i < layer_list->count; i++) {
377 const VkLayerProperties *item = &layer_list->list[i].info;
378 if (strcmp(name, item->layerName) == 0)
379 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600380 }
381 return NULL;
382}
383
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600384static void loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -0600385 const PFN_vkGetGlobalExtensionProperties fp_get_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600386 const char *lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600387 const loader_platform_dl_handle lib_handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600388 const enum extension_origin origin,
389 struct loader_extension_list *ext_list)
390{
391 uint32_t i, count;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600392 struct loader_extension_property ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600393 VkExtensionProperties *extension_properties;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600394 VkResult res;
395
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600396 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600397 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600398 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600399 return;
400 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600401
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600402 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600403
404 res = fp_get_props(NULL, &count, extension_properties);
405 if (res != VK_SUCCESS) {
406 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
407 return;
408 }
Tony Barbour59a47322015-06-24 16:06:58 -0600409
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600410 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600411 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600412 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
413 //TODO eventually get this from the layer config file
414 ext_props.origin = origin;
415 ext_props.lib_name = lib_name;
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600416
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600417 char spec_version[64], version[64];
418
419 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
420 VK_MAJOR(ext_props.info.specVersion),
421 VK_MINOR(ext_props.info.specVersion),
422 VK_PATCH(ext_props.info.specVersion));
423 snprintf(version, sizeof(version), "%d.%d.%d",
424 VK_MAJOR(ext_props.info.version),
425 VK_MINOR(ext_props.info.version),
426 VK_PATCH(ext_props.info.version));
427
428 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
429 "Global Extension: %s (%s) version %s, Vulkan version %s",
430 ext_props.info.extName, lib_name, version, spec_version);
431 loader_add_to_ext_list(ext_list, 1, &ext_props);
432 }
433
434 return;
435}
436
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600437/* TODO: Need to use loader_heap_alloc or loader_stack_alloc */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600438static void loader_add_global_layer_properties(
439 const char *lib_name,
440 const loader_platform_dl_handle lib_handle,
441 struct loader_layer_list *layer_list)
442{
443 uint32_t i, count;
444 VkLayerProperties *layer_properties;
445 PFN_vkGetGlobalExtensionProperties fp_get_ext_props;
446 PFN_vkGetGlobalLayerProperties fp_get_layer_props;
447 VkResult res;
448
449 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalExtensionProperties");
450 if (!fp_get_ext_props) {
451 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
452 "Couldn't dlsym vkGetGlobalExtensionProperties from library %s",
453 lib_name);
454 return;
455 }
456
457 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
458 if (!fp_get_layer_props) {
459 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
460 "Couldn't dlsym vkGetGlobalLayerProperties from library %s",
461 lib_name);
462 return;
463 }
464
465 res = fp_get_layer_props(&count, NULL);
466 if (res != VK_SUCCESS) {
467 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global layer count from %s", lib_name);
468 return;
469 }
470
471 if (count == 0) {
472 return;
473 }
474
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600475 layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600476
477 res = fp_get_layer_props(&count, layer_properties);
478 if (res != VK_SUCCESS) {
479 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting %d global layer properties from %s",
480 count, lib_name);
481 return;
482 }
483
484 for (i = 0; i < count; i++) {
485 struct loader_layer_properties *layer = &layer_list->list[layer_list->count];
486 layer->lib_info.lib_name = malloc(strlen(lib_name) + 1);
487 if (layer->lib_info.lib_name == NULL) {
488 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "layer library %s ignored: out of memory", lib_name);
489 return;
490 }
491
492 strcpy(layer->lib_info.lib_name, lib_name);
493 memcpy(&layer->info, &layer_properties[i], sizeof(VkLayerProperties));
494 loader_init_ext_list(&layer->instance_extension_list);
495 loader_init_ext_list(&layer->device_extension_list);
496 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for layer %s (%s)",
497 layer->info.layerName, layer->info.description);
498
499 loader_add_to_layer_list(layer_list, 1, layer);
500
501 loader_add_global_extensions(
502 fp_get_ext_props,
503 lib_name,
504 lib_handle,
505 VK_EXTENSION_ORIGIN_LAYER,
506 &layer->instance_extension_list);
507 }
508
509 return;
510}
511
512static void loader_add_physical_device_extensions(
513 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
514 VkPhysicalDevice physical_device,
515 const enum extension_origin origin,
516 const char *lib_name,
517 struct loader_extension_list *ext_list)
518{
519 uint32_t i, count;
520 VkResult res;
521 struct loader_extension_property ext_props;
522 VkExtensionProperties *extension_properties;
523
524 memset(&ext_props, 0, sizeof(ext_props));
525 ext_props.origin = origin;
526 ext_props.lib_name = lib_name;
527
528 if (get_phys_dev_ext_props) {
529 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
530 if (res == VK_SUCCESS && count > 0) {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600531
532 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
533
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600534 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties);
535 for (i = 0; i < count; i++) {
536 char spec_version[64], version[64];
537
538 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
539
540 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
541 VK_MAJOR(ext_props.info.specVersion),
542 VK_MINOR(ext_props.info.specVersion),
543 VK_PATCH(ext_props.info.specVersion));
544 snprintf(version, sizeof(version), "%d.%d.%d",
545 VK_MAJOR(ext_props.info.version),
546 VK_MINOR(ext_props.info.version),
547 VK_PATCH(ext_props.info.version));
548
549 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
550 "PhysicalDevice Extension: %s (%s) version %s, Vulkan version %s",
551 ext_props.info.extName, lib_name, version, spec_version);
552 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600553 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600554 } else {
555 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 -0600556 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600557 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600558
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600559 return;
560}
561
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600562static void loader_add_physical_device_layer_properties(
563 struct loader_icd *icd,
564 char *lib_name,
565 const loader_platform_dl_handle lib_handle)
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600566{
567 uint32_t i, count;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600568 VkLayerProperties *layer_properties;
569 PFN_vkGetPhysicalDeviceExtensionProperties fp_get_ext_props;
570 PFN_vkGetPhysicalDeviceLayerProperties fp_get_layer_props;
571 VkPhysicalDevice gpu = icd->gpus[0];
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600572 VkResult res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600573
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600574 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties");
575 if (!fp_get_ext_props) {
576 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
577 "Couldn't dlsym vkGetPhysicalDeviceExtensionProperties from library %s",
578 lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600579 return;
580 }
581
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600582 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
583 if (!fp_get_layer_props) {
584 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
585 "Couldn't dlsym vkGetPhysicalDeviceLayerProperties from library %s",
586 lib_name);
587 return;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600588 }
589
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600590 /*
591 * NOTE: We assume that all GPUs of an ICD support the same PhysicalDevice
592 * layers and extensions. Thus only ask for info about the first gpu.
593 */
594 res = fp_get_layer_props(gpu, &count, NULL);
595 if (res != VK_SUCCESS) {
596 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting PhysicalDevice layer count from %s", lib_name);
597 return;
598 }
599
600 if (count == 0) {
601 return;
602 }
603
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600604 layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600605
606 res = fp_get_layer_props(gpu, &count, layer_properties);
607 if (res != VK_SUCCESS) {
608 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d PhysicalDevice layer properties from %s",
609 count, lib_name);
610 return;
611 }
612
613 for (i = 0; i < count; i++) {
614 struct loader_layer_properties layer;
615 memset(&layer, 0, sizeof(struct loader_layer_properties));
616 layer.lib_info.lib_name = lib_name;
617 memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
618 loader_init_ext_list(&layer.instance_extension_list);
619 loader_init_ext_list(&layer.device_extension_list);
620 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting PhysicalDevice extensions for layer %s (%s)",
621 layer.info.layerName, layer.info.description);
622 loader_add_to_layer_list(&icd->layer_properties_cache, 1, &layer);
623 loader_add_physical_device_extensions(
624 fp_get_ext_props,
625 icd->gpus[i],
626 VK_EXTENSION_ORIGIN_LAYER,
627 lib_name,
628 &layer.device_extension_list);
629 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -0600630 return;
631}
632
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600633static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600634{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600635 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600636 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600637 ext_info->list = malloc(ext_info->capacity);
638 if (ext_info->list == NULL) {
639 return false;
640 }
641 memset(ext_info->list, 0, ext_info->capacity);
642 ext_info->count = 0;
643 return true;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600644}
645
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -0600646void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600647{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600648 free(ext_info->list);
649 ext_info->count = 0;
650 ext_info->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600651}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600652
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600653/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600654 * Search the given search_list for any layers in the props list.
655 * Add these to the output layer_list. Don't add duplicates to the output layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600656 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600657static void loader_add_layer_names_to_list(
658 struct loader_layer_list *output_list,
659 uint32_t name_count,
660 const char * const *names,
661 const struct loader_layer_list *search_list)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600662{
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600663 struct loader_layer_properties *layer_prop;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600664
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600665 for (uint32_t i = 0; i < name_count; i++) {
666 const char *search_target = names[i];
667 layer_prop = get_layer_property(search_target, search_list);
668 if (!layer_prop) {
669 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unable to find extension %s", search_target);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600670 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600671 }
672
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600673 loader_add_to_layer_list(output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600674 }
675}
676
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600677/*
678 * Append non-duplicate extension properties defined in prop_list
679 * to the given ext_info list
680 */
681void loader_add_to_ext_list(
682 struct loader_extension_list *ext_list,
683 uint32_t prop_list_count,
684 const struct loader_extension_property *props)
685{
686 uint32_t i;
687 struct loader_extension_property *cur_ext;
688
689 if (ext_list->list == NULL || ext_list->capacity == 0) {
690 loader_init_ext_list(ext_list);
691 }
692
693 if (ext_list->list == NULL)
694 return;
695
696 for (i = 0; i < prop_list_count; i++) {
697 cur_ext = (struct loader_extension_property *) &props[i];
698
699 // look for duplicates
700 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
701 continue;
702 }
703
704 // add to list at end
705 // check for enough capacity
706 if (ext_list->count * sizeof(struct loader_extension_property)
707 >= ext_list->capacity) {
708 // double capacity
709 ext_list->capacity *= 2;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600710 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600711 ext_list->list = realloc(ext_list->list, ext_list->capacity);
712 }
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -0600713
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600714 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
715 ext_list->count++;
716 }
717}
718
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600719/*
720 * Manage lists of VkLayerProperties
721 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600722static bool loader_init_layer_list(struct loader_layer_list *list)
723{
724 list->capacity = 32 * sizeof(struct loader_layer_properties);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600725 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600726 list->list = malloc(list->capacity);
727 if (list->list == NULL) {
728 return false;
729 }
730 memset(list->list, 0, list->capacity);
731 list->count = 0;
732 return true;
733}
734
735void loader_destroy_layer_list(struct loader_layer_list *layer_list)
736{
737 free(layer_list->list);
738 layer_list->count = 0;
739 layer_list->capacity = 0;
740}
741
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600742/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600743 * Search the given layer list for a list
744 * matching the given VkLayerProperties
745 */
746bool has_vk_layer_property(
747 const VkLayerProperties *vk_layer_prop,
748 const struct loader_layer_list *list)
749{
750 for (uint32_t i = 0; i < list->count; i++) {
751 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
752 return true;
753 }
754 return false;
755}
756
757/*
758 * Search the given layer list for a layer
759 * matching the given name
760 */
761bool has_layer_name(
762 const char *name,
763 const struct loader_layer_list *list)
764{
765 for (uint32_t i = 0; i < list->count; i++) {
766 if (strcmp(name, list->list[i].info.layerName) == 0)
767 return true;
768 }
769 return false;
770}
771
772/*
773 * Append non-duplicate layer properties defined in prop_list
774 * to the given layer_info list
775 */
776void loader_add_to_layer_list(
777 struct loader_layer_list *list,
778 uint32_t prop_list_count,
779 const struct loader_layer_properties *props)
780{
781 uint32_t i;
782 struct loader_layer_properties *layer;
783
784 if (list->list == NULL || list->capacity == 0) {
785 loader_init_layer_list(list);
786 }
787
788 if (list->list == NULL)
789 return;
790
791 for (i = 0; i < prop_list_count; i++) {
792 layer = (struct loader_layer_properties *) &props[i];
793
794 // look for duplicates
795 if (has_vk_layer_property(&layer->info, list)) {
796 continue;
797 }
798
799 // add to list at end
800 // check for enough capacity
801 if (list->count * sizeof(struct loader_layer_properties)
802 >= list->capacity) {
803 // double capacity
804 list->capacity *= 2;
805 list->list = realloc(list->list, list->capacity);
806 }
807
808 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
809 list->count++;
810 }
811}
812
813/*
814 * Search the search_list for any layer with
815 * a name that matches the given layer_name.
816 * Add all matching layers to the found_list
817 * Do not add if found VkLayerProperties is already
818 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600819 */
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600820static void loader_find_layer_name_add_list(
821 const char *name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600822 const struct loader_layer_list *search_list,
823 struct loader_layer_list *found_list)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600824{
825 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600826 struct loader_layer_properties *layer_prop = &search_list->list[i];
827 if (0 == strcmp(layer_prop->info.layerName, name)) {
828 /* Found a layer with the same name, add to found_list */
829 loader_add_to_layer_list(found_list, 1, layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600830 }
831 }
832}
833
834bool loader_is_extension_scanned(const VkExtensionProperties *ext_prop)
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600835{
836 uint32_t i;
837
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600838 for (i = 0; i < loader.global_extensions.count; i++) {
839 if (compare_vk_extension_properties(&loader.global_extensions.list[i].info, ext_prop))
Jon Ashburnfc2e38c2015-04-14 09:15:32 -0600840 return true;
841 }
842 return false;
843}
844
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600845/*
846 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
847 * the extension must provide two entry points for the loader to use:
848 * - "trampoline" entry point - this is the address returned by GetProcAddr
849 * and will always do what's necessary to support a global call.
850 * - "terminator" function - this function will be put at the end of the
851 * instance chain and will contain the necessary logica to call / process
852 * the extension for the appropriate ICDs that are available.
853 * There is no generic mechanism for including these functions, the references
854 * must be placed into the appropriate loader entry points.
855 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
856 * loader_coalesce_extensions(void) - add extension records to the list of global
857 * extension available to the app.
858 * instance_disp - add function pointer for terminator function to this array.
859 * The extension itself should be in a separate file that will be
860 * linked directly with the loader.
861 */
Jon Ashburn27cd5842015-05-12 17:26:48 -0600862void loader_coalesce_extensions(void)
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600863{
864 uint32_t i;
865 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
866
867 // traverse scanned icd list adding non-duplicate extensions to the list
868 while (icd_list != NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600869 loader_add_to_ext_list(&loader.global_extensions,
870 icd_list->global_extension_list.count,
871 icd_list->global_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600872 icd_list = icd_list->next;
873 };
874
875 //Traverse layers list adding non-duplicate extensions to the list
Jon Ashburn5ef20602015-07-02 09:40:15 -0600876 for (i = 0; i < loader.scanned_layers.count; i++) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600877 loader_add_to_ext_list(&loader.global_extensions,
Jon Ashburn5ef20602015-07-02 09:40:15 -0600878 loader.scanned_layers.list[i].instance_extension_list.count,
879 loader.scanned_layers.list[i].instance_extension_list.list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600880 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600881
882 // Traverse loader's extensions, adding non-duplicate extensions to the list
883 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600884}
885
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600886static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
887 struct loader_device **found_dev)
888{
889 *found_dev = NULL;
890 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
891 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
892 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
893 if (dev->device == device) {
894 *found_dev = dev;
895 return icd;
896 }
897 }
898 }
899 return NULL;
900}
901
902static void loader_destroy_logical_device(struct loader_device *dev)
903{
904 free(dev->app_extension_props);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600905 if (dev->activated_layer_list.count)
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600906 loader_destroy_layer_list(&dev->activated_layer_list);
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600907 free(dev);
908}
909
910static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
911{
912 struct loader_device *new_dev;
913
914 new_dev = malloc(sizeof(struct loader_device));
915 if (!new_dev) {
916 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
917 return NULL;
918 }
919
920 memset(new_dev, 0, sizeof(struct loader_device));
921
922 new_dev->next = *device_list;
923 new_dev->device = dev;
924 *device_list = new_dev;
925 return new_dev;
926}
927
928void loader_remove_logical_device(VkDevice device)
929{
930 struct loader_device *found_dev, *dev, *prev_dev;
931 struct loader_icd *icd;
932 icd = loader_get_icd_and_device(device, &found_dev);
933
934 if (!icd || !found_dev)
935 return;
936
937 prev_dev = NULL;
938 dev = icd->logical_device_list;
939 while (dev && dev != found_dev) {
940 prev_dev = dev;
941 dev = dev->next;
942 }
943
944 if (prev_dev)
945 prev_dev->next = found_dev->next;
946 else
947 icd->logical_device_list = found_dev->next;
948 loader_destroy_logical_device(found_dev);
949}
950
951
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600952static void loader_icd_destroy(
953 struct loader_instance *ptr_inst,
954 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800955{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600956 ptr_inst->total_icd_count--;
Jon Ashburn128f9422015-05-28 19:16:58 -0600957 free(icd->gpus);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600958 for (struct loader_device *dev = icd->logical_device_list; dev; ) {
959 struct loader_device *next_dev = dev->next;
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600960 loader_destroy_logical_device(dev);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -0600961 dev = next_dev;
962 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -0600963
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800964 free(icd);
965}
966
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600967static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800968{
969 struct loader_icd *icd;
970
971 icd = malloc(sizeof(*icd));
972 if (!icd)
973 return NULL;
974
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -0600975 memset(icd, 0, sizeof(*icd));
976
Jon Ashburn46d1f582015-01-28 11:01:35 -0700977 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800978
979 return icd;
980}
981
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600982static struct loader_icd *loader_icd_add(
983 struct loader_instance *ptr_inst,
984 const struct loader_scanned_icds *scanned)
Chia-I Wu13a61a52014-08-04 11:18:20 +0800985{
986 struct loader_icd *icd;
987
Jon Ashburn46d1f582015-01-28 11:01:35 -0700988 icd = loader_icd_create(scanned);
Chia-I Wu13a61a52014-08-04 11:18:20 +0800989 if (!icd)
990 return NULL;
991
Chia-I Wu13a61a52014-08-04 11:18:20 +0800992 /* prepend to the list */
Jon Ashburn46888392015-01-29 15:45:51 -0700993 icd->next = ptr_inst->icds;
994 ptr_inst->icds = icd;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600995 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +0800996
997 return icd;
998}
999
Jon Ashburn46d1f582015-01-28 11:01:35 -07001000static void loader_scanned_icd_add(const char *filename)
1001{
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001002 loader_platform_dl_handle handle;
Jon Ashburn3da71f22015-05-14 12:43:38 -06001003 void *fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -06001004 void *fp_get_global_ext_props;
Tony Barbour59a47322015-06-24 16:06:58 -06001005 void *fp_get_device_ext_props;
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001006 PFN_vkGPA fp_get_proc_addr;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001007 struct loader_scanned_icds *new_node;
1008
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001009 // Used to call: dlopen(filename, RTLD_LAZY);
1010 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001011 if (!handle) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001012 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn46d1f582015-01-28 11:01:35 -07001013 return;
1014 }
1015
1016#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06001017 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn46d1f582015-01-28 11:01:35 -07001018 if (!func_ptr) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001019 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn46d1f582015-01-28 11:01:35 -07001020 return; \
1021 } \
1022} while (0)
1023
Jon Ashburn46888392015-01-29 15:45:51 -07001024 LOOKUP(fp_create_inst, CreateInstance);
Tony Barbour59a47322015-06-24 16:06:58 -06001025 LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
Tony Barbour59a47322015-06-24 16:06:58 -06001026 LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001027 LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001028#undef LOOKUP
1029
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001030 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
1031 + strlen(filename) + 1);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001032 if (!new_node) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001033 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn46d1f582015-01-28 11:01:35 -07001034 return;
1035 }
1036
1037 new_node->handle = handle;
Jon Ashburn46888392015-01-29 15:45:51 -07001038 new_node->CreateInstance = fp_create_inst;
Tony Barbour59a47322015-06-24 16:06:58 -06001039 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001040 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001041 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001042 new_node->next = loader.scanned_icd_list;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001043
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001044 new_node->lib_name = (char *) (new_node + 1);
1045 if (!new_node->lib_name) {
1046 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
1047 return;
1048 }
1049 strcpy(new_node->lib_name, filename);
1050
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001051 loader.scanned_icd_list = new_node;
1052
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001053 loader_add_global_extensions(
Tony Barbour59a47322015-06-24 16:06:58 -06001054 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001055 new_node->lib_name,
Jon Ashburn953bb3c2015-06-10 16:11:42 -06001056 handle,
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001057 VK_EXTENSION_ORIGIN_ICD,
1058 &new_node->global_extension_list);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001059}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001060
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001061static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
1062{
1063 if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
1064 return &loader.global_extensions;
1065 }
1066
1067 /* TODO: Add code to query global extensions from layer */
1068 for (uint32_t i = 0; i < loader.scanned_layers.count; i++) {
1069 struct loader_layer_properties *work_layer = &loader.scanned_layers.list[i];
1070 if (strcmp(work_layer->info.layerName, pLayerName) == 0) {
1071 return &work_layer->instance_extension_list;
1072 }
1073 }
1074
1075 return NULL;
1076}
1077
1078static struct loader_layer_list *loader_global_layers()
1079{
1080 return &loader.scanned_layers;
1081}
1082
1083static void loader_physical_device_layers(
1084 struct loader_icd *icd,
1085 uint32_t *count,
1086 struct loader_layer_list **list)
1087{
1088 *count = icd->layer_properties_cache.count;
1089 *list = &icd->layer_properties_cache;
1090}
1091
1092static void loader_physical_device_extensions(
1093 struct loader_icd *icd,
1094 uint32_t gpu_idx,
1095 const char *layer_name,
1096 uint32_t *count,
1097 struct loader_extension_list **list)
1098{
1099 if (layer_name == NULL || (strlen(layer_name) == 0)) {
1100 *count = icd->device_extension_cache[gpu_idx].count;
1101 *list = &icd->device_extension_cache[gpu_idx];
1102 return;
1103 }
1104 for (uint32_t i = 0; i < icd->layer_properties_cache.count; i++) {
1105 if (strcmp(layer_name, icd->layer_properties_cache.list[i].info.layerName) == 0) {
1106 *count = icd->layer_properties_cache.list[i].device_extension_list.count;
1107 *list = &icd->layer_properties_cache.list[i].device_extension_list;
1108 }
1109 }
1110}
1111
Jon Ashburn3da71f22015-05-14 12:43:38 -06001112static void loader_icd_init_entrys(struct loader_icd *icd,
1113 struct loader_scanned_icds *scanned_icds)
1114{
1115 /* initialize entrypoint function pointers */
1116
1117 #define LOOKUP(func) do { \
1118 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
1119 if (!icd->func) { \
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001120 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001121 return; \
1122 } \
1123 } while (0)
1124
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06001125 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
1126 LOOKUP(GetDeviceProcAddr);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001127 LOOKUP(DestroyInstance);
1128 LOOKUP(EnumeratePhysicalDevices);
Chris Forbesbc0bb772015-06-21 22:55:02 +12001129 LOOKUP(GetPhysicalDeviceFeatures);
1130 LOOKUP(GetPhysicalDeviceFormatInfo);
1131 LOOKUP(GetPhysicalDeviceLimits);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001132 LOOKUP(CreateDevice);
Tony Barbour59a47322015-06-24 16:06:58 -06001133 LOOKUP(GetPhysicalDeviceProperties);
1134 LOOKUP(GetPhysicalDeviceMemoryProperties);
1135 LOOKUP(GetPhysicalDevicePerformance);
1136 LOOKUP(GetPhysicalDeviceQueueCount);
1137 LOOKUP(GetPhysicalDeviceQueueProperties);
1138 LOOKUP(GetPhysicalDeviceExtensionProperties);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001139 LOOKUP(DbgCreateMsgCallback);
1140 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001141#undef LOOKUP
1142
1143 return;
1144}
1145
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001146static void loader_debug_init(void)
1147{
1148 const char *env;
1149
1150 if (g_loader_debug > 0)
1151 return;
1152
1153 g_loader_debug = 0;
1154
1155 /* parse comma-separated debug options */
1156 env = getenv("LOADER_DEBUG");
1157 while (env) {
1158 const char *p = strchr(env, ',');
1159 size_t len;
1160
1161 if (p)
1162 len = p - env;
1163 else
1164 len = strlen(env);
1165
1166 if (len > 0) {
1167 if (strncmp(env, "warn", len) == 0) {
1168 g_loader_debug |= LOADER_WARN_BIT;
1169 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1170 } else if (strncmp(env, "info", len) == 0) {
1171 g_loader_debug |= LOADER_INFO_BIT;
1172 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1173 } else if (strncmp(env, "perf", len) == 0) {
1174 g_loader_debug |= LOADER_PERF_BIT;
1175 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1176 } else if (strncmp(env, "error", len) == 0) {
1177 g_loader_debug |= LOADER_ERROR_BIT;
1178 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1179 } else if (strncmp(env, "debug", len) == 0) {
1180 g_loader_debug |= LOADER_DEBUG_BIT;
1181 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1182 }
1183 }
1184
1185 if (!p)
1186 break;
1187
1188 env = p + 1;
1189 }
1190}
1191
Jon Ashburn2077e382015-06-29 11:25:34 -06001192struct loader_manifest_files {
1193 uint32_t count;
1194 char **filename_list;
1195};
1196
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001197/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001198 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001199 *
1200 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001201 * A pointer to first char in the next path.
1202 * The next path (or NULL) in the list is returned in next_path.
1203 * Note: input string is modified in some cases. PASS IN A COPY!
1204 */
Jon Ashburn2077e382015-06-29 11:25:34 -06001205static char *loader_get_next_path(char *path)
1206{
1207 uint32_t len;
1208 char *next;
1209
1210 if (path == NULL)
1211 return NULL;
1212 next = strchr(path, PATH_SEPERATOR);
1213 if (next == NULL) {
1214 len = (uint32_t) strlen(path);
1215 next = path + len;
1216 }
1217 else {
1218 *next = '\0';
1219 next++;
1220 }
1221
1222 return next;
1223}
1224
1225/**
1226 * Given a filename (file) and a list of paths (dir), try to find an existing
1227 * file in the paths. If filename already is a path then no
1228 * searching in the given paths.
1229 *
1230 * \returns
1231 * A string in out_fullpath of either the full path or file.
1232 * Side effect is that dir string maybe modified.
1233 */
1234static void loader_get_fullpath(const char *file,
1235 char *dir,
1236 size_t out_size,
1237 char *out_fullpath)
1238{
1239 char *next_dir;
1240 if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1241 //find file exists with prepending given path
1242 while (*dir) {
1243 next_dir = loader_get_next_path(dir);
1244 snprintf(out_fullpath, out_size, "%s%c%s",
1245 dir, DIRECTORY_SYMBOL, file);
1246 if (loader_platform_file_exists(out_fullpath)) {
1247 return;
1248 }
1249 dir = next_dir;
1250 }
1251 }
1252 snprintf(out_fullpath, out_size, "%s", file);
1253}
1254
1255/**
1256 * Read a JSON file into a buffer.
1257 *
1258 * \returns
1259 * A pointer to a cJSON object representing the JSON parse tree.
1260 * This returned buffer should be freed by caller.
1261 */
1262static cJSON *loader_get_json(const char *filename)
1263{
1264 FILE *file;
1265 char *json_buf;
1266 cJSON *json;
1267 uint64_t len;
1268 file = fopen(filename,"rb");
1269 fseek(file, 0, SEEK_END);
1270 len = ftell(file);
1271 fseek(file, 0, SEEK_SET);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001272 json_buf = (char*) loader_stack_alloc(len+1);
Jon Ashburn2077e382015-06-29 11:25:34 -06001273 if (json_buf == NULL) {
1274 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1275 fclose(file);
1276 return NULL;
1277 }
1278 if (fread(json_buf, sizeof(char), len, file) != len) {
1279 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1280 fclose(file);
1281 return NULL;
1282 }
1283 fclose(file);
1284 json_buf[len] = '\0';
1285
1286 //parse text from file
1287 json = cJSON_Parse(json_buf);
1288 if (json == NULL)
1289 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1290 return json;
1291}
1292
1293/**
1294 * Find the Vulkan library manifest files.
1295 *
1296 * This function scans the location or env_override directories/files
1297 * for a list of JSON manifest files. If env_override is non-NULL
1298 * and has a valid value. Then the location is ignored. Otherwise
1299 * location is used to look for manifest files. The location
1300 * is interpreted as Registry path on Windows and a directory path(s)
1301 * on Linux.
1302 *
1303 * \returns
1304 * A string list of manifest files to be opened in out_files param.
1305 * List has a pointer to string for each manifest filename.
1306 * When done using the list in out_files, pointers should be freed.
Jon Ashburnffad94d2015-06-30 14:46:22 -07001307 * Location or override string lists can be either files or directories as follows:
1308 * | location | override
1309 * --------------------------------
1310 * Win ICD | files | files
1311 * Win Layer | files | dirs
1312 * Linux ICD | dirs | files
1313 * Linux Layer| dirs | dirs
Jon Ashburn2077e382015-06-29 11:25:34 -06001314 */
1315static void loader_get_manifest_files(const char *env_override,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001316 bool is_layer,
1317 const char *location,
1318 struct loader_manifest_files *out_files)
Jon Ashburn2077e382015-06-29 11:25:34 -06001319{
1320 char *override = NULL;
1321 char *loc;
1322 char *file, *next_file, *name;
1323 size_t alloced_count = 64;
1324 char full_path[2048];
1325 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001326 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06001327 struct dirent *dent;
1328
1329 out_files->count = 0;
1330 out_files->filename_list = NULL;
1331
Jon Ashburn2077e382015-06-29 11:25:34 -06001332 if (env_override != NULL && (override = getenv(env_override))) {
1333#if defined(__linux__)
1334 if (geteuid() != getuid()) {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001335 /* Don't allow setuid apps to use the env var: */
Jon Ashburn2077e382015-06-29 11:25:34 -06001336 override = NULL;
1337 }
1338#endif
1339 }
1340
1341 if (location == NULL) {
1342 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
Jon Ashburnffad94d2015-06-30 14:46:22 -07001343 "Can't get manifest files with NULL location, env_override=%s",
1344 env_override);
Jon Ashburn2077e382015-06-29 11:25:34 -06001345 return;
1346 }
1347
Jon Ashburnffad94d2015-06-30 14:46:22 -07001348#if defined(__linux__)
1349 list_is_dirs = (override == NULL || is_layer) ? true : false;
1350#else //WIN32
1351 list_is_dirs = (is_layer && override != NULL) ? true : false;
1352#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001353 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07001354 // Also handle getting the location(s) from registry on Windows
1355 if (override == NULL) {
1356#if defined (_WIN32)
1357 loc = loader_get_registry_files(location);
1358 if (loc == NULL) {
1359 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1360 return;
1361 }
1362#else
Jon Ashburn2077e382015-06-29 11:25:34 -06001363 loc = alloca(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001364 if (loc == NULL) {
1365 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1366 return;
1367 }
1368 strcpy(loc, location);
1369#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001370 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001371 else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001372 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001373 if (loc == NULL) {
1374 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1375 return;
1376 }
1377 strcpy(loc, override);
1378 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001379
1380 file = loc;
1381 while (*file) {
1382 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001383 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001384 sysdir = opendir(file);
1385 name = NULL;
1386 if (sysdir) {
1387 dent = readdir(sysdir);
1388 if (dent == NULL)
1389 break;
1390 name = &(dent->d_name[0]);
1391 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1392 name = full_path;
1393 }
1394 }
1395 else {
Jon Ashburnffad94d2015-06-30 14:46:22 -07001396#if defined(__linux__)
1397 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06001398 char *dir;
1399 // make a copy of location so it isn't modified
1400 dir = alloca(strlen(location) + 1);
1401 if (dir == NULL) {
1402 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1403 return;
1404 }
1405 strcpy(dir, location);
1406
1407 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1408
1409 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001410#else // WIN32
1411 name = file;
1412#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001413 }
1414 while (name) {
1415 /* Look for files ending with ".json" suffix */
1416 uint32_t nlen = (uint32_t) strlen(name);
1417 const char *suf = name + nlen - 5;
1418 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1419 if (out_files->count == 0) {
1420 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1421 }
1422 else if (out_files->count == alloced_count) {
1423 out_files->filename_list = realloc(out_files->filename_list,
1424 alloced_count * sizeof(char *) * 2);
1425 alloced_count *= 2;
1426 }
1427 if (out_files->filename_list == NULL) {
1428 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1429 return;
1430 }
1431 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1432 if (out_files->filename_list[out_files->count] == NULL) {
1433 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1434 return;
1435 }
1436 strcpy(out_files->filename_list[out_files->count], name);
1437 out_files->count++;
Jon Ashburnf70f3612015-07-02 10:08:47 -06001438 } else if (!list_is_dirs) {
1439 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 -06001440 }
Jon Ashburnffad94d2015-06-30 14:46:22 -07001441 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001442 dent = readdir(sysdir);
1443 if (dent == NULL)
1444 break;
1445 name = &(dent->d_name[0]);
1446 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1447 name = full_path;
1448 }
1449 else {
1450 break;
1451 }
1452 }
1453 if (sysdir)
1454 closedir(sysdir);
1455 file = next_file;
1456 }
1457 return;
1458}
1459
1460/**
1461 * Try to find the Vulkan ICD driver(s).
1462 *
1463 * This function scans the default system loader path(s) or path
1464 * specified by the \c VK_ICD_FILENAMES environment variable in
1465 * order to find loadable VK ICDs manifest files. From these
1466 * manifest files it finds the ICD libraries.
1467 *
1468 * \returns
Jon Ashburn3a37aee2015-06-30 16:44:28 -06001469 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001470 */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001471void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001472{
Jon Ashburn2077e382015-06-29 11:25:34 -06001473 char *file_str;
1474 struct loader_manifest_files manifest_files;
1475
Jon Ashburn6301a0f2015-05-29 13:15:39 -06001476
1477 // convenient place to initialize a mutex
1478 loader_platform_thread_create_mutex(&loader_lock);
1479
Jon Ashburn2077e382015-06-29 11:25:34 -06001480 // convenient place to initialize logging
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001481 loader_debug_init();
1482
Jon Ashburn2077e382015-06-29 11:25:34 -06001483 // Get a list of manifest files for ICDs
1484 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1485 &manifest_files);
1486 for (uint32_t i = 0; i < manifest_files.count; i++) {
1487 file_str = manifest_files.filename_list[i];
1488 if (file_str == NULL)
1489 continue;
1490
1491 cJSON *json, *icd_json;
1492 json = loader_get_json(file_str);
1493 icd_json = cJSON_GetObjectItem(json, "ICD");
1494 if (icd_json != NULL) {
1495 icd_json = cJSON_GetObjectItem(icd_json, "library_path");
1496 if (icd_json != NULL) {
1497 char *icd_filename = cJSON_PrintUnformatted(icd_json);
1498 char *icd_file = icd_filename;
1499 if (icd_filename != NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001500 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1501 char *dir = def_dir;
1502 // strip off extra quotes
1503 if (icd_filename[strlen(icd_filename) - 1] == '"')
1504 icd_filename[strlen(icd_filename) - 1] = '\0';
1505 if (icd_filename[0] == '"')
1506 icd_filename++;
Jon Ashburnffad94d2015-06-30 14:46:22 -07001507#if defined(__linux__)
1508 char full_path[2048];
Jon Ashburn2077e382015-06-29 11:25:34 -06001509 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1510 loader_scanned_icd_add(full_path);
Jon Ashburnffad94d2015-06-30 14:46:22 -07001511#else // WIN32
1512 loader_scanned_icd_add(icd_filename);
1513#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06001514 free(icd_file);
1515 }
1516 }
1517 else
1518 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1519 }
1520 else
1521 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1522
1523 free(file_str);
1524 cJSON_Delete(json);
1525 }
1526 free(manifest_files.filename_list);
1527
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001528}
1529
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001530
Jon Ashburn5ef20602015-07-02 09:40:15 -06001531void loader_layer_scan(void)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001532{
1533 const char *p, *next;
Ian Elliott4470a302015-02-17 10:33:47 -07001534 char *libPaths = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001535 DIR *curdir;
1536 struct dirent *dent;
Ian Elliott4470a302015-02-17 10:33:47 -07001537 size_t len, i;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001538 char temp_str[1024];
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001539
Ian Elliott4470a302015-02-17 10:33:47 -07001540#if defined(WIN32)
1541 bool must_free_libPaths;
1542 libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV,
1543 LAYERS_PATH_REGISTRY_VALUE);
1544 if (libPaths != NULL) {
1545 must_free_libPaths = true;
1546 } else {
1547 must_free_libPaths = false;
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001548 libPaths = DEFAULT_VK_LAYERS_PATH;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001549 }
Ian Elliott4470a302015-02-17 10:33:47 -07001550#else // WIN32
1551 if (geteuid() == getuid()) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001552 /* Don't allow setuid apps to use the LAYERS_PATH_ENV env var: */
Courtney Goeltzenleuchter66b72f92015-02-18 20:03:02 -07001553 libPaths = getenv(LAYERS_PATH_ENV);
Ian Elliott4470a302015-02-17 10:33:47 -07001554 }
1555 if (libPaths == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06001556 libPaths = DEFAULT_VK_LAYERS_PATH;
Ian Elliott4470a302015-02-17 10:33:47 -07001557 }
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001558#endif // WIN32
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001559
Ian Elliott4470a302015-02-17 10:33:47 -07001560 if (libPaths == NULL) {
1561 // Have no paths to search:
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001562 return;
1563 }
Ian Elliott4470a302015-02-17 10:33:47 -07001564 len = strlen(libPaths);
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001565 loader.layer_dirs = malloc(len+1);
Ian Elliott4470a302015-02-17 10:33:47 -07001566 if (loader.layer_dirs == NULL) {
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06001567 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add layer directories");
1568
Ian Elliott4470a302015-02-17 10:33:47 -07001569 free(libPaths);
Courtney Goeltzenleuchtera66265b2014-12-02 18:12:51 -07001570 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001571 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001572 // Alloc passed, so we know there is enough space to hold the string
Ian Elliott4470a302015-02-17 10:33:47 -07001573 strcpy(loader.layer_dirs, libPaths);
1574#if defined(WIN32)
1575 // Free any allocated memory:
1576 if (must_free_libPaths) {
1577 free(libPaths);
1578 must_free_libPaths = false;
1579 }
1580#endif // WIN32
Courtney Goeltzenleuchter57985ce2014-12-01 09:29:42 -07001581 libPaths = loader.layer_dirs;
1582
Jon Ashburn5ef20602015-07-02 09:40:15 -06001583 if (loader.scanned_layers.capacity == 0) {
1584 loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1585 if (loader.scanned_layers.list == NULL) {
1586 //TODO ERR log
1587 return;
1588 }
1589 memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1590 loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001591 }
Jon Ashburn5ef20602015-07-02 09:40:15 -06001592 else {
1593 /* cleanup any previously scanned libraries */
1594 //TODO make sure everything is cleaned up properly
1595 for (i = 0; i < loader.scanned_layers.count; i++) {
1596 if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
1597 free(loader.scanned_layers.list[i].lib_info.lib_name);
Jon Ashburn5ef20602015-07-02 09:40:15 -06001598 loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
1599 loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
1600 loader.scanned_layers.list[i].lib_info.lib_name = NULL;
1601 }
1602 loader.scanned_layers.count = 0;
1603 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001604
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001605 for (p = libPaths; *p; p = next) {
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001606 next = strchr(p, PATH_SEPERATOR);
1607 if (next == NULL) {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001608 len = (uint32_t) strlen(p);
1609 next = p + len;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001610 }
1611 else {
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001612 len = (uint32_t) (next - p);
1613 *(char *) next = '\0';
1614 next++;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001615 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001616
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001617 curdir = opendir(p);
1618 if (curdir) {
1619 dent = readdir(curdir);
1620 while (dent) {
1621 /* Look for layers starting with VK_LAYER_LIBRARY_PREFIX and
1622 * ending with VK_LIBRARY_SUFFIX
1623 */
1624 if (!strncmp(dent->d_name,
1625 VK_LAYER_LIBRARY_PREFIX,
1626 VK_LAYER_LIBRARY_PREFIX_LEN)) {
1627 uint32_t nlen = (uint32_t) strlen(dent->d_name);
1628 const char *suf = dent->d_name + nlen - VK_LIBRARY_SUFFIX_LEN;
1629 if ((nlen > VK_LIBRARY_SUFFIX_LEN) &&
1630 !strncmp(suf,
1631 VK_LIBRARY_SUFFIX,
1632 VK_LIBRARY_SUFFIX_LEN)) {
1633 loader_platform_dl_handle handle;
1634 snprintf(temp_str, sizeof(temp_str),
Jon Ashburn2077e382015-06-29 11:25:34 -06001635 "%s%c%s",p, DIRECTORY_SYMBOL, dent->d_name);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001636 // Used to call: dlopen(temp_str, RTLD_LAZY)
1637 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001638 "Attempt to open library: %s", temp_str);
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001639 if ((handle = loader_platform_open_library(temp_str)) == NULL) {
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001640 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed");
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001641 dent = readdir(curdir);
1642 continue;
1643 }
1644 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001645 "Opened library: %s", temp_str);
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06001646
Courtney Goeltzenleuchter1e4602f2015-06-09 09:44:13 -06001647 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting global extensions for %s", temp_str);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001648
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001649 loader_add_global_layer_properties(temp_str, handle, &loader.scanned_layers);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001650
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001651 loader_platform_close_library(handle);
1652 }
1653 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001654
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001655 dent = readdir(curdir);
1656 } // while (dir_entry)
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001657 closedir(curdir);
1658 } // if (curdir))
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001659 } // for (libpaths)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001660}
1661
Jon Ashburn27cd5842015-05-12 17:26:48 -06001662static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1663{
1664 // inst is not wrapped
1665 if (inst == VK_NULL_HANDLE) {
1666 return NULL;
1667 }
1668 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1669 void *addr;
1670
Jon Ashburn8fd08252015-05-28 16:25:02 -06001671 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1672 return (void *) loader_gpa_instance_internal;
1673
Jon Ashburn27cd5842015-05-12 17:26:48 -06001674 if (disp_table == NULL)
1675 return NULL;
1676
1677 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001678 if (addr) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001679 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001680 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001681
1682 if (disp_table->GetInstanceProcAddr == NULL) {
1683 return NULL;
1684 }
1685 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburn3d526cb2015-04-13 18:10:06 -06001686}
1687
Jon Ashburn128f9422015-05-28 19:16:58 -06001688struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001689{
Jon Ashburn128f9422015-05-28 19:16:58 -06001690
Jon Ashburn98bd4542015-01-29 16:44:24 -07001691 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1692 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1693 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburn128f9422015-05-28 19:16:58 -06001694 if (icd->gpus[i] == gpu) {
Jon Ashburn98bd4542015-01-29 16:44:24 -07001695 *gpu_index = i;
1696 return icd;
1697 }
1698 }
Jon Ashburn876b1ac2014-10-17 15:09:07 -06001699 }
1700 return NULL;
1701}
1702
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001703static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn4f67d742015-05-27 13:19:22 -06001704 const char *chain_type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001705 struct loader_layer_properties *layer_prop)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001706{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001707 struct loader_lib_info *new_layer_lib_list, *my_lib;
1708
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001709 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001710 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001711 /* Have already loaded this library, just increment ref count */
1712 loader.loaded_layer_lib_list[i].ref_count++;
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001713 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001714 "%s Chain: Increment layer reference count for 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 return loader.loaded_layer_lib_list[i].lib_handle;
1717 }
1718 }
1719
1720 /* Haven't seen this library so load it */
1721 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1722 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1723 if (!new_layer_lib_list) {
1724 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1725 return NULL;
1726 }
1727
1728 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1729
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001730 /* NOTE: We require that the layer property be immutable */
1731 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001732 my_lib->ref_count = 0;
1733 my_lib->lib_handle = NULL;
1734
1735 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1736 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1737 loader_platform_open_library_error(my_lib->lib_name));
1738 return NULL;
1739 } else {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001740 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001741 "Chain: %s: Loading layer library %s",
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001742 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001743 }
1744 loader.loaded_layer_lib_count++;
1745 loader.loaded_layer_lib_list = new_layer_lib_list;
1746 my_lib->ref_count++;
1747
1748 return my_lib->lib_handle;
1749}
1750
1751static void loader_remove_layer_lib(
1752 struct loader_instance *inst,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001753 struct loader_layer_properties *layer_prop)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001754{
1755 uint32_t idx;
1756 struct loader_lib_info *new_layer_lib_list, *my_lib;
1757
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001758 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001759 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001760 /* found matching library */
1761 idx = i;
1762 my_lib = &loader.loaded_layer_lib_list[i];
1763 break;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001764 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001765 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001766
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001767 my_lib->ref_count--;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001768 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001769 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001770 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001771 return;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001772 }
Jon Ashburn19c25022015-04-14 14:14:48 -06001773
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001774 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchterca8c81a2015-06-14 11:59:07 -06001775 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001776 "Unloading layer library %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001777
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001778 /* Need to remove unused library from list */
1779 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1780 if (!new_layer_lib_list) {
1781 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1782 return;
1783 }
1784
1785 if (idx > 0) {
1786 /* Copy records before idx */
1787 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1788 sizeof(struct loader_lib_info) * idx);
1789 }
1790 if (idx < (loader.loaded_layer_lib_count - 1)) {
1791 /* Copy records after idx */
1792 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1793 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1794 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001795
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001796 free(loader.loaded_layer_lib_list);
1797 loader.loaded_layer_lib_count--;
1798 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnb8358052014-11-18 09:06:04 -07001799}
1800
Jon Ashburn0c26e712015-07-02 16:10:32 -06001801static void loader_add_layer_implicit(
1802 const enum layer_type type,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001803 struct loader_layer_list *list,
1804 struct loader_layer_list *search_list)
Jon Ashburn0c26e712015-07-02 16:10:32 -06001805{
1806 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001807 for (i = 0; i < search_list->count; i++) {
1808 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06001809 if (prop->type & type) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001810 /* Found an layer with the same type, add to layer_list */
1811 loader_add_to_layer_list(list, 1, prop);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001812 }
1813 }
1814
1815}
1816
1817/**
1818 * Get the layer name(s) from the env_name environment variable. If layer
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001819 * is found in search_list then add it to layer_list.
Jon Ashburn0c26e712015-07-02 16:10:32 -06001820 */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001821static void loader_add_layer_env(
Jon Ashburneb6d5682015-07-02 14:10:53 -06001822 const char *env_name,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001823 struct loader_layer_list *layer_list,
1824 const struct loader_layer_list *search_list)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001825{
Ian Elliott4470a302015-02-17 10:33:47 -07001826 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06001827 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001828
Jon Ashburneb6d5682015-07-02 14:10:53 -06001829 layerEnv = getenv(env_name);
Ian Elliott4470a302015-02-17 10:33:47 -07001830 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001831 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001832 }
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001833 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001834 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001835 return;
Ian Elliott4470a302015-02-17 10:33:47 -07001836 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06001837 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001838
Jon Ashburneb6d5682015-07-02 14:10:53 -06001839 while (name && *name ) {
1840 next = loader_get_next_path(name);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001841 loader_find_layer_name_add_list(name, search_list, layer_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06001842 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07001843 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001844
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001845 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06001846}
1847
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001848void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001849{
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001850 if (!instance->activated_layer_list.count) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001851 return;
1852 }
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001853
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001854 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter7d0023c2015-06-08 15:09:22 -06001855 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001856 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001857
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001858 loader_remove_layer_lib(instance, layer_prop);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001859 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001860 loader_destroy_layer_list(&instance->activated_layer_list);
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06001861}
1862
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001863void loader_enable_instance_layers(
1864 struct loader_instance *inst,
1865 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001866{
1867 if (inst == NULL)
1868 return;
1869
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001870 if (!loader_init_layer_list(&inst->activated_layer_list)) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001871 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
1872 return;
1873 }
1874
Jon Ashburn0c26e712015-07-02 16:10:32 -06001875 /* Add any implicit layers first */
1876 loader_add_layer_implicit(
1877 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
1878 &inst->activated_layer_list,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001879 &loader.scanned_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06001880
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001881 /* Add any layers specified via environment variable first */
Jon Ashburneb6d5682015-07-02 14:10:53 -06001882 loader_add_layer_env(
1883 "VK_INSTANCE_LAYERS",
1884 &inst->activated_layer_list,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001885 &loader.scanned_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001886
1887 /* Add layers specified by the application */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001888 loader_add_layer_names_to_list(
1889 &inst->activated_layer_list,
1890 pCreateInfo->layerCount,
1891 pCreateInfo->ppEnabledLayerNames,
1892 &loader.scanned_layers);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001893}
1894
Jon Ashburn27cd5842015-05-12 17:26:48 -06001895uint32_t loader_activate_instance_layers(struct loader_instance *inst)
1896{
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001897 uint32_t layer_idx;
Jon Ashburn128f9422015-05-28 19:16:58 -06001898 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001899
David Pinedoa0a8a242015-06-24 15:29:18 -06001900 if (inst == NULL) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001901 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06001902 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06001903
1904 // NOTE inst is unwrapped at this point in time
1905 VkObject baseObj = (VkObject) inst;
1906 VkObject nextObj = (VkObject) inst;
1907 VkBaseLayerObject *nextInstObj;
1908 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
1909
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001910 if (!inst->activated_layer_list.count) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06001911 return 0;
1912 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001913
Jon Ashburn128f9422015-05-28 19:16:58 -06001914 wrappedInstance = malloc(sizeof(VkBaseLayerObject)
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001915 * inst->activated_layer_list.count);
Jon Ashburn128f9422015-05-28 19:16:58 -06001916 if (!wrappedInstance) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001917 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
1918 return 0;
1919 }
1920
1921 /* Create instance chain of enabled layers */
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001922 layer_idx = inst->activated_layer_list.count - 1;
Courtney Goeltzenleuchter0f1d8eb2015-06-07 17:28:17 -06001923 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001924 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001925 loader_platform_dl_handle lib_handle;
1926
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001927 /*
Courtney Goeltzenleuchteree3b16a2015-06-01 14:12:42 -06001928 * Note: An extension's Get*ProcAddr should not return a function pointer for
1929 * any extension entry points until the extension has been enabled.
1930 * To do this requires a different behavior from Get*ProcAddr functions implemented
1931 * in layers.
1932 * The very first call to a layer will be it's Get*ProcAddr function requesting
1933 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
1934 * with the wrapped object given (either Instance or Device) and return the layer's
1935 * Get*ProcAddr function. The layer should also use this opportunity to record the
1936 * baseObject so that it can find the correct local dispatch table on future calls.
1937 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
1938 * will not use a wrapped object and must look up their local dispatch table from
1939 * the given baseObject.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001940 */
Jon Ashburn128f9422015-05-28 19:16:58 -06001941 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburn27cd5842015-05-12 17:26:48 -06001942 nextInstObj->pGPA = nextGPA;
1943 nextInstObj->baseObject = baseObj;
1944 nextInstObj->nextObject = nextObj;
1945 nextObj = (VkObject) nextInstObj;
1946
1947 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001948 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
1949 lib_handle = loader_add_layer_lib("instance", layer_prop);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001950 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
1951 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburn27cd5842015-05-12 17:26:48 -06001952 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001953 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 -06001954
1955 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburn27cd5842015-05-12 17:26:48 -06001956 continue;
1957 }
1958
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001959 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001960 "Insert instance layer %s (%s)",
1961 layer_prop->info.layerName,
1962 layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001963
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001964 layer_idx--;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001965 }
1966
Jon Ashburn8fd08252015-05-28 16:25:02 -06001967 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001968
Jon Ashburn128f9422015-05-28 19:16:58 -06001969 free(wrappedInstance);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001970 return inst->activated_layer_list.count;
Jon Ashburn27cd5842015-05-12 17:26:48 -06001971}
1972
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001973void loader_activate_instance_layer_extensions(struct loader_instance *inst)
1974{
1975
1976 loader_init_instance_extension_dispatch_table(inst->disp,
1977 inst->disp->GetInstanceProcAddr,
Jon Ashburn128f9422015-05-28 19:16:58 -06001978 (VkInstance) inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06001979}
1980
Courtney Goeltzenleuchtera6628c22015-06-25 16:27:24 -06001981static void loader_enable_device_layers(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001982 struct loader_device *dev,
1983 const VkDeviceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001984{
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001985 if (dev == NULL)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001986 return;
1987
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001988 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001989 loader_init_layer_list(&dev->activated_layer_list);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001990 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001991
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001992 if (dev->activated_layer_list.list == NULL) {
1993 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
1994 return;
1995 }
1996
Jon Ashburn0c26e712015-07-02 16:10:32 -06001997 /* Add any implicit layers first */
1998 loader_add_layer_implicit(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001999 VK_LAYER_TYPE_DEVICE_IMPLICIT,
2000 &dev->activated_layer_list,
2001 &loader.scanned_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06002002
2003 /* Add any layers specified via environment variable next */
Jon Ashburneb6d5682015-07-02 14:10:53 -06002004 loader_add_layer_env(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002005 "VK_DEVICE_LAYERS",
2006 &dev->activated_layer_list,
2007 &loader.scanned_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06002008
2009 /* Add layers specified by the application */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002010 loader_add_layer_names_to_list(
2011 &dev->activated_layer_list,
2012 pCreateInfo->layerCount,
2013 pCreateInfo->ppEnabledLayerNames,
2014 &loader.scanned_layers);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002015}
2016
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002017/*
2018 * This function terminates the device chain fro CreateDevice.
2019 * CreateDevice is a special case and so the loader call's
2020 * the ICD's CreateDevice before creating the chain. Since
2021 * we can't call CreateDevice twice we must terminate the
2022 * device chain with something else.
2023 */
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002024static VkResult scratch_vkCreateDevice(
2025 VkPhysicalDevice gpu,
2026 const VkDeviceCreateInfo *pCreateInfo,
2027 VkDevice *pDevice)
2028{
2029 return VK_SUCCESS;
2030}
2031
2032static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2033{
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002034 if (!strcmp(name, "vkGetDeviceProcAddr"))
2035 return (void *) loader_GetDeviceChainProcAddr;
2036 if (!strcmp(name, "vkCreateDevice"))
2037 return (void *) scratch_vkCreateDevice;
2038
Courtney Goeltzenleuchter3e029d12015-06-29 16:09:23 -06002039 struct loader_device *found_dev;
2040 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2041 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002042}
2043
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002044static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002045 VkPhysicalDevice gpu,
2046 VkDevice device,
2047 struct loader_device *dev,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002048 struct loader_icd *icd)
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002049{
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002050 if (!icd)
2051 return 0;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002052
David Pinedoa0a8a242015-06-24 15:29:18 -06002053 if (!dev) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002054 return 0;
David Pinedoa0a8a242015-06-24 15:29:18 -06002055 }
Jon Ashburn94e70492015-06-10 10:13:10 -06002056
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002057 /* activate any layer libraries */
Jon Ashburn94e70492015-06-10 10:13:10 -06002058 VkObject nextObj = (VkObject) device;
2059 VkObject baseObj = nextObj;
2060 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002061 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn94e70492015-06-10 10:13:10 -06002062 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002063
Jon Ashburn94e70492015-06-10 10:13:10 -06002064 if (!dev->activated_layer_list.count)
2065 return 0;
2066
2067 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2068 if (!wrappedGpus) {
2069 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2070 return 0;
2071 }
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002072
Jon Ashburn94e70492015-06-10 10:13:10 -06002073 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2074
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002075 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
Jon Ashburn94e70492015-06-10 10:13:10 -06002076 loader_platform_dl_handle lib_handle;
2077
Jon Ashburn94e70492015-06-10 10:13:10 -06002078 nextGpuObj = (wrappedGpus + i);
2079 nextGpuObj->pGPA = nextGPA;
2080 nextGpuObj->baseObject = baseObj;
2081 nextGpuObj->nextObject = nextObj;
2082 nextObj = (VkObject) nextGpuObj;
2083
2084 char funcStr[256];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002085 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2086 lib_handle = loader_add_layer_lib("device", layer_prop);
Jon Ashburn94e70492015-06-10 10:13:10 -06002087 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2088 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2089 if (!nextGPA) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002090 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 -06002091 continue;
2092 }
2093
2094 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002095 "Insert device layer library %s (%s)",
2096 layer_prop->info.layerName,
2097 layer_prop->lib_info.lib_name);
Jon Ashburn94e70492015-06-10 10:13:10 -06002098
2099 }
2100
2101 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2102 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
2103 free(wrappedGpus);
2104
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002105 return dev->activated_layer_list.count;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06002106}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002107
Jon Ashburn27cd5842015-05-12 17:26:48 -06002108VkResult loader_CreateInstance(
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002109 const VkInstanceCreateInfo* pCreateInfo,
2110 VkInstance* pInstance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002111{
Jon Ashburneed0c002015-05-21 17:42:17 -06002112 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn46888392015-01-29 15:45:51 -07002113 struct loader_scanned_icds *scanned_icds;
2114 struct loader_icd *icd;
Jon Ashburn27cd5842015-05-12 17:26:48 -06002115 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002116
Jon Ashburn46888392015-01-29 15:45:51 -07002117 scanned_icds = loader.scanned_icd_list;
2118 while (scanned_icds) {
2119 icd = loader_icd_add(ptr_instance, scanned_icds);
2120 if (icd) {
Jon Ashburnb317fad2015-04-04 14:52:07 -06002121 res = scanned_icds->CreateInstance(pCreateInfo,
Jon Ashburn3da71f22015-05-14 12:43:38 -06002122 &(icd->instance));
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002123 if (res != VK_SUCCESS)
Jon Ashburn46888392015-01-29 15:45:51 -07002124 {
2125 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002126 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002127 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002128 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn46888392015-01-29 15:45:51 -07002129 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn3da71f22015-05-14 12:43:38 -06002130 } else
2131 {
2132 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn46888392015-01-29 15:45:51 -07002133 }
2134 }
2135 scanned_icds = scanned_icds->next;
2136 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002137
Ian Elliotteb450762015-02-05 15:19:15 -07002138 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002139 return VK_ERROR_INCOMPATIBLE_DRIVER;
Ian Elliotteb450762015-02-05 15:19:15 -07002140 }
Jon Ashburn46888392015-01-29 15:45:51 -07002141
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002142 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002143}
2144
Jon Ashburn27cd5842015-05-12 17:26:48 -06002145VkResult loader_DestroyInstance(
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002146 VkInstance instance)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002147{
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06002148 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002149 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002150 struct loader_icd *next_icd;
Courtney Goeltzenleuchterfb4efc62015-04-10 08:34:15 -06002151 VkResult res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002152
2153 // Remove this instance from the list of instances:
2154 struct loader_instance *prev = NULL;
2155 struct loader_instance *next = loader.instances;
2156 while (next != NULL) {
2157 if (next == ptr_instance) {
2158 // Remove this instance from the list:
2159 if (prev)
2160 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07002161 else
2162 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002163 break;
2164 }
2165 prev = next;
2166 next = next->next;
2167 }
2168 if (next == NULL) {
2169 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002170 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002171 }
2172
Jon Ashburn3da71f22015-05-14 12:43:38 -06002173 while (icds) {
2174 if (icds->instance) {
2175 res = icds->DestroyInstance(icds->instance);
Tony Barbourf20f87b2015-04-22 09:02:32 -06002176 if (res != VK_SUCCESS)
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002177 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbourf20f87b2015-04-22 09:02:32 -06002178 "ICD ignored: failed to DestroyInstance on device");
2179 }
Jon Ashburna6fd2612015-06-16 14:43:19 -06002180 next_icd = icds->next;
Jon Ashburn3da71f22015-05-14 12:43:38 -06002181 icds->instance = VK_NULL_HANDLE;
Jon Ashburna6fd2612015-06-16 14:43:19 -06002182 loader_icd_destroy(ptr_instance, icds);
2183
2184 icds = next_icd;
Jon Ashburn46888392015-01-29 15:45:51 -07002185 }
2186
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002187
Courtney Goeltzenleuchterd8e229c2015-04-08 15:36:08 -06002188 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002189}
2190
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002191VkResult loader_init_physical_device_info(
2192 struct loader_instance *ptr_instance)
2193{
2194 struct loader_icd *icd;
2195 uint32_t n, count = 0;
2196 VkResult res = VK_ERROR_UNKNOWN;
2197
2198 icd = ptr_instance->icds;
2199 while (icd) {
2200 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2201 if (res != VK_SUCCESS)
2202 return res;
2203 icd->gpu_count = n;
2204 count += n;
2205 icd = icd->next;
2206 }
2207
2208 ptr_instance->total_gpu_count = count;
2209
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002210 icd = ptr_instance->icds;
2211 while (icd) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002212
2213 n = icd->gpu_count;
Jon Ashburn128f9422015-05-28 19:16:58 -06002214 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2215 if (!icd->gpus) {
2216 /* TODO: Add cleanup code here */
2217 return VK_ERROR_OUT_OF_HOST_MEMORY;
2218 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002219 res = icd->EnumeratePhysicalDevices(
2220 icd->instance,
2221 &n,
Jon Ashburn128f9422015-05-28 19:16:58 -06002222 icd->gpus);
2223 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002224
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002225 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002226
Jon Ashburn128f9422015-05-28 19:16:58 -06002227 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002228
2229 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2230 /* TODO: Add cleanup code here */
2231 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2232 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002233 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002234
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002235 loader_add_physical_device_extensions(
2236 icd->GetPhysicalDeviceExtensionProperties,
2237 icd->gpus[0],
2238 VK_EXTENSION_ORIGIN_ICD,
2239 icd->scanned_icds->lib_name,
2240 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002241
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002242 for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
2243 loader_platform_dl_handle lib_handle;
2244 char *lib_name = loader.scanned_layers.list[i].lib_info.lib_name;
2245
2246 lib_handle = loader_platform_open_library(lib_name);
2247 if (lib_handle == NULL) {
2248 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed: %s", lib_name);
2249 continue;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002250 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002251 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2252 "library: %s", lib_name);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002253
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002254 loader_add_physical_device_layer_properties(
2255 icd, lib_name, lib_handle);
2256
2257 loader_platform_close_library(lib_handle);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002258 }
2259 }
2260
2261 if (res != VK_SUCCESS) {
2262 /* clean up any extension lists previously created before this request failed */
2263 for (uint32_t j = 0; j < i; j++) {
2264 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2265 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002266
2267 loader_destroy_layer_list(&icd->layer_properties_cache);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002268 return res;
2269 }
2270 }
2271
2272 count += n;
2273 }
2274
2275 icd = icd->next;
2276 }
2277
2278 return VK_SUCCESS;
2279}
2280
Jon Ashburn27cd5842015-05-12 17:26:48 -06002281VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter5e41f1d2015-04-20 12:48:54 -06002282 VkInstance instance,
2283 uint32_t* pPhysicalDeviceCount,
2284 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002285{
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002286 uint32_t index = 0;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002287 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002288 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002289
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002290 if (ptr_instance->total_gpu_count == 0) {
2291 loader_init_physical_device_info(ptr_instance);
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002292 }
2293
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002294 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2295 if (!pPhysicalDevices) {
2296 return VK_SUCCESS;
2297 }
Jon Ashburn4c392fb2015-01-28 19:57:09 -07002298
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002299 while (icd) {
2300 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburn128f9422015-05-28 19:16:58 -06002301 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002302 index += icd->gpu_count;
2303 icd = icd->next;
2304 }
2305
2306 return VK_SUCCESS;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002307}
2308
Tony Barbour59a47322015-06-24 16:06:58 -06002309VkResult loader_GetPhysicalDeviceProperties(
Jon Ashburn3da71f22015-05-14 12:43:38 -06002310 VkPhysicalDevice gpu,
Tony Barbour59a47322015-06-24 16:06:58 -06002311 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn3da71f22015-05-14 12:43:38 -06002312{
2313 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002314 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002315 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2316
Tony Barbour59a47322015-06-24 16:06:58 -06002317 if (icd->GetPhysicalDeviceProperties)
2318 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2319
2320 return res;
2321}
2322
2323VkResult loader_GetPhysicalDevicePerformance(
2324 VkPhysicalDevice gpu,
2325 VkPhysicalDevicePerformance* pPerformance)
2326{
2327 uint32_t gpu_index;
2328 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2329 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2330
2331 if (icd->GetPhysicalDevicePerformance)
2332 res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2333
2334 return res;
2335}
2336
2337VkResult loader_GetPhysicalDeviceQueueCount(
2338 VkPhysicalDevice gpu,
2339 uint32_t* pCount)
2340{
2341 uint32_t gpu_index;
2342 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2343 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2344
2345 if (icd->GetPhysicalDeviceQueueCount)
2346 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2347
2348 return res;
2349}
2350
2351VkResult loader_GetPhysicalDeviceQueueProperties (
2352 VkPhysicalDevice gpu,
2353 uint32_t count,
2354 VkPhysicalDeviceQueueProperties * pProperties)
2355{
2356 uint32_t gpu_index;
2357 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2358 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2359
2360 if (icd->GetPhysicalDeviceQueueProperties)
2361 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2362
2363 return res;
2364}
2365
2366VkResult loader_GetPhysicalDeviceMemoryProperties (
2367 VkPhysicalDevice gpu,
2368 VkPhysicalDeviceMemoryProperties* pProperties)
2369{
2370 uint32_t gpu_index;
2371 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2372 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2373
2374 if (icd->GetPhysicalDeviceMemoryProperties)
2375 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn3da71f22015-05-14 12:43:38 -06002376
2377 return res;
2378}
2379
Chris Forbesbc0bb772015-06-21 22:55:02 +12002380VkResult loader_GetPhysicalDeviceFeatures(
2381 VkPhysicalDevice physicalDevice,
2382 VkPhysicalDeviceFeatures* pFeatures)
2383{
2384 uint32_t gpu_index;
2385 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2386 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2387
2388 if (icd->GetPhysicalDeviceFeatures)
2389 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2390
2391 return res;
2392}
2393
2394VkResult loader_GetPhysicalDeviceFormatInfo(
2395 VkPhysicalDevice physicalDevice,
2396 VkFormat format,
2397 VkFormatProperties* pFormatInfo)
2398{
2399 uint32_t gpu_index;
2400 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2401 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2402
2403 if (icd->GetPhysicalDeviceFormatInfo)
2404 res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2405
2406 return res;
2407}
2408
2409VkResult loader_GetPhysicalDeviceLimits(
2410 VkPhysicalDevice physicalDevice,
2411 VkPhysicalDeviceLimits* pLimits)
2412{
2413 uint32_t gpu_index;
2414 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2415 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2416
2417 if (icd->GetPhysicalDeviceLimits)
2418 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2419
2420 return res;
2421}
2422
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002423VkResult loader_CreateDevice(
2424 VkPhysicalDevice gpu,
2425 const VkDeviceCreateInfo* pCreateInfo,
2426 VkDevice* pDevice)
2427{
2428 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002429 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06002430 struct loader_device *dev;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002431 VkResult res;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002432
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002433 if (!icd->CreateDevice) {
2434 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002435 }
2436
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002437 /*
2438 * TODO: Must filter CreateInfo extension list to only
2439 * those extensions supported by the ICD.
2440 * TODO: Probably should verify that every extension is
2441 * covered by either the ICD or some layer.
2442 */
2443
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002444 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2445 if (res != VK_SUCCESS) {
2446 return res;
2447 }
2448
2449 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2450 if (dev == NULL) {
2451 return VK_ERROR_OUT_OF_HOST_MEMORY;
2452 }
2453 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2454 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2455 icd->gpus[gpu_index], icd->gpus[gpu_index]);
2456
2457 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2458 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2459
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002460 /*
2461 * Put together the complete list of extensions to enable
2462 * This includes extensions requested via environment variables.
2463 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002464 loader_enable_device_layers(dev, pCreateInfo);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002465
2466 /*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002467 * Load the libraries and build the device chain
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002468 * terminating with the selected device.
2469 */
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002470 loader_activate_device_layers(gpu, *pDevice, dev, icd);
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06002471
2472 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2473
2474 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2475
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002476 return res;
2477}
2478
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002479static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002480{
Jon Ashburn07daee72015-05-21 18:13:33 -06002481 if (instance == VK_NULL_HANDLE)
2482 return NULL;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002483
Jon Ashburn07daee72015-05-21 18:13:33 -06002484 void *addr;
2485 /* get entrypoint addresses that are global (in the loader)*/
2486 addr = globalGetProcAddr(pName);
2487 if (addr)
2488 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002489
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002490 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2491
Jon Ashburn922c8f62015-06-18 09:05:37 -06002492 /* return any extension global entrypoints */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002493 addr = debug_report_instance_gpa(ptr_instance, pName);
2494 if (addr) {
2495 return addr;
2496 }
2497
Jon Ashburn922c8f62015-06-18 09:05:37 -06002498 /* TODO Remove this once WSI has no loader special code */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002499 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002500 if (addr) {
Jon Ashburn922c8f62015-06-18 09:05:37 -06002501 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002502 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002503
2504 /* return the instance dispatch table entrypoint for extensions */
2505 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2506 if (disp_table == NULL)
2507 return NULL;
2508
2509 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2510 if (addr)
2511 return addr;
Jon Ashburnb0fbe912015-05-06 10:15:07 -06002512
2513 return NULL;
2514}
2515
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002516LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2517{
2518 return loader_GetInstanceProcAddr(instance, pName);
2519}
2520
2521static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn1beab2d2015-01-26 14:51:40 -07002522{
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002523 if (device == VK_NULL_HANDLE) {
2524 return NULL;
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07002525 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002526
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002527 void *addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002528
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002529 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2530 make sure the loader entrypoint is returned */
2531 addr = loader_non_passthrough_gpa(pName);
Ian Elliotte19c9152015-04-15 12:53:19 -06002532 if (addr) {
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002533 return addr;
Ian Elliotte19c9152015-04-15 12:53:19 -06002534 }
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002535
Jon Ashburn07daee72015-05-21 18:13:33 -06002536 /* return any extension device entrypoints the loader knows about */
Jon Ashburn922c8f62015-06-18 09:05:37 -06002537 /* TODO once WSI has no loader special code remove this */
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002538 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
David Pinedoa0a8a242015-06-24 15:29:18 -06002539 if (addr) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06002540 return addr;
David Pinedoa0a8a242015-06-24 15:29:18 -06002541 }
Jon Ashburn07daee72015-05-21 18:13:33 -06002542
Jon Ashburn3d526cb2015-04-13 18:10:06 -06002543 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002544 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002545 if (disp_table == NULL)
2546 return NULL;
2547
Jon Ashburn27cd5842015-05-12 17:26:48 -06002548 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wuf46b81a2015-01-04 11:12:47 +08002549 if (addr)
2550 return addr;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002551 else {
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002552 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002553 return NULL;
Jon Ashburn8d1b0b52015-05-18 13:20:15 -06002554 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06002555 }
2556}
2557
Courtney Goeltzenleuchter9ec39ac2015-06-22 17:45:21 -06002558LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2559{
2560 return loader_GetDeviceProcAddr(device, pName);
2561}
2562
Tony Barbour59a47322015-06-24 16:06:58 -06002563LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002564 const char* pLayerName,
2565 uint32_t* pCount,
2566 VkExtensionProperties* pProperties)
2567{
2568 struct loader_extension_list *global_extension_list;
2569
2570 /* Scan/discover all ICD libraries in a single-threaded manner */
2571 loader_platform_thread_once(&once_icd, loader_icd_scan);
2572
2573 /* get layer libraries in a single-threaded manner */
2574 loader_platform_thread_once(&once_layer, loader_layer_scan);
2575
2576 /* merge any duplicate extensions */
2577 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2578
2579 uint32_t copy_size;
2580
2581 if (pCount == NULL) {
2582 return VK_ERROR_INVALID_POINTER;
2583 }
2584
2585 loader_platform_thread_lock_mutex(&loader_lock);
2586
2587 global_extension_list = loader_global_extensions(pLayerName);
2588 if (global_extension_list == NULL) {
2589 loader_platform_thread_unlock_mutex(&loader_lock);
2590 return VK_ERROR_INVALID_LAYER;
2591 }
2592
2593 if (pProperties == NULL) {
2594 *pCount = global_extension_list->count;
2595 loader_platform_thread_unlock_mutex(&loader_lock);
2596 return VK_SUCCESS;
2597 }
2598
2599 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2600 for (uint32_t i = 0; i < copy_size; i++) {
2601 memcpy(&pProperties[i],
2602 &global_extension_list->list[i].info,
2603 sizeof(VkExtensionProperties));
2604 }
2605 *pCount = copy_size;
2606
2607 loader_platform_thread_unlock_mutex(&loader_lock);
2608
2609 if (copy_size < global_extension_list->count) {
2610 return VK_INCOMPLETE;
2611 }
2612
2613 return VK_SUCCESS;
2614}
2615
2616LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2617 uint32_t* pCount,
2618 VkLayerProperties* pProperties)
Tony Barbour59a47322015-06-24 16:06:58 -06002619{
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002620
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002621 /* Scan/discover all ICD libraries in a single-threaded manner */
2622 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002623
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002624 /* get layer libraries in a single-threaded manner */
Jon Ashburn5ef20602015-07-02 09:40:15 -06002625 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002626
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002627 /* merge any duplicate extensions */
2628 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2629
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002630 uint32_t copy_size;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06002631
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002632 if (pCount == NULL) {
2633 return VK_ERROR_INVALID_POINTER;
2634 }
2635
2636 /* TODO: do we still need to lock */
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002637 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002638
2639 struct loader_layer_list *layer_list;
2640 layer_list = loader_global_layers();
2641
2642 if (pProperties == NULL) {
2643 *pCount = layer_list->count;
2644 loader_platform_thread_unlock_mutex(&loader_lock);
2645 return VK_SUCCESS;
2646 }
2647
2648 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
2649 for (uint32_t i = 0; i < copy_size; i++) {
2650 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
2651 }
2652 *pCount = copy_size;
Tony Barbour59a47322015-06-24 16:06:58 -06002653
Jon Ashburn6301a0f2015-05-29 13:15:39 -06002654 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002655
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002656 if (copy_size < layer_list->count) {
2657 return VK_INCOMPLETE;
2658 }
Tony Barbour59a47322015-06-24 16:06:58 -06002659
2660 return VK_SUCCESS;
2661}
2662
2663VkResult loader_GetPhysicalDeviceExtensionProperties(
2664 VkPhysicalDevice gpu,
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002665 const char* pLayerName,
2666 uint32_t* pCount,
Tony Barbour59a47322015-06-24 16:06:58 -06002667 VkExtensionProperties* pProperties)
2668{
2669 uint32_t gpu_index;
Jon Ashburn128f9422015-05-28 19:16:58 -06002670 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002671 uint32_t copy_size;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07002672
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002673 if (pCount == NULL) {
2674 return VK_ERROR_INVALID_POINTER;
2675 }
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002676
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06002677 uint32_t count;
2678 struct loader_extension_list *list;
2679 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
2680
2681 if (pProperties == NULL) {
2682 *pCount = count;
2683 return VK_SUCCESS;
2684 }
2685
2686 copy_size = *pCount < count ? *pCount : count;
2687 for (uint32_t i = 0; i < copy_size; i++) {
2688 memcpy(&pProperties[i],
2689 &list->list[i].info,
2690 sizeof(VkExtensionProperties));
2691 }
2692 *pCount = copy_size;
2693
2694 if (copy_size < count) {
2695 return VK_INCOMPLETE;
2696 }
2697
2698 return VK_SUCCESS;
2699}
2700
2701VkResult loader_GetPhysicalDeviceLayerProperties(
2702 VkPhysicalDevice gpu,
2703 uint32_t* pCount,
2704 VkLayerProperties* pProperties)
2705{
2706 uint32_t gpu_index;
2707 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2708 uint32_t copy_size;
2709
2710 if (pCount == NULL) {
2711 return VK_ERROR_INVALID_POINTER;
2712 }
2713
2714 uint32_t count;
2715 struct loader_layer_list *layer_list;
2716 loader_physical_device_layers(icd, &count, &layer_list);
2717
2718 if (pProperties == NULL) {
2719 *pCount = count;
2720 return VK_SUCCESS;
2721 }
2722
2723 copy_size = *pCount < count ? *pCount : count;
2724 for (uint32_t i = 0; i < copy_size; i++) {
2725 memcpy(&pProperties[i],
2726 &layer_list->list[i].info,
2727 sizeof(VkLayerProperties));
2728 }
2729 *pCount = copy_size;
2730
2731 if (copy_size < count) {
2732 return VK_INCOMPLETE;
2733 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06002734
2735 return VK_SUCCESS;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06002736}