blob: 8dc0af75c892fdc68bceaf2c3986b970008b09a7 [file] [log] [blame]
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001/*
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06002 * Vulkan
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003 *
4 * Copyright (C) 2014 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Chia-I Wu44e42362014-09-02 08:32:09 +080023 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
Jon Ashburn406a0fe2014-11-14 09:52:42 -070026 * Jon Ashburn <jon@lunarg.com>
Chia-I Wu44e42362014-09-02 08:32:09 +080027 * Courtney Goeltzenleuchter <courtney@lunarg.com>
Ian Elliott76005132015-03-31 15:32:41 -060028 * Ian Elliott <ian@lunarg.com>
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080029 */
Jon Ashburn183dfd02014-10-22 18:13:16 -060030#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080031#include <stdio.h>
32#include <stdlib.h>
33#include <stdarg.h>
34#include <stdbool.h>
35#include <string.h>
36
Chia-I Wu894a1172014-08-04 11:18:20 +080037#include <sys/types.h>
Ian Elliott81ac44c2015-01-13 17:52:38 -070038#if defined(WIN32)
39#include "dirent_on_windows.h"
40#else // WIN32
Chia-I Wu894a1172014-08-04 11:18:20 +080041#include <dirent.h>
Ian Elliott81ac44c2015-01-13 17:52:38 -070042#endif // WIN32
Tobin Ehlis7a51d902015-07-03 10:34:49 -060043#include "vk_loader_platform.h"
Chia-I Wu468e3c32014-08-04 08:03:57 +080044#include "loader.h"
Jon Ashburncedc15f2015-05-21 18:13:33 -060045#include "wsi_lunarg.h"
Jon Ashburnfce93d92015-05-12 17:26:48 -060046#include "gpa_helper.h"
47#include "table_ops.h"
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060048#include "debug_report.h"
Tobin Ehlis2d1d9702015-07-03 09:42:57 -060049#include "vk_icd.h"
Jon Ashburnffd5d672015-06-29 11:25:34 -060050#include "cJSON.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080051
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -060052void loader_add_to_ext_list(
53 struct loader_extension_list *ext_list,
54 uint32_t prop_list_count,
55 const struct loader_extension_property *prop_list);
56
Courtney Goeltzenleuchter71cd74d2015-06-01 14:09:34 -060057static loader_platform_dl_handle loader_add_layer_lib(
58 const char *chain_type,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060059 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchter71cd74d2015-06-01 14:09:34 -060060
61static void loader_remove_layer_lib(
62 struct loader_instance *inst,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060063 struct loader_layer_properties *layer_prop);
Courtney Goeltzenleuchter71cd74d2015-06-01 14:09:34 -060064
Jon Ashburnfce93d92015-05-12 17:26:48 -060065struct loader_struct loader = {0};
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080066
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -060067static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName);
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -060068static bool loader_init_ext_list(struct loader_extension_list *ext_info);
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -060069
Courtney Goeltzenleuchter8b253f92015-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 Ashburnb40f2562015-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 Ashburnffd5d672015-06-29 11:25:34 -060083// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburnb40f2562015-05-29 13:15:39 -060084loader_platform_thread_mutex loader_lock;
85
86const VkLayerInstanceDispatchTable instance_disp = {
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -060087 .GetInstanceProcAddr = loader_GetInstanceProcAddr,
Jon Ashburnfce93d92015-05-12 17:26:48 -060088 .CreateInstance = loader_CreateInstance,
89 .DestroyInstance = loader_DestroyInstance,
90 .EnumeratePhysicalDevices = loader_EnumeratePhysicalDevices,
Chris Forbesd7576302015-06-21 22:55:02 +120091 .GetPhysicalDeviceFeatures = loader_GetPhysicalDeviceFeatures,
92 .GetPhysicalDeviceFormatInfo = loader_GetPhysicalDeviceFormatInfo,
93 .GetPhysicalDeviceLimits = loader_GetPhysicalDeviceLimits,
Tony Barbour426b9052015-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 Barbour426b9052015-06-24 16:06:58 -060099 .GetPhysicalDeviceExtensionProperties = loader_GetPhysicalDeviceExtensionProperties,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600100 .GetPhysicalDeviceLayerProperties = loader_GetPhysicalDeviceLayerProperties,
Mark Lobodzinski83d4e6a2015-07-03 15:58:09 -0600101 .GetPhysicalDeviceSparseImageFormatProperties = loader_GetPhysicalDeviceSparseImageFormatProperties,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600102 .DbgCreateMsgCallback = loader_DbgCreateMsgCallback,
103 .DbgDestroyMsgCallback = loader_DbgDestroyMsgCallback,
Jon Ashburnfce93d92015-05-12 17:26:48 -0600104};
105
106LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
107LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
108LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_exts);
Ian Elliott81ac44c2015-01-13 17:52:38 -0700109
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600110void* loader_heap_alloc(
111 struct loader_instance *instance,
112 size_t size,
113 VkSystemAllocType alloc_type)
114{
115 if (instance && instance->alloc_callbacks.pfnAlloc) {
116 /* TODO: What should default alignment be? 1, 4, 8, other? */
117 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, 4, alloc_type);
118 }
119 return malloc(size);
120}
121
122void* loader_aligned_heap_alloc(
123 struct loader_instance *instance,
124 size_t size,
125 size_t alignment,
126 VkSystemAllocType alloc_type)
127{
128 if (!instance && instance->alloc_callbacks.pfnAlloc) {
129 return instance->alloc_callbacks.pfnAlloc(instance->alloc_callbacks.pUserData, size, alignment, alloc_type);
130 }
Cody Northrop62ac1c52015-07-08 16:48:37 -0600131#if defined(_WIN32)
132 return _aligned_malloc(alignment, size);
133#else
134 return aligned_alloc(alignment, size);
135#endif
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600136}
137
138void loader_heap_free(
139 struct loader_instance *instance,
140 void *pMem)
141{
142 if (!instance && instance->alloc_callbacks.pfnFree) {
143 return instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMem);
144 }
145 return free(pMem);
146}
147
Jon Ashburnee33ae72015-06-30 14:46:22 -0700148static void loader_log(VkFlags msg_type, int32_t msg_code,
149 const char *format, ...)
150{
151 char msg[256];
152 va_list ap;
153 int ret;
154
155 if (!(msg_type & g_loader_log_msgs)) {
156 return;
157 }
158
159 va_start(ap, format);
160 ret = vsnprintf(msg, sizeof(msg), format, ap);
161 if ((ret >= (int) sizeof(msg)) || ret < 0) {
162 msg[sizeof(msg)-1] = '\0';
163 }
164 va_end(ap);
165
Ian Elliott225188f2015-02-17 10:33:47 -0700166#if defined(WIN32)
Jon Ashburnee33ae72015-06-30 14:46:22 -0700167 OutputDebugString(msg);
168#endif
169 fputs(msg, stderr);
170 fputc('\n', stderr);
171}
172
173#if defined(WIN32)
174/**
175* Find the list of registry files (names within a key) in key "location".
176*
177* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as given in "location"
178* for a list or name/values which are added to a returned list (function return value).
179* The DWORD values within the key must be 0 or they are skipped.
180* Function return is a string with a ';' seperated list of filenames.
181* Function return is NULL if no valid name/value pairs are found in the key,
182* or the key is not found.
183*
184* \returns
185* A string list of filenames as pointer.
186* When done using the returned string list, pointer should be freed.
187*/
188static char *loader_get_registry_files(const char *location)
189{
190 LONG rtn_value;
191 HKEY hive, key;
192 DWORD access_flags = KEY_QUERY_VALUE;
193 char name[2048];
194 char *out = NULL;
195
196 hive = DEFAULT_VK_REGISTRY_HIVE;
197 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
198 if (rtn_value != ERROR_SUCCESS) {
199 // We didn't find the key. Try the 32-bit hive (where we've seen the
200 // key end up on some people's systems):
201 access_flags |= KEY_WOW64_32KEY;
202 rtn_value = RegOpenKeyEx(hive, location, 0, access_flags, &key);
203 if (rtn_value != ERROR_SUCCESS) {
204 // We still couldn't find the key, so give up:
205 return NULL;
206 }
207 }
208
209 DWORD idx = 0;
210 DWORD name_size = sizeof(name);
211 DWORD value;
212 DWORD total_size = 4096;
213 DWORD value_size = sizeof(value);
214 while((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE) &value, &value_size)) == ERROR_SUCCESS) {
215 if (value_size == sizeof(value) && value == 0) {
216 if (out == NULL) {
217 out = malloc(total_size);
218 out[0] = '\0';
219 }
220 else if (strlen(out) + name_size + 1 > total_size) {
221 out = realloc(out, total_size * 2);
222 total_size *= 2;
223 }
224 if (out == NULL) {
225 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory, failed loader_get_registry_files");
226 return NULL;
227 }
228 if (strlen(out) == 0)
229 snprintf(out, name_size + 1, "%s", name);
230 else
231 snprintf(out + strlen(out), name_size + 1, "%c%s", PATH_SEPERATOR, name);
232 }
233 }
234 return out;
235}
236
Ian Elliott225188f2015-02-17 10:33:47 -0700237#endif // WIN32
238
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600239bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2)
240{
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600241 return strcmp(op1->extName, op2->extName) == 0 ? true : false;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600242}
243
Jon Ashburn1b111de2015-07-06 15:40:35 -0600244/**
Jon Ashburn60378412015-07-02 12:59:25 -0600245 * Search the given ext_array for an extension
246 * matching the given vk_ext_prop
247 */
248bool has_vk_extension_property_array(
249 const VkExtensionProperties *vk_ext_prop,
250 const uint32_t count,
251 const VkExtensionProperties *ext_array)
252{
253 for (uint32_t i = 0; i < count; i++) {
254 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
255 return true;
256 }
257 return false;
258}
259
Jon Ashburn1b111de2015-07-06 15:40:35 -0600260/**
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600261 * Search the given ext_list for an extension
262 * matching the given vk_ext_prop
263 */
264bool has_vk_extension_property(
265 const VkExtensionProperties *vk_ext_prop,
266 const struct loader_extension_list *ext_list)
267{
268 for (uint32_t i = 0; i < ext_list->count; i++) {
269 if (compare_vk_extension_properties(&ext_list->list[i].info, vk_ext_prop))
270 return true;
271 }
272 return false;
273}
274
275/*
Jon Ashburn1b111de2015-07-06 15:40:35 -0600276 * Search the given layer list for a layer matching the given layer name
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600277 */
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600278static struct loader_layer_properties *get_layer_property(
279 const char *name,
280 const struct loader_layer_list *layer_list)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600281{
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600282 for (uint32_t i = 0; i < layer_list->count; i++) {
283 const VkLayerProperties *item = &layer_list->list[i].info;
284 if (strcmp(name, item->layerName) == 0)
285 return &layer_list->list[i];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600286 }
287 return NULL;
288}
289
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600290static void loader_add_global_extensions(
Tony Barbour426b9052015-06-24 16:06:58 -0600291 const PFN_vkGetGlobalExtensionProperties fp_get_props,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600292 const char *lib_name,
Jon Ashburn60699262015-06-10 16:11:42 -0600293 const loader_platform_dl_handle lib_handle,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600294 const enum extension_origin origin,
295 struct loader_extension_list *ext_list)
296{
297 uint32_t i, count;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600298 struct loader_extension_property ext_props;
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600299 VkExtensionProperties *extension_properties;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600300 VkResult res;
301
Courtney Goeltzenleuchteraa9faab2015-07-06 22:28:18 -0600302 if (!fp_get_props) {
303 /* No GetGlobalExtensionProperties defined */
304 return;
305 }
306
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600307 res = fp_get_props(NULL, &count, NULL);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600308 if (res != VK_SUCCESS) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600309 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extension count from %s", lib_name);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600310 return;
311 }
Jon Ashburn60699262015-06-10 16:11:42 -0600312
Courtney Goeltzenleuchteraa9faab2015-07-06 22:28:18 -0600313 if (count == 0) {
314 /* No ExtensionProperties to report */
315 return;
316 }
317
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600318 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600319
320 res = fp_get_props(NULL, &count, extension_properties);
321 if (res != VK_SUCCESS) {
322 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Error getting global extensions from %s", lib_name);
323 return;
324 }
Tony Barbour426b9052015-06-24 16:06:58 -0600325
Jon Ashburneb2728b2015-04-10 14:33:07 -0600326 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -0600327 memset(&ext_props, 0, sizeof(ext_props));
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600328 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
329 //TODO eventually get this from the layer config file
330 ext_props.origin = origin;
331 ext_props.lib_name = lib_name;
Jon Ashburn60699262015-06-10 16:11:42 -0600332
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600333 char spec_version[64], version[64];
334
335 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
336 VK_MAJOR(ext_props.info.specVersion),
337 VK_MINOR(ext_props.info.specVersion),
338 VK_PATCH(ext_props.info.specVersion));
339 snprintf(version, sizeof(version), "%d.%d.%d",
340 VK_MAJOR(ext_props.info.version),
341 VK_MINOR(ext_props.info.version),
342 VK_PATCH(ext_props.info.version));
343
344 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
345 "Global Extension: %s (%s) version %s, Vulkan version %s",
346 ext_props.info.extName, lib_name, version, spec_version);
347 loader_add_to_ext_list(ext_list, 1, &ext_props);
348 }
349
350 return;
351}
352
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600353static void loader_add_physical_device_extensions(
354 PFN_vkGetPhysicalDeviceExtensionProperties get_phys_dev_ext_props,
355 VkPhysicalDevice physical_device,
356 const enum extension_origin origin,
357 const char *lib_name,
358 struct loader_extension_list *ext_list)
359{
360 uint32_t i, count;
361 VkResult res;
362 struct loader_extension_property ext_props;
363 VkExtensionProperties *extension_properties;
364
365 memset(&ext_props, 0, sizeof(ext_props));
366 ext_props.origin = origin;
367 ext_props.lib_name = lib_name;
368
369 if (get_phys_dev_ext_props) {
370 res = get_phys_dev_ext_props(physical_device, NULL, &count, NULL);
371 if (res == VK_SUCCESS && count > 0) {
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600372
373 extension_properties = loader_stack_alloc(count * sizeof(VkExtensionProperties));
374
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600375 res = get_phys_dev_ext_props(physical_device, NULL, &count, extension_properties);
376 for (i = 0; i < count; i++) {
377 char spec_version[64], version[64];
378
379 memcpy(&ext_props.info, &extension_properties[i], sizeof(VkExtensionProperties));
380
381 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
382 VK_MAJOR(ext_props.info.specVersion),
383 VK_MINOR(ext_props.info.specVersion),
384 VK_PATCH(ext_props.info.specVersion));
385 snprintf(version, sizeof(version), "%d.%d.%d",
386 VK_MAJOR(ext_props.info.version),
387 VK_MINOR(ext_props.info.version),
388 VK_PATCH(ext_props.info.version));
389
390 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
391 "PhysicalDevice Extension: %s (%s) version %s, Vulkan version %s",
392 ext_props.info.extName, lib_name, version, spec_version);
393 loader_add_to_ext_list(ext_list, 1, &ext_props);
Jon Ashburn60699262015-06-10 16:11:42 -0600394 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600395 } else {
396 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting physical device extension info count from Layer %s", ext_props.lib_name);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600397 }
Jon Ashburneb2728b2015-04-10 14:33:07 -0600398 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600399
Jon Ashburneb2728b2015-04-10 14:33:07 -0600400 return;
401}
402
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600403static void loader_add_physical_device_layer_properties(
404 struct loader_icd *icd,
405 char *lib_name,
406 const loader_platform_dl_handle lib_handle)
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600407{
408 uint32_t i, count;
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600409 VkLayerProperties *layer_properties;
410 PFN_vkGetPhysicalDeviceExtensionProperties fp_get_ext_props;
411 PFN_vkGetPhysicalDeviceLayerProperties fp_get_layer_props;
412 VkPhysicalDevice gpu = icd->gpus[0];
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600413 VkResult res;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600414
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600415 fp_get_ext_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceExtensionProperties");
416 if (!fp_get_ext_props) {
417 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
418 "Couldn't dlsym vkGetPhysicalDeviceExtensionProperties from library %s",
419 lib_name);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600420 }
421
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600422 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
423 if (!fp_get_layer_props) {
424 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
425 "Couldn't dlsym vkGetPhysicalDeviceLayerProperties from library %s",
426 lib_name);
427 return;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600428 }
429
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600430 /*
431 * NOTE: We assume that all GPUs of an ICD support the same PhysicalDevice
432 * layers and extensions. Thus only ask for info about the first gpu.
433 */
434 res = fp_get_layer_props(gpu, &count, NULL);
435 if (res != VK_SUCCESS) {
436 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting PhysicalDevice layer count from %s", lib_name);
437 return;
438 }
439
440 if (count == 0) {
441 return;
442 }
443
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600444 layer_properties = loader_stack_alloc(count * sizeof(VkLayerProperties));
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600445
446 res = fp_get_layer_props(gpu, &count, layer_properties);
447 if (res != VK_SUCCESS) {
448 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Error getting %d PhysicalDevice layer properties from %s",
449 count, lib_name);
450 return;
451 }
452
Jon Ashburn1b111de2015-07-06 15:40:35 -0600453 //TODO get layer properties from manifest file
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600454 for (i = 0; i < count; i++) {
455 struct loader_layer_properties layer;
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600456
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600457 memset(&layer, 0, sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600458
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600459 layer.lib_info.lib_name = lib_name;
460 memcpy(&layer.info, &layer_properties[i], sizeof(VkLayerProperties));
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600461
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600462 loader_init_ext_list(&layer.instance_extension_list);
463 loader_init_ext_list(&layer.device_extension_list);
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600464
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600465 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "Collecting PhysicalDevice extensions for layer %s (%s)",
466 layer.info.layerName, layer.info.description);
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600467
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600468 loader_add_physical_device_extensions(
469 fp_get_ext_props,
470 icd->gpus[i],
471 VK_EXTENSION_ORIGIN_LAYER,
472 lib_name,
473 &layer.device_extension_list);
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600474
475 loader_add_to_layer_list(&icd->layer_properties_cache, 1, &layer);
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600476 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600477 return;
478}
479
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600480static bool loader_init_ext_list(struct loader_extension_list *ext_info)
Jon Ashburneb2728b2015-04-10 14:33:07 -0600481{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600482 ext_info->capacity = 32 * sizeof(struct loader_extension_property);
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600483 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600484 ext_info->list = malloc(ext_info->capacity);
485 if (ext_info->list == NULL) {
486 return false;
487 }
488 memset(ext_info->list, 0, ext_info->capacity);
489 ext_info->count = 0;
490 return true;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600491}
492
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -0600493void loader_destroy_ext_list(struct loader_extension_list *ext_info)
Jon Ashburneb2728b2015-04-10 14:33:07 -0600494{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600495 free(ext_info->list);
496 ext_info->count = 0;
497 ext_info->capacity = 0;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600498}
Jon Ashburneb2728b2015-04-10 14:33:07 -0600499
Jon Ashburn60378412015-07-02 12:59:25 -0600500/**
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600501 * Search the given search_list for any layers in the props list.
502 * Add these to the output layer_list. Don't add duplicates to the output layer_list.
Jon Ashburn60378412015-07-02 12:59:25 -0600503 */
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -0600504static VkResult loader_add_layer_names_to_list(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600505 struct loader_layer_list *output_list,
506 uint32_t name_count,
507 const char * const *names,
508 const struct loader_layer_list *search_list)
Jon Ashburneb2728b2015-04-10 14:33:07 -0600509{
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600510 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -0600511 VkResult err = VK_SUCCESS;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600512
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600513 for (uint32_t i = 0; i < name_count; i++) {
514 const char *search_target = names[i];
515 layer_prop = get_layer_property(search_target, search_list);
516 if (!layer_prop) {
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -0600517 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Unable to find layer %s", search_target);
518 err = VK_ERROR_INVALID_LAYER;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600519 continue;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600520 }
521
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600522 loader_add_to_layer_list(output_list, 1, layer_prop);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600523 }
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -0600524
525 return err;
Jon Ashburneb2728b2015-04-10 14:33:07 -0600526}
527
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600528/*
Jon Ashburn1b111de2015-07-06 15:40:35 -0600529 * Append non-duplicate extension properties defined in props
530 * to the given ext_list.
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600531 */
532void loader_add_to_ext_list(
533 struct loader_extension_list *ext_list,
534 uint32_t prop_list_count,
535 const struct loader_extension_property *props)
536{
537 uint32_t i;
538 struct loader_extension_property *cur_ext;
539
540 if (ext_list->list == NULL || ext_list->capacity == 0) {
541 loader_init_ext_list(ext_list);
542 }
543
544 if (ext_list->list == NULL)
545 return;
546
547 for (i = 0; i < prop_list_count; i++) {
548 cur_ext = (struct loader_extension_property *) &props[i];
549
550 // look for duplicates
551 if (has_vk_extension_property(&cur_ext->info, ext_list)) {
552 continue;
553 }
554
555 // add to list at end
556 // check for enough capacity
557 if (ext_list->count * sizeof(struct loader_extension_property)
558 >= ext_list->capacity) {
559 // double capacity
560 ext_list->capacity *= 2;
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600561 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600562 ext_list->list = realloc(ext_list->list, ext_list->capacity);
563 }
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -0600564
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600565 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(struct loader_extension_property));
566 ext_list->count++;
567 }
568}
569
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600570/*
571 * Manage lists of VkLayerProperties
572 */
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600573static bool loader_init_layer_list(struct loader_layer_list *list)
574{
575 list->capacity = 32 * sizeof(struct loader_layer_properties);
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -0600576 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600577 list->list = malloc(list->capacity);
578 if (list->list == NULL) {
579 return false;
580 }
581 memset(list->list, 0, list->capacity);
582 list->count = 0;
583 return true;
584}
585
586void loader_destroy_layer_list(struct loader_layer_list *layer_list)
587{
588 free(layer_list->list);
589 layer_list->count = 0;
590 layer_list->capacity = 0;
591}
592
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600593/*
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600594 * Manage list of layer libraries (loader_lib_info)
595 */
596static bool loader_init_layer_library_list(struct loader_layer_library_list *list)
597{
598 list->capacity = 32 * sizeof(struct loader_lib_info);
599 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
600 list->list = malloc(list->capacity);
601 if (list->list == NULL) {
602 return false;
603 }
604 memset(list->list, 0, list->capacity);
605 list->count = 0;
606 return true;
607}
608
609void loader_destroy_layer_library_list(struct loader_layer_library_list *list)
610{
611 for (uint32_t i = 0; i < list->count; i++) {
612 free(list->list[i].lib_name);
613 }
614 free(list->list);
615 list->count = 0;
616 list->capacity = 0;
617}
618
619void loader_add_to_layer_library_list(
620 struct loader_layer_library_list *list,
621 uint32_t item_count,
622 const struct loader_lib_info *new_items)
623{
624 uint32_t i;
625 struct loader_lib_info *item;
626
627 if (list->list == NULL || list->capacity == 0) {
628 loader_init_layer_library_list(list);
629 }
630
631 if (list->list == NULL)
632 return;
633
634 for (i = 0; i < item_count; i++) {
635 item = (struct loader_lib_info *) &new_items[i];
636
637 // look for duplicates
638 for (uint32_t j = 0; j < list->count; j++) {
639 if (strcmp(list->list[i].lib_name, new_items->lib_name) == 0) {
640 continue;
641 }
642 }
643
644 // add to list at end
645 // check for enough capacity
646 if (list->count * sizeof(struct loader_lib_info)
647 >= list->capacity) {
648 // double capacity
649 list->capacity *= 2;
650 /* TODO: Need to use loader_stack_alloc or loader_heap_alloc */
651 list->list = realloc(list->list, list->capacity);
652 }
653
654 memcpy(&list->list[list->count], item, sizeof(struct loader_lib_info));
655 list->count++;
656 }
657}
658
Jon Ashburn1b111de2015-07-06 15:40:35 -0600659#if 0
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600660/*
661 * Add's library indicated by lib_name to list if it
662 * implements vkGetGlobalLayerProperties or
663 * vkGetPhysicalDeviceLayerProperties.
664 */
665static void loader_add_layer_library(
666 struct loader_instance *instance,
667 const char *lib_name,
668 const loader_platform_dl_handle lib_handle,
669 struct loader_layer_library_list *list)
670{
671 struct loader_lib_info *library_info;
672 PFN_vkGetPhysicalDeviceLayerProperties fp_get_phydev_props;
673 PFN_vkGetGlobalLayerProperties fp_get_layer_props;
674
675 fp_get_layer_props = loader_platform_get_proc_address(lib_handle, "vkGetGlobalLayerProperties");
676 fp_get_phydev_props = loader_platform_get_proc_address(lib_handle, "vkGetPhysicalDeviceLayerProperties");
677
678 if (!fp_get_layer_props && !fp_get_phydev_props)
679 return;
680
681 /*
682 * Allocate enough space for the library name to
683 * immediately follow the loader_lib_info structure
684 */
685 library_info = loader_heap_alloc(instance, sizeof(struct loader_lib_info) + strlen(lib_name) + 1, VK_SYSTEM_ALLOC_TYPE_INTERNAL);
686 if (!library_info) {
687 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
688 "Malloc for layer library list failed: %s line: %d", __FILE__, __LINE__);
689 return;
690 }
691 memset(library_info, 0, sizeof(struct loader_lib_info));
692 library_info->lib_name = (char *) &library_info[1];
693 strcpy(library_info->lib_name, lib_name);
694
695 loader_add_to_layer_library_list(list, 1, library_info);
696}
Jon Ashburn1b111de2015-07-06 15:40:35 -0600697#endif
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -0600698/*
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600699 * Search the given layer list for a list
700 * matching the given VkLayerProperties
701 */
702bool has_vk_layer_property(
703 const VkLayerProperties *vk_layer_prop,
704 const struct loader_layer_list *list)
705{
706 for (uint32_t i = 0; i < list->count; i++) {
707 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
708 return true;
709 }
710 return false;
711}
712
713/*
714 * Search the given layer list for a layer
715 * matching the given name
716 */
717bool has_layer_name(
718 const char *name,
719 const struct loader_layer_list *list)
720{
721 for (uint32_t i = 0; i < list->count; i++) {
722 if (strcmp(name, list->list[i].info.layerName) == 0)
723 return true;
724 }
725 return false;
726}
727
728/*
729 * Append non-duplicate layer properties defined in prop_list
730 * to the given layer_info list
731 */
732void loader_add_to_layer_list(
733 struct loader_layer_list *list,
734 uint32_t prop_list_count,
735 const struct loader_layer_properties *props)
736{
737 uint32_t i;
738 struct loader_layer_properties *layer;
739
740 if (list->list == NULL || list->capacity == 0) {
741 loader_init_layer_list(list);
742 }
743
744 if (list->list == NULL)
745 return;
746
747 for (i = 0; i < prop_list_count; i++) {
748 layer = (struct loader_layer_properties *) &props[i];
749
750 // look for duplicates
751 if (has_vk_layer_property(&layer->info, list)) {
752 continue;
753 }
754
755 // add to list at end
756 // check for enough capacity
757 if (list->count * sizeof(struct loader_layer_properties)
758 >= list->capacity) {
759 // double capacity
760 list->capacity *= 2;
761 list->list = realloc(list->list, list->capacity);
762 }
763
764 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
765 list->count++;
766 }
767}
768
Jon Ashburnf2ddb732015-07-07 10:27:45 -0600769/**
770 * Search the search_list for any layer with a name
771 * that matches the given name and a type that matches the given type
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600772 * Add all matching layers to the found_list
Jon Ashburnf2ddb732015-07-07 10:27:45 -0600773 * Do not add if found loader_layer_properties is already
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600774 * on the found_list.
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600775 */
Jon Ashburn60378412015-07-02 12:59:25 -0600776static void loader_find_layer_name_add_list(
777 const char *name,
Jon Ashburnf2ddb732015-07-07 10:27:45 -0600778 const enum layer_type type,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600779 const struct loader_layer_list *search_list,
780 struct loader_layer_list *found_list)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600781{
782 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600783 struct loader_layer_properties *layer_prop = &search_list->list[i];
Jon Ashburnf2ddb732015-07-07 10:27:45 -0600784 if (0 == strcmp(layer_prop->info.layerName, name) &&
785 (layer_prop->type & type)) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600786 /* Found a layer with the same name, add to found_list */
787 loader_add_to_layer_list(found_list, 1, layer_prop);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600788 }
789 }
790}
791
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -0600792static struct loader_extension_property *get_extension_property(
793 const char *name,
794 const struct loader_extension_list *list)
Jon Ashburn42e41032015-04-14 09:15:32 -0600795{
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -0600796 for (uint32_t i = 0; i < list->count; i++) {
797 const VkExtensionProperties *item = &list->list[i].info;
798 if (strcmp(name, item->extName) == 0)
799 return &list->list[i];
Jon Ashburn42e41032015-04-14 09:15:32 -0600800 }
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -0600801 return NULL;
Jon Ashburn42e41032015-04-14 09:15:32 -0600802}
803
Jon Ashburn60378412015-07-02 12:59:25 -0600804/*
805 * For global exenstions implemented within the loader (i.e. DEBUG_REPORT
806 * the extension must provide two entry points for the loader to use:
807 * - "trampoline" entry point - this is the address returned by GetProcAddr
808 * and will always do what's necessary to support a global call.
809 * - "terminator" function - this function will be put at the end of the
810 * instance chain and will contain the necessary logica to call / process
811 * the extension for the appropriate ICDs that are available.
812 * There is no generic mechanism for including these functions, the references
813 * must be placed into the appropriate loader entry points.
814 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr requests
815 * loader_coalesce_extensions(void) - add extension records to the list of global
816 * extension available to the app.
817 * instance_disp - add function pointer for terminator function to this array.
818 * The extension itself should be in a separate file that will be
819 * linked directly with the loader.
820 */
Jon Ashburnfce93d92015-05-12 17:26:48 -0600821void loader_coalesce_extensions(void)
Jon Ashburneb2728b2015-04-10 14:33:07 -0600822{
Jon Ashburneb2728b2015-04-10 14:33:07 -0600823 struct loader_scanned_icds *icd_list = loader.scanned_icd_list;
824
825 // traverse scanned icd list adding non-duplicate extensions to the list
826 while (icd_list != NULL) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600827 loader_add_to_ext_list(&loader.global_extensions,
828 icd_list->global_extension_list.count,
829 icd_list->global_extension_list.list);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600830 icd_list = icd_list->next;
831 };
832
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600833 // Traverse loader's extensions, adding non-duplicate extensions to the list
834 debug_report_add_instance_extensions(&loader.global_extensions);
Jon Ashburneb2728b2015-04-10 14:33:07 -0600835}
836
Jon Ashburncb5a5ac2015-06-10 10:06:06 -0600837static struct loader_icd *loader_get_icd_and_device(const VkDevice device,
838 struct loader_device **found_dev)
839{
840 *found_dev = NULL;
841 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
842 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
843 for (struct loader_device *dev = icd->logical_device_list; dev; dev = dev->next)
844 if (dev->device == device) {
845 *found_dev = dev;
846 return icd;
847 }
848 }
849 }
850 return NULL;
851}
852
853static void loader_destroy_logical_device(struct loader_device *dev)
854{
855 free(dev->app_extension_props);
Jon Ashburncb5a5ac2015-06-10 10:06:06 -0600856 if (dev->activated_layer_list.count)
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -0600857 loader_destroy_layer_list(&dev->activated_layer_list);
Jon Ashburncb5a5ac2015-06-10 10:06:06 -0600858 free(dev);
859}
860
861static struct loader_device *loader_add_logical_device(const VkDevice dev, struct loader_device **device_list)
862{
863 struct loader_device *new_dev;
864
865 new_dev = malloc(sizeof(struct loader_device));
866 if (!new_dev) {
867 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc struct laoder-device");
868 return NULL;
869 }
870
871 memset(new_dev, 0, sizeof(struct loader_device));
872
873 new_dev->next = *device_list;
874 new_dev->device = dev;
875 *device_list = new_dev;
876 return new_dev;
877}
878
879void loader_remove_logical_device(VkDevice device)
880{
881 struct loader_device *found_dev, *dev, *prev_dev;
882 struct loader_icd *icd;
883 icd = loader_get_icd_and_device(device, &found_dev);
884
885 if (!icd || !found_dev)
886 return;
887
888 prev_dev = NULL;
889 dev = icd->logical_device_list;
890 while (dev && dev != found_dev) {
891 prev_dev = dev;
892 dev = dev->next;
893 }
894
895 if (prev_dev)
896 prev_dev->next = found_dev->next;
897 else
898 icd->logical_device_list = found_dev->next;
899 loader_destroy_logical_device(found_dev);
900}
901
902
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600903static void loader_icd_destroy(
904 struct loader_instance *ptr_inst,
905 struct loader_icd *icd)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800906{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600907 ptr_inst->total_icd_count--;
Jon Ashburnd5df54d2015-05-28 19:16:58 -0600908 free(icd->gpus);
Courtney Goeltzenleuchter6b70e362015-06-14 19:57:15 -0600909 for (struct loader_device *dev = icd->logical_device_list; dev; ) {
910 struct loader_device *next_dev = dev->next;
Jon Ashburncb5a5ac2015-06-10 10:06:06 -0600911 loader_destroy_logical_device(dev);
Courtney Goeltzenleuchter6b70e362015-06-14 19:57:15 -0600912 dev = next_dev;
913 }
Jon Ashburncb5a5ac2015-06-10 10:06:06 -0600914
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800915 free(icd);
916}
917
Jon Ashburneb2728b2015-04-10 14:33:07 -0600918static struct loader_icd * loader_icd_create(const struct loader_scanned_icds *scanned)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800919{
920 struct loader_icd *icd;
921
922 icd = malloc(sizeof(*icd));
923 if (!icd)
924 return NULL;
925
Courtney Goeltzenleuchter6f928162014-10-28 10:29:27 -0600926 memset(icd, 0, sizeof(*icd));
927
Jon Ashburn14275da2015-01-28 11:01:35 -0700928 icd->scanned_icds = scanned;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +0800929
930 return icd;
931}
932
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600933static struct loader_icd *loader_icd_add(
934 struct loader_instance *ptr_inst,
935 const struct loader_scanned_icds *scanned)
Chia-I Wu894a1172014-08-04 11:18:20 +0800936{
937 struct loader_icd *icd;
938
Jon Ashburn14275da2015-01-28 11:01:35 -0700939 icd = loader_icd_create(scanned);
Chia-I Wu894a1172014-08-04 11:18:20 +0800940 if (!icd)
941 return NULL;
942
Chia-I Wu894a1172014-08-04 11:18:20 +0800943 /* prepend to the list */
Jon Ashburn3336df82015-01-29 15:45:51 -0700944 icd->next = ptr_inst->icds;
945 ptr_inst->icds = icd;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600946 ptr_inst->total_icd_count++;
Chia-I Wu894a1172014-08-04 11:18:20 +0800947
948 return icd;
949}
950
Jon Ashburn14275da2015-01-28 11:01:35 -0700951static void loader_scanned_icd_add(const char *filename)
952{
Ian Elliott81ac44c2015-01-13 17:52:38 -0700953 loader_platform_dl_handle handle;
Jon Ashburn0dd356d2015-05-14 12:43:38 -0600954 void *fp_create_inst;
Tony Barbour426b9052015-06-24 16:06:58 -0600955 void *fp_get_global_ext_props;
Tony Barbour426b9052015-06-24 16:06:58 -0600956 void *fp_get_device_ext_props;
Jon Ashburn60699262015-06-10 16:11:42 -0600957 PFN_vkGPA fp_get_proc_addr;
Jon Ashburn14275da2015-01-28 11:01:35 -0700958 struct loader_scanned_icds *new_node;
959
Ian Elliott81ac44c2015-01-13 17:52:38 -0700960 // Used to call: dlopen(filename, RTLD_LAZY);
961 handle = loader_platform_open_library(filename);
Jon Ashburn14275da2015-01-28 11:01:35 -0700962 if (!handle) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600963 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_open_library_error(filename));
Jon Ashburn14275da2015-01-28 11:01:35 -0700964 return;
965 }
966
967#define LOOKUP(func_ptr, func) do { \
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -0600968 func_ptr = (PFN_vk ##func) loader_platform_get_proc_address(handle, "vk" #func); \
Jon Ashburn14275da2015-01-28 11:01:35 -0700969 if (!func_ptr) { \
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600970 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn14275da2015-01-28 11:01:35 -0700971 return; \
972 } \
973} while (0)
974
Jon Ashburn3336df82015-01-29 15:45:51 -0700975 LOOKUP(fp_create_inst, CreateInstance);
Tony Barbour426b9052015-06-24 16:06:58 -0600976 LOOKUP(fp_get_global_ext_props, GetGlobalExtensionProperties);
Tony Barbour426b9052015-06-24 16:06:58 -0600977 LOOKUP(fp_get_device_ext_props, GetPhysicalDeviceExtensionProperties);
Jon Ashburn60699262015-06-10 16:11:42 -0600978 LOOKUP(fp_get_proc_addr, GetDeviceProcAddr);
Jon Ashburn14275da2015-01-28 11:01:35 -0700979#undef LOOKUP
980
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600981 new_node = (struct loader_scanned_icds *) malloc(sizeof(struct loader_scanned_icds)
982 + strlen(filename) + 1);
Jon Ashburn14275da2015-01-28 11:01:35 -0700983 if (!new_node) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600984 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
Jon Ashburn14275da2015-01-28 11:01:35 -0700985 return;
986 }
987
988 new_node->handle = handle;
Jon Ashburn3336df82015-01-29 15:45:51 -0700989 new_node->CreateInstance = fp_create_inst;
Tony Barbour426b9052015-06-24 16:06:58 -0600990 new_node->GetGlobalExtensionProperties = fp_get_global_ext_props;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600991 loader_init_ext_list(&new_node->global_extension_list);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -0600992 loader_init_ext_list(&new_node->device_extension_list);
Jon Ashburn14275da2015-01-28 11:01:35 -0700993 new_node->next = loader.scanned_icd_list;
Jon Ashburn14275da2015-01-28 11:01:35 -0700994
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -0600995 new_node->lib_name = (char *) (new_node + 1);
996 if (!new_node->lib_name) {
997 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Out of memory can't add icd");
998 return;
999 }
1000 strcpy(new_node->lib_name, filename);
1001
Jon Ashburneb2728b2015-04-10 14:33:07 -06001002 loader.scanned_icd_list = new_node;
1003
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001004 loader_add_global_extensions(
Tony Barbour426b9052015-06-24 16:06:58 -06001005 (PFN_vkGetGlobalExtensionProperties) fp_get_global_ext_props,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001006 new_node->lib_name,
Jon Ashburn60699262015-06-10 16:11:42 -06001007 handle,
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001008 VK_EXTENSION_ORIGIN_ICD,
1009 &new_node->global_extension_list);
Jon Ashburneb2728b2015-04-10 14:33:07 -06001010}
Ian Elliott81ac44c2015-01-13 17:52:38 -07001011
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001012static struct loader_extension_list *loader_global_extensions(const char *pLayerName)
1013{
1014 if (pLayerName == NULL || (strlen(pLayerName) == 0)) {
1015 return &loader.global_extensions;
1016 }
1017
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06001018 /* Find and return global extension list for given layer */
Jon Ashburn1b111de2015-07-06 15:40:35 -06001019 for (uint32_t i = 0; i < loader.scanned_layers.count; i++) {
1020 struct loader_layer_properties *work_layer = &loader.scanned_layers.list[i];
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001021 if (strcmp(work_layer->info.layerName, pLayerName) == 0) {
1022 return &work_layer->instance_extension_list;
1023 }
1024 }
1025
1026 return NULL;
1027}
1028
Jon Ashburn1b111de2015-07-06 15:40:35 -06001029static struct loader_layer_list *loader_scanned_layers()
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001030{
Jon Ashburn1b111de2015-07-06 15:40:35 -06001031 return &loader.scanned_layers;
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001032}
1033
1034static void loader_physical_device_layers(
1035 struct loader_icd *icd,
1036 uint32_t *count,
1037 struct loader_layer_list **list)
1038{
1039 *count = icd->layer_properties_cache.count;
1040 *list = &icd->layer_properties_cache;
1041}
1042
1043static void loader_physical_device_extensions(
1044 struct loader_icd *icd,
1045 uint32_t gpu_idx,
1046 const char *layer_name,
1047 uint32_t *count,
1048 struct loader_extension_list **list)
1049{
1050 if (layer_name == NULL || (strlen(layer_name) == 0)) {
1051 *count = icd->device_extension_cache[gpu_idx].count;
1052 *list = &icd->device_extension_cache[gpu_idx];
1053 return;
1054 }
1055 for (uint32_t i = 0; i < icd->layer_properties_cache.count; i++) {
1056 if (strcmp(layer_name, icd->layer_properties_cache.list[i].info.layerName) == 0) {
1057 *count = icd->layer_properties_cache.list[i].device_extension_list.count;
1058 *list = &icd->layer_properties_cache.list[i].device_extension_list;
1059 }
1060 }
1061}
1062
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001063static void loader_icd_init_entrys(struct loader_icd *icd,
1064 struct loader_scanned_icds *scanned_icds)
1065{
1066 /* initialize entrypoint function pointers */
1067
1068 #define LOOKUP(func) do { \
1069 icd->func = (PFN_vk ##func) loader_platform_get_proc_address(scanned_icds->handle, "vk" #func); \
1070 if (!icd->func) { \
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001071 loader_log(VK_DBG_REPORT_WARN_BIT, 0, loader_platform_get_proc_address_error("vk" #func)); \
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001072 return; \
1073 } \
1074 } while (0)
1075
Jon Ashburn1245cec2015-05-18 13:20:15 -06001076 /* could change this to use GetInstanceProcAddr in driver instead of dlsym */
1077 LOOKUP(GetDeviceProcAddr);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001078 LOOKUP(DestroyInstance);
1079 LOOKUP(EnumeratePhysicalDevices);
Chris Forbesd7576302015-06-21 22:55:02 +12001080 LOOKUP(GetPhysicalDeviceFeatures);
1081 LOOKUP(GetPhysicalDeviceFormatInfo);
1082 LOOKUP(GetPhysicalDeviceLimits);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001083 LOOKUP(CreateDevice);
Tony Barbour426b9052015-06-24 16:06:58 -06001084 LOOKUP(GetPhysicalDeviceProperties);
1085 LOOKUP(GetPhysicalDeviceMemoryProperties);
1086 LOOKUP(GetPhysicalDevicePerformance);
1087 LOOKUP(GetPhysicalDeviceQueueCount);
1088 LOOKUP(GetPhysicalDeviceQueueProperties);
1089 LOOKUP(GetPhysicalDeviceExtensionProperties);
Mark Lobodzinski83d4e6a2015-07-03 15:58:09 -06001090 LOOKUP(GetPhysicalDeviceSparseImageFormatProperties);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001091 LOOKUP(DbgCreateMsgCallback);
1092 LOOKUP(DbgDestroyMsgCallback);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06001093#undef LOOKUP
1094
1095 return;
1096}
1097
Courtney Goeltzenleuchter8b253f92015-06-08 15:11:18 -06001098static void loader_debug_init(void)
1099{
1100 const char *env;
1101
1102 if (g_loader_debug > 0)
1103 return;
1104
1105 g_loader_debug = 0;
1106
1107 /* parse comma-separated debug options */
1108 env = getenv("LOADER_DEBUG");
1109 while (env) {
1110 const char *p = strchr(env, ',');
1111 size_t len;
1112
1113 if (p)
1114 len = p - env;
1115 else
1116 len = strlen(env);
1117
1118 if (len > 0) {
1119 if (strncmp(env, "warn", len) == 0) {
1120 g_loader_debug |= LOADER_WARN_BIT;
1121 g_loader_log_msgs |= VK_DBG_REPORT_WARN_BIT;
1122 } else if (strncmp(env, "info", len) == 0) {
1123 g_loader_debug |= LOADER_INFO_BIT;
1124 g_loader_log_msgs |= VK_DBG_REPORT_INFO_BIT;
1125 } else if (strncmp(env, "perf", len) == 0) {
1126 g_loader_debug |= LOADER_PERF_BIT;
1127 g_loader_log_msgs |= VK_DBG_REPORT_PERF_WARN_BIT;
1128 } else if (strncmp(env, "error", len) == 0) {
1129 g_loader_debug |= LOADER_ERROR_BIT;
1130 g_loader_log_msgs |= VK_DBG_REPORT_ERROR_BIT;
1131 } else if (strncmp(env, "debug", len) == 0) {
1132 g_loader_debug |= LOADER_DEBUG_BIT;
1133 g_loader_log_msgs |= VK_DBG_REPORT_DEBUG_BIT;
1134 }
1135 }
1136
1137 if (!p)
1138 break;
1139
1140 env = p + 1;
1141 }
1142}
1143
Jon Ashburnffd5d672015-06-29 11:25:34 -06001144struct loader_manifest_files {
1145 uint32_t count;
1146 char **filename_list;
1147};
1148
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001149/**
Jon Ashburnffd5d672015-06-29 11:25:34 -06001150 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001151 *
1152 * \returns
Jon Ashburnffd5d672015-06-29 11:25:34 -06001153 * A pointer to first char in the next path.
1154 * The next path (or NULL) in the list is returned in next_path.
1155 * Note: input string is modified in some cases. PASS IN A COPY!
1156 */
Jon Ashburnffd5d672015-06-29 11:25:34 -06001157static char *loader_get_next_path(char *path)
1158{
1159 uint32_t len;
1160 char *next;
1161
1162 if (path == NULL)
1163 return NULL;
1164 next = strchr(path, PATH_SEPERATOR);
1165 if (next == NULL) {
1166 len = (uint32_t) strlen(path);
1167 next = path + len;
1168 }
1169 else {
1170 *next = '\0';
1171 next++;
1172 }
1173
1174 return next;
1175}
1176
1177/**
Jon Ashburn38144502015-07-07 15:06:25 -06001178 * Given a path which is absolute or relative. Expand the path if relative otherwise
1179 * leave the path unmodified if absolute. The path which is relative from is
1180 * given in rel_base and should include trailing directory seperator '/'
1181 *
1182 * \returns
1183 * A string in out_fullpath of the full absolute path
1184 * Side effect is that dir string maybe modified.
1185 */
1186static void loader_expand_path(const char *path,
1187 const char *rel_base,
1188 size_t out_size,
1189 char *out_fullpath)
1190{
1191 if (loader_platform_is_path_absolute(path)) {
1192 strncpy(out_fullpath, path, out_size);
1193 out_fullpath[out_size - 1] = '\0';
1194 }
1195 else {
1196 // convert relative to absolute path based on rel_base
1197 size_t len = strlen(path);
1198 strncpy(out_fullpath, rel_base, out_size);
1199 out_fullpath[out_size - 1] = '\0';
1200 assert(out_size >= strlen(out_fullpath) + len + 1);
1201 strncat(out_fullpath, path, len);
1202 }
1203}
1204
1205/**
Jon Ashburnffd5d672015-06-29 11:25:34 -06001206 * Given a filename (file) and a list of paths (dir), try to find an existing
1207 * file in the paths. If filename already is a path then no
1208 * searching in the given paths.
1209 *
1210 * \returns
1211 * A string in out_fullpath of either the full path or file.
1212 * Side effect is that dir string maybe modified.
1213 */
1214static void loader_get_fullpath(const char *file,
1215 char *dir,
1216 size_t out_size,
1217 char *out_fullpath)
1218{
1219 char *next_dir;
1220 if (strchr(file,DIRECTORY_SYMBOL) == NULL) {
1221 //find file exists with prepending given path
1222 while (*dir) {
1223 next_dir = loader_get_next_path(dir);
1224 snprintf(out_fullpath, out_size, "%s%c%s",
1225 dir, DIRECTORY_SYMBOL, file);
1226 if (loader_platform_file_exists(out_fullpath)) {
1227 return;
1228 }
1229 dir = next_dir;
1230 }
1231 }
1232 snprintf(out_fullpath, out_size, "%s", file);
1233}
1234
1235/**
1236 * Read a JSON file into a buffer.
1237 *
1238 * \returns
1239 * A pointer to a cJSON object representing the JSON parse tree.
1240 * This returned buffer should be freed by caller.
1241 */
1242static cJSON *loader_get_json(const char *filename)
1243{
1244 FILE *file;
1245 char *json_buf;
1246 cJSON *json;
1247 uint64_t len;
1248 file = fopen(filename,"rb");
1249 fseek(file, 0, SEEK_END);
1250 len = ftell(file);
1251 fseek(file, 0, SEEK_SET);
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -06001252 json_buf = (char*) loader_stack_alloc(len+1);
Jon Ashburnffd5d672015-06-29 11:25:34 -06001253 if (json_buf == NULL) {
1254 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get JSON file");
1255 fclose(file);
1256 return NULL;
1257 }
1258 if (fread(json_buf, sizeof(char), len, file) != len) {
1259 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "fread failed can't get JSON file");
1260 fclose(file);
1261 return NULL;
1262 }
1263 fclose(file);
1264 json_buf[len] = '\0';
1265
1266 //parse text from file
1267 json = cJSON_Parse(json_buf);
1268 if (json == NULL)
1269 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Can't parse JSON file %s", filename);
1270 return json;
1271}
1272
1273/**
Jon Ashburn1b111de2015-07-06 15:40:35 -06001274 * Given a cJSON struct (json) of the top level JSON object from layer manifest
1275 * file, add entry to the layer_list.
1276 * Fill out the layer_properties in this list entry from the input cHJSON object.
1277 *
1278 * \returns
1279 * void
1280 * layer_list has a new entry and initialized accordingly.
1281 * If the json input object does not have all the required fields no entry
1282 * is added to the list.
1283 */
1284static void loader_add_layer_properties(struct loader_layer_list *layer_list,
1285 cJSON *json,
1286 bool is_implicit,
1287 char *filename)
1288{
1289 /* Fields in layer manifest file that are required:
1290 * (required) “file_format_version”
1291 * following are required in the "layer" object:
1292 * (required) "name"
1293 * (required) "type"
1294 * (required) “library_path”
1295 * (required) “abi_versions”
1296 * (required) “implementation_version”
1297 * (required) “description”
1298 * (required for implicit layers) “disable_environment”
1299 *
1300 * First get all required items and if any missing abort
1301 */
1302
1303 cJSON *item, *layer_node, *ext_item;
1304 char *temp;
1305 char *name, *type, *library_path, *abi_versions;
1306 char *implementation_version, *description;
1307 cJSON *disable_environment;
1308 int i;
1309 struct loader_extension_property ext_prop;
1310 item = cJSON_GetObjectItem(json, "file_format_version");
1311 if (item == NULL) {
1312 return;
1313 }
1314 char *file_vers = cJSON_PrintUnformatted(item);
1315 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1316 filename, file_vers);
1317 if (strcmp(file_vers, "\"0.9.0\"") != 0)
1318 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1319 free(file_vers);
1320
1321 //TODO handle multiple layer nodes in the file
1322 //TODO handle scanned libraries not one per layer property
1323 layer_node = cJSON_GetObjectItem(json, "layer");
1324 if (layer_node == NULL) {
1325 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"layer\" object in manifest JSON file, skipping");
1326 return;
1327 }
1328#define GET_JSON_OBJECT(node, var) { \
1329 var = cJSON_GetObjectItem(node, #var); \
1330 if (var == NULL) \
1331 return; \
1332 }
1333#define GET_JSON_ITEM(node, var) { \
1334 item = cJSON_GetObjectItem(node, #var); \
1335 if (item == NULL) \
1336 return; \
1337 temp = cJSON_Print(item); \
1338 temp[strlen(temp) - 1] = '\0'; \
1339 var = malloc(strlen(temp) + 1); \
1340 strcpy(var, &temp[1]); \
1341 free(temp); \
1342 }
1343 GET_JSON_ITEM(layer_node, name)
1344 GET_JSON_ITEM(layer_node, type)
1345 GET_JSON_ITEM(layer_node, library_path)
1346 GET_JSON_ITEM(layer_node, abi_versions)
1347 GET_JSON_ITEM(layer_node, implementation_version)
1348 GET_JSON_ITEM(layer_node, description)
1349 if (is_implicit) {
1350 GET_JSON_OBJECT(layer_node, disable_environment)
1351 }
1352#undef GET_JSON_ITEM
1353#undef GET_JSON_OBJECT
1354
1355 // add list entry
1356 assert((layer_list->count + 1) * sizeof(struct loader_layer_properties) <= layer_list->capacity);
1357 struct loader_layer_properties *props = &(layer_list->list[layer_list->count]);
Jon Ashburn38144502015-07-07 15:06:25 -06001358 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
1359 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
Jon Ashburn1b111de2015-07-06 15:40:35 -06001360 free(name);
Jon Ashburn38144502015-07-07 15:06:25 -06001361
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001362 if (!strcmp(type, "DEVICE"))
Jon Ashburn1b111de2015-07-06 15:40:35 -06001363 props->type = (is_implicit) ? VK_LAYER_TYPE_DEVICE_IMPLICIT : VK_LAYER_TYPE_DEVICE_EXPLICIT;
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001364 if (!strcmp(type, "INSTANCE"))
Jon Ashburn1b111de2015-07-06 15:40:35 -06001365 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001366 if (!strcmp(type, "GLOBAL"))
Jon Ashburn1b111de2015-07-06 15:40:35 -06001367 props->type = (is_implicit) ? VK_LAYER_TYPE_GLOBAL_IMPLICIT : VK_LAYER_TYPE_GLOBAL_EXPLICIT;
1368 free(type);
Jon Ashburn38144502015-07-07 15:06:25 -06001369
1370 char *fullpath = malloc(2048);
1371 char *rel_base;
1372 if (strchr(library_path, DIRECTORY_SYMBOL) == NULL) {
1373 // a filename which is assumed in the system directory
1374 loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH, 2048, fullpath);
1375 }
1376 else {
1377 // a relative or absolute path
1378 char *name_copy = loader_stack_alloc(strlen(filename) + 2);
1379 size_t len;
1380 strcpy(name_copy, filename);
1381 rel_base = loader_platform_dirname(name_copy);
1382 len = strlen(rel_base);
1383 rel_base[len] = DIRECTORY_SYMBOL;
1384 rel_base[len + 1] = '\0';
1385 loader_expand_path(library_path, rel_base, 2048, fullpath);
1386 }
1387 props->lib_info.lib_name = fullpath;
1388 free(library_path);
1389 //TODO merge the info with the versions and convert string to int
Jon Ashburn1b111de2015-07-06 15:40:35 -06001390 props->abi_version = abi_versions;
1391 props->impl_version = implementation_version;
Jon Ashburn38144502015-07-07 15:06:25 -06001392 strncpy(props->info.description, description, sizeof(props->info.description));
1393 props->info.description[sizeof(props->info.description) - 1] = '\0';
Jon Ashburn1b111de2015-07-06 15:40:35 -06001394 free(description);
1395 if (is_implicit) {
1396 props->disable_env_var.name = disable_environment->child->string;
1397 props->disable_env_var.value = disable_environment->child->valuestring;
1398 }
1399 layer_list->count++;
1400
1401 /**
1402 * Now get all optional items and objects and put in list:
1403 * functions
1404 * instance_extensions
1405 * device_extensions
1406 * enable_environment (implicit layers only)
1407 */
1408#define GET_JSON_OBJECT(node, var) { \
1409 var = cJSON_GetObjectItem(node, #var); \
1410 }
1411#define GET_JSON_ITEM(node, var) { \
1412 item = cJSON_GetObjectItem(node, #var); \
1413 if (item != NULL) \
1414 temp = cJSON_Print(item); \
1415 temp[strlen(temp) - 1] = '\0'; \
1416 var = malloc(strlen(temp) + 1); \
1417 strcpy(var, &temp[1]); \
1418 free(temp); \
1419 }
1420
1421 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
1422 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version;
1423 GET_JSON_OBJECT(layer_node, functions)
1424 if (functions != NULL) {
1425 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
1426 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
1427 props->functions.str_gipa = vkGetInstanceProcAddr;
1428 props->functions.str_gdpa = vkGetDeviceProcAddr;
1429 }
1430 GET_JSON_OBJECT(layer_node, instance_extensions)
1431 if (instance_extensions != NULL) {
1432 int count = cJSON_GetArraySize(instance_extensions);
1433 for (i = 0; i < count; i++) {
1434 ext_item = cJSON_GetArrayItem(instance_extensions, i);
1435 GET_JSON_ITEM(ext_item, name)
1436 GET_JSON_ITEM(ext_item, version)
1437 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1438 ext_prop.lib_name = library_path;
1439 strcpy(ext_prop.info.extName, name);
1440 //TODO convert from string to int ext_prop.info.version = version;
1441 loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop);
1442 }
1443 }
1444 GET_JSON_OBJECT(layer_node, device_extensions)
1445 if (device_extensions != NULL) {
1446 int count = cJSON_GetArraySize(device_extensions);
1447 for (i = 0; i < count; i++) {
1448 ext_item = cJSON_GetArrayItem(device_extensions, i);
1449 GET_JSON_ITEM(ext_item, name);
1450 GET_JSON_ITEM(ext_item, version);
1451 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1452 ext_prop.lib_name = library_path;
1453 strcpy(ext_prop.info.extName, name);
1454 //TODO convert from string to int ext_prop.info.version = version;
1455 loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop);
1456 }
1457 }
1458 if (is_implicit) {
1459 GET_JSON_OBJECT(layer_node, enable_environment)
1460 props->enable_env_var.name = enable_environment->child->string;
1461 props->enable_env_var.value = enable_environment->child->valuestring;
1462 }
1463#undef GET_JSON_ITEM
1464#undef GET_JSON_OBJECT
1465
1466}
1467
1468/**
Jon Ashburnffd5d672015-06-29 11:25:34 -06001469 * Find the Vulkan library manifest files.
1470 *
1471 * This function scans the location or env_override directories/files
1472 * for a list of JSON manifest files. If env_override is non-NULL
1473 * and has a valid value. Then the location is ignored. Otherwise
1474 * location is used to look for manifest files. The location
1475 * is interpreted as Registry path on Windows and a directory path(s)
1476 * on Linux.
1477 *
1478 * \returns
1479 * A string list of manifest files to be opened in out_files param.
1480 * List has a pointer to string for each manifest filename.
1481 * When done using the list in out_files, pointers should be freed.
Jon Ashburnee33ae72015-06-30 14:46:22 -07001482 * Location or override string lists can be either files or directories as follows:
1483 * | location | override
1484 * --------------------------------
1485 * Win ICD | files | files
1486 * Win Layer | files | dirs
1487 * Linux ICD | dirs | files
1488 * Linux Layer| dirs | dirs
Jon Ashburnffd5d672015-06-29 11:25:34 -06001489 */
1490static void loader_get_manifest_files(const char *env_override,
Jon Ashburnee33ae72015-06-30 14:46:22 -07001491 bool is_layer,
1492 const char *location,
1493 struct loader_manifest_files *out_files)
Jon Ashburnffd5d672015-06-29 11:25:34 -06001494{
1495 char *override = NULL;
1496 char *loc;
1497 char *file, *next_file, *name;
1498 size_t alloced_count = 64;
1499 char full_path[2048];
1500 DIR *sysdir = NULL;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001501 bool list_is_dirs = false;
Jon Ashburnffd5d672015-06-29 11:25:34 -06001502 struct dirent *dent;
1503
1504 out_files->count = 0;
1505 out_files->filename_list = NULL;
1506
Jon Ashburnffd5d672015-06-29 11:25:34 -06001507 if (env_override != NULL && (override = getenv(env_override))) {
1508#if defined(__linux__)
1509 if (geteuid() != getuid()) {
Jon Ashburnee33ae72015-06-30 14:46:22 -07001510 /* Don't allow setuid apps to use the env var: */
Jon Ashburnffd5d672015-06-29 11:25:34 -06001511 override = NULL;
1512 }
1513#endif
1514 }
1515
1516 if (location == NULL) {
1517 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
Jon Ashburnee33ae72015-06-30 14:46:22 -07001518 "Can't get manifest files with NULL location, env_override=%s",
1519 env_override);
Jon Ashburnffd5d672015-06-29 11:25:34 -06001520 return;
1521 }
1522
Jon Ashburnee33ae72015-06-30 14:46:22 -07001523#if defined(__linux__)
1524 list_is_dirs = (override == NULL || is_layer) ? true : false;
1525#else //WIN32
1526 list_is_dirs = (is_layer && override != NULL) ? true : false;
1527#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001528 // Make a copy of the input we are using so it is not modified
Jon Ashburnee33ae72015-06-30 14:46:22 -07001529 // Also handle getting the location(s) from registry on Windows
1530 if (override == NULL) {
1531#if defined (_WIN32)
1532 loc = loader_get_registry_files(location);
1533 if (loc == NULL) {
1534 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1535 return;
1536 }
1537#else
Jon Ashburnffd5d672015-06-29 11:25:34 -06001538 loc = alloca(strlen(location) + 1);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001539 if (loc == NULL) {
1540 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1541 return;
1542 }
1543 strcpy(loc, location);
1544#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001545 }
Jon Ashburnee33ae72015-06-30 14:46:22 -07001546 else {
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -06001547 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001548 if (loc == NULL) {
1549 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1550 return;
1551 }
1552 strcpy(loc, override);
1553 }
Jon Ashburnffd5d672015-06-29 11:25:34 -06001554
1555 file = loc;
1556 while (*file) {
1557 next_file = loader_get_next_path(file);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001558 if (list_is_dirs) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001559 sysdir = opendir(file);
1560 name = NULL;
1561 if (sysdir) {
1562 dent = readdir(sysdir);
1563 if (dent == NULL)
1564 break;
1565 name = &(dent->d_name[0]);
1566 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1567 name = full_path;
1568 }
1569 }
1570 else {
Jon Ashburnee33ae72015-06-30 14:46:22 -07001571#if defined(__linux__)
1572 // only Linux has relative paths
Jon Ashburnffd5d672015-06-29 11:25:34 -06001573 char *dir;
1574 // make a copy of location so it isn't modified
1575 dir = alloca(strlen(location) + 1);
1576 if (dir == NULL) {
1577 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1578 return;
1579 }
1580 strcpy(dir, location);
1581
1582 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1583
1584 name = full_path;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001585#else // WIN32
1586 name = file;
1587#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001588 }
1589 while (name) {
1590 /* Look for files ending with ".json" suffix */
1591 uint32_t nlen = (uint32_t) strlen(name);
1592 const char *suf = name + nlen - 5;
1593 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1594 if (out_files->count == 0) {
1595 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1596 }
1597 else if (out_files->count == alloced_count) {
1598 out_files->filename_list = realloc(out_files->filename_list,
1599 alloced_count * sizeof(char *) * 2);
1600 alloced_count *= 2;
1601 }
1602 if (out_files->filename_list == NULL) {
1603 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1604 return;
1605 }
1606 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1607 if (out_files->filename_list[out_files->count] == NULL) {
1608 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1609 return;
1610 }
1611 strcpy(out_files->filename_list[out_files->count], name);
1612 out_files->count++;
Jon Ashburnc5662f62015-07-02 10:08:47 -06001613 } else if (!list_is_dirs) {
1614 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Skipping manifest file %s, file name must end in .json", name);
Jon Ashburnffd5d672015-06-29 11:25:34 -06001615 }
Jon Ashburnee33ae72015-06-30 14:46:22 -07001616 if (list_is_dirs) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001617 dent = readdir(sysdir);
1618 if (dent == NULL)
1619 break;
1620 name = &(dent->d_name[0]);
1621 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1622 name = full_path;
1623 }
1624 else {
1625 break;
1626 }
1627 }
1628 if (sysdir)
1629 closedir(sysdir);
1630 file = next_file;
1631 }
1632 return;
1633}
1634
1635/**
1636 * Try to find the Vulkan ICD driver(s).
1637 *
1638 * This function scans the default system loader path(s) or path
1639 * specified by the \c VK_ICD_FILENAMES environment variable in
1640 * order to find loadable VK ICDs manifest files. From these
1641 * manifest files it finds the ICD libraries.
1642 *
1643 * \returns
Jon Ashburn622ca2f2015-06-30 16:44:28 -06001644 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001645 */
Jon Ashburnfce93d92015-05-12 17:26:48 -06001646void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001647{
Jon Ashburnffd5d672015-06-29 11:25:34 -06001648 char *file_str;
1649 struct loader_manifest_files manifest_files;
1650
Jon Ashburnb40f2562015-05-29 13:15:39 -06001651
1652 // convenient place to initialize a mutex
1653 loader_platform_thread_create_mutex(&loader_lock);
1654
Jon Ashburnffd5d672015-06-29 11:25:34 -06001655 // convenient place to initialize logging
Courtney Goeltzenleuchter8b253f92015-06-08 15:11:18 -06001656 loader_debug_init();
1657
Jon Ashburnffd5d672015-06-29 11:25:34 -06001658 // Get a list of manifest files for ICDs
1659 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1660 &manifest_files);
Jon Ashburn1b111de2015-07-06 15:40:35 -06001661 if (manifest_files.count == 0)
1662 return;
Jon Ashburnffd5d672015-06-29 11:25:34 -06001663 for (uint32_t i = 0; i < manifest_files.count; i++) {
1664 file_str = manifest_files.filename_list[i];
1665 if (file_str == NULL)
1666 continue;
1667
Jon Ashburn1b111de2015-07-06 15:40:35 -06001668 cJSON *json;
Jon Ashburnffd5d672015-06-29 11:25:34 -06001669 json = loader_get_json(file_str);
Jon Ashburn1b111de2015-07-06 15:40:35 -06001670 cJSON *item;
1671 item = cJSON_GetObjectItem(json, "file_format_version");
1672 if (item == NULL)
1673 return;
1674 char *file_vers = cJSON_Print(item);
1675 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1676 file_str, file_vers);
1677 if (strcmp(file_vers, "\"1.0.0\"") != 0)
1678 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1679 free(file_vers);
1680 item = cJSON_GetObjectItem(json, "ICD");
1681 if (item != NULL) {
1682 item = cJSON_GetObjectItem(item, "library_path");
1683 if (item != NULL) {
1684 char *icd_filename = cJSON_PrintUnformatted(item);
Jon Ashburnffd5d672015-06-29 11:25:34 -06001685 char *icd_file = icd_filename;
1686 if (icd_filename != NULL) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001687 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1688 char *dir = def_dir;
1689 // strip off extra quotes
1690 if (icd_filename[strlen(icd_filename) - 1] == '"')
1691 icd_filename[strlen(icd_filename) - 1] = '\0';
1692 if (icd_filename[0] == '"')
1693 icd_filename++;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001694#if defined(__linux__)
1695 char full_path[2048];
Jon Ashburnffd5d672015-06-29 11:25:34 -06001696 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1697 loader_scanned_icd_add(full_path);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001698#else // WIN32
1699 loader_scanned_icd_add(icd_filename);
1700#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001701 free(icd_file);
1702 }
1703 }
1704 else
1705 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1706 }
1707 else
1708 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1709
1710 free(file_str);
1711 cJSON_Delete(json);
1712 }
1713 free(manifest_files.filename_list);
1714
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001715}
1716
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001717
Jon Ashburn68a63922015-07-02 09:40:15 -06001718void loader_layer_scan(void)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001719{
Jon Ashburn1b111de2015-07-06 15:40:35 -06001720 char *file_str;
1721 struct loader_manifest_files manifest_files;
1722 cJSON *json;
1723 uint32_t i;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001724
Jon Ashburn1b111de2015-07-06 15:40:35 -06001725 // Get a list of manifest files for layers
1726 loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO,
1727 &manifest_files);
1728 if (manifest_files.count == 0)
Courtney Goeltzenleuchterbce445a2014-12-01 09:29:42 -07001729 return;
Jon Ashburn0dcd6192015-06-04 15:30:58 -06001730
Jon Ashburn1b111de2015-07-06 15:40:35 -06001731#if 0
1732 /**
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06001733 * We need a list of the layer libraries, not just a list of
1734 * the layer properties (a layer library could expose more than
1735 * one layer property). This list of scanned layers would be
1736 * used to check for global and physicaldevice layer properties.
1737 */
1738 if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
1739 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1740 "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
1741 return;
Jon Ashburn68a63922015-07-02 09:40:15 -06001742 }
Jon Ashburn1b111de2015-07-06 15:40:35 -06001743#endif
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001744
Jon Ashburn1b111de2015-07-06 15:40:35 -06001745 // TODO use global_layer add and delete functions instead
1746 if (loader.scanned_layers.capacity == 0) {
1747 loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1748 if (loader.scanned_layers.list == NULL) {
1749 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list");
1750 return;
Jon Ashburneb2728b2015-04-10 14:33:07 -06001751 }
Jon Ashburn1b111de2015-07-06 15:40:35 -06001752 memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1753 loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
1754 }
1755 else {
1756 /* cleanup any previously scanned libraries */
1757 //TODO make sure everything is cleaned up properly
1758 for (i = 0; i < loader.scanned_layers.count; i++) {
1759 if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
1760 free(loader.scanned_layers.list[i].lib_info.lib_name);
1761 loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
1762 loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
1763 loader.scanned_layers.list[i].lib_info.lib_name = NULL;
Jon Ashburneb2728b2015-04-10 14:33:07 -06001764 }
Jon Ashburn1b111de2015-07-06 15:40:35 -06001765 loader.scanned_layers.count = 0;
1766 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001767
Jon Ashburn1b111de2015-07-06 15:40:35 -06001768 for (i = 0; i < manifest_files.count; i++) {
1769 file_str = manifest_files.filename_list[i];
1770 if (file_str == NULL)
1771 continue;
Courtney Goeltzenleuchteraa685052015-06-01 14:49:17 -06001772
Jon Ashburn1b111de2015-07-06 15:40:35 -06001773 // parse file into JSON struct
1774 json = loader_get_json(file_str);
1775 if (!json) {
1776 continue;
1777 }
1778 // ensure enough room to add an entry
1779 if ((loader.scanned_layers.count + 1) * sizeof (struct loader_layer_properties)
1780 > loader.scanned_layers.capacity) {
1781 loader.scanned_layers.list = realloc(loader.scanned_layers.list,
1782 loader.scanned_layers.capacity * 2);
1783 if (loader.scanned_layers.list == NULL) {
1784 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1785 "realloc failed for scanned layers");
1786 break;
1787 }
1788 loader.scanned_layers.capacity *= 2;
1789 }
1790 //TODO pass in implicit versus explicit bool
1791 loader_add_layer_properties(&loader.scanned_layers, json, false, file_str);
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06001792
Jon Ashburn1b111de2015-07-06 15:40:35 -06001793 free(file_str);
1794 cJSON_Delete(json);
1795 }
1796 free(manifest_files.filename_list);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001797
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001798}
1799
Jon Ashburnfce93d92015-05-12 17:26:48 -06001800static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1801{
1802 // inst is not wrapped
1803 if (inst == VK_NULL_HANDLE) {
1804 return NULL;
1805 }
1806 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1807 void *addr;
1808
Jon Ashburn4f2575f2015-05-28 16:25:02 -06001809 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1810 return (void *) loader_gpa_instance_internal;
1811
Jon Ashburnfce93d92015-05-12 17:26:48 -06001812 if (disp_table == NULL)
1813 return NULL;
1814
1815 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001816 if (addr) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06001817 return addr;
Jon Ashburne18431b2015-04-13 18:10:06 -06001818 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001819
1820 if (disp_table->GetInstanceProcAddr == NULL) {
1821 return NULL;
1822 }
1823 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburne18431b2015-04-13 18:10:06 -06001824}
1825
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001826struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburnb55278a2014-10-17 15:09:07 -06001827{
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001828
Jon Ashburndc67ef52015-01-29 16:44:24 -07001829 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1830 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1831 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001832 if (icd->gpus[i] == gpu) {
Jon Ashburndc67ef52015-01-29 16:44:24 -07001833 *gpu_index = i;
1834 return icd;
1835 }
1836 }
Jon Ashburnb55278a2014-10-17 15:09:07 -06001837 }
1838 return NULL;
1839}
1840
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001841static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn9a9de1f2015-05-27 13:19:22 -06001842 const char *chain_type,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001843 struct loader_layer_properties *layer_prop)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001844{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001845 struct loader_lib_info *new_layer_lib_list, *my_lib;
1846
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06001847 /*
1848 * TODO: We can now track this information in the
1849 * scanned_layer_libraries list.
1850 */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001851 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001852 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001853 /* Have already loaded this library, just increment ref count */
1854 loader.loaded_layer_lib_list[i].ref_count++;
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001855 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001856 "%s Chain: Increment layer reference count for layer library %s",
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001857 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001858 return loader.loaded_layer_lib_list[i].lib_handle;
1859 }
1860 }
1861
1862 /* Haven't seen this library so load it */
1863 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1864 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1865 if (!new_layer_lib_list) {
1866 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1867 return NULL;
1868 }
1869
1870 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1871
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001872 /* NOTE: We require that the layer property be immutable */
1873 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001874 my_lib->ref_count = 0;
1875 my_lib->lib_handle = NULL;
1876
1877 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1878 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1879 loader_platform_open_library_error(my_lib->lib_name));
1880 return NULL;
1881 } else {
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001882 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001883 "Chain: %s: Loading layer library %s",
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001884 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001885 }
1886 loader.loaded_layer_lib_count++;
1887 loader.loaded_layer_lib_list = new_layer_lib_list;
1888 my_lib->ref_count++;
1889
1890 return my_lib->lib_handle;
1891}
1892
1893static void loader_remove_layer_lib(
1894 struct loader_instance *inst,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001895 struct loader_layer_properties *layer_prop)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001896{
1897 uint32_t idx;
1898 struct loader_lib_info *new_layer_lib_list, *my_lib;
1899
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001900 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001901 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001902 /* found matching library */
1903 idx = i;
1904 my_lib = &loader.loaded_layer_lib_list[i];
1905 break;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001906 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001907 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001908
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001909 my_lib->ref_count--;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001910 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001911 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001912 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
Jon Ashburnfce93d92015-05-12 17:26:48 -06001913 return;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07001914 }
Jon Ashburn4d3b7522015-04-14 14:14:48 -06001915
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001916 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001917 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001918 "Unloading layer library %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001919
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001920 /* Need to remove unused library from list */
1921 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1922 if (!new_layer_lib_list) {
1923 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1924 return;
1925 }
1926
1927 if (idx > 0) {
1928 /* Copy records before idx */
1929 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1930 sizeof(struct loader_lib_info) * idx);
1931 }
1932 if (idx < (loader.loaded_layer_lib_count - 1)) {
1933 /* Copy records after idx */
1934 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1935 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1936 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001937
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001938 free(loader.loaded_layer_lib_list);
1939 loader.loaded_layer_lib_count--;
1940 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnead95c52014-11-18 09:06:04 -07001941}
1942
Jon Ashburn1b111de2015-07-06 15:40:35 -06001943
1944/**
1945 * Go through the search_list and find any layers which match type. If layer
1946 * type match is found in then add it to ext_list.
1947 */
1948//TODO need to handle implict layer enable env var and disable env var
Jon Ashburn535bd002015-07-02 16:10:32 -06001949static void loader_add_layer_implicit(
1950 const enum layer_type type,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001951 struct loader_layer_list *list,
1952 struct loader_layer_list *search_list)
Jon Ashburn535bd002015-07-02 16:10:32 -06001953{
1954 uint32_t i;
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001955 for (i = 0; i < search_list->count; i++) {
1956 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn535bd002015-07-02 16:10:32 -06001957 if (prop->type & type) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001958 /* Found an layer with the same type, add to layer_list */
1959 loader_add_to_layer_list(list, 1, prop);
Jon Ashburn535bd002015-07-02 16:10:32 -06001960 }
1961 }
1962
1963}
1964
1965/**
1966 * Get the layer name(s) from the env_name environment variable. If layer
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001967 * is found in search_list then add it to layer_list. But only add it to
1968 * layer_list if type matches.
Jon Ashburn535bd002015-07-02 16:10:32 -06001969 */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001970static void loader_add_layer_env(
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001971 const enum layer_type type,
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001972 const char *env_name,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001973 struct loader_layer_list *layer_list,
1974 const struct loader_layer_list *search_list)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001975{
Ian Elliott225188f2015-02-17 10:33:47 -07001976 char *layerEnv;
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001977 char *next, *name;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001978
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001979 layerEnv = getenv(env_name);
Ian Elliott225188f2015-02-17 10:33:47 -07001980 if (layerEnv == NULL) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001981 return;
Ian Elliott225188f2015-02-17 10:33:47 -07001982 }
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -06001983 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001984 if (name == NULL) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001985 return;
Ian Elliott225188f2015-02-17 10:33:47 -07001986 }
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001987 strcpy(name, layerEnv);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001988
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001989 while (name && *name ) {
1990 next = loader_get_next_path(name);
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001991 loader_find_layer_name_add_list(name, type, search_list, layer_list);
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001992 name = next;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07001993 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001994
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001995 return;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001996}
1997
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -06001998void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn183dfd02014-10-22 18:13:16 -06001999{
Jon Ashburn60378412015-07-02 12:59:25 -06002000 if (!instance->activated_layer_list.count) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002001 return;
2002 }
Jon Ashburn183dfd02014-10-22 18:13:16 -06002003
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002004 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -06002005 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002006 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002007
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002008 loader_remove_layer_lib(instance, layer_prop);
Jon Ashburn183dfd02014-10-22 18:13:16 -06002009 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002010 loader_destroy_layer_list(&instance->activated_layer_list);
Jon Ashburn183dfd02014-10-22 18:13:16 -06002011}
2012
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002013VkResult loader_enable_instance_layers(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002014 struct loader_instance *inst,
2015 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002016{
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002017 VkResult err;
2018
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002019 if (inst == NULL)
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002020 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002021
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002022 if (!loader_init_layer_list(&inst->activated_layer_list)) {
Jon Ashburn60378412015-07-02 12:59:25 -06002023 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002024 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn60378412015-07-02 12:59:25 -06002025 }
2026
Jon Ashburn535bd002015-07-02 16:10:32 -06002027 /* Add any implicit layers first */
2028 loader_add_layer_implicit(
2029 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
2030 &inst->activated_layer_list,
Jon Ashburn1b111de2015-07-06 15:40:35 -06002031 &loader.scanned_layers);
Jon Ashburn535bd002015-07-02 16:10:32 -06002032
Jon Ashburn1b111de2015-07-06 15:40:35 -06002033 /* Add any layers specified via environment variable next */
Jon Ashburna2e6efe2015-07-02 14:10:53 -06002034 loader_add_layer_env(
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002035 VK_LAYER_TYPE_INSTANCE_EXPLICIT,
Jon Ashburna2e6efe2015-07-02 14:10:53 -06002036 "VK_INSTANCE_LAYERS",
2037 &inst->activated_layer_list,
Jon Ashburn1b111de2015-07-06 15:40:35 -06002038 &loader.scanned_layers);
Jon Ashburn60378412015-07-02 12:59:25 -06002039
2040 /* Add layers specified by the application */
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002041 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002042 &inst->activated_layer_list,
2043 pCreateInfo->layerCount,
2044 pCreateInfo->ppEnabledLayerNames,
Jon Ashburn1b111de2015-07-06 15:40:35 -06002045 &loader.scanned_layers);
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002046
2047 return err;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002048}
2049
Jon Ashburnfce93d92015-05-12 17:26:48 -06002050uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2051{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002052 uint32_t layer_idx;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002053 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002054
David Pinedo0fab78b2015-06-24 15:29:18 -06002055 if (inst == NULL) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06002056 return 0;
David Pinedo0fab78b2015-06-24 15:29:18 -06002057 }
Jon Ashburnfce93d92015-05-12 17:26:48 -06002058
2059 // NOTE inst is unwrapped at this point in time
2060 VkObject baseObj = (VkObject) inst;
2061 VkObject nextObj = (VkObject) inst;
2062 VkBaseLayerObject *nextInstObj;
2063 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2064
Jon Ashburn60378412015-07-02 12:59:25 -06002065 if (!inst->activated_layer_list.count) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06002066 return 0;
2067 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002068
Courtney Goeltzenleuchter0248b992015-07-06 09:04:55 -06002069 wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
Jon Ashburn60378412015-07-02 12:59:25 -06002070 * inst->activated_layer_list.count);
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002071 if (!wrappedInstance) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002072 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
2073 return 0;
2074 }
2075
2076 /* Create instance chain of enabled layers */
Jon Ashburn60378412015-07-02 12:59:25 -06002077 layer_idx = inst->activated_layer_list.count - 1;
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06002078 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002079 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002080 loader_platform_dl_handle lib_handle;
2081
Jon Ashburn60378412015-07-02 12:59:25 -06002082 /*
Courtney Goeltzenleuchterc27292a2015-06-01 14:12:42 -06002083 * Note: An extension's Get*ProcAddr should not return a function pointer for
2084 * any extension entry points until the extension has been enabled.
2085 * To do this requires a different behavior from Get*ProcAddr functions implemented
2086 * in layers.
2087 * The very first call to a layer will be it's Get*ProcAddr function requesting
2088 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
2089 * with the wrapped object given (either Instance or Device) and return the layer's
2090 * Get*ProcAddr function. The layer should also use this opportunity to record the
2091 * baseObject so that it can find the correct local dispatch table on future calls.
2092 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2093 * will not use a wrapped object and must look up their local dispatch table from
2094 * the given baseObject.
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002095 */
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002096 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburnfce93d92015-05-12 17:26:48 -06002097 nextInstObj->pGPA = nextGPA;
2098 nextInstObj->baseObject = baseObj;
2099 nextInstObj->nextObject = nextObj;
2100 nextObj = (VkObject) nextInstObj;
2101
2102 char funcStr[256];
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002103 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
2104 lib_handle = loader_add_layer_lib("instance", layer_prop);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002105 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2106 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburnfce93d92015-05-12 17:26:48 -06002107 if (!nextGPA) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002108 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetInstanceProcAddr in layer %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchteraa685052015-06-01 14:49:17 -06002109
2110 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburnfce93d92015-05-12 17:26:48 -06002111 continue;
2112 }
2113
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002114 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002115 "Insert instance layer %s (%s)",
2116 layer_prop->info.layerName,
2117 layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002118
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002119 layer_idx--;
Jon Ashburnfce93d92015-05-12 17:26:48 -06002120 }
2121
Jon Ashburn4f2575f2015-05-28 16:25:02 -06002122 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002123
Jon Ashburn60378412015-07-02 12:59:25 -06002124 return inst->activated_layer_list.count;
Jon Ashburnfce93d92015-05-12 17:26:48 -06002125}
2126
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002127void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2128{
2129
2130 loader_init_instance_extension_dispatch_table(inst->disp,
2131 inst->disp->GetInstanceProcAddr,
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002132 (VkInstance) inst);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002133}
2134
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002135static VkResult loader_enable_device_layers(
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002136 struct loader_icd *icd,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002137 struct loader_device *dev,
2138 const VkDeviceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002139{
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002140 VkResult err;
2141
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002142 if (dev == NULL)
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002143 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002144
Jon Ashburn60378412015-07-02 12:59:25 -06002145 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002146 loader_init_layer_list(&dev->activated_layer_list);
Jon Ashburn60378412015-07-02 12:59:25 -06002147 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002148
Jon Ashburn60378412015-07-02 12:59:25 -06002149 if (dev->activated_layer_list.list == NULL) {
2150 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002151 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn60378412015-07-02 12:59:25 -06002152 }
2153
Jon Ashburn535bd002015-07-02 16:10:32 -06002154 /* Add any implicit layers first */
2155 loader_add_layer_implicit(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002156 VK_LAYER_TYPE_DEVICE_IMPLICIT,
2157 &dev->activated_layer_list,
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002158 &loader.scanned_layers);
Jon Ashburn535bd002015-07-02 16:10:32 -06002159
2160 /* Add any layers specified via environment variable next */
Jon Ashburna2e6efe2015-07-02 14:10:53 -06002161 loader_add_layer_env(
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002162 VK_LAYER_TYPE_DEVICE_EXPLICIT,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002163 "VK_DEVICE_LAYERS",
2164 &dev->activated_layer_list,
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002165 &loader.scanned_layers);
Jon Ashburn60378412015-07-02 12:59:25 -06002166
2167 /* Add layers specified by the application */
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002168 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002169 &dev->activated_layer_list,
2170 pCreateInfo->layerCount,
2171 pCreateInfo->ppEnabledLayerNames,
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002172 &loader.scanned_layers);
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002173
2174 return err;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002175}
2176
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002177/*
2178 * This function terminates the device chain fro CreateDevice.
2179 * CreateDevice is a special case and so the loader call's
2180 * the ICD's CreateDevice before creating the chain. Since
2181 * we can't call CreateDevice twice we must terminate the
2182 * device chain with something else.
2183 */
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002184static VkResult scratch_vkCreateDevice(
2185 VkPhysicalDevice gpu,
2186 const VkDeviceCreateInfo *pCreateInfo,
2187 VkDevice *pDevice)
2188{
2189 return VK_SUCCESS;
2190}
2191
2192static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2193{
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002194 if (!strcmp(name, "vkGetDeviceProcAddr"))
2195 return (void *) loader_GetDeviceChainProcAddr;
2196 if (!strcmp(name, "vkCreateDevice"))
2197 return (void *) scratch_vkCreateDevice;
2198
Courtney Goeltzenleuchtere76db422015-06-29 16:09:23 -06002199 struct loader_device *found_dev;
2200 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2201 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002202}
2203
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002204static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002205 struct loader_icd *icd,
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002206 struct loader_device *dev,
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002207 VkDevice device)
Jon Ashburn183dfd02014-10-22 18:13:16 -06002208{
Jon Ashburn183dfd02014-10-22 18:13:16 -06002209 if (!icd)
2210 return 0;
Jon Ashburn183dfd02014-10-22 18:13:16 -06002211
David Pinedo0fab78b2015-06-24 15:29:18 -06002212 if (!dev) {
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002213 return 0;
David Pinedo0fab78b2015-06-24 15:29:18 -06002214 }
Jon Ashburn612539f2015-06-10 10:13:10 -06002215
Jon Ashburn183dfd02014-10-22 18:13:16 -06002216 /* activate any layer libraries */
Jon Ashburn612539f2015-06-10 10:13:10 -06002217 VkObject nextObj = (VkObject) device;
2218 VkObject baseObj = nextObj;
2219 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002220 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn612539f2015-06-10 10:13:10 -06002221 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002222
Jon Ashburn612539f2015-06-10 10:13:10 -06002223 if (!dev->activated_layer_list.count)
2224 return 0;
2225
2226 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2227 if (!wrappedGpus) {
2228 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2229 return 0;
2230 }
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002231
Jon Ashburn612539f2015-06-10 10:13:10 -06002232 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2233
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002234 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
Jon Ashburn612539f2015-06-10 10:13:10 -06002235 loader_platform_dl_handle lib_handle;
2236
Jon Ashburn612539f2015-06-10 10:13:10 -06002237 nextGpuObj = (wrappedGpus + i);
2238 nextGpuObj->pGPA = nextGPA;
2239 nextGpuObj->baseObject = baseObj;
2240 nextGpuObj->nextObject = nextObj;
2241 nextObj = (VkObject) nextGpuObj;
2242
2243 char funcStr[256];
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002244 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2245 lib_handle = loader_add_layer_lib("device", layer_prop);
Jon Ashburn612539f2015-06-10 10:13:10 -06002246 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2247 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2248 if (!nextGPA) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002249 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to find vkGetDeviceProcAddr in layer %s", layer_prop->info.layerName);
Jon Ashburn612539f2015-06-10 10:13:10 -06002250 continue;
2251 }
2252
2253 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002254 "Insert device layer library %s (%s)",
2255 layer_prop->info.layerName,
2256 layer_prop->lib_info.lib_name);
Jon Ashburn612539f2015-06-10 10:13:10 -06002257
2258 }
2259
2260 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2261 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
2262 free(wrappedGpus);
2263
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002264 return dev->activated_layer_list.count;
Jon Ashburn183dfd02014-10-22 18:13:16 -06002265}
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002266
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002267VkResult loader_validate_layers(
2268 const uint32_t layer_count,
2269 const char * const *ppEnabledLayerNames,
2270 struct loader_layer_list *list)
Courtney Goeltzenleuchter5d9f29b2015-07-06 17:45:08 -06002271{
2272 struct loader_layer_properties *prop;
2273
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002274 for (uint32_t i = 0; i < layer_count; i++) {
2275 prop = get_layer_property(ppEnabledLayerNames[i],
2276 list);
Courtney Goeltzenleuchter5d9f29b2015-07-06 17:45:08 -06002277 if (!prop) {
2278 return VK_ERROR_INVALID_LAYER;
2279 }
2280 }
2281
2282 return VK_SUCCESS;
2283}
2284
2285VkResult loader_validate_instance_extensions(
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002286 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter5d9f29b2015-07-06 17:45:08 -06002287{
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002288 struct loader_extension_property *extension_prop;
2289 struct loader_layer_properties *layer_prop;
2290
2291 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2292 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2293 &loader.global_extensions);
2294
2295 if (extension_prop) {
2296 continue;
2297 }
2298
2299 extension_prop = NULL;
2300
2301 /* Not in global list, search layer extension lists */
2302 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2303 layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
Jon Ashburn1b111de2015-07-06 15:40:35 -06002304 &loader.scanned_layers);
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002305
2306 if (!layer_prop) {
Courtney Goeltzenleuchter91371ff2015-07-06 20:46:50 -06002307 /* Should NOT get here, loader_validate_layers
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002308 * should have already filtered this case out.
2309 */
2310 continue;
2311 }
2312
2313 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2314 &layer_prop->instance_extension_list);
2315 if (extension_prop) {
2316 /* Found the extension in one of the layers enabled by the app. */
2317 break;
2318 }
2319 }
2320
2321 if (!extension_prop) {
2322 /* Didn't find extension name in any of the global layers, error out */
2323 return VK_ERROR_INVALID_EXTENSION;
2324 }
2325 }
2326 return VK_SUCCESS;
2327}
2328
2329VkResult loader_validate_device_extensions(
2330 struct loader_icd *icd,
2331 const VkDeviceCreateInfo *pCreateInfo)
2332{
2333 struct loader_extension_property *extension_prop;
2334 struct loader_layer_properties *layer_prop;
2335
2336 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2337 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2338 extension_prop = get_extension_property(extension_name,
2339 &loader.global_extensions);
2340
2341 if (extension_prop) {
2342 continue;
2343 }
2344
2345 /* Not in global list, search layer extension lists */
2346 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2347 const char *layer_name = pCreateInfo->ppEnabledLayerNames[j];
2348 layer_prop = get_layer_property(layer_name,
2349 &icd->layer_properties_cache);
2350
2351 if (!layer_prop) {
2352 /* Should NOT get here, loader_validate_instance_layers
2353 * should have already filtered this case out.
2354 */
2355 continue;
2356 }
2357
2358 extension_prop = get_extension_property(extension_name,
2359 &layer_prop->device_extension_list);
2360 if (extension_prop) {
2361 /* Found the extension in one of the layers enabled by the app. */
2362 break;
2363 }
2364 }
2365
2366 if (!extension_prop) {
2367 /* Didn't find extension name in any of the device layers, error out */
2368 return VK_ERROR_INVALID_EXTENSION;
2369 }
2370 }
Courtney Goeltzenleuchter5d9f29b2015-07-06 17:45:08 -06002371 return VK_SUCCESS;
2372}
2373
Jon Ashburnfce93d92015-05-12 17:26:48 -06002374VkResult loader_CreateInstance(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002375 const VkInstanceCreateInfo* pCreateInfo,
2376 VkInstance* pInstance)
Jon Ashburn349508d2015-01-26 14:51:40 -07002377{
Jon Ashburna179dcf2015-05-21 17:42:17 -06002378 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn3336df82015-01-29 15:45:51 -07002379 struct loader_scanned_icds *scanned_icds;
2380 struct loader_icd *icd;
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -06002381 struct loader_extension_property *prop;
2382 char **filtered_extension_names = NULL;
2383 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002384 VkResult res = VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002385
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -06002386 icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
2387 icd_create_info.layerCount = 0;
2388 icd_create_info.ppEnabledLayerNames = NULL;
2389 icd_create_info.pAllocCb = pCreateInfo->pAllocCb;
2390 icd_create_info.pAppInfo = pCreateInfo->pAppInfo;
2391 icd_create_info.pNext = pCreateInfo->pNext;
2392
2393 /*
2394 * NOTE: Need to filter the extensions to only those
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002395 * supported by the ICD.
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -06002396 * No ICD will advertise support for layers. An ICD
2397 * library could support a layer, but it would be
2398 * independent of the actual ICD, just in the same library.
2399 */
2400 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2401 if (!filtered_extension_names) {
2402 return VK_ERROR_OUT_OF_HOST_MEMORY;
2403 }
2404 icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2405
Jon Ashburn3336df82015-01-29 15:45:51 -07002406 scanned_icds = loader.scanned_icd_list;
2407 while (scanned_icds) {
2408 icd = loader_icd_add(ptr_instance, scanned_icds);
2409 if (icd) {
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -06002410
2411 icd_create_info.extensionCount = 0;
2412 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2413 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2414 &scanned_icds->global_extension_list);
2415 if (prop) {
2416 filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i];
2417 icd_create_info.extensionCount++;
2418 }
2419 }
2420
2421 res = scanned_icds->CreateInstance(&icd_create_info,
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002422 &(icd->instance));
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06002423 if (res != VK_SUCCESS)
Jon Ashburn3336df82015-01-29 15:45:51 -07002424 {
2425 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002426 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002427 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002428 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn3336df82015-01-29 15:45:51 -07002429 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002430 } else
2431 {
2432 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn3336df82015-01-29 15:45:51 -07002433 }
2434 }
2435 scanned_icds = scanned_icds->next;
2436 }
Jon Ashburn349508d2015-01-26 14:51:40 -07002437
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002438 /*
2439 * If no ICDs were added to instance list and res is unchanged
2440 * from it's initial value, the loader was unable to find
2441 * a suitable ICD.
2442 */
Ian Elliott617fdec2015-02-05 15:19:15 -07002443 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002444 if (res == VK_SUCCESS) {
2445 return VK_ERROR_INCOMPATIBLE_DRIVER;
2446 } else {
2447 return res;
2448 }
Ian Elliott617fdec2015-02-05 15:19:15 -07002449 }
Jon Ashburn3336df82015-01-29 15:45:51 -07002450
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002451 return VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002452}
2453
Jon Ashburnfce93d92015-05-12 17:26:48 -06002454VkResult loader_DestroyInstance(
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -06002455 VkInstance instance)
Jon Ashburn349508d2015-01-26 14:51:40 -07002456{
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -06002457 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002458 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburn16a16d62015-06-16 14:43:19 -06002459 struct loader_icd *next_icd;
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -06002460 VkResult res;
Jon Ashburn349508d2015-01-26 14:51:40 -07002461
2462 // Remove this instance from the list of instances:
2463 struct loader_instance *prev = NULL;
2464 struct loader_instance *next = loader.instances;
2465 while (next != NULL) {
2466 if (next == ptr_instance) {
2467 // Remove this instance from the list:
2468 if (prev)
2469 prev->next = next->next;
Jon Ashburn2cabd252015-02-03 09:26:59 -07002470 else
2471 loader.instances = next->next;
Jon Ashburn349508d2015-01-26 14:51:40 -07002472 break;
2473 }
2474 prev = next;
2475 next = next->next;
2476 }
2477 if (next == NULL) {
2478 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06002479 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn349508d2015-01-26 14:51:40 -07002480 }
2481
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002482 while (icds) {
2483 if (icds->instance) {
2484 res = icds->DestroyInstance(icds->instance);
Tony Barbour22a30862015-04-22 09:02:32 -06002485 if (res != VK_SUCCESS)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002486 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbour22a30862015-04-22 09:02:32 -06002487 "ICD ignored: failed to DestroyInstance on device");
2488 }
Jon Ashburn16a16d62015-06-16 14:43:19 -06002489 next_icd = icds->next;
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002490 icds->instance = VK_NULL_HANDLE;
Jon Ashburn16a16d62015-06-16 14:43:19 -06002491 loader_icd_destroy(ptr_instance, icds);
2492
2493 icds = next_icd;
Jon Ashburn3336df82015-01-29 15:45:51 -07002494 }
2495
Jon Ashburn349508d2015-01-26 14:51:40 -07002496
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06002497 return VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002498}
2499
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002500VkResult loader_init_physical_device_info(
2501 struct loader_instance *ptr_instance)
2502{
2503 struct loader_icd *icd;
2504 uint32_t n, count = 0;
2505 VkResult res = VK_ERROR_UNKNOWN;
2506
2507 icd = ptr_instance->icds;
2508 while (icd) {
2509 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2510 if (res != VK_SUCCESS)
2511 return res;
2512 icd->gpu_count = n;
2513 count += n;
2514 icd = icd->next;
2515 }
2516
2517 ptr_instance->total_gpu_count = count;
2518
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002519 icd = ptr_instance->icds;
2520 while (icd) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002521
2522 n = icd->gpu_count;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002523 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2524 if (!icd->gpus) {
2525 /* TODO: Add cleanup code here */
2526 return VK_ERROR_OUT_OF_HOST_MEMORY;
2527 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002528 res = icd->EnumeratePhysicalDevices(
2529 icd->instance,
2530 &n,
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002531 icd->gpus);
2532 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002533
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002534 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002535
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002536 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002537
2538 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2539 /* TODO: Add cleanup code here */
2540 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2541 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002542 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002543
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002544 loader_add_physical_device_extensions(
2545 icd->GetPhysicalDeviceExtensionProperties,
2546 icd->gpus[0],
2547 VK_EXTENSION_ORIGIN_ICD,
2548 icd->scanned_icds->lib_name,
2549 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002550
Jon Ashburn1b111de2015-07-06 15:40:35 -06002551 for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002552 loader_platform_dl_handle lib_handle;
Jon Ashburn1b111de2015-07-06 15:40:35 -06002553 char *lib_name = loader.scanned_layers.list[l].lib_info.lib_name;
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002554
2555 lib_handle = loader_platform_open_library(lib_name);
2556 if (lib_handle == NULL) {
2557 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed: %s", lib_name);
2558 continue;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002559 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002560 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2561 "library: %s", lib_name);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002562
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002563 loader_add_physical_device_layer_properties(
2564 icd, lib_name, lib_handle);
2565
2566 loader_platform_close_library(lib_handle);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002567 }
2568 }
2569
2570 if (res != VK_SUCCESS) {
2571 /* clean up any extension lists previously created before this request failed */
2572 for (uint32_t j = 0; j < i; j++) {
2573 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2574 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002575
2576 loader_destroy_layer_list(&icd->layer_properties_cache);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002577 return res;
2578 }
2579 }
2580
2581 count += n;
2582 }
2583
2584 icd = icd->next;
2585 }
2586
2587 return VK_SUCCESS;
2588}
2589
Jon Ashburnfce93d92015-05-12 17:26:48 -06002590VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter9f530cb2015-04-20 12:48:54 -06002591 VkInstance instance,
2592 uint32_t* pPhysicalDeviceCount,
2593 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn349508d2015-01-26 14:51:40 -07002594{
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002595 uint32_t index = 0;
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002596 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002597 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002598
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002599 if (ptr_instance->total_gpu_count == 0) {
2600 loader_init_physical_device_info(ptr_instance);
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002601 }
2602
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002603 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2604 if (!pPhysicalDevices) {
2605 return VK_SUCCESS;
2606 }
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002607
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002608 while (icd) {
2609 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002610 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002611 index += icd->gpu_count;
2612 icd = icd->next;
2613 }
2614
2615 return VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002616}
2617
Tony Barbour426b9052015-06-24 16:06:58 -06002618VkResult loader_GetPhysicalDeviceProperties(
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002619 VkPhysicalDevice gpu,
Tony Barbour426b9052015-06-24 16:06:58 -06002620 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002621{
2622 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002623 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002624 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2625
Tony Barbour426b9052015-06-24 16:06:58 -06002626 if (icd->GetPhysicalDeviceProperties)
2627 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2628
2629 return res;
2630}
2631
2632VkResult loader_GetPhysicalDevicePerformance(
2633 VkPhysicalDevice gpu,
2634 VkPhysicalDevicePerformance* pPerformance)
2635{
2636 uint32_t gpu_index;
2637 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2638 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2639
2640 if (icd->GetPhysicalDevicePerformance)
2641 res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2642
2643 return res;
2644}
2645
2646VkResult loader_GetPhysicalDeviceQueueCount(
2647 VkPhysicalDevice gpu,
2648 uint32_t* pCount)
2649{
2650 uint32_t gpu_index;
2651 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2652 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2653
2654 if (icd->GetPhysicalDeviceQueueCount)
2655 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2656
2657 return res;
2658}
2659
2660VkResult loader_GetPhysicalDeviceQueueProperties (
2661 VkPhysicalDevice gpu,
2662 uint32_t count,
2663 VkPhysicalDeviceQueueProperties * pProperties)
2664{
2665 uint32_t gpu_index;
2666 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2667 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2668
2669 if (icd->GetPhysicalDeviceQueueProperties)
2670 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2671
2672 return res;
2673}
2674
2675VkResult loader_GetPhysicalDeviceMemoryProperties (
2676 VkPhysicalDevice gpu,
2677 VkPhysicalDeviceMemoryProperties* pProperties)
2678{
2679 uint32_t gpu_index;
2680 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2681 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2682
2683 if (icd->GetPhysicalDeviceMemoryProperties)
2684 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002685
2686 return res;
2687}
2688
Chris Forbesd7576302015-06-21 22:55:02 +12002689VkResult loader_GetPhysicalDeviceFeatures(
2690 VkPhysicalDevice physicalDevice,
2691 VkPhysicalDeviceFeatures* pFeatures)
2692{
2693 uint32_t gpu_index;
2694 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2695 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2696
2697 if (icd->GetPhysicalDeviceFeatures)
2698 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2699
2700 return res;
2701}
2702
2703VkResult loader_GetPhysicalDeviceFormatInfo(
2704 VkPhysicalDevice physicalDevice,
2705 VkFormat format,
2706 VkFormatProperties* pFormatInfo)
2707{
2708 uint32_t gpu_index;
2709 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2710 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2711
2712 if (icd->GetPhysicalDeviceFormatInfo)
2713 res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2714
2715 return res;
2716}
2717
2718VkResult loader_GetPhysicalDeviceLimits(
2719 VkPhysicalDevice physicalDevice,
2720 VkPhysicalDeviceLimits* pLimits)
2721{
2722 uint32_t gpu_index;
2723 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2724 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2725
2726 if (icd->GetPhysicalDeviceLimits)
2727 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2728
2729 return res;
2730}
2731
Mark Lobodzinski83d4e6a2015-07-03 15:58:09 -06002732VkResult loader_GetPhysicalDeviceSparseImageFormatProperties(
2733 VkPhysicalDevice physicalDevice,
2734 VkFormat format,
2735 VkImageType type,
2736 uint32_t samples,
2737 VkImageUsageFlags usage,
2738 VkImageTiling tiling,
2739 uint32_t* pNumProperties,
2740 VkSparseImageFormatProperties* pProperties)
2741{
2742 uint32_t gpu_index;
2743 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2744 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2745
2746 if (icd->GetPhysicalDeviceSparseImageFormatProperties)
2747 res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
2748
2749 return res;
2750}
2751
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002752VkResult loader_CreateDevice(
2753 VkPhysicalDevice gpu,
2754 const VkDeviceCreateInfo* pCreateInfo,
2755 VkDevice* pDevice)
2756{
2757 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002758 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002759 struct loader_device *dev;
Courtney Goeltzenleuchter91371ff2015-07-06 20:46:50 -06002760 VkDeviceCreateInfo device_create_info;
2761 char **filtered_extension_names = NULL;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002762 VkResult res;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002763
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002764 if (!icd->CreateDevice) {
2765 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002766 }
2767
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002768 res = loader_validate_layers(pCreateInfo->layerCount,
2769 pCreateInfo->ppEnabledLayerNames,
2770 &icd->layer_properties_cache);
2771 if (res != VK_SUCCESS) {
2772 return res;
2773 }
2774
2775 res = loader_validate_device_extensions(icd, pCreateInfo);
2776 if (res != VK_SUCCESS) {
2777 return res;
2778 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002779
Courtney Goeltzenleuchter91371ff2015-07-06 20:46:50 -06002780 /*
2781 * NOTE: Need to filter the extensions to only those
2782 * supported by the ICD.
2783 * No ICD will advertise support for layers. An ICD
2784 * library could support a layer, but it would be
2785 * independent of the actual ICD, just in the same library.
2786 */
2787 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2788 if (!filtered_extension_names) {
2789 return VK_ERROR_OUT_OF_HOST_MEMORY;
2790 }
2791
2792 /* Copy user's data */
2793 memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
2794
2795 /* ICD's do not use layers */
2796 device_create_info.layerCount = 0;
2797 device_create_info.ppEnabledLayerNames = NULL;
2798
2799 device_create_info.extensionCount = 0;
2800 device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2801
2802 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2803 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2804 struct loader_extension_property *prop = get_extension_property(extension_name,
2805 &icd->device_extension_cache[gpu_index]);
2806 if (prop) {
2807 filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name;
2808 device_create_info.extensionCount++;
2809 }
2810 }
2811
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002812 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2813 if (res != VK_SUCCESS) {
2814 return res;
2815 }
2816
2817 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2818 if (dev == NULL) {
2819 return VK_ERROR_OUT_OF_HOST_MEMORY;
2820 }
2821 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2822 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2823 icd->gpus[gpu_index], icd->gpus[gpu_index]);
2824
2825 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2826 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2827
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002828 /*
2829 * Put together the complete list of extensions to enable
2830 * This includes extensions requested via environment variables.
2831 */
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002832 loader_enable_device_layers(icd, dev, pCreateInfo);
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002833
2834 /*
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002835 * Load the libraries and build the device chain
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002836 * terminating with the selected device.
2837 */
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002838 loader_activate_device_layers(icd, dev, *pDevice);
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002839
2840 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2841
2842 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2843
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002844 return res;
2845}
2846
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002847static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburn53c16772015-05-06 10:15:07 -06002848{
Jon Ashburncedc15f2015-05-21 18:13:33 -06002849 if (instance == VK_NULL_HANDLE)
2850 return NULL;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002851
Jon Ashburncedc15f2015-05-21 18:13:33 -06002852 void *addr;
2853 /* get entrypoint addresses that are global (in the loader)*/
2854 addr = globalGetProcAddr(pName);
2855 if (addr)
2856 return addr;
Jon Ashburn53c16772015-05-06 10:15:07 -06002857
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002858 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2859
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002860 /* return any extension global entrypoints */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002861 addr = debug_report_instance_gpa(ptr_instance, pName);
2862 if (addr) {
2863 return addr;
2864 }
2865
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002866 /* TODO Remove this once WSI has no loader special code */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002867 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
David Pinedo0fab78b2015-06-24 15:29:18 -06002868 if (addr) {
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002869 return addr;
David Pinedo0fab78b2015-06-24 15:29:18 -06002870 }
Jon Ashburncedc15f2015-05-21 18:13:33 -06002871
2872 /* return the instance dispatch table entrypoint for extensions */
2873 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2874 if (disp_table == NULL)
2875 return NULL;
2876
2877 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2878 if (addr)
2879 return addr;
Jon Ashburn53c16772015-05-06 10:15:07 -06002880
2881 return NULL;
2882}
2883
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002884LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2885{
2886 return loader_GetInstanceProcAddr(instance, pName);
2887}
2888
2889static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn349508d2015-01-26 14:51:40 -07002890{
Jon Ashburn1245cec2015-05-18 13:20:15 -06002891 if (device == VK_NULL_HANDLE) {
2892 return NULL;
Ian Elliott81ac44c2015-01-13 17:52:38 -07002893 }
Jon Ashburne18431b2015-04-13 18:10:06 -06002894
Chia-I Wu38e5a2c2015-01-04 11:12:47 +08002895 void *addr;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002896
Jon Ashburne18431b2015-04-13 18:10:06 -06002897 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2898 make sure the loader entrypoint is returned */
2899 addr = loader_non_passthrough_gpa(pName);
Ian Elliottfdf00b62015-04-15 12:53:19 -06002900 if (addr) {
Jon Ashburne18431b2015-04-13 18:10:06 -06002901 return addr;
Ian Elliottfdf00b62015-04-15 12:53:19 -06002902 }
Jon Ashburne18431b2015-04-13 18:10:06 -06002903
Jon Ashburncedc15f2015-05-21 18:13:33 -06002904 /* return any extension device entrypoints the loader knows about */
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002905 /* TODO once WSI has no loader special code remove this */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002906 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
David Pinedo0fab78b2015-06-24 15:29:18 -06002907 if (addr) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002908 return addr;
David Pinedo0fab78b2015-06-24 15:29:18 -06002909 }
Jon Ashburncedc15f2015-05-21 18:13:33 -06002910
Jon Ashburne18431b2015-04-13 18:10:06 -06002911 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn1245cec2015-05-18 13:20:15 -06002912 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002913 if (disp_table == NULL)
2914 return NULL;
2915
Jon Ashburnfce93d92015-05-12 17:26:48 -06002916 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wu38e5a2c2015-01-04 11:12:47 +08002917 if (addr)
2918 return addr;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002919 else {
Jon Ashburn1245cec2015-05-18 13:20:15 -06002920 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002921 return NULL;
Jon Ashburn1245cec2015-05-18 13:20:15 -06002922 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002923 }
2924}
2925
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002926LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2927{
2928 return loader_GetDeviceProcAddr(device, pName);
2929}
2930
Tony Barbour426b9052015-06-24 16:06:58 -06002931LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002932 const char* pLayerName,
2933 uint32_t* pCount,
2934 VkExtensionProperties* pProperties)
2935{
2936 struct loader_extension_list *global_extension_list;
2937
2938 /* Scan/discover all ICD libraries in a single-threaded manner */
2939 loader_platform_thread_once(&once_icd, loader_icd_scan);
2940
2941 /* get layer libraries in a single-threaded manner */
2942 loader_platform_thread_once(&once_layer, loader_layer_scan);
2943
2944 /* merge any duplicate extensions */
2945 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2946
2947 uint32_t copy_size;
2948
2949 if (pCount == NULL) {
2950 return VK_ERROR_INVALID_POINTER;
2951 }
2952
2953 loader_platform_thread_lock_mutex(&loader_lock);
2954
2955 global_extension_list = loader_global_extensions(pLayerName);
2956 if (global_extension_list == NULL) {
2957 loader_platform_thread_unlock_mutex(&loader_lock);
2958 return VK_ERROR_INVALID_LAYER;
2959 }
2960
2961 if (pProperties == NULL) {
2962 *pCount = global_extension_list->count;
2963 loader_platform_thread_unlock_mutex(&loader_lock);
2964 return VK_SUCCESS;
2965 }
2966
2967 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2968 for (uint32_t i = 0; i < copy_size; i++) {
2969 memcpy(&pProperties[i],
2970 &global_extension_list->list[i].info,
2971 sizeof(VkExtensionProperties));
2972 }
2973 *pCount = copy_size;
2974
2975 loader_platform_thread_unlock_mutex(&loader_lock);
2976
2977 if (copy_size < global_extension_list->count) {
2978 return VK_INCOMPLETE;
2979 }
2980
2981 return VK_SUCCESS;
2982}
2983
2984LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2985 uint32_t* pCount,
2986 VkLayerProperties* pProperties)
Tony Barbour426b9052015-06-24 16:06:58 -06002987{
Jon Ashburnb40f2562015-05-29 13:15:39 -06002988
Jon Ashburneb2728b2015-04-10 14:33:07 -06002989 /* Scan/discover all ICD libraries in a single-threaded manner */
2990 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002991
Jon Ashburneb2728b2015-04-10 14:33:07 -06002992 /* get layer libraries in a single-threaded manner */
Jon Ashburn68a63922015-07-02 09:40:15 -06002993 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002994
Jon Ashburneb2728b2015-04-10 14:33:07 -06002995 /* merge any duplicate extensions */
2996 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2997
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002998 uint32_t copy_size;
Jon Ashburneb2728b2015-04-10 14:33:07 -06002999
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003000 if (pCount == NULL) {
3001 return VK_ERROR_INVALID_POINTER;
3002 }
3003
3004 /* TODO: do we still need to lock */
Jon Ashburnb40f2562015-05-29 13:15:39 -06003005 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003006
3007 struct loader_layer_list *layer_list;
Jon Ashburn1b111de2015-07-06 15:40:35 -06003008 layer_list = loader_scanned_layers();
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003009
3010 if (pProperties == NULL) {
3011 *pCount = layer_list->count;
3012 loader_platform_thread_unlock_mutex(&loader_lock);
3013 return VK_SUCCESS;
3014 }
3015
3016 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
3017 for (uint32_t i = 0; i < copy_size; i++) {
3018 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
3019 }
3020 *pCount = copy_size;
Tony Barbour426b9052015-06-24 16:06:58 -06003021
Jon Ashburnb40f2562015-05-29 13:15:39 -06003022 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06003023
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003024 if (copy_size < layer_list->count) {
3025 return VK_INCOMPLETE;
3026 }
Tony Barbour426b9052015-06-24 16:06:58 -06003027
3028 return VK_SUCCESS;
3029}
3030
3031VkResult loader_GetPhysicalDeviceExtensionProperties(
3032 VkPhysicalDevice gpu,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003033 const char* pLayerName,
3034 uint32_t* pCount,
Tony Barbour426b9052015-06-24 16:06:58 -06003035 VkExtensionProperties* pProperties)
3036{
3037 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06003038 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003039 uint32_t copy_size;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07003040
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003041 if (pCount == NULL) {
3042 return VK_ERROR_INVALID_POINTER;
3043 }
Jon Ashburn2666e2f2015-05-15 15:09:35 -06003044
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003045 uint32_t count;
3046 struct loader_extension_list *list;
3047 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
3048
3049 if (pProperties == NULL) {
3050 *pCount = count;
3051 return VK_SUCCESS;
3052 }
3053
3054 copy_size = *pCount < count ? *pCount : count;
3055 for (uint32_t i = 0; i < copy_size; i++) {
3056 memcpy(&pProperties[i],
3057 &list->list[i].info,
3058 sizeof(VkExtensionProperties));
3059 }
3060 *pCount = copy_size;
3061
3062 if (copy_size < count) {
3063 return VK_INCOMPLETE;
3064 }
3065
3066 return VK_SUCCESS;
3067}
3068
3069VkResult loader_GetPhysicalDeviceLayerProperties(
3070 VkPhysicalDevice gpu,
3071 uint32_t* pCount,
3072 VkLayerProperties* pProperties)
3073{
3074 uint32_t gpu_index;
3075 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
3076 uint32_t copy_size;
3077
3078 if (pCount == NULL) {
3079 return VK_ERROR_INVALID_POINTER;
3080 }
3081
3082 uint32_t count;
3083 struct loader_layer_list *layer_list;
3084 loader_physical_device_layers(icd, &count, &layer_list);
3085
3086 if (pProperties == NULL) {
3087 *pCount = count;
3088 return VK_SUCCESS;
3089 }
3090
3091 copy_size = *pCount < count ? *pCount : count;
3092 for (uint32_t i = 0; i < copy_size; i++) {
3093 memcpy(&pProperties[i],
3094 &layer_list->list[i].info,
3095 sizeof(VkLayerProperties));
3096 }
3097 *pCount = copy_size;
3098
3099 if (copy_size < count) {
3100 return VK_INCOMPLETE;
3101 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06003102
3103 return VK_SUCCESS;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06003104}