blob: 8fe2d3acf5cb135d8f13449db0abeb550f62568b [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
Jon Ashburnd9a9d1a2015-07-09 14:06:55 -06001374 char *def_path = loader_stack_alloc(strlen(DEFAULT_VK_LAYERS_PATH) + 1);
1375 strcpy(def_path, DEFAULT_VK_LAYERS_PATH);
1376 loader_get_fullpath(library_path, def_path, 2048, fullpath);
Jon Ashburn38144502015-07-07 15:06:25 -06001377 }
1378 else {
1379 // a relative or absolute path
1380 char *name_copy = loader_stack_alloc(strlen(filename) + 2);
1381 size_t len;
1382 strcpy(name_copy, filename);
1383 rel_base = loader_platform_dirname(name_copy);
1384 len = strlen(rel_base);
1385 rel_base[len] = DIRECTORY_SYMBOL;
1386 rel_base[len + 1] = '\0';
1387 loader_expand_path(library_path, rel_base, 2048, fullpath);
1388 }
1389 props->lib_info.lib_name = fullpath;
1390 free(library_path);
1391 //TODO merge the info with the versions and convert string to int
Jon Ashburn1b111de2015-07-06 15:40:35 -06001392 props->abi_version = abi_versions;
1393 props->impl_version = implementation_version;
Jon Ashburn38144502015-07-07 15:06:25 -06001394 strncpy(props->info.description, description, sizeof(props->info.description));
1395 props->info.description[sizeof(props->info.description) - 1] = '\0';
Jon Ashburn1b111de2015-07-06 15:40:35 -06001396 free(description);
1397 if (is_implicit) {
1398 props->disable_env_var.name = disable_environment->child->string;
1399 props->disable_env_var.value = disable_environment->child->valuestring;
1400 }
1401 layer_list->count++;
1402
1403 /**
1404 * Now get all optional items and objects and put in list:
1405 * functions
1406 * instance_extensions
1407 * device_extensions
1408 * enable_environment (implicit layers only)
1409 */
1410#define GET_JSON_OBJECT(node, var) { \
1411 var = cJSON_GetObjectItem(node, #var); \
1412 }
1413#define GET_JSON_ITEM(node, var) { \
1414 item = cJSON_GetObjectItem(node, #var); \
1415 if (item != NULL) \
1416 temp = cJSON_Print(item); \
1417 temp[strlen(temp) - 1] = '\0'; \
1418 var = malloc(strlen(temp) + 1); \
1419 strcpy(var, &temp[1]); \
1420 free(temp); \
1421 }
1422
1423 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
1424 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *version;
1425 GET_JSON_OBJECT(layer_node, functions)
1426 if (functions != NULL) {
1427 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
1428 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
1429 props->functions.str_gipa = vkGetInstanceProcAddr;
1430 props->functions.str_gdpa = vkGetDeviceProcAddr;
1431 }
1432 GET_JSON_OBJECT(layer_node, instance_extensions)
1433 if (instance_extensions != NULL) {
1434 int count = cJSON_GetArraySize(instance_extensions);
1435 for (i = 0; i < count; i++) {
1436 ext_item = cJSON_GetArrayItem(instance_extensions, i);
1437 GET_JSON_ITEM(ext_item, name)
1438 GET_JSON_ITEM(ext_item, version)
1439 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1440 ext_prop.lib_name = library_path;
1441 strcpy(ext_prop.info.extName, name);
1442 //TODO convert from string to int ext_prop.info.version = version;
1443 loader_add_to_ext_list(&props->instance_extension_list, 1, &ext_prop);
1444 }
1445 }
1446 GET_JSON_OBJECT(layer_node, device_extensions)
1447 if (device_extensions != NULL) {
1448 int count = cJSON_GetArraySize(device_extensions);
1449 for (i = 0; i < count; i++) {
1450 ext_item = cJSON_GetArrayItem(device_extensions, i);
1451 GET_JSON_ITEM(ext_item, name);
1452 GET_JSON_ITEM(ext_item, version);
1453 ext_prop.origin = VK_EXTENSION_ORIGIN_LAYER;
1454 ext_prop.lib_name = library_path;
1455 strcpy(ext_prop.info.extName, name);
1456 //TODO convert from string to int ext_prop.info.version = version;
1457 loader_add_to_ext_list(&props->device_extension_list, 1, &ext_prop);
1458 }
1459 }
1460 if (is_implicit) {
1461 GET_JSON_OBJECT(layer_node, enable_environment)
1462 props->enable_env_var.name = enable_environment->child->string;
1463 props->enable_env_var.value = enable_environment->child->valuestring;
1464 }
1465#undef GET_JSON_ITEM
1466#undef GET_JSON_OBJECT
1467
1468}
1469
1470/**
Jon Ashburnffd5d672015-06-29 11:25:34 -06001471 * Find the Vulkan library manifest files.
1472 *
1473 * This function scans the location or env_override directories/files
1474 * for a list of JSON manifest files. If env_override is non-NULL
1475 * and has a valid value. Then the location is ignored. Otherwise
1476 * location is used to look for manifest files. The location
1477 * is interpreted as Registry path on Windows and a directory path(s)
1478 * on Linux.
1479 *
1480 * \returns
1481 * A string list of manifest files to be opened in out_files param.
1482 * List has a pointer to string for each manifest filename.
1483 * When done using the list in out_files, pointers should be freed.
Jon Ashburnee33ae72015-06-30 14:46:22 -07001484 * Location or override string lists can be either files or directories as follows:
1485 * | location | override
1486 * --------------------------------
1487 * Win ICD | files | files
1488 * Win Layer | files | dirs
1489 * Linux ICD | dirs | files
1490 * Linux Layer| dirs | dirs
Jon Ashburnffd5d672015-06-29 11:25:34 -06001491 */
1492static void loader_get_manifest_files(const char *env_override,
Jon Ashburnee33ae72015-06-30 14:46:22 -07001493 bool is_layer,
1494 const char *location,
1495 struct loader_manifest_files *out_files)
Jon Ashburnffd5d672015-06-29 11:25:34 -06001496{
1497 char *override = NULL;
1498 char *loc;
1499 char *file, *next_file, *name;
1500 size_t alloced_count = 64;
1501 char full_path[2048];
1502 DIR *sysdir = NULL;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001503 bool list_is_dirs = false;
Jon Ashburnffd5d672015-06-29 11:25:34 -06001504 struct dirent *dent;
1505
1506 out_files->count = 0;
1507 out_files->filename_list = NULL;
1508
Jon Ashburnffd5d672015-06-29 11:25:34 -06001509 if (env_override != NULL && (override = getenv(env_override))) {
1510#if defined(__linux__)
1511 if (geteuid() != getuid()) {
Jon Ashburnee33ae72015-06-30 14:46:22 -07001512 /* Don't allow setuid apps to use the env var: */
Jon Ashburnffd5d672015-06-29 11:25:34 -06001513 override = NULL;
1514 }
1515#endif
1516 }
1517
1518 if (location == NULL) {
1519 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
Jon Ashburnee33ae72015-06-30 14:46:22 -07001520 "Can't get manifest files with NULL location, env_override=%s",
1521 env_override);
Jon Ashburnffd5d672015-06-29 11:25:34 -06001522 return;
1523 }
1524
Jon Ashburnee33ae72015-06-30 14:46:22 -07001525#if defined(__linux__)
1526 list_is_dirs = (override == NULL || is_layer) ? true : false;
1527#else //WIN32
1528 list_is_dirs = (is_layer && override != NULL) ? true : false;
1529#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001530 // Make a copy of the input we are using so it is not modified
Jon Ashburnee33ae72015-06-30 14:46:22 -07001531 // Also handle getting the location(s) from registry on Windows
1532 if (override == NULL) {
1533#if defined (_WIN32)
1534 loc = loader_get_registry_files(location);
1535 if (loc == NULL) {
1536 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Registry lookup failed can't get manifest files");
1537 return;
1538 }
1539#else
Jon Ashburnffd5d672015-06-29 11:25:34 -06001540 loc = alloca(strlen(location) + 1);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001541 if (loc == NULL) {
1542 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1543 return;
1544 }
1545 strcpy(loc, location);
1546#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001547 }
Jon Ashburnee33ae72015-06-30 14:46:22 -07001548 else {
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -06001549 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001550 if (loc == NULL) {
1551 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1552 return;
1553 }
1554 strcpy(loc, override);
1555 }
Jon Ashburnffd5d672015-06-29 11:25:34 -06001556
1557 file = loc;
1558 while (*file) {
1559 next_file = loader_get_next_path(file);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001560 if (list_is_dirs) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001561 sysdir = opendir(file);
1562 name = NULL;
1563 if (sysdir) {
1564 dent = readdir(sysdir);
1565 if (dent == NULL)
1566 break;
1567 name = &(dent->d_name[0]);
1568 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1569 name = full_path;
1570 }
1571 }
1572 else {
Jon Ashburnee33ae72015-06-30 14:46:22 -07001573#if defined(__linux__)
1574 // only Linux has relative paths
Jon Ashburnffd5d672015-06-29 11:25:34 -06001575 char *dir;
1576 // make a copy of location so it isn't modified
1577 dir = alloca(strlen(location) + 1);
1578 if (dir == NULL) {
1579 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1580 return;
1581 }
1582 strcpy(dir, location);
1583
1584 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
1585
1586 name = full_path;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001587#else // WIN32
1588 name = file;
1589#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001590 }
1591 while (name) {
1592 /* Look for files ending with ".json" suffix */
1593 uint32_t nlen = (uint32_t) strlen(name);
1594 const char *suf = name + nlen - 5;
1595 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
1596 if (out_files->count == 0) {
1597 out_files->filename_list = malloc(alloced_count * sizeof(char *));
1598 }
1599 else if (out_files->count == alloced_count) {
1600 out_files->filename_list = realloc(out_files->filename_list,
1601 alloced_count * sizeof(char *) * 2);
1602 alloced_count *= 2;
1603 }
1604 if (out_files->filename_list == NULL) {
1605 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't alloc manifest file list");
1606 return;
1607 }
1608 out_files->filename_list[out_files->count] = malloc(strlen(name) + 1);
1609 if (out_files->filename_list[out_files->count] == NULL) {
1610 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can't get manifest files");
1611 return;
1612 }
1613 strcpy(out_files->filename_list[out_files->count], name);
1614 out_files->count++;
Jon Ashburnc5662f62015-07-02 10:08:47 -06001615 } else if (!list_is_dirs) {
1616 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 -06001617 }
Jon Ashburnee33ae72015-06-30 14:46:22 -07001618 if (list_is_dirs) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001619 dent = readdir(sysdir);
1620 if (dent == NULL)
1621 break;
1622 name = &(dent->d_name[0]);
1623 loader_get_fullpath(name, file, sizeof(full_path), full_path);
1624 name = full_path;
1625 }
1626 else {
1627 break;
1628 }
1629 }
1630 if (sysdir)
1631 closedir(sysdir);
1632 file = next_file;
1633 }
1634 return;
1635}
1636
1637/**
1638 * Try to find the Vulkan ICD driver(s).
1639 *
1640 * This function scans the default system loader path(s) or path
1641 * specified by the \c VK_ICD_FILENAMES environment variable in
1642 * order to find loadable VK ICDs manifest files. From these
1643 * manifest files it finds the ICD libraries.
1644 *
1645 * \returns
Jon Ashburn622ca2f2015-06-30 16:44:28 -06001646 * void
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001647 */
Jon Ashburnfce93d92015-05-12 17:26:48 -06001648void loader_icd_scan(void)
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001649{
Jon Ashburnffd5d672015-06-29 11:25:34 -06001650 char *file_str;
1651 struct loader_manifest_files manifest_files;
1652
Jon Ashburnb40f2562015-05-29 13:15:39 -06001653
1654 // convenient place to initialize a mutex
1655 loader_platform_thread_create_mutex(&loader_lock);
1656
Jon Ashburnffd5d672015-06-29 11:25:34 -06001657 // convenient place to initialize logging
Courtney Goeltzenleuchter8b253f92015-06-08 15:11:18 -06001658 loader_debug_init();
1659
Jon Ashburnffd5d672015-06-29 11:25:34 -06001660 // Get a list of manifest files for ICDs
1661 loader_get_manifest_files("VK_ICD_FILENAMES", false, DEFAULT_VK_DRIVERS_INFO,
1662 &manifest_files);
Jon Ashburn1b111de2015-07-06 15:40:35 -06001663 if (manifest_files.count == 0)
1664 return;
Jon Ashburnffd5d672015-06-29 11:25:34 -06001665 for (uint32_t i = 0; i < manifest_files.count; i++) {
1666 file_str = manifest_files.filename_list[i];
1667 if (file_str == NULL)
1668 continue;
1669
Jon Ashburn1b111de2015-07-06 15:40:35 -06001670 cJSON *json;
Jon Ashburnffd5d672015-06-29 11:25:34 -06001671 json = loader_get_json(file_str);
Jon Ashburn1b111de2015-07-06 15:40:35 -06001672 cJSON *item;
1673 item = cJSON_GetObjectItem(json, "file_format_version");
1674 if (item == NULL)
1675 return;
1676 char *file_vers = cJSON_Print(item);
1677 loader_log(VK_DBG_REPORT_INFO_BIT, 0, "Found manifest file %s, version %s",
1678 file_str, file_vers);
1679 if (strcmp(file_vers, "\"1.0.0\"") != 0)
1680 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Unexpected manifest file version (expected 1.0.0), may cause errors");
1681 free(file_vers);
1682 item = cJSON_GetObjectItem(json, "ICD");
1683 if (item != NULL) {
1684 item = cJSON_GetObjectItem(item, "library_path");
1685 if (item != NULL) {
1686 char *icd_filename = cJSON_PrintUnformatted(item);
Jon Ashburnffd5d672015-06-29 11:25:34 -06001687 char *icd_file = icd_filename;
1688 if (icd_filename != NULL) {
Jon Ashburnffd5d672015-06-29 11:25:34 -06001689 char def_dir[] = DEFAULT_VK_DRIVERS_PATH;
1690 char *dir = def_dir;
1691 // strip off extra quotes
1692 if (icd_filename[strlen(icd_filename) - 1] == '"')
1693 icd_filename[strlen(icd_filename) - 1] = '\0';
1694 if (icd_filename[0] == '"')
1695 icd_filename++;
Jon Ashburnee33ae72015-06-30 14:46:22 -07001696#if defined(__linux__)
1697 char full_path[2048];
Jon Ashburnffd5d672015-06-29 11:25:34 -06001698 loader_get_fullpath(icd_filename, dir, sizeof(full_path), full_path);
1699 loader_scanned_icd_add(full_path);
Jon Ashburnee33ae72015-06-30 14:46:22 -07001700#else // WIN32
1701 loader_scanned_icd_add(icd_filename);
1702#endif
Jon Ashburnffd5d672015-06-29 11:25:34 -06001703 free(icd_file);
1704 }
1705 }
1706 else
1707 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"library_path\" in ICD JSON file %s, skipping", file_str);
1708 }
1709 else
1710 loader_log(VK_DBG_REPORT_WARN_BIT, 0, "Can't find \"ICD\" object in ICD JSON file %s, skipping", file_str);
1711
1712 free(file_str);
1713 cJSON_Delete(json);
1714 }
1715 free(manifest_files.filename_list);
1716
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001717}
1718
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001719
Jon Ashburn68a63922015-07-02 09:40:15 -06001720void loader_layer_scan(void)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001721{
Jon Ashburn1b111de2015-07-06 15:40:35 -06001722 char *file_str;
1723 struct loader_manifest_files manifest_files;
1724 cJSON *json;
1725 uint32_t i;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001726
Jon Ashburn1b111de2015-07-06 15:40:35 -06001727 // Get a list of manifest files for layers
1728 loader_get_manifest_files(LAYERS_PATH_ENV, true, DEFAULT_VK_LAYERS_INFO,
1729 &manifest_files);
1730 if (manifest_files.count == 0)
Courtney Goeltzenleuchterbce445a2014-12-01 09:29:42 -07001731 return;
Jon Ashburn0dcd6192015-06-04 15:30:58 -06001732
Jon Ashburn1b111de2015-07-06 15:40:35 -06001733#if 0
1734 /**
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06001735 * We need a list of the layer libraries, not just a list of
1736 * the layer properties (a layer library could expose more than
1737 * one layer property). This list of scanned layers would be
1738 * used to check for global and physicaldevice layer properties.
1739 */
1740 if (!loader_init_layer_library_list(&loader.scanned_layer_libraries)) {
1741 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1742 "Malloc for layer list failed: %s line: %d", __FILE__, __LINE__);
1743 return;
Jon Ashburn68a63922015-07-02 09:40:15 -06001744 }
Jon Ashburn1b111de2015-07-06 15:40:35 -06001745#endif
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001746
Jon Ashburn1b111de2015-07-06 15:40:35 -06001747 // TODO use global_layer add and delete functions instead
1748 if (loader.scanned_layers.capacity == 0) {
1749 loader.scanned_layers.list = malloc(sizeof(struct loader_layer_properties) * 64);
1750 if (loader.scanned_layers.list == NULL) {
1751 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Out of memory can'add any layer properties to list");
1752 return;
Jon Ashburneb2728b2015-04-10 14:33:07 -06001753 }
Jon Ashburn1b111de2015-07-06 15:40:35 -06001754 memset(loader.scanned_layers.list, 0, sizeof(struct loader_layer_properties) * 64);
1755 loader.scanned_layers.capacity = sizeof(struct loader_layer_properties) * 64;
1756 }
1757 else {
1758 /* cleanup any previously scanned libraries */
1759 //TODO make sure everything is cleaned up properly
1760 for (i = 0; i < loader.scanned_layers.count; i++) {
1761 if (loader.scanned_layers.list[i].lib_info.lib_name != NULL)
1762 free(loader.scanned_layers.list[i].lib_info.lib_name);
1763 loader_destroy_ext_list(&loader.scanned_layers.list[i].instance_extension_list);
1764 loader_destroy_ext_list(&loader.scanned_layers.list[i].device_extension_list);
1765 loader.scanned_layers.list[i].lib_info.lib_name = NULL;
Jon Ashburneb2728b2015-04-10 14:33:07 -06001766 }
Jon Ashburn1b111de2015-07-06 15:40:35 -06001767 loader.scanned_layers.count = 0;
1768 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001769
Jon Ashburn1b111de2015-07-06 15:40:35 -06001770 for (i = 0; i < manifest_files.count; i++) {
1771 file_str = manifest_files.filename_list[i];
1772 if (file_str == NULL)
1773 continue;
Courtney Goeltzenleuchteraa685052015-06-01 14:49:17 -06001774
Jon Ashburn1b111de2015-07-06 15:40:35 -06001775 // parse file into JSON struct
1776 json = loader_get_json(file_str);
1777 if (!json) {
1778 continue;
1779 }
1780 // ensure enough room to add an entry
1781 if ((loader.scanned_layers.count + 1) * sizeof (struct loader_layer_properties)
1782 > loader.scanned_layers.capacity) {
1783 loader.scanned_layers.list = realloc(loader.scanned_layers.list,
1784 loader.scanned_layers.capacity * 2);
1785 if (loader.scanned_layers.list == NULL) {
1786 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1787 "realloc failed for scanned layers");
1788 break;
1789 }
1790 loader.scanned_layers.capacity *= 2;
1791 }
1792 //TODO pass in implicit versus explicit bool
1793 loader_add_layer_properties(&loader.scanned_layers, json, false, file_str);
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06001794
Jon Ashburn1b111de2015-07-06 15:40:35 -06001795 free(file_str);
1796 cJSON_Delete(json);
1797 }
1798 free(manifest_files.filename_list);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001799
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001800}
1801
Jon Ashburnfce93d92015-05-12 17:26:48 -06001802static void* VKAPI loader_gpa_instance_internal(VkInstance inst, const char * pName)
1803{
1804 // inst is not wrapped
1805 if (inst == VK_NULL_HANDLE) {
1806 return NULL;
1807 }
1808 VkLayerInstanceDispatchTable* disp_table = * (VkLayerInstanceDispatchTable **) inst;
1809 void *addr;
1810
Jon Ashburn4f2575f2015-05-28 16:25:02 -06001811 if (!strcmp(pName, "vkGetInstanceProcAddr"))
1812 return (void *) loader_gpa_instance_internal;
1813
Jon Ashburnfce93d92015-05-12 17:26:48 -06001814 if (disp_table == NULL)
1815 return NULL;
1816
1817 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001818 if (addr) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06001819 return addr;
Jon Ashburne18431b2015-04-13 18:10:06 -06001820 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001821
1822 if (disp_table->GetInstanceProcAddr == NULL) {
1823 return NULL;
1824 }
1825 return disp_table->GetInstanceProcAddr(inst, pName);
Jon Ashburne18431b2015-04-13 18:10:06 -06001826}
1827
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001828struct loader_icd * loader_get_icd(const VkPhysicalDevice gpu, uint32_t *gpu_index)
Jon Ashburnb55278a2014-10-17 15:09:07 -06001829{
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001830
Jon Ashburndc67ef52015-01-29 16:44:24 -07001831 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
1832 for (struct loader_icd *icd = inst->icds; icd; icd = icd->next) {
1833 for (uint32_t i = 0; i < icd->gpu_count; i++)
Jon Ashburnd5df54d2015-05-28 19:16:58 -06001834 if (icd->gpus[i] == gpu) {
Jon Ashburndc67ef52015-01-29 16:44:24 -07001835 *gpu_index = i;
1836 return icd;
1837 }
1838 }
Jon Ashburnb55278a2014-10-17 15:09:07 -06001839 }
1840 return NULL;
1841}
1842
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001843static loader_platform_dl_handle loader_add_layer_lib(
Jon Ashburn9a9de1f2015-05-27 13:19:22 -06001844 const char *chain_type,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001845 struct loader_layer_properties *layer_prop)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001846{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001847 struct loader_lib_info *new_layer_lib_list, *my_lib;
1848
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06001849 /*
1850 * TODO: We can now track this information in the
1851 * scanned_layer_libraries list.
1852 */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001853 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001854 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001855 /* Have already loaded this library, just increment ref count */
1856 loader.loaded_layer_lib_list[i].ref_count++;
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001857 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001858 "%s Chain: Increment layer reference count for layer library %s",
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001859 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001860 return loader.loaded_layer_lib_list[i].lib_handle;
1861 }
1862 }
1863
1864 /* Haven't seen this library so load it */
1865 new_layer_lib_list = realloc(loader.loaded_layer_lib_list,
1866 (loader.loaded_layer_lib_count + 1) * sizeof(struct loader_lib_info));
1867 if (!new_layer_lib_list) {
1868 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1869 return NULL;
1870 }
1871
1872 my_lib = &new_layer_lib_list[loader.loaded_layer_lib_count];
1873
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001874 /* NOTE: We require that the layer property be immutable */
1875 my_lib->lib_name = (char *) layer_prop->lib_info.lib_name;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001876 my_lib->ref_count = 0;
1877 my_lib->lib_handle = NULL;
1878
1879 if ((my_lib->lib_handle = loader_platform_open_library(my_lib->lib_name)) == NULL) {
1880 loader_log(VK_DBG_REPORT_ERROR_BIT, 0,
1881 loader_platform_open_library_error(my_lib->lib_name));
1882 return NULL;
1883 } else {
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001884 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001885 "Chain: %s: Loading layer library %s",
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001886 chain_type, layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001887 }
1888 loader.loaded_layer_lib_count++;
1889 loader.loaded_layer_lib_list = new_layer_lib_list;
1890 my_lib->ref_count++;
1891
1892 return my_lib->lib_handle;
1893}
1894
1895static void loader_remove_layer_lib(
1896 struct loader_instance *inst,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001897 struct loader_layer_properties *layer_prop)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001898{
1899 uint32_t idx;
1900 struct loader_lib_info *new_layer_lib_list, *my_lib;
1901
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001902 for (uint32_t i = 0; i < loader.loaded_layer_lib_count; i++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001903 if (strcmp(loader.loaded_layer_lib_list[i].lib_name, layer_prop->lib_info.lib_name) == 0) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001904 /* found matching library */
1905 idx = i;
1906 my_lib = &loader.loaded_layer_lib_list[i];
1907 break;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001908 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001909 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001910
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001911 my_lib->ref_count--;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001912 if (my_lib->ref_count > 0) {
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001913 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001914 "Decrement reference count for layer library %s", layer_prop->lib_info.lib_name);
Jon Ashburnfce93d92015-05-12 17:26:48 -06001915 return;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07001916 }
Jon Ashburn4d3b7522015-04-14 14:14:48 -06001917
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001918 loader_platform_close_library(my_lib->lib_handle);
Courtney Goeltzenleuchter926f39e2015-06-14 11:59:07 -06001919 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001920 "Unloading layer library %s", layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001921
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001922 /* Need to remove unused library from list */
1923 new_layer_lib_list = malloc((loader.loaded_layer_lib_count - 1) * sizeof(struct loader_lib_info));
1924 if (!new_layer_lib_list) {
1925 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "loader: malloc failed");
1926 return;
1927 }
1928
1929 if (idx > 0) {
1930 /* Copy records before idx */
1931 memcpy(new_layer_lib_list, &loader.loaded_layer_lib_list[0],
1932 sizeof(struct loader_lib_info) * idx);
1933 }
1934 if (idx < (loader.loaded_layer_lib_count - 1)) {
1935 /* Copy records after idx */
1936 memcpy(&new_layer_lib_list[idx], &loader.loaded_layer_lib_list[idx+1],
1937 sizeof(struct loader_lib_info) * (loader.loaded_layer_lib_count - idx - 1));
1938 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06001939
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001940 free(loader.loaded_layer_lib_list);
1941 loader.loaded_layer_lib_count--;
1942 loader.loaded_layer_lib_list = new_layer_lib_list;
Jon Ashburnead95c52014-11-18 09:06:04 -07001943}
1944
Jon Ashburn1b111de2015-07-06 15:40:35 -06001945
1946/**
1947 * Go through the search_list and find any layers which match type. If layer
1948 * type match is found in then add it to ext_list.
1949 */
1950//TODO need to handle implict layer enable env var and disable env var
Jon Ashburn535bd002015-07-02 16:10:32 -06001951static void loader_add_layer_implicit(
1952 const enum layer_type type,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001953 struct loader_layer_list *list,
1954 struct loader_layer_list *search_list)
Jon Ashburn535bd002015-07-02 16:10:32 -06001955{
1956 uint32_t i;
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001957 for (i = 0; i < search_list->count; i++) {
1958 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn535bd002015-07-02 16:10:32 -06001959 if (prop->type & type) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001960 /* Found an layer with the same type, add to layer_list */
1961 loader_add_to_layer_list(list, 1, prop);
Jon Ashburn535bd002015-07-02 16:10:32 -06001962 }
1963 }
1964
1965}
1966
1967/**
1968 * Get the layer name(s) from the env_name environment variable. If layer
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001969 * is found in search_list then add it to layer_list. But only add it to
1970 * layer_list if type matches.
Jon Ashburn535bd002015-07-02 16:10:32 -06001971 */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001972static void loader_add_layer_env(
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001973 const enum layer_type type,
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001974 const char *env_name,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06001975 struct loader_layer_list *layer_list,
1976 const struct loader_layer_list *search_list)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001977{
Ian Elliott225188f2015-02-17 10:33:47 -07001978 char *layerEnv;
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001979 char *next, *name;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001980
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001981 layerEnv = getenv(env_name);
Ian Elliott225188f2015-02-17 10:33:47 -07001982 if (layerEnv == NULL) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001983 return;
Ian Elliott225188f2015-02-17 10:33:47 -07001984 }
Courtney Goeltzenleuchterb620ace2015-07-05 11:28:29 -06001985 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001986 if (name == NULL) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001987 return;
Ian Elliott225188f2015-02-17 10:33:47 -07001988 }
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001989 strcpy(name, layerEnv);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001990
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001991 while (name && *name ) {
1992 next = loader_get_next_path(name);
Jon Ashburnf2ddb732015-07-07 10:27:45 -06001993 loader_find_layer_name_add_list(name, type, search_list, layer_list);
Jon Ashburna2e6efe2015-07-02 14:10:53 -06001994 name = next;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07001995 }
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001996
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06001997 return;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06001998}
1999
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -06002000void loader_deactivate_instance_layers(struct loader_instance *instance)
Jon Ashburn183dfd02014-10-22 18:13:16 -06002001{
Jon Ashburn60378412015-07-02 12:59:25 -06002002 if (!instance->activated_layer_list.count) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002003 return;
2004 }
Jon Ashburn183dfd02014-10-22 18:13:16 -06002005
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002006 /* Create instance chain of enabled layers */
Courtney Goeltzenleuchter3d8dc1f2015-06-08 15:09:22 -06002007 for (uint32_t i = 0; i < instance->activated_layer_list.count; i++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002008 struct loader_layer_properties *layer_prop = &instance->activated_layer_list.list[i];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002009
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002010 loader_remove_layer_lib(instance, layer_prop);
Jon Ashburn183dfd02014-10-22 18:13:16 -06002011 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002012 loader_destroy_layer_list(&instance->activated_layer_list);
Jon Ashburn183dfd02014-10-22 18:13:16 -06002013}
2014
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002015VkResult loader_enable_instance_layers(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002016 struct loader_instance *inst,
2017 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002018{
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002019 VkResult err;
2020
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002021 if (inst == NULL)
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002022 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002023
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002024 if (!loader_init_layer_list(&inst->activated_layer_list)) {
Jon Ashburn60378412015-07-02 12:59:25 -06002025 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance activated layer list");
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002026 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn60378412015-07-02 12:59:25 -06002027 }
2028
Jon Ashburn535bd002015-07-02 16:10:32 -06002029 /* Add any implicit layers first */
2030 loader_add_layer_implicit(
2031 VK_LAYER_TYPE_INSTANCE_IMPLICIT,
2032 &inst->activated_layer_list,
Jon Ashburn1b111de2015-07-06 15:40:35 -06002033 &loader.scanned_layers);
Jon Ashburn535bd002015-07-02 16:10:32 -06002034
Jon Ashburn1b111de2015-07-06 15:40:35 -06002035 /* Add any layers specified via environment variable next */
Jon Ashburna2e6efe2015-07-02 14:10:53 -06002036 loader_add_layer_env(
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002037 VK_LAYER_TYPE_INSTANCE_EXPLICIT,
Jon Ashburna2e6efe2015-07-02 14:10:53 -06002038 "VK_INSTANCE_LAYERS",
2039 &inst->activated_layer_list,
Jon Ashburn1b111de2015-07-06 15:40:35 -06002040 &loader.scanned_layers);
Jon Ashburn60378412015-07-02 12:59:25 -06002041
2042 /* Add layers specified by the application */
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002043 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002044 &inst->activated_layer_list,
2045 pCreateInfo->layerCount,
2046 pCreateInfo->ppEnabledLayerNames,
Jon Ashburn1b111de2015-07-06 15:40:35 -06002047 &loader.scanned_layers);
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002048
2049 return err;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002050}
2051
Jon Ashburnfce93d92015-05-12 17:26:48 -06002052uint32_t loader_activate_instance_layers(struct loader_instance *inst)
2053{
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002054 uint32_t layer_idx;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002055 VkBaseLayerObject *wrappedInstance;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002056
David Pinedo0fab78b2015-06-24 15:29:18 -06002057 if (inst == NULL) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06002058 return 0;
David Pinedo0fab78b2015-06-24 15:29:18 -06002059 }
Jon Ashburnfce93d92015-05-12 17:26:48 -06002060
2061 // NOTE inst is unwrapped at this point in time
2062 VkObject baseObj = (VkObject) inst;
2063 VkObject nextObj = (VkObject) inst;
2064 VkBaseLayerObject *nextInstObj;
2065 PFN_vkGetInstanceProcAddr nextGPA = loader_gpa_instance_internal;
2066
Jon Ashburn60378412015-07-02 12:59:25 -06002067 if (!inst->activated_layer_list.count) {
Jon Ashburnfce93d92015-05-12 17:26:48 -06002068 return 0;
2069 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002070
Courtney Goeltzenleuchter0248b992015-07-06 09:04:55 -06002071 wrappedInstance = loader_stack_alloc(sizeof(VkBaseLayerObject)
Jon Ashburn60378412015-07-02 12:59:25 -06002072 * inst->activated_layer_list.count);
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002073 if (!wrappedInstance) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002074 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Instance objects for layer");
2075 return 0;
2076 }
2077
2078 /* Create instance chain of enabled layers */
Jon Ashburn60378412015-07-02 12:59:25 -06002079 layer_idx = inst->activated_layer_list.count - 1;
Courtney Goeltzenleuchterf4b430e2015-06-07 17:28:17 -06002080 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002081 struct loader_layer_properties *layer_prop = &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002082 loader_platform_dl_handle lib_handle;
2083
Jon Ashburn60378412015-07-02 12:59:25 -06002084 /*
Courtney Goeltzenleuchterc27292a2015-06-01 14:12:42 -06002085 * Note: An extension's Get*ProcAddr should not return a function pointer for
2086 * any extension entry points until the extension has been enabled.
2087 * To do this requires a different behavior from Get*ProcAddr functions implemented
2088 * in layers.
2089 * The very first call to a layer will be it's Get*ProcAddr function requesting
2090 * the layer's vkGet*ProcAddr. The layer should intialize it's internal dispatch table
2091 * with the wrapped object given (either Instance or Device) and return the layer's
2092 * Get*ProcAddr function. The layer should also use this opportunity to record the
2093 * baseObject so that it can find the correct local dispatch table on future calls.
2094 * Subsequent calls to Get*ProcAddr, CreateInstance, CreateDevice
2095 * will not use a wrapped object and must look up their local dispatch table from
2096 * the given baseObject.
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002097 */
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002098 nextInstObj = (wrappedInstance + layer_idx);
Jon Ashburnfce93d92015-05-12 17:26:48 -06002099 nextInstObj->pGPA = nextGPA;
2100 nextInstObj->baseObject = baseObj;
2101 nextInstObj->nextObject = nextObj;
2102 nextObj = (VkObject) nextInstObj;
2103
2104 char funcStr[256];
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002105 snprintf(funcStr, 256, "%sGetInstanceProcAddr", layer_prop->info.layerName);
2106 lib_handle = loader_add_layer_lib("instance", layer_prop);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002107 if ((nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2108 nextGPA = (PFN_vkGetInstanceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Jon Ashburnfce93d92015-05-12 17:26:48 -06002109 if (!nextGPA) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002110 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 -06002111
2112 /* TODO: Should we return nextObj, nextGPA to previous? */
Jon Ashburnfce93d92015-05-12 17:26:48 -06002113 continue;
2114 }
2115
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002116 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002117 "Insert instance layer %s (%s)",
2118 layer_prop->info.layerName,
2119 layer_prop->lib_info.lib_name);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002120
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002121 layer_idx--;
Jon Ashburnfce93d92015-05-12 17:26:48 -06002122 }
2123
Jon Ashburn4f2575f2015-05-28 16:25:02 -06002124 loader_init_instance_core_dispatch_table(inst->disp, nextGPA, (VkInstance) nextObj, (VkInstance) baseObj);
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002125
Jon Ashburn60378412015-07-02 12:59:25 -06002126 return inst->activated_layer_list.count;
Jon Ashburnfce93d92015-05-12 17:26:48 -06002127}
2128
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002129void loader_activate_instance_layer_extensions(struct loader_instance *inst)
2130{
2131
2132 loader_init_instance_extension_dispatch_table(inst->disp,
2133 inst->disp->GetInstanceProcAddr,
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002134 (VkInstance) inst);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002135}
2136
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002137static VkResult loader_enable_device_layers(
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002138 struct loader_icd *icd,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002139 struct loader_device *dev,
2140 const VkDeviceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002141{
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002142 VkResult err;
2143
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002144 if (dev == NULL)
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002145 return VK_ERROR_UNKNOWN;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002146
Jon Ashburn60378412015-07-02 12:59:25 -06002147 if (dev->activated_layer_list.list == NULL || dev->activated_layer_list.capacity == 0) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002148 loader_init_layer_list(&dev->activated_layer_list);
Jon Ashburn60378412015-07-02 12:59:25 -06002149 }
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002150
Jon Ashburn60378412015-07-02 12:59:25 -06002151 if (dev->activated_layer_list.list == NULL) {
2152 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc device activated layer list");
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002153 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn60378412015-07-02 12:59:25 -06002154 }
2155
Jon Ashburn535bd002015-07-02 16:10:32 -06002156 /* Add any implicit layers first */
2157 loader_add_layer_implicit(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002158 VK_LAYER_TYPE_DEVICE_IMPLICIT,
2159 &dev->activated_layer_list,
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002160 &loader.scanned_layers);
Jon Ashburn535bd002015-07-02 16:10:32 -06002161
2162 /* Add any layers specified via environment variable next */
Jon Ashburna2e6efe2015-07-02 14:10:53 -06002163 loader_add_layer_env(
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002164 VK_LAYER_TYPE_DEVICE_EXPLICIT,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002165 "VK_DEVICE_LAYERS",
2166 &dev->activated_layer_list,
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002167 &loader.scanned_layers);
Jon Ashburn60378412015-07-02 12:59:25 -06002168
2169 /* Add layers specified by the application */
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002170 err = loader_add_layer_names_to_list(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002171 &dev->activated_layer_list,
2172 pCreateInfo->layerCount,
2173 pCreateInfo->ppEnabledLayerNames,
Jon Ashburnf2ddb732015-07-07 10:27:45 -06002174 &loader.scanned_layers);
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002175
2176 return err;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002177}
2178
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002179/*
2180 * This function terminates the device chain fro CreateDevice.
2181 * CreateDevice is a special case and so the loader call's
2182 * the ICD's CreateDevice before creating the chain. Since
2183 * we can't call CreateDevice twice we must terminate the
2184 * device chain with something else.
2185 */
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002186static VkResult scratch_vkCreateDevice(
2187 VkPhysicalDevice gpu,
2188 const VkDeviceCreateInfo *pCreateInfo,
2189 VkDevice *pDevice)
2190{
2191 return VK_SUCCESS;
2192}
2193
2194static void * VKAPI loader_GetDeviceChainProcAddr(VkDevice device, const char * name)
2195{
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002196 if (!strcmp(name, "vkGetDeviceProcAddr"))
2197 return (void *) loader_GetDeviceChainProcAddr;
2198 if (!strcmp(name, "vkCreateDevice"))
2199 return (void *) scratch_vkCreateDevice;
2200
Courtney Goeltzenleuchtere76db422015-06-29 16:09:23 -06002201 struct loader_device *found_dev;
2202 struct loader_icd *icd = loader_get_icd_and_device(device, &found_dev);
2203 return icd->GetDeviceProcAddr(device, name);
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002204}
2205
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002206static uint32_t loader_activate_device_layers(
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002207 struct loader_icd *icd,
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002208 struct loader_device *dev,
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002209 VkDevice device)
Jon Ashburn183dfd02014-10-22 18:13:16 -06002210{
Jon Ashburn183dfd02014-10-22 18:13:16 -06002211 if (!icd)
2212 return 0;
Jon Ashburn183dfd02014-10-22 18:13:16 -06002213
David Pinedo0fab78b2015-06-24 15:29:18 -06002214 if (!dev) {
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002215 return 0;
David Pinedo0fab78b2015-06-24 15:29:18 -06002216 }
Jon Ashburn612539f2015-06-10 10:13:10 -06002217
Jon Ashburn183dfd02014-10-22 18:13:16 -06002218 /* activate any layer libraries */
Jon Ashburn612539f2015-06-10 10:13:10 -06002219 VkObject nextObj = (VkObject) device;
2220 VkObject baseObj = nextObj;
2221 VkBaseLayerObject *nextGpuObj;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002222 PFN_vkGetDeviceProcAddr nextGPA = loader_GetDeviceChainProcAddr;
Jon Ashburn612539f2015-06-10 10:13:10 -06002223 VkBaseLayerObject *wrappedGpus;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002224
Jon Ashburn612539f2015-06-10 10:13:10 -06002225 if (!dev->activated_layer_list.count)
2226 return 0;
2227
2228 wrappedGpus = malloc(sizeof (VkBaseLayerObject) * dev->activated_layer_list.count);
2229 if (!wrappedGpus) {
2230 loader_log(VK_DBG_REPORT_ERROR_BIT, 0, "Failed to malloc Gpu objects for layer");
2231 return 0;
2232 }
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002233
Jon Ashburn612539f2015-06-10 10:13:10 -06002234 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
2235
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002236 struct loader_layer_properties *layer_prop = &dev->activated_layer_list.list[i];
Jon Ashburn612539f2015-06-10 10:13:10 -06002237 loader_platform_dl_handle lib_handle;
2238
Jon Ashburn612539f2015-06-10 10:13:10 -06002239 nextGpuObj = (wrappedGpus + i);
2240 nextGpuObj->pGPA = nextGPA;
2241 nextGpuObj->baseObject = baseObj;
2242 nextGpuObj->nextObject = nextObj;
2243 nextObj = (VkObject) nextGpuObj;
2244
2245 char funcStr[256];
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002246 snprintf(funcStr, 256, "%sGetDeviceProcAddr", layer_prop->info.layerName);
2247 lib_handle = loader_add_layer_lib("device", layer_prop);
Jon Ashburn612539f2015-06-10 10:13:10 -06002248 if ((nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, funcStr)) == NULL)
2249 nextGPA = (PFN_vkGetDeviceProcAddr) loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
2250 if (!nextGPA) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002251 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 -06002252 continue;
2253 }
2254
2255 loader_log(VK_DBG_REPORT_INFO_BIT, 0,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002256 "Insert device layer library %s (%s)",
2257 layer_prop->info.layerName,
2258 layer_prop->lib_info.lib_name);
Jon Ashburn612539f2015-06-10 10:13:10 -06002259
2260 }
2261
2262 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGPA,
2263 (VkPhysicalDevice) nextObj, (VkPhysicalDevice) baseObj);
2264 free(wrappedGpus);
2265
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002266 return dev->activated_layer_list.count;
Jon Ashburn183dfd02014-10-22 18:13:16 -06002267}
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002268
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002269VkResult loader_validate_layers(
2270 const uint32_t layer_count,
2271 const char * const *ppEnabledLayerNames,
2272 struct loader_layer_list *list)
Courtney Goeltzenleuchter5d9f29b2015-07-06 17:45:08 -06002273{
2274 struct loader_layer_properties *prop;
2275
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002276 for (uint32_t i = 0; i < layer_count; i++) {
2277 prop = get_layer_property(ppEnabledLayerNames[i],
2278 list);
Courtney Goeltzenleuchter5d9f29b2015-07-06 17:45:08 -06002279 if (!prop) {
2280 return VK_ERROR_INVALID_LAYER;
2281 }
2282 }
2283
2284 return VK_SUCCESS;
2285}
2286
2287VkResult loader_validate_instance_extensions(
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002288 const VkInstanceCreateInfo *pCreateInfo)
Courtney Goeltzenleuchter5d9f29b2015-07-06 17:45:08 -06002289{
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002290 struct loader_extension_property *extension_prop;
2291 struct loader_layer_properties *layer_prop;
2292
2293 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2294 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2295 &loader.global_extensions);
2296
2297 if (extension_prop) {
2298 continue;
2299 }
2300
2301 extension_prop = NULL;
2302
2303 /* Not in global list, search layer extension lists */
2304 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2305 layer_prop = get_layer_property(pCreateInfo->ppEnabledLayerNames[i],
Jon Ashburn1b111de2015-07-06 15:40:35 -06002306 &loader.scanned_layers);
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002307
2308 if (!layer_prop) {
Courtney Goeltzenleuchter91371ff2015-07-06 20:46:50 -06002309 /* Should NOT get here, loader_validate_layers
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002310 * should have already filtered this case out.
2311 */
2312 continue;
2313 }
2314
2315 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2316 &layer_prop->instance_extension_list);
2317 if (extension_prop) {
2318 /* Found the extension in one of the layers enabled by the app. */
2319 break;
2320 }
2321 }
2322
2323 if (!extension_prop) {
2324 /* Didn't find extension name in any of the global layers, error out */
2325 return VK_ERROR_INVALID_EXTENSION;
2326 }
2327 }
2328 return VK_SUCCESS;
2329}
2330
2331VkResult loader_validate_device_extensions(
2332 struct loader_icd *icd,
2333 const VkDeviceCreateInfo *pCreateInfo)
2334{
2335 struct loader_extension_property *extension_prop;
2336 struct loader_layer_properties *layer_prop;
2337
2338 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2339 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2340 extension_prop = get_extension_property(extension_name,
2341 &loader.global_extensions);
2342
2343 if (extension_prop) {
2344 continue;
2345 }
2346
2347 /* Not in global list, search layer extension lists */
2348 for (uint32_t j = 0; j < pCreateInfo->layerCount; j++) {
2349 const char *layer_name = pCreateInfo->ppEnabledLayerNames[j];
2350 layer_prop = get_layer_property(layer_name,
2351 &icd->layer_properties_cache);
2352
2353 if (!layer_prop) {
2354 /* Should NOT get here, loader_validate_instance_layers
2355 * should have already filtered this case out.
2356 */
2357 continue;
2358 }
2359
2360 extension_prop = get_extension_property(extension_name,
2361 &layer_prop->device_extension_list);
2362 if (extension_prop) {
2363 /* Found the extension in one of the layers enabled by the app. */
2364 break;
2365 }
2366 }
2367
2368 if (!extension_prop) {
2369 /* Didn't find extension name in any of the device layers, error out */
2370 return VK_ERROR_INVALID_EXTENSION;
2371 }
2372 }
Courtney Goeltzenleuchter5d9f29b2015-07-06 17:45:08 -06002373 return VK_SUCCESS;
2374}
2375
Jon Ashburnfce93d92015-05-12 17:26:48 -06002376VkResult loader_CreateInstance(
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002377 const VkInstanceCreateInfo* pCreateInfo,
2378 VkInstance* pInstance)
Jon Ashburn349508d2015-01-26 14:51:40 -07002379{
Jon Ashburna179dcf2015-05-21 17:42:17 -06002380 struct loader_instance *ptr_instance = *(struct loader_instance **) pInstance;
Jon Ashburn3336df82015-01-29 15:45:51 -07002381 struct loader_scanned_icds *scanned_icds;
2382 struct loader_icd *icd;
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -06002383 struct loader_extension_property *prop;
2384 char **filtered_extension_names = NULL;
2385 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002386 VkResult res = VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002387
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -06002388 icd_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
2389 icd_create_info.layerCount = 0;
2390 icd_create_info.ppEnabledLayerNames = NULL;
2391 icd_create_info.pAllocCb = pCreateInfo->pAllocCb;
2392 icd_create_info.pAppInfo = pCreateInfo->pAppInfo;
2393 icd_create_info.pNext = pCreateInfo->pNext;
2394
2395 /*
2396 * NOTE: Need to filter the extensions to only those
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002397 * supported by the ICD.
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -06002398 * No ICD will advertise support for layers. An ICD
2399 * library could support a layer, but it would be
2400 * independent of the actual ICD, just in the same library.
2401 */
2402 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2403 if (!filtered_extension_names) {
2404 return VK_ERROR_OUT_OF_HOST_MEMORY;
2405 }
2406 icd_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2407
Jon Ashburn3336df82015-01-29 15:45:51 -07002408 scanned_icds = loader.scanned_icd_list;
2409 while (scanned_icds) {
2410 icd = loader_icd_add(ptr_instance, scanned_icds);
2411 if (icd) {
Courtney Goeltzenleuchterab27f462015-07-06 17:42:01 -06002412
2413 icd_create_info.extensionCount = 0;
2414 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2415 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
2416 &scanned_icds->global_extension_list);
2417 if (prop) {
2418 filtered_extension_names[icd_create_info.extensionCount] = (char *) pCreateInfo->ppEnabledExtensionNames[i];
2419 icd_create_info.extensionCount++;
2420 }
2421 }
2422
2423 res = scanned_icds->CreateInstance(&icd_create_info,
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002424 &(icd->instance));
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06002425 if (res != VK_SUCCESS)
Jon Ashburn3336df82015-01-29 15:45:51 -07002426 {
2427 ptr_instance->icds = ptr_instance->icds->next;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002428 loader_icd_destroy(ptr_instance, icd);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002429 icd->instance = VK_NULL_HANDLE;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002430 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Jon Ashburn3336df82015-01-29 15:45:51 -07002431 "ICD ignored: failed to CreateInstance on device");
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002432 } else
2433 {
2434 loader_icd_init_entrys(icd, scanned_icds);
Jon Ashburn3336df82015-01-29 15:45:51 -07002435 }
2436 }
2437 scanned_icds = scanned_icds->next;
2438 }
Jon Ashburn349508d2015-01-26 14:51:40 -07002439
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002440 /*
2441 * If no ICDs were added to instance list and res is unchanged
2442 * from it's initial value, the loader was unable to find
2443 * a suitable ICD.
2444 */
Ian Elliott617fdec2015-02-05 15:19:15 -07002445 if (ptr_instance->icds == NULL) {
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002446 if (res == VK_SUCCESS) {
2447 return VK_ERROR_INCOMPATIBLE_DRIVER;
2448 } else {
2449 return res;
2450 }
Ian Elliott617fdec2015-02-05 15:19:15 -07002451 }
Jon Ashburn3336df82015-01-29 15:45:51 -07002452
Courtney Goeltzenleuchter1fcceeb2015-07-06 09:06:34 -06002453 return VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002454}
2455
Jon Ashburnfce93d92015-05-12 17:26:48 -06002456VkResult loader_DestroyInstance(
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -06002457 VkInstance instance)
Jon Ashburn349508d2015-01-26 14:51:40 -07002458{
Courtney Goeltzenleuchter8afefb52015-06-08 15:04:02 -06002459 struct loader_instance *ptr_instance = loader_instance(instance);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002460 struct loader_icd *icds = ptr_instance->icds;
Jon Ashburn16a16d62015-06-16 14:43:19 -06002461 struct loader_icd *next_icd;
Courtney Goeltzenleuchter382489d2015-04-10 08:34:15 -06002462 VkResult res;
Jon Ashburn349508d2015-01-26 14:51:40 -07002463
2464 // Remove this instance from the list of instances:
2465 struct loader_instance *prev = NULL;
2466 struct loader_instance *next = loader.instances;
2467 while (next != NULL) {
2468 if (next == ptr_instance) {
2469 // Remove this instance from the list:
2470 if (prev)
2471 prev->next = next->next;
Jon Ashburn2cabd252015-02-03 09:26:59 -07002472 else
2473 loader.instances = next->next;
Jon Ashburn349508d2015-01-26 14:51:40 -07002474 break;
2475 }
2476 prev = next;
2477 next = next->next;
2478 }
2479 if (next == NULL) {
2480 // This must be an invalid instance handle or empty list
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06002481 return VK_ERROR_INVALID_HANDLE;
Jon Ashburn349508d2015-01-26 14:51:40 -07002482 }
2483
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002484 while (icds) {
2485 if (icds->instance) {
2486 res = icds->DestroyInstance(icds->instance);
Tony Barbour22a30862015-04-22 09:02:32 -06002487 if (res != VK_SUCCESS)
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002488 loader_log(VK_DBG_REPORT_WARN_BIT, 0,
Tony Barbour22a30862015-04-22 09:02:32 -06002489 "ICD ignored: failed to DestroyInstance on device");
2490 }
Jon Ashburn16a16d62015-06-16 14:43:19 -06002491 next_icd = icds->next;
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002492 icds->instance = VK_NULL_HANDLE;
Jon Ashburn16a16d62015-06-16 14:43:19 -06002493 loader_icd_destroy(ptr_instance, icds);
2494
2495 icds = next_icd;
Jon Ashburn3336df82015-01-29 15:45:51 -07002496 }
2497
Jon Ashburn349508d2015-01-26 14:51:40 -07002498
Courtney Goeltzenleuchter9cc421e2015-04-08 15:36:08 -06002499 return VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002500}
2501
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002502VkResult loader_init_physical_device_info(
2503 struct loader_instance *ptr_instance)
2504{
2505 struct loader_icd *icd;
2506 uint32_t n, count = 0;
2507 VkResult res = VK_ERROR_UNKNOWN;
2508
2509 icd = ptr_instance->icds;
2510 while (icd) {
2511 res = icd->EnumeratePhysicalDevices(icd->instance, &n, NULL);
2512 if (res != VK_SUCCESS)
2513 return res;
2514 icd->gpu_count = n;
2515 count += n;
2516 icd = icd->next;
2517 }
2518
2519 ptr_instance->total_gpu_count = count;
2520
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002521 icd = ptr_instance->icds;
2522 while (icd) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002523
2524 n = icd->gpu_count;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002525 icd->gpus = (VkPhysicalDevice *) malloc(n * sizeof(VkPhysicalDevice));
2526 if (!icd->gpus) {
2527 /* TODO: Add cleanup code here */
2528 return VK_ERROR_OUT_OF_HOST_MEMORY;
2529 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002530 res = icd->EnumeratePhysicalDevices(
2531 icd->instance,
2532 &n,
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002533 icd->gpus);
2534 if ((res == VK_SUCCESS) && (n == icd->gpu_count)) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002535
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002536 for (unsigned int i = 0; i < n; i++) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002537
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002538 loader_init_dispatch(icd->gpus[i], ptr_instance->disp);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002539
2540 if (!loader_init_ext_list(&icd->device_extension_cache[i])) {
2541 /* TODO: Add cleanup code here */
2542 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2543 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002544 if (res == VK_SUCCESS) {
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002545
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002546 loader_add_physical_device_extensions(
2547 icd->GetPhysicalDeviceExtensionProperties,
2548 icd->gpus[0],
2549 VK_EXTENSION_ORIGIN_ICD,
2550 icd->scanned_icds->lib_name,
2551 &icd->device_extension_cache[i]);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002552
Jon Ashburn1b111de2015-07-06 15:40:35 -06002553 for (uint32_t l = 0; l < loader.scanned_layers.count; l++) {
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002554 loader_platform_dl_handle lib_handle;
Jon Ashburn1b111de2015-07-06 15:40:35 -06002555 char *lib_name = loader.scanned_layers.list[l].lib_info.lib_name;
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002556
2557 lib_handle = loader_platform_open_library(lib_name);
2558 if (lib_handle == NULL) {
2559 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0, "open library failed: %s", lib_name);
2560 continue;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002561 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002562 loader_log(VK_DBG_REPORT_DEBUG_BIT, 0,
2563 "library: %s", lib_name);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002564
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002565 loader_add_physical_device_layer_properties(
2566 icd, lib_name, lib_handle);
2567
2568 loader_platform_close_library(lib_handle);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002569 }
2570 }
2571
2572 if (res != VK_SUCCESS) {
2573 /* clean up any extension lists previously created before this request failed */
2574 for (uint32_t j = 0; j < i; j++) {
2575 loader_destroy_ext_list(&icd->device_extension_cache[i]);
2576 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002577
2578 loader_destroy_layer_list(&icd->layer_properties_cache);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002579 return res;
2580 }
2581 }
2582
2583 count += n;
2584 }
2585
2586 icd = icd->next;
2587 }
2588
2589 return VK_SUCCESS;
2590}
2591
Jon Ashburnfce93d92015-05-12 17:26:48 -06002592VkResult loader_EnumeratePhysicalDevices(
Courtney Goeltzenleuchter9f530cb2015-04-20 12:48:54 -06002593 VkInstance instance,
2594 uint32_t* pPhysicalDeviceCount,
2595 VkPhysicalDevice* pPhysicalDevices)
Jon Ashburn349508d2015-01-26 14:51:40 -07002596{
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002597 uint32_t index = 0;
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002598 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002599 struct loader_icd *icd = ptr_instance->icds;
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002600
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002601 if (ptr_instance->total_gpu_count == 0) {
2602 loader_init_physical_device_info(ptr_instance);
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002603 }
2604
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002605 *pPhysicalDeviceCount = ptr_instance->total_gpu_count;
2606 if (!pPhysicalDevices) {
2607 return VK_SUCCESS;
2608 }
Jon Ashburnb048a9b2015-01-28 19:57:09 -07002609
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002610 while (icd) {
2611 assert((index + icd->gpu_count) <= *pPhysicalDeviceCount);
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002612 memcpy(&pPhysicalDevices[index], icd->gpus, icd->gpu_count * sizeof(VkPhysicalDevice));
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06002613 index += icd->gpu_count;
2614 icd = icd->next;
2615 }
2616
2617 return VK_SUCCESS;
Jon Ashburn349508d2015-01-26 14:51:40 -07002618}
2619
Tony Barbour426b9052015-06-24 16:06:58 -06002620VkResult loader_GetPhysicalDeviceProperties(
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002621 VkPhysicalDevice gpu,
Tony Barbour426b9052015-06-24 16:06:58 -06002622 VkPhysicalDeviceProperties* pProperties)
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002623{
2624 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002625 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002626 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2627
Tony Barbour426b9052015-06-24 16:06:58 -06002628 if (icd->GetPhysicalDeviceProperties)
2629 res = icd->GetPhysicalDeviceProperties(gpu, pProperties);
2630
2631 return res;
2632}
2633
2634VkResult loader_GetPhysicalDevicePerformance(
2635 VkPhysicalDevice gpu,
2636 VkPhysicalDevicePerformance* pPerformance)
2637{
2638 uint32_t gpu_index;
2639 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2640 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2641
2642 if (icd->GetPhysicalDevicePerformance)
2643 res = icd->GetPhysicalDevicePerformance(gpu, pPerformance);
2644
2645 return res;
2646}
2647
2648VkResult loader_GetPhysicalDeviceQueueCount(
2649 VkPhysicalDevice gpu,
2650 uint32_t* pCount)
2651{
2652 uint32_t gpu_index;
2653 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2654 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2655
2656 if (icd->GetPhysicalDeviceQueueCount)
2657 res = icd->GetPhysicalDeviceQueueCount(gpu, pCount);
2658
2659 return res;
2660}
2661
2662VkResult loader_GetPhysicalDeviceQueueProperties (
2663 VkPhysicalDevice gpu,
2664 uint32_t count,
2665 VkPhysicalDeviceQueueProperties * pProperties)
2666{
2667 uint32_t gpu_index;
2668 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2669 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2670
2671 if (icd->GetPhysicalDeviceQueueProperties)
2672 res = icd->GetPhysicalDeviceQueueProperties(gpu, count, pProperties);
2673
2674 return res;
2675}
2676
2677VkResult loader_GetPhysicalDeviceMemoryProperties (
2678 VkPhysicalDevice gpu,
2679 VkPhysicalDeviceMemoryProperties* pProperties)
2680{
2681 uint32_t gpu_index;
2682 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
2683 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2684
2685 if (icd->GetPhysicalDeviceMemoryProperties)
2686 res = icd->GetPhysicalDeviceMemoryProperties(gpu, pProperties);
Jon Ashburn0dd356d2015-05-14 12:43:38 -06002687
2688 return res;
2689}
2690
Chris Forbesd7576302015-06-21 22:55:02 +12002691VkResult loader_GetPhysicalDeviceFeatures(
2692 VkPhysicalDevice physicalDevice,
2693 VkPhysicalDeviceFeatures* pFeatures)
2694{
2695 uint32_t gpu_index;
2696 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2697 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2698
2699 if (icd->GetPhysicalDeviceFeatures)
2700 res = icd->GetPhysicalDeviceFeatures(physicalDevice, pFeatures);
2701
2702 return res;
2703}
2704
2705VkResult loader_GetPhysicalDeviceFormatInfo(
2706 VkPhysicalDevice physicalDevice,
2707 VkFormat format,
2708 VkFormatProperties* pFormatInfo)
2709{
2710 uint32_t gpu_index;
2711 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2712 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2713
2714 if (icd->GetPhysicalDeviceFormatInfo)
2715 res = icd->GetPhysicalDeviceFormatInfo(physicalDevice, format, pFormatInfo);
2716
2717 return res;
2718}
2719
2720VkResult loader_GetPhysicalDeviceLimits(
2721 VkPhysicalDevice physicalDevice,
2722 VkPhysicalDeviceLimits* pLimits)
2723{
2724 uint32_t gpu_index;
2725 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2726 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2727
2728 if (icd->GetPhysicalDeviceLimits)
2729 res = icd->GetPhysicalDeviceLimits(physicalDevice, pLimits);
2730
2731 return res;
2732}
2733
Mark Lobodzinski83d4e6a2015-07-03 15:58:09 -06002734VkResult loader_GetPhysicalDeviceSparseImageFormatProperties(
2735 VkPhysicalDevice physicalDevice,
2736 VkFormat format,
2737 VkImageType type,
2738 uint32_t samples,
2739 VkImageUsageFlags usage,
2740 VkImageTiling tiling,
2741 uint32_t* pNumProperties,
2742 VkSparseImageFormatProperties* pProperties)
2743{
2744 uint32_t gpu_index;
2745 struct loader_icd *icd = loader_get_icd(physicalDevice, &gpu_index);
2746 VkResult res = VK_ERROR_INITIALIZATION_FAILED;
2747
2748 if (icd->GetPhysicalDeviceSparseImageFormatProperties)
2749 res = icd->GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, format, type, samples, usage, tiling, pNumProperties, pProperties);
2750
2751 return res;
2752}
2753
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002754VkResult loader_CreateDevice(
2755 VkPhysicalDevice gpu,
2756 const VkDeviceCreateInfo* pCreateInfo,
2757 VkDevice* pDevice)
2758{
2759 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06002760 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Jon Ashburncb5a5ac2015-06-10 10:06:06 -06002761 struct loader_device *dev;
Courtney Goeltzenleuchter91371ff2015-07-06 20:46:50 -06002762 VkDeviceCreateInfo device_create_info;
2763 char **filtered_extension_names = NULL;
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002764 VkResult res;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002765
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002766 if (!icd->CreateDevice) {
2767 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002768 }
2769
Courtney Goeltzenleuchtera17697f2015-07-06 20:14:18 -06002770 res = loader_validate_layers(pCreateInfo->layerCount,
2771 pCreateInfo->ppEnabledLayerNames,
2772 &icd->layer_properties_cache);
2773 if (res != VK_SUCCESS) {
2774 return res;
2775 }
2776
2777 res = loader_validate_device_extensions(icd, pCreateInfo);
2778 if (res != VK_SUCCESS) {
2779 return res;
2780 }
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002781
Courtney Goeltzenleuchter91371ff2015-07-06 20:46:50 -06002782 /*
2783 * NOTE: Need to filter the extensions to only those
2784 * supported by the ICD.
2785 * No ICD will advertise support for layers. An ICD
2786 * library could support a layer, but it would be
2787 * independent of the actual ICD, just in the same library.
2788 */
2789 filtered_extension_names = loader_stack_alloc(pCreateInfo->extensionCount * sizeof(char *));
2790 if (!filtered_extension_names) {
2791 return VK_ERROR_OUT_OF_HOST_MEMORY;
2792 }
2793
2794 /* Copy user's data */
2795 memcpy(&device_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
2796
2797 /* ICD's do not use layers */
2798 device_create_info.layerCount = 0;
2799 device_create_info.ppEnabledLayerNames = NULL;
2800
2801 device_create_info.extensionCount = 0;
2802 device_create_info.ppEnabledExtensionNames = (const char * const *) filtered_extension_names;
2803
2804 for (uint32_t i = 0; i < pCreateInfo->extensionCount; i++) {
2805 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
2806 struct loader_extension_property *prop = get_extension_property(extension_name,
2807 &icd->device_extension_cache[gpu_index]);
2808 if (prop) {
2809 filtered_extension_names[device_create_info.extensionCount] = (char *) extension_name;
2810 device_create_info.extensionCount++;
2811 }
2812 }
2813
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002814 res = icd->CreateDevice(gpu, pCreateInfo, pDevice);
2815 if (res != VK_SUCCESS) {
2816 return res;
2817 }
2818
2819 dev = loader_add_logical_device(*pDevice, &icd->logical_device_list);
2820 if (dev == NULL) {
2821 return VK_ERROR_OUT_OF_HOST_MEMORY;
2822 }
2823 PFN_vkGetDeviceProcAddr get_proc_addr = icd->GetDeviceProcAddr;
2824 loader_init_device_dispatch_table(&dev->loader_dispatch, get_proc_addr,
2825 icd->gpus[gpu_index], icd->gpus[gpu_index]);
2826
2827 dev->loader_dispatch.CreateDevice = scratch_vkCreateDevice;
2828 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
2829
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002830 /*
2831 * Put together the complete list of extensions to enable
2832 * This includes extensions requested via environment variables.
2833 */
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002834 loader_enable_device_layers(icd, dev, pCreateInfo);
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002835
2836 /*
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002837 * Load the libraries and build the device chain
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002838 * terminating with the selected device.
2839 */
Courtney Goeltzenleuchterc5cf7d72015-07-05 12:53:31 -06002840 loader_activate_device_layers(icd, dev, *pDevice);
Courtney Goeltzenleuchterbe637992015-06-25 18:01:43 -06002841
2842 res = dev->loader_dispatch.CreateDevice(gpu, pCreateInfo, pDevice);
2843
2844 dev->loader_dispatch.CreateDevice = icd->CreateDevice;
2845
Jon Ashburn2666e2f2015-05-15 15:09:35 -06002846 return res;
2847}
2848
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002849static void * VKAPI loader_GetInstanceProcAddr(VkInstance instance, const char * pName)
Jon Ashburn53c16772015-05-06 10:15:07 -06002850{
Jon Ashburncedc15f2015-05-21 18:13:33 -06002851 if (instance == VK_NULL_HANDLE)
2852 return NULL;
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002853
Jon Ashburncedc15f2015-05-21 18:13:33 -06002854 void *addr;
2855 /* get entrypoint addresses that are global (in the loader)*/
2856 addr = globalGetProcAddr(pName);
2857 if (addr)
2858 return addr;
Jon Ashburn53c16772015-05-06 10:15:07 -06002859
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002860 struct loader_instance *ptr_instance = (struct loader_instance *) instance;
2861
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002862 /* return any extension global entrypoints */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002863 addr = debug_report_instance_gpa(ptr_instance, pName);
2864 if (addr) {
2865 return addr;
2866 }
2867
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002868 /* TODO Remove this once WSI has no loader special code */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002869 addr = wsi_lunarg_GetInstanceProcAddr(instance, pName);
David Pinedo0fab78b2015-06-24 15:29:18 -06002870 if (addr) {
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002871 return addr;
David Pinedo0fab78b2015-06-24 15:29:18 -06002872 }
Jon Ashburncedc15f2015-05-21 18:13:33 -06002873
2874 /* return the instance dispatch table entrypoint for extensions */
2875 const VkLayerInstanceDispatchTable *disp_table = * (VkLayerInstanceDispatchTable **) instance;
2876 if (disp_table == NULL)
2877 return NULL;
2878
2879 addr = loader_lookup_instance_dispatch_table(disp_table, pName);
2880 if (addr)
2881 return addr;
Jon Ashburn53c16772015-05-06 10:15:07 -06002882
2883 return NULL;
2884}
2885
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002886LOADER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char * pName)
2887{
2888 return loader_GetInstanceProcAddr(instance, pName);
2889}
2890
2891static void * VKAPI loader_GetDeviceProcAddr(VkDevice device, const char * pName)
Jon Ashburn349508d2015-01-26 14:51:40 -07002892{
Jon Ashburn1245cec2015-05-18 13:20:15 -06002893 if (device == VK_NULL_HANDLE) {
2894 return NULL;
Ian Elliott81ac44c2015-01-13 17:52:38 -07002895 }
Jon Ashburne18431b2015-04-13 18:10:06 -06002896
Chia-I Wu38e5a2c2015-01-04 11:12:47 +08002897 void *addr;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002898
Jon Ashburne18431b2015-04-13 18:10:06 -06002899 /* for entrypoints that loader must handle (ie non-dispatchable or create object)
2900 make sure the loader entrypoint is returned */
2901 addr = loader_non_passthrough_gpa(pName);
Ian Elliottfdf00b62015-04-15 12:53:19 -06002902 if (addr) {
Jon Ashburne18431b2015-04-13 18:10:06 -06002903 return addr;
Ian Elliottfdf00b62015-04-15 12:53:19 -06002904 }
Jon Ashburne18431b2015-04-13 18:10:06 -06002905
Jon Ashburncedc15f2015-05-21 18:13:33 -06002906 /* return any extension device entrypoints the loader knows about */
Jon Ashburn4ebc0962015-06-18 09:05:37 -06002907 /* TODO once WSI has no loader special code remove this */
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002908 addr = wsi_lunarg_GetDeviceProcAddr(device, pName);
David Pinedo0fab78b2015-06-24 15:29:18 -06002909 if (addr) {
Courtney Goeltzenleuchter1c7c65d2015-06-10 17:39:03 -06002910 return addr;
David Pinedo0fab78b2015-06-24 15:29:18 -06002911 }
Jon Ashburncedc15f2015-05-21 18:13:33 -06002912
Jon Ashburne18431b2015-04-13 18:10:06 -06002913 /* return the dispatch table entrypoint for the fastest case */
Jon Ashburn1245cec2015-05-18 13:20:15 -06002914 const VkLayerDispatchTable *disp_table = * (VkLayerDispatchTable **) device;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002915 if (disp_table == NULL)
2916 return NULL;
2917
Jon Ashburnfce93d92015-05-12 17:26:48 -06002918 addr = loader_lookup_device_dispatch_table(disp_table, pName);
Chia-I Wu38e5a2c2015-01-04 11:12:47 +08002919 if (addr)
2920 return addr;
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002921 else {
Jon Ashburn1245cec2015-05-18 13:20:15 -06002922 if (disp_table->GetDeviceProcAddr == NULL)
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002923 return NULL;
Jon Ashburn1245cec2015-05-18 13:20:15 -06002924 return disp_table->GetDeviceProcAddr(device, pName);
Jon Ashburnd43f9b62014-10-14 19:15:22 -06002925 }
2926}
2927
Courtney Goeltzenleuchter9a4f38c2015-06-22 17:45:21 -06002928LOADER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char * pName)
2929{
2930 return loader_GetDeviceProcAddr(device, pName);
2931}
2932
Tony Barbour426b9052015-06-24 16:06:58 -06002933LOADER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06002934 const char* pLayerName,
2935 uint32_t* pCount,
2936 VkExtensionProperties* pProperties)
2937{
2938 struct loader_extension_list *global_extension_list;
2939
2940 /* Scan/discover all ICD libraries in a single-threaded manner */
2941 loader_platform_thread_once(&once_icd, loader_icd_scan);
2942
2943 /* get layer libraries in a single-threaded manner */
2944 loader_platform_thread_once(&once_layer, loader_layer_scan);
2945
2946 /* merge any duplicate extensions */
2947 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2948
2949 uint32_t copy_size;
2950
2951 if (pCount == NULL) {
2952 return VK_ERROR_INVALID_POINTER;
2953 }
2954
2955 loader_platform_thread_lock_mutex(&loader_lock);
2956
2957 global_extension_list = loader_global_extensions(pLayerName);
2958 if (global_extension_list == NULL) {
2959 loader_platform_thread_unlock_mutex(&loader_lock);
2960 return VK_ERROR_INVALID_LAYER;
2961 }
2962
2963 if (pProperties == NULL) {
2964 *pCount = global_extension_list->count;
2965 loader_platform_thread_unlock_mutex(&loader_lock);
2966 return VK_SUCCESS;
2967 }
2968
2969 copy_size = *pCount < global_extension_list->count ? *pCount : global_extension_list->count;
2970 for (uint32_t i = 0; i < copy_size; i++) {
2971 memcpy(&pProperties[i],
2972 &global_extension_list->list[i].info,
2973 sizeof(VkExtensionProperties));
2974 }
2975 *pCount = copy_size;
2976
2977 loader_platform_thread_unlock_mutex(&loader_lock);
2978
2979 if (copy_size < global_extension_list->count) {
2980 return VK_INCOMPLETE;
2981 }
2982
2983 return VK_SUCCESS;
2984}
2985
2986LOADER_EXPORT VkResult VKAPI vkGetGlobalLayerProperties(
2987 uint32_t* pCount,
2988 VkLayerProperties* pProperties)
Tony Barbour426b9052015-06-24 16:06:58 -06002989{
Jon Ashburnb40f2562015-05-29 13:15:39 -06002990
Jon Ashburneb2728b2015-04-10 14:33:07 -06002991 /* Scan/discover all ICD libraries in a single-threaded manner */
2992 loader_platform_thread_once(&once_icd, loader_icd_scan);
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002993
Jon Ashburneb2728b2015-04-10 14:33:07 -06002994 /* get layer libraries in a single-threaded manner */
Jon Ashburn68a63922015-07-02 09:40:15 -06002995 loader_platform_thread_once(&once_layer, loader_layer_scan);
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07002996
Jon Ashburneb2728b2015-04-10 14:33:07 -06002997 /* merge any duplicate extensions */
2998 loader_platform_thread_once(&once_exts, loader_coalesce_extensions);
2999
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003000 uint32_t copy_size;
Jon Ashburneb2728b2015-04-10 14:33:07 -06003001
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003002 if (pCount == NULL) {
3003 return VK_ERROR_INVALID_POINTER;
3004 }
3005
3006 /* TODO: do we still need to lock */
Jon Ashburnb40f2562015-05-29 13:15:39 -06003007 loader_platform_thread_lock_mutex(&loader_lock);
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003008
3009 struct loader_layer_list *layer_list;
Jon Ashburn1b111de2015-07-06 15:40:35 -06003010 layer_list = loader_scanned_layers();
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003011
3012 if (pProperties == NULL) {
3013 *pCount = layer_list->count;
3014 loader_platform_thread_unlock_mutex(&loader_lock);
3015 return VK_SUCCESS;
3016 }
3017
3018 copy_size = *pCount < layer_list->count ? *pCount : layer_list->count;
3019 for (uint32_t i = 0; i < copy_size; i++) {
3020 memcpy(&pProperties[i], &layer_list->list[i].info, sizeof(VkLayerProperties));
3021 }
3022 *pCount = copy_size;
Tony Barbour426b9052015-06-24 16:06:58 -06003023
Jon Ashburnb40f2562015-05-29 13:15:39 -06003024 loader_platform_thread_unlock_mutex(&loader_lock);
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06003025
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003026 if (copy_size < layer_list->count) {
3027 return VK_INCOMPLETE;
3028 }
Tony Barbour426b9052015-06-24 16:06:58 -06003029
3030 return VK_SUCCESS;
3031}
3032
3033VkResult loader_GetPhysicalDeviceExtensionProperties(
3034 VkPhysicalDevice gpu,
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003035 const char* pLayerName,
3036 uint32_t* pCount,
Tony Barbour426b9052015-06-24 16:06:58 -06003037 VkExtensionProperties* pProperties)
3038{
3039 uint32_t gpu_index;
Jon Ashburnd5df54d2015-05-28 19:16:58 -06003040 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003041 uint32_t copy_size;
Courtney Goeltzenleuchter0199e952015-02-27 15:19:33 -07003042
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003043 if (pCount == NULL) {
3044 return VK_ERROR_INVALID_POINTER;
3045 }
Jon Ashburn2666e2f2015-05-15 15:09:35 -06003046
Courtney Goeltzenleuchter18061cd2015-06-29 15:39:26 -06003047 uint32_t count;
3048 struct loader_extension_list *list;
3049 loader_physical_device_extensions(icd, gpu_index, pLayerName, &count, &list);
3050
3051 if (pProperties == NULL) {
3052 *pCount = count;
3053 return VK_SUCCESS;
3054 }
3055
3056 copy_size = *pCount < count ? *pCount : count;
3057 for (uint32_t i = 0; i < copy_size; i++) {
3058 memcpy(&pProperties[i],
3059 &list->list[i].info,
3060 sizeof(VkExtensionProperties));
3061 }
3062 *pCount = copy_size;
3063
3064 if (copy_size < count) {
3065 return VK_INCOMPLETE;
3066 }
3067
3068 return VK_SUCCESS;
3069}
3070
3071VkResult loader_GetPhysicalDeviceLayerProperties(
3072 VkPhysicalDevice gpu,
3073 uint32_t* pCount,
3074 VkLayerProperties* pProperties)
3075{
3076 uint32_t gpu_index;
3077 struct loader_icd *icd = loader_get_icd(gpu, &gpu_index);
3078 uint32_t copy_size;
3079
3080 if (pCount == NULL) {
3081 return VK_ERROR_INVALID_POINTER;
3082 }
3083
3084 uint32_t count;
3085 struct loader_layer_list *layer_list;
3086 loader_physical_device_layers(icd, &count, &layer_list);
3087
3088 if (pProperties == NULL) {
3089 *pCount = count;
3090 return VK_SUCCESS;
3091 }
3092
3093 copy_size = *pCount < count ? *pCount : count;
3094 for (uint32_t i = 0; i < copy_size; i++) {
3095 memcpy(&pProperties[i],
3096 &layer_list->list[i].info,
3097 sizeof(VkLayerProperties));
3098 }
3099 *pCount = copy_size;
3100
3101 if (copy_size < count) {
3102 return VK_INCOMPLETE;
3103 }
Courtney Goeltzenleuchter23b5f8d2015-06-17 20:51:59 -06003104
3105 return VK_SUCCESS;
Jon Ashburn2666e2f2015-05-15 15:09:35 -06003106}