blob: 2ed52c4b08350a11756fbe5e868660fc83f44a8b [file] [log] [blame]
Mark Lobodzinski317574e2016-08-29 14:21:14 -06001/*
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08002 *
Jon Ashburn23d36b12016-02-02 17:47:28 -07003 * Copyright (c) 2014-2016 The Khronos Group Inc.
4 * Copyright (c) 2014-2016 Valve Corporation
5 * Copyright (c) 2014-2016 LunarG, Inc.
Courtney Goeltzenleuchterf821dad2015-12-02 14:53:22 -07006 * Copyright (C) 2015 Google Inc.
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08007 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -06008 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080011 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060012 * http://www.apache.org/licenses/LICENSE-2.0
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080013 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060014 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19
Jon Ashburn23d36b12016-02-02 17:47:28 -070020 *
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060021 * Author: Jon Ashburn <jon@lunarg.com>
Jon Ashburn23d36b12016-02-02 17:47:28 -070022 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060023 *
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080024 */
Mark Lobodzinskifaa90812015-11-25 13:26:15 -070025
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060026#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080027#include <stdio.h>
28#include <stdlib.h>
29#include <stdarg.h>
30#include <stdbool.h>
31#include <string.h>
32
Chia-I Wu13a61a52014-08-04 11:18:20 +080033#include <sys/types.h>
Johannes van Waveren9bd805012015-10-28 11:45:00 -050034#if defined(_WIN32)
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070035#include "dirent_on_windows.h"
Johannes van Waveren9bd805012015-10-28 11:45:00 -050036#else // _WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080037#include <dirent.h>
Johannes van Waveren9bd805012015-10-28 11:45:00 -050038#endif // _WIN32
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060039#include "vk_loader_platform.h"
Chia-I Wu19300602014-08-04 08:03:57 +080040#include "loader.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060041#include "gpa_helper.h"
42#include "table_ops.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060043#include "debug_report.h"
Ian Elliott954fa342015-10-30 15:28:23 -060044#include "wsi.h"
Mark Lobodzinski317574e2016-08-29 14:21:14 -060045#include "extensions.h"
David Pinedo9316d3b2015-11-06 12:54:48 -070046#include "vulkan/vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060047#include "cJSON.h"
Jon Ashburnfc1031e2015-11-17 15:31:02 -070048#include "murmurhash.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080049
Jon Ashburnd8ed7992016-04-04 13:52:53 -060050#if defined(__GNUC__)
Jon Ashburn10b3f832016-05-09 11:31:40 -060051#if (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 17))
Jon Ashburncc407a22016-04-15 09:25:03 -060052#define secure_getenv __secure_getenv
53#endif
Jon Ashburnd8ed7992016-04-04 13:52:53 -060054#endif
55
Jon Ashburn27cd5842015-05-12 17:26:48 -060056struct loader_struct loader = {0};
Jon Ashburn87d6aa92015-08-28 15:19:27 -060057// TLS for instance for alloc/free callbacks
58THREAD_LOCAL_DECL struct loader_instance *tls_instance;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080059
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -070060static size_t loader_platform_combine_path(char *dest, size_t len, ...);
Daniel Dadap00b4aba2015-09-30 11:50:51 -050061
Jon Ashburn24cd4be2015-11-01 14:04:06 -070062struct loader_phys_dev_per_icd {
63 uint32_t count;
64 VkPhysicalDevice *phys_devs;
Mark Young0153e0b2016-11-03 14:27:13 -060065 struct loader_icd_term *this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -070066};
67
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060068enum loader_debug {
Jon Ashburn23d36b12016-02-02 17:47:28 -070069 LOADER_INFO_BIT = 0x01,
70 LOADER_WARN_BIT = 0x02,
71 LOADER_PERF_BIT = 0x04,
72 LOADER_ERROR_BIT = 0x08,
73 LOADER_DEBUG_BIT = 0x10,
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060074};
75
76uint32_t g_loader_debug = 0;
77uint32_t g_loader_log_msgs = 0;
78
Jon Ashburn23d36b12016-02-02 17:47:28 -070079// thread safety lock for accessing global data structures such as "loader"
Jon Ashburn6301a0f2015-05-29 13:15:39 -060080// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060081// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060082loader_platform_thread_mutex loader_lock;
Jon Ashburn6461ef22015-09-22 13:11:00 -060083loader_platform_thread_mutex loader_json_lock;
Jon Ashburn6301a0f2015-05-29 13:15:39 -060084
Jon Ashburn86a527a2016-02-10 20:59:26 -070085const char *std_validation_str = "VK_LAYER_LUNARG_standard_validation";
86
Ian Elliottd3ef02f2015-07-06 14:36:13 -060087// This table contains the loader's instance dispatch table, which contains
88// default functions if no instance layers are activated. This contains
89// pointers to "terminator functions".
Jon Ashburn6301a0f2015-05-29 13:15:39 -060090const VkLayerInstanceDispatchTable instance_disp = {
Jon Ashburn69e9ea22015-09-28 16:15:00 -060091 .GetInstanceProcAddr = vkGetInstanceProcAddr,
Jon Ashburn1530c342016-02-26 13:14:27 -070092 .DestroyInstance = terminator_DestroyInstance,
93 .EnumeratePhysicalDevices = terminator_EnumeratePhysicalDevices,
94 .GetPhysicalDeviceFeatures = terminator_GetPhysicalDeviceFeatures,
Jon Ashburn23d36b12016-02-02 17:47:28 -070095 .GetPhysicalDeviceFormatProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -070096 terminator_GetPhysicalDeviceFormatProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -070097 .GetPhysicalDeviceImageFormatProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -070098 terminator_GetPhysicalDeviceImageFormatProperties,
99 .GetPhysicalDeviceProperties = terminator_GetPhysicalDeviceProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700100 .GetPhysicalDeviceQueueFamilyProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -0700101 terminator_GetPhysicalDeviceQueueFamilyProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700102 .GetPhysicalDeviceMemoryProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -0700103 terminator_GetPhysicalDeviceMemoryProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700104 .EnumerateDeviceExtensionProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -0700105 terminator_EnumerateDeviceExtensionProperties,
106 .EnumerateDeviceLayerProperties = terminator_EnumerateDeviceLayerProperties,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700107 .GetPhysicalDeviceSparseImageFormatProperties =
Jon Ashburn1530c342016-02-26 13:14:27 -0700108 terminator_GetPhysicalDeviceSparseImageFormatProperties,
109 .DestroySurfaceKHR = terminator_DestroySurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700110 .GetPhysicalDeviceSurfaceSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700111 terminator_GetPhysicalDeviceSurfaceSupportKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700112 .GetPhysicalDeviceSurfaceCapabilitiesKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700113 terminator_GetPhysicalDeviceSurfaceCapabilitiesKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700114 .GetPhysicalDeviceSurfaceFormatsKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700115 terminator_GetPhysicalDeviceSurfaceFormatsKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700116 .GetPhysicalDeviceSurfacePresentModesKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700117 terminator_GetPhysicalDeviceSurfacePresentModesKHR,
118 .CreateDebugReportCallbackEXT = terminator_CreateDebugReportCallback,
119 .DestroyDebugReportCallbackEXT = terminator_DestroyDebugReportCallback,
120 .DebugReportMessageEXT = terminator_DebugReportMessage,
Mark Lobodzinski317574e2016-08-29 14:21:14 -0600121 .GetPhysicalDeviceExternalImageFormatPropertiesNV =
122 terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700123#ifdef VK_USE_PLATFORM_MIR_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700124 .CreateMirSurfaceKHR = terminator_CreateMirSurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700125 .GetPhysicalDeviceMirPresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700126 terminator_GetPhysicalDeviceMirPresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700127#endif
128#ifdef VK_USE_PLATFORM_WAYLAND_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700129 .CreateWaylandSurfaceKHR = terminator_CreateWaylandSurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700130 .GetPhysicalDeviceWaylandPresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700131 terminator_GetPhysicalDeviceWaylandPresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700132#endif
133#ifdef VK_USE_PLATFORM_WIN32_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700134 .CreateWin32SurfaceKHR = terminator_CreateWin32SurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700135 .GetPhysicalDeviceWin32PresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700136 terminator_GetPhysicalDeviceWin32PresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700137#endif
138#ifdef VK_USE_PLATFORM_XCB_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700139 .CreateXcbSurfaceKHR = terminator_CreateXcbSurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700140 .GetPhysicalDeviceXcbPresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700141 terminator_GetPhysicalDeviceXcbPresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700142#endif
143#ifdef VK_USE_PLATFORM_XLIB_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700144 .CreateXlibSurfaceKHR = terminator_CreateXlibSurfaceKHR,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700145 .GetPhysicalDeviceXlibPresentationSupportKHR =
Jon Ashburn1530c342016-02-26 13:14:27 -0700146 terminator_GetPhysicalDeviceXlibPresentationSupportKHR,
Ian Elliottdb4300a2015-11-23 10:17:23 -0700147#endif
Mark Lobodzinskia8a5f852015-12-10 16:25:21 -0700148#ifdef VK_USE_PLATFORM_ANDROID_KHR
Jon Ashburn1530c342016-02-26 13:14:27 -0700149 .CreateAndroidSurfaceKHR = terminator_CreateAndroidSurfaceKHR,
Mark Lobodzinskia8a5f852015-12-10 16:25:21 -0700150#endif
Jon Ashburnc7d3e732016-03-08 09:30:30 -0700151 .GetPhysicalDeviceDisplayPropertiesKHR =
152 terminator_GetPhysicalDeviceDisplayPropertiesKHR,
153 .GetPhysicalDeviceDisplayPlanePropertiesKHR =
154 terminator_GetPhysicalDeviceDisplayPlanePropertiesKHR,
155 .GetDisplayPlaneSupportedDisplaysKHR =
156 terminator_GetDisplayPlaneSupportedDisplaysKHR,
Jon Ashburncc407a22016-04-15 09:25:03 -0600157 .GetDisplayModePropertiesKHR = terminator_GetDisplayModePropertiesKHR,
158 .CreateDisplayModeKHR = terminator_CreateDisplayModeKHR,
159 .GetDisplayPlaneCapabilitiesKHR = terminator_GetDisplayPlaneCapabilitiesKHR,
160 .CreateDisplayPlaneSurfaceKHR = terminator_CreateDisplayPlaneSurfaceKHR,
Mark Youngfa552782016-12-12 16:14:55 -0700161
162 // NVX_device_generated_commands
163 .GetPhysicalDeviceGeneratedCommandsPropertiesNVX =
164 terminator_GetPhysicalDeviceGeneratedCommandsPropertiesNVX,
Jon Ashburn27cd5842015-05-12 17:26:48 -0600165};
166
Jon Ashburn8810c5f2015-08-18 18:04:47 -0600167LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700168
Mark Young0ad83132016-06-30 13:02:42 -0600169void *loader_instance_heap_alloc(const struct loader_instance *instance,
170 size_t size,
171 VkSystemAllocationScope alloc_scope) {
172 void *pMemory = NULL;
173#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
174 {
175#else
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800176 if (instance && instance->alloc_callbacks.pfnAllocation) {
Mark Young0ad83132016-06-30 13:02:42 -0600177 /* These are internal structures, so it's best to align everything to
178 * the largest unit size which is the size of a uint64_t.
179 */
180 pMemory = instance->alloc_callbacks.pfnAllocation(
181 instance->alloc_callbacks.pUserData, size, sizeof(uint64_t),
Jon Ashburn23d36b12016-02-02 17:47:28 -0700182 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600183 } else {
184#endif
185 pMemory = malloc(size);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600186 }
Mark Young0ad83132016-06-30 13:02:42 -0600187 return pMemory;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600188}
189
Mark Young0ad83132016-06-30 13:02:42 -0600190void loader_instance_heap_free(const struct loader_instance *instance,
191 void *pMemory) {
192 if (pMemory != NULL) {
193#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
194 {
195#else
196 if (instance && instance->alloc_callbacks.pfnFree) {
197 instance->alloc_callbacks.pfnFree(
198 instance->alloc_callbacks.pUserData, pMemory);
199 } else {
200#endif
201 free(pMemory);
Mark Youngd077f992016-06-30 11:03:59 -0600202 }
Mark Young4b0b9222016-06-29 18:33:53 -0600203 }
Mark Young4b0b9222016-06-29 18:33:53 -0600204}
205
Mark Young0ad83132016-06-30 13:02:42 -0600206void *loader_instance_heap_realloc(const struct loader_instance *instance,
207 void *pMemory, size_t orig_size, size_t size,
208 VkSystemAllocationScope alloc_scope) {
209 void *pNewMem = NULL;
210 if (pMemory == NULL || orig_size == 0) {
211 pNewMem = loader_instance_heap_alloc(instance, size, alloc_scope);
212 } else if (size == 0) {
213 loader_instance_heap_free(instance, pMemory);
214#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
215#else
216 } else if (instance && instance->alloc_callbacks.pfnReallocation) {
217 /* These are internal structures, so it's best to align everything to
218 * the largest unit size which is the size of a uint64_t.
219 */
220 pNewMem = instance->alloc_callbacks.pfnReallocation(
221 instance->alloc_callbacks.pUserData, pMemory, size,
222 sizeof(uint64_t), alloc_scope);
223#endif
224 } else {
225 pNewMem = realloc(pMemory, size);
226 }
227 return pNewMem;
Mark Young4b0b9222016-06-29 18:33:53 -0600228}
229
Mark Young0ad83132016-06-30 13:02:42 -0600230void *loader_instance_tls_heap_alloc(size_t size) {
231 return loader_instance_heap_alloc(tls_instance, size,
232 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young4b0b9222016-06-29 18:33:53 -0600233}
Mark Young4b0b9222016-06-29 18:33:53 -0600234
Mark Young0ad83132016-06-30 13:02:42 -0600235void loader_instance_tls_heap_free(void *pMemory) {
236 loader_instance_heap_free(tls_instance, pMemory);
237}
238
239void *loader_device_heap_alloc(const struct loader_device *device, size_t size,
240 VkSystemAllocationScope alloc_scope) {
241 void *pMemory = NULL;
242#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
243 {
244#else
245 if (device && device->alloc_callbacks.pfnAllocation) {
246 /* These are internal structures, so it's best to align everything to
247 * the largest unit size which is the size of a uint64_t.
248 */
249 pMemory = device->alloc_callbacks.pfnAllocation(
250 device->alloc_callbacks.pUserData, size, sizeof(uint64_t),
251 alloc_scope);
252 } else {
253#endif
254 pMemory = malloc(size);
255 }
256 return pMemory;
257}
258
259void loader_device_heap_free(const struct loader_device *device,
260 void *pMemory) {
261 if (pMemory != NULL) {
262#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
263 {
264#else
265 if (device && device->alloc_callbacks.pfnFree) {
266 device->alloc_callbacks.pfnFree(device->alloc_callbacks.pUserData,
267 pMemory);
268 } else {
269#endif
270 free(pMemory);
271 }
272 }
273}
274
275void *loader_device_heap_realloc(const struct loader_device *device,
276 void *pMemory, size_t orig_size, size_t size,
277 VkSystemAllocationScope alloc_scope) {
278 void *pNewMem = NULL;
279 if (pMemory == NULL || orig_size == 0) {
280 pNewMem = loader_device_heap_alloc(device, size, alloc_scope);
281 } else if (size == 0) {
282 loader_device_heap_free(device, pMemory);
283#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
284#else
285 } else if (device && device->alloc_callbacks.pfnReallocation) {
286 /* These are internal structures, so it's best to align everything to
287 * the largest unit size which is the size of a uint64_t.
288 */
289 pNewMem = device->alloc_callbacks.pfnReallocation(
290 device->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
291 alloc_scope);
292#endif
293 } else {
294 pNewMem = realloc(pMemory, size);
295 }
296 return pNewMem;
297}
298
299// Environment variables
300#if defined(__linux__)
301
302static inline char *loader_getenv(const char *name,
303 const struct loader_instance *inst) {
304 // No allocation of memory necessary for Linux, but we should at least touch
305 // the inst pointer to get rid of compiler warnings.
306 (void)inst;
307 return getenv(name);
308}
Frank Henigmanb1c27cb2016-11-24 20:02:09 -0500309static inline void loader_free_getenv(char *val,
Mark Young0ad83132016-06-30 13:02:42 -0600310 const struct loader_instance *inst) {
311 // No freeing of memory necessary for Linux, but we should at least touch
312 // the val and inst pointers to get rid of compiler warnings.
313 (void)val;
314 (void)inst;
315}
316
317#elif defined(WIN32)
318
319static inline char *loader_getenv(const char *name,
320 const struct loader_instance *inst) {
321 char *retVal;
322 DWORD valSize;
323
324 valSize = GetEnvironmentVariableA(name, NULL, 0);
325
326 // valSize DOES include the null terminator, so for any set variable
327 // will always be at least 1. If it's 0, the variable wasn't set.
328 if (valSize == 0)
329 return NULL;
330
331 // Allocate the space necessary for the registry entry
332 if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) {
333 retVal = (char *)inst->alloc_callbacks.pfnAllocation(
334 inst->alloc_callbacks.pUserData, valSize, sizeof(char *),
335 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
336 } else {
337 retVal = (char *)malloc(valSize);
338 }
339
340 if (NULL != retVal) {
341 GetEnvironmentVariableA(name, retVal, valSize);
342 }
343
344 return retVal;
345}
346
347static inline void loader_free_getenv(char *val,
348 const struct loader_instance *inst) {
349 if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) {
350 inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val);
351 } else {
352 free((void *)val);
353 }
354}
355
356#else
357
358static inline char *loader_getenv(const char *name,
Mark Young0153e0b2016-11-03 14:27:13 -0600359 const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600360 // stub func
361 (void)inst;
362 (void)name;
363 return NULL;
364}
Frank Henigmanb1c27cb2016-11-24 20:02:09 -0500365static inline void loader_free_getenv(char *val,
Mark Young0153e0b2016-11-03 14:27:13 -0600366 const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600367 // stub func
368 (void)val;
369 (void)inst;
370}
371
372#endif
373
Jon Ashburn2e37d752016-02-12 08:20:06 -0700374void loader_log(const struct loader_instance *inst, VkFlags msg_type,
Jon Ashburn1530c342016-02-26 13:14:27 -0700375 int32_t msg_code, const char *format, ...) {
Jon Ashburn86723b02015-07-31 15:47:59 -0600376 char msg[512];
Jon Ashburnffad94d2015-06-30 14:46:22 -0700377 va_list ap;
378 int ret;
379
Jon Ashburnffad94d2015-06-30 14:46:22 -0700380 va_start(ap, format);
381 ret = vsnprintf(msg, sizeof(msg), format, ap);
Jon Ashburn23d36b12016-02-02 17:47:28 -0700382 if ((ret >= (int)sizeof(msg)) || ret < 0) {
383 msg[sizeof(msg) - 1] = '\0';
Jon Ashburnffad94d2015-06-30 14:46:22 -0700384 }
385 va_end(ap);
386
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700387 if (inst) {
Karl Schultz94971292016-11-19 09:02:27 -0700388 util_DebugReportMessage(
389 inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
390 (uint64_t)(uintptr_t)inst, 0, msg_code, "loader", msg);
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700391 }
392
393 if (!(msg_type & g_loader_log_msgs)) {
394 return;
395 }
396
Ian Elliott4470a302015-02-17 10:33:47 -0700397#if defined(WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -0700398 OutputDebugString(msg);
mschottb9cdb782015-07-22 14:11:29 +0200399 OutputDebugString("\n");
Jon Ashburnffad94d2015-06-30 14:46:22 -0700400#endif
401 fputs(msg, stderr);
402 fputc('\n', stderr);
403}
404
Mark Young0153e0b2016-11-03 14:27:13 -0600405VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance,
406 void *object) {
Jon Ashburnc3c58772016-03-29 11:16:01 -0600407
408 struct loader_instance *inst = loader_get_instance(instance);
409 if (!inst) {
410 return VK_ERROR_INITIALIZATION_FAILED;
411 }
412 loader_set_dispatch(object, inst->disp);
413 return VK_SUCCESS;
414}
415
Mark Young0153e0b2016-11-03 14:27:13 -0600416VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device,
417 void *object) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600418 struct loader_device *dev;
Mark Young0153e0b2016-11-03 14:27:13 -0600419 struct loader_icd_term *icd_term =
420 loader_get_icd_and_device(device, &dev, NULL);
Jon Ashburned8f2312016-03-31 10:52:22 -0600421
Mark Young0153e0b2016-11-03 14:27:13 -0600422 if (NULL == icd_term) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600423 return VK_ERROR_INITIALIZATION_FAILED;
424 }
425 loader_set_dispatch(object, &dev->loader_dispatch);
426 return VK_SUCCESS;
427}
428
Jon Ashburnffad94d2015-06-30 14:46:22 -0700429#if defined(WIN32)
Tony Barbourea968902015-07-29 14:26:21 -0600430static char *loader_get_next_path(char *path);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700431/**
432* Find the list of registry files (names within a key) in key "location".
433*
Jon Ashburn23d36b12016-02-02 17:47:28 -0700434* This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
435*given in "location"
436* for a list or name/values which are added to a returned list (function return
437*value).
Jon Ashburnffad94d2015-06-30 14:46:22 -0700438* The DWORD values within the key must be 0 or they are skipped.
Jon Ashburne39a4f82015-08-28 13:38:21 -0600439* Function return is a string with a ';' separated list of filenames.
Jon Ashburnffad94d2015-06-30 14:46:22 -0700440* Function return is NULL if no valid name/value pairs are found in the key,
441* or the key is not found.
442*
443* \returns
444* A string list of filenames as pointer.
445* When done using the returned string list, pointer should be freed.
446*/
Jon Ashburn23d36b12016-02-02 17:47:28 -0700447static char *loader_get_registry_files(const struct loader_instance *inst,
448 char *location) {
Jon Ashburnffad94d2015-06-30 14:46:22 -0700449 LONG rtn_value;
450 HKEY hive, key;
Piers Daniell524ec732015-11-05 16:58:26 -0700451 DWORD access_flags;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700452 char name[2048];
453 char *out = NULL;
Tony Barbourea968902015-07-29 14:26:21 -0600454 char *loc = location;
455 char *next;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700456 DWORD idx = 0;
457 DWORD name_size = sizeof(name);
458 DWORD value;
459 DWORD total_size = 4096;
460 DWORD value_size = sizeof(value);
Tony Barbourea968902015-07-29 14:26:21 -0600461
Jon Ashburn23d36b12016-02-02 17:47:28 -0700462 while (*loc) {
Tony Barbourea968902015-07-29 14:26:21 -0600463 next = loader_get_next_path(loc);
464 hive = DEFAULT_VK_REGISTRY_HIVE;
Piers Daniell524ec732015-11-05 16:58:26 -0700465 access_flags = KEY_QUERY_VALUE;
Tony Barbourea968902015-07-29 14:26:21 -0600466 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
467 if (rtn_value != ERROR_SUCCESS) {
Mark Young93ecb1d2016-01-13 13:47:16 -0700468 // We still couldn't find the key, so give up:
469 loc = next;
470 continue;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700471 }
Tony Barbourea968902015-07-29 14:26:21 -0600472
Jon Ashburn23d36b12016-02-02 17:47:28 -0700473 while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL,
474 NULL, (LPBYTE)&value, &value_size)) ==
475 ERROR_SUCCESS) {
Tony Barbourea968902015-07-29 14:26:21 -0600476 if (value_size == sizeof(value) && value == 0) {
477 if (out == NULL) {
Mark Young0ad83132016-06-30 13:02:42 -0600478 out = loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700479 inst, total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -0600480 if (NULL == out) {
481 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young0153e0b2016-11-03 14:27:13 -0600482 "Out of memory can't alloc space for "
483 "registry data");
Mark Young0ad83132016-06-30 13:02:42 -0600484 return NULL;
485 }
Tony Barbourea968902015-07-29 14:26:21 -0600486 out[0] = '\0';
Jon Ashburn23d36b12016-02-02 17:47:28 -0700487 } else if (strlen(out) + name_size + 1 > total_size) {
Mark Young0ad83132016-06-30 13:02:42 -0600488 out = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700489 inst, out, total_size, total_size * 2,
490 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -0600491 if (NULL == out) {
492 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young0153e0b2016-11-03 14:27:13 -0600493 "Out of memory can't realloc space for "
494 "registry data");
Mark Young0ad83132016-06-30 13:02:42 -0600495 return NULL;
496 }
Tony Barbourea968902015-07-29 14:26:21 -0600497 total_size *= 2;
498 }
Tony Barbourea968902015-07-29 14:26:21 -0600499 if (strlen(out) == 0)
Jon Ashburn23d36b12016-02-02 17:47:28 -0700500 snprintf(out, name_size + 1, "%s", name);
Tony Barbourea968902015-07-29 14:26:21 -0600501 else
Jon Ashburn23d36b12016-02-02 17:47:28 -0700502 snprintf(out + strlen(out), name_size + 2, "%c%s",
Frank Henigman57173102016-11-24 22:15:20 -0500503 PATH_SEPARATOR, name);
Tony Barbourea968902015-07-29 14:26:21 -0600504 }
505 name_size = 2048;
506 }
507 loc = next;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700508 }
Tony Barbourea968902015-07-29 14:26:21 -0600509
Jon Ashburnffad94d2015-06-30 14:46:22 -0700510 return out;
511}
512
Ian Elliott4470a302015-02-17 10:33:47 -0700513#endif // WIN32
514
Jon Ashburnc7237a72015-08-03 09:08:46 -0600515/**
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500516 * Combine path elements, separating each element with the platform-specific
517 * directory separator, and save the combined string to a destination buffer,
518 * not exceeding the given length. Path elements are given as variadic args,
519 * with a NULL element terminating the list.
520 *
521 * \returns the total length of the combined string, not including an ASCII
522 * NUL termination character. This length may exceed the available storage:
523 * in this case, the written string will be truncated to avoid a buffer
524 * overrun, and the return value will greater than or equal to the storage
525 * size. A NULL argument may be provided as the destination buffer in order
526 * to determine the required string length without actually writing a string.
527 */
528
Jon Ashburn23d36b12016-02-02 17:47:28 -0700529static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -0700530 size_t required_len = 0;
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500531 va_list ap;
532 const char *component;
533
534 va_start(ap, len);
535
Jon Ashburn23d36b12016-02-02 17:47:28 -0700536 while ((component = va_arg(ap, const char *))) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500537 if (required_len > 0) {
538 // This path element is not the first non-empty element; prepend
539 // a directory separator if space allows
540 if (dest && required_len + 1 < len) {
541 snprintf(dest + required_len, len - required_len, "%c",
542 DIRECTORY_SYMBOL);
543 }
544 required_len++;
545 }
546
547 if (dest && required_len < len) {
548 strncpy(dest + required_len, component, len - required_len);
549 }
550 required_len += strlen(component);
551 }
552
553 va_end(ap);
554
555 // strncpy(3) won't add a NUL terminating byte in the event of truncation.
556 if (dest && required_len >= len) {
557 dest[len - 1] = '\0';
558 }
559
560 return required_len;
561}
562
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500563/**
Jon Ashburnc7237a72015-08-03 09:08:46 -0600564 * Given string of three part form "maj.min.pat" convert to a vulkan version
565 * number.
566 */
Mark Young60861ac2016-09-02 11:39:26 -0600567static uint32_t loader_make_version(char *vers_str) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700568 uint32_t vers = 0, major = 0, minor = 0, patch = 0;
Mark Young60861ac2016-09-02 11:39:26 -0600569 char *vers_tok;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600570
Mark Young60861ac2016-09-02 11:39:26 -0600571 if (!vers_str) {
Jon Ashburnc7237a72015-08-03 09:08:46 -0600572 return vers;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600573 }
Mark Young60861ac2016-09-02 11:39:26 -0600574
575 vers_tok = strtok(vers_str, ".\"\n\r");
576 if (NULL != vers_tok) {
577 major = (uint16_t)atoi(vers_tok);
578 vers_tok = strtok(NULL, ".\"\n\r");
579 if (NULL != vers_tok) {
580 minor = (uint16_t)atoi(vers_tok);
581 vers_tok = strtok(NULL, ".\"\n\r");
582 if (NULL != vers_tok) {
583 patch = (uint16_t)atoi(vers_tok);
584 }
585 }
586 }
Jon Ashburnc7237a72015-08-03 09:08:46 -0600587
588 return VK_MAKE_VERSION(major, minor, patch);
Jon Ashburnc7237a72015-08-03 09:08:46 -0600589}
590
Jon Ashburn23d36b12016-02-02 17:47:28 -0700591bool compare_vk_extension_properties(const VkExtensionProperties *op1,
592 const VkExtensionProperties *op2) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800593 return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600594}
595
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600596/**
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600597 * Search the given ext_array for an extension
598 * matching the given vk_ext_prop
599 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700600bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop,
601 const uint32_t count,
602 const VkExtensionProperties *ext_array) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600603 for (uint32_t i = 0; i < count; i++) {
604 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
605 return true;
606 }
607 return false;
608}
609
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600610/**
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600611 * Search the given ext_list for an extension
612 * matching the given vk_ext_prop
613 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700614bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop,
615 const struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600616 for (uint32_t i = 0; i < ext_list->count; i++) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600617 if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600618 return true;
619 }
620 return false;
621}
622
Jon Ashburnb8726962016-04-08 15:03:35 -0600623/**
624 * Search the given ext_list for a device extension matching the given ext_prop
625 */
Jon Ashburncc407a22016-04-15 09:25:03 -0600626bool has_vk_dev_ext_property(
627 const VkExtensionProperties *ext_prop,
628 const struct loader_device_extension_list *ext_list) {
Jon Ashburnb8726962016-04-08 15:03:35 -0600629 for (uint32_t i = 0; i < ext_list->count; i++) {
630 if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop))
631 return true;
632 }
633 return false;
634}
635
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600636/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600637 * Search the given layer list for a layer matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600638 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700639static struct loader_layer_properties *
640loader_get_layer_property(const char *name,
641 const struct loader_layer_list *layer_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600642 for (uint32_t i = 0; i < layer_list->count; i++) {
643 const VkLayerProperties *item = &layer_list->list[i].info;
644 if (strcmp(name, item->layerName) == 0)
645 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600646 }
647 return NULL;
648}
649
Jon Ashburne13ecc92015-08-03 17:19:30 -0600650/**
651 * Get the next unused layer property in the list. Init the property to zero.
652 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700653static struct loader_layer_properties *
654loader_get_next_layer_property(const struct loader_instance *inst,
655 struct loader_layer_list *layer_list) {
Jon Ashburne13ecc92015-08-03 17:19:30 -0600656 if (layer_list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -0600657 layer_list->list = loader_instance_heap_alloc(
658 inst, sizeof(struct loader_layer_properties) * 64,
659 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600660 if (layer_list->list == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700661 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
662 "Out of memory can't add any layer properties to list");
Jon Ashburne13ecc92015-08-03 17:19:30 -0600663 return NULL;
664 }
Jon Ashburn23d36b12016-02-02 17:47:28 -0700665 memset(layer_list->list, 0,
666 sizeof(struct loader_layer_properties) * 64);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600667 layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
668 }
669
670 // ensure enough room to add an entry
Jon Ashburn23d36b12016-02-02 17:47:28 -0700671 if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) >
672 layer_list->capacity) {
Mark Young0ad83132016-06-30 13:02:42 -0600673 layer_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700674 inst, layer_list->list, layer_list->capacity,
675 layer_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600676 if (layer_list->list == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -0700677 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700678 "realloc failed for layer list");
Mark Young0ad83132016-06-30 13:02:42 -0600679 return NULL;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600680 }
681 layer_list->capacity *= 2;
682 }
683
684 layer_list->count++;
685 return &(layer_list->list[layer_list->count - 1]);
686}
687
688/**
689 * Remove all layer properties entrys from the list
690 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700691void loader_delete_layer_properties(const struct loader_instance *inst,
692 struct loader_layer_list *layer_list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700693 uint32_t i, j;
694 struct loader_device_extension_list *dev_ext_list;
Jon Ashburnb82c1852015-08-11 14:49:54 -0600695 if (!layer_list)
696 return;
697
Jon Ashburne13ecc92015-08-03 17:19:30 -0600698 for (i = 0; i < layer_list->count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700699 loader_destroy_generic_list(
700 inst, (struct loader_generic_list *)&layer_list->list[i]
701 .instance_extension_list);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700702 dev_ext_list = &layer_list->list[i].device_extension_list;
Mark Young0153e0b2016-11-03 14:27:13 -0600703 if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list &&
Jon Ashburn23d36b12016-02-02 17:47:28 -0700704 dev_ext_list->list->entrypoint_count > 0) {
705 for (j = 0; j < dev_ext_list->list->entrypoint_count; j++) {
Mark Young0153e0b2016-11-03 14:27:13 -0600706 loader_instance_heap_free(inst,
707 dev_ext_list->list->entrypoints[j]);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700708 }
Mark Young0ad83132016-06-30 13:02:42 -0600709 loader_instance_heap_free(inst, dev_ext_list->list->entrypoints);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700710 }
Jon Ashburn23d36b12016-02-02 17:47:28 -0700711 loader_destroy_generic_list(inst,
712 (struct loader_generic_list *)dev_ext_list);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600713 }
714 layer_list->count = 0;
715
Jon Ashburnb82c1852015-08-11 14:49:54 -0600716 if (layer_list->capacity > 0) {
717 layer_list->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -0600718 loader_instance_heap_free(inst, layer_list->list);
Jon Ashburnb82c1852015-08-11 14:49:54 -0600719 }
Jon Ashburne13ecc92015-08-03 17:19:30 -0600720}
721
Mark Young3a587792016-08-19 15:25:08 -0600722static VkResult loader_add_instance_extensions(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700723 const struct loader_instance *inst,
724 const PFN_vkEnumerateInstanceExtensionProperties fp_get_props,
725 const char *lib_name, struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -0700726 uint32_t i, count = 0;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600727 VkExtensionProperties *ext_props;
Mark Young3a587792016-08-19 15:25:08 -0600728 VkResult res = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600729
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600730 if (!fp_get_props) {
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -0600731 /* No EnumerateInstanceExtensionProperties defined */
Mark Young3a587792016-08-19 15:25:08 -0600732 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600733 }
734
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600735 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600736 if (res != VK_SUCCESS) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -0700737 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700738 "Error getting Instance extension count from %s", lib_name);
Mark Young3a587792016-08-19 15:25:08 -0600739 goto out;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600740 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600741
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600742 if (count == 0) {
743 /* No ExtensionProperties to report */
Mark Young3a587792016-08-19 15:25:08 -0600744 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600745 }
746
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600747 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600748
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600749 res = fp_get_props(NULL, &count, ext_props);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600750 if (res != VK_SUCCESS) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -0700751 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700752 "Error getting Instance extensions from %s", lib_name);
Mark Young3a587792016-08-19 15:25:08 -0600753 goto out;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600754 }
Tony Barbour59a47322015-06-24 16:06:58 -0600755
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600756 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600757 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600758
Jon Ashburncc407a22016-04-15 09:25:03 -0600759 bool ext_unsupported =
760 wsi_unsupported_instance_extension(&ext_props[i]);
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600761 if (!ext_unsupported) {
762 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
763 VK_MAJOR(ext_props[i].specVersion),
764 VK_MINOR(ext_props[i].specVersion),
765 VK_PATCH(ext_props[i].specVersion));
766 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
767 "Instance Extension: %s (%s) version %s",
768 ext_props[i].extensionName, lib_name, spec_version);
Mark Young3a587792016-08-19 15:25:08 -0600769 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
770 if (res != VK_SUCCESS) {
771 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
772 "Failed to add %s to Instance extension list",
773 lib_name);
774 goto out;
775 }
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600776 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600777 }
Mark Young3a587792016-08-19 15:25:08 -0600778out:
779 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600780}
781
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700782/*
783 * Initialize ext_list with the physical device extensions.
784 * The extension properties are passed as inputs in count and ext_props.
785 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700786static VkResult
787loader_init_device_extensions(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -0600788 struct loader_physical_device_term *phys_dev_term,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700789 uint32_t count, VkExtensionProperties *ext_props,
790 struct loader_extension_list *ext_list) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700791 VkResult res;
792 uint32_t i;
793
Mark Young3a587792016-08-19 15:25:08 -0600794 res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list,
795 sizeof(VkExtensionProperties));
796 if (VK_SUCCESS != res) {
797 return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700798 }
799
800 for (i = 0; i < count; i++) {
801 char spec_version[64];
802
Jon Ashburn23d36b12016-02-02 17:47:28 -0700803 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
804 VK_MAJOR(ext_props[i].specVersion),
805 VK_MINOR(ext_props[i].specVersion),
806 VK_PATCH(ext_props[i].specVersion));
Mark Young0153e0b2016-11-03 14:27:13 -0600807 loader_log(
808 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
809 "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
810 phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700811 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
812 if (res != VK_SUCCESS)
813 return res;
814 }
815
816 return VK_SUCCESS;
817}
818
Jon Ashburn1530c342016-02-26 13:14:27 -0700819VkResult loader_add_device_extensions(const struct loader_instance *inst,
Jon Ashburncc407a22016-04-15 09:25:03 -0600820 PFN_vkEnumerateDeviceExtensionProperties
821 fpEnumerateDeviceExtensionProperties,
Jon Ashburn1530c342016-02-26 13:14:27 -0700822 VkPhysicalDevice physical_device,
823 const char *lib_name,
824 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600825 uint32_t i, count;
826 VkResult res;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600827 VkExtensionProperties *ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600828
Piers Daniell295fe402016-03-29 11:51:11 -0600829 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count,
830 NULL);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700831 if (res == VK_SUCCESS && count > 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700832 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young9a3ddd42016-10-21 16:25:47 -0600833 if (!ext_props) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700834 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young9a3ddd42016-10-21 16:25:47 -0600835 }
Piers Daniell295fe402016-03-29 11:51:11 -0600836 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL,
837 &count, ext_props);
Mark Young9a3ddd42016-10-21 16:25:47 -0600838 if (res != VK_SUCCESS) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700839 return res;
Mark Young9a3ddd42016-10-21 16:25:47 -0600840 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700841 for (i = 0; i < count; i++) {
842 char spec_version[64];
843
Jon Ashburn23d36b12016-02-02 17:47:28 -0700844 snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
845 VK_MAJOR(ext_props[i].specVersion),
846 VK_MINOR(ext_props[i].specVersion),
847 VK_PATCH(ext_props[i].specVersion));
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -0700848 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700849 "Device Extension: %s (%s) version %s",
850 ext_props[i].extensionName, lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700851 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
852 if (res != VK_SUCCESS)
853 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600854 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700855 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700856 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
857 "Error getting physical device extension info count from "
858 "library %s",
859 lib_name);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700860 return res;
861 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600862
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700863 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600864}
865
Mark Young3a587792016-08-19 15:25:08 -0600866VkResult loader_init_generic_list(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -0600867 struct loader_generic_list *list_info,
868 size_t element_size) {
Mark Young84ba0482016-09-02 11:45:00 -0600869 size_t capacity = 32 * element_size;
870 list_info->count = 0;
871 list_info->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -0600872 list_info->list = loader_instance_heap_alloc(
Mark Young84ba0482016-09-02 11:45:00 -0600873 inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700874 if (list_info->list == NULL) {
Mark Young3a587792016-08-19 15:25:08 -0600875 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600876 }
Mark Young84ba0482016-09-02 11:45:00 -0600877 memset(list_info->list, 0, capacity);
878 list_info->capacity = capacity;
Mark Young3a587792016-08-19 15:25:08 -0600879 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600880}
881
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700882void loader_destroy_generic_list(const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700883 struct loader_generic_list *list) {
Mark Young0ad83132016-06-30 13:02:42 -0600884 loader_instance_heap_free(inst, list->list);
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700885 list->count = 0;
886 list->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600887}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600888
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600889/*
890 * Append non-duplicate extension properties defined in props
891 * to the given ext_list.
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700892 * Return
893 * Vk_SUCCESS on success
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600894 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700895VkResult loader_add_to_ext_list(const struct loader_instance *inst,
896 struct loader_extension_list *ext_list,
897 uint32_t prop_list_count,
898 const VkExtensionProperties *props) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600899 uint32_t i;
900 const VkExtensionProperties *cur_ext;
901
902 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -0600903 VkResult res = loader_init_generic_list(
904 inst, (struct loader_generic_list *)ext_list,
905 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -0600906 if (VK_SUCCESS != res) {
907 return res;
908 }
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600909 }
910
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600911 for (i = 0; i < prop_list_count; i++) {
912 cur_ext = &props[i];
913
914 // look for duplicates
915 if (has_vk_extension_property(cur_ext, ext_list)) {
916 continue;
917 }
918
919 // add to list at end
920 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -0700921 if (ext_list->count * sizeof(VkExtensionProperties) >=
922 ext_list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -0600923
Mark Young0ad83132016-06-30 13:02:42 -0600924 ext_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700925 inst, ext_list->list, ext_list->capacity,
926 ext_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700927
928 if (ext_list->list == NULL)
929 return VK_ERROR_OUT_OF_HOST_MEMORY;
930
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600931 // double capacity
932 ext_list->capacity *= 2;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600933 }
934
Jon Ashburn23d36b12016-02-02 17:47:28 -0700935 memcpy(&ext_list->list[ext_list->count], cur_ext,
936 sizeof(VkExtensionProperties));
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600937 ext_list->count++;
938 }
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700939 return VK_SUCCESS;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600940}
941
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700942/*
943 * Append one extension property defined in props with entrypoints
Jon Ashburnb8726962016-04-08 15:03:35 -0600944 * defined in entrys to the given ext_list. Do not append if a duplicate
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700945 * Return
946 * Vk_SUCCESS on success
947 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700948VkResult
949loader_add_to_dev_ext_list(const struct loader_instance *inst,
950 struct loader_device_extension_list *ext_list,
951 const VkExtensionProperties *props,
952 uint32_t entry_count, char **entrys) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700953 uint32_t idx;
954 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Young3a587792016-08-19 15:25:08 -0600955 VkResult res = loader_init_generic_list(
956 inst, (struct loader_generic_list *)ext_list,
957 sizeof(struct loader_dev_ext_props));
958 if (VK_SUCCESS != res) {
959 return res;
960 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700961 }
962
Jon Ashburnb8726962016-04-08 15:03:35 -0600963 // look for duplicates
964 if (has_vk_dev_ext_property(props, ext_list)) {
965 return VK_SUCCESS;
966 }
967
Jon Ashburn23d36b12016-02-02 17:47:28 -0700968 idx = ext_list->count;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700969 // add to list at end
970 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -0700971 if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700972
Mark Young0ad83132016-06-30 13:02:42 -0600973 ext_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700974 inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
975 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700976
977 if (ext_list->list == NULL)
978 return VK_ERROR_OUT_OF_HOST_MEMORY;
979
980 // double capacity
981 ext_list->capacity *= 2;
982 }
983
Jon Ashburn23d36b12016-02-02 17:47:28 -0700984 memcpy(&ext_list->list[idx].props, props,
985 sizeof(struct loader_dev_ext_props));
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700986 ext_list->list[idx].entrypoint_count = entry_count;
Jon Ashburn23d36b12016-02-02 17:47:28 -0700987 ext_list->list[idx].entrypoints =
Mark Young0ad83132016-06-30 13:02:42 -0600988 loader_instance_heap_alloc(inst, sizeof(char *) * entry_count,
989 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
990 if (ext_list->list[idx].entrypoints == NULL) {
991 ext_list->list[idx].entrypoint_count = 0;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700992 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -0600993 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700994 for (uint32_t i = 0; i < entry_count; i++) {
Mark Young0ad83132016-06-30 13:02:42 -0600995 ext_list->list[idx].entrypoints[i] = loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700996 inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -0600997 if (ext_list->list[idx].entrypoints[i] == NULL) {
998 for (uint32_t j = 0; j < i; j++) {
999 loader_instance_heap_free(inst,
1000 ext_list->list[idx].entrypoints[j]);
1001 }
1002 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints);
1003 ext_list->list[idx].entrypoint_count = 0;
1004 ext_list->list[idx].entrypoints = NULL;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001005 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001006 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001007 strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
1008 }
1009 ext_list->count++;
1010
1011 return VK_SUCCESS;
1012}
1013
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001014/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001015 * Search the given search_list for any layers in the props list.
Jon Ashburn23d36b12016-02-02 17:47:28 -07001016 * Add these to the output layer_list. Don't add duplicates to the output
1017 * layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001018 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001019static VkResult
1020loader_add_layer_names_to_list(const struct loader_instance *inst,
1021 struct loader_layer_list *output_list,
1022 uint32_t name_count, const char *const *names,
1023 const struct loader_layer_list *search_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001024 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001025 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001026
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001027 for (uint32_t i = 0; i < name_count; i++) {
1028 const char *search_target = names[i];
Jon Ashburne13ecc92015-08-03 17:19:30 -06001029 layer_prop = loader_get_layer_property(search_target, search_list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001030 if (!layer_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001031 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1032 "Unable to find layer %s", search_target);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06001033 err = VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001034 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001035 }
1036
Mark Young0ad83132016-06-30 13:02:42 -06001037 err = loader_add_to_layer_list(inst, output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001038 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001039
1040 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001041}
1042
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001043/*
1044 * Manage lists of VkLayerProperties
1045 */
Jon Ashburne39a4f82015-08-28 13:38:21 -06001046static bool loader_init_layer_list(const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001047 struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001048 list->capacity = 32 * sizeof(struct loader_layer_properties);
Mark Young0ad83132016-06-30 13:02:42 -06001049 list->list = loader_instance_heap_alloc(
1050 inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001051 if (list->list == NULL) {
1052 return false;
1053 }
1054 memset(list->list, 0, list->capacity);
1055 list->count = 0;
1056 return true;
1057}
1058
Jon Ashburne39a4f82015-08-28 13:38:21 -06001059void loader_destroy_layer_list(const struct loader_instance *inst,
Mark Young0ad83132016-06-30 13:02:42 -06001060 struct loader_device *device,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001061 struct loader_layer_list *layer_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001062 if (device) {
1063 loader_device_heap_free(device, layer_list->list);
1064 } else {
1065 loader_instance_heap_free(inst, layer_list->list);
1066 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001067 layer_list->count = 0;
1068 layer_list->capacity = 0;
1069}
1070
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001071/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001072 * Search the given layer list for a list
1073 * matching the given VkLayerProperties
1074 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001075bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop,
1076 const struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001077 for (uint32_t i = 0; i < list->count; i++) {
1078 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
1079 return true;
1080 }
1081 return false;
1082}
1083
1084/*
1085 * Search the given layer list for a layer
1086 * matching the given name
1087 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001088bool has_layer_name(const char *name, const struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001089 for (uint32_t i = 0; i < list->count; i++) {
1090 if (strcmp(name, list->list[i].info.layerName) == 0)
1091 return true;
1092 }
1093 return false;
1094}
1095
1096/*
1097 * Append non-duplicate layer properties defined in prop_list
1098 * to the given layer_info list
1099 */
Mark Young0ad83132016-06-30 13:02:42 -06001100VkResult loader_add_to_layer_list(const struct loader_instance *inst,
1101 struct loader_layer_list *list,
1102 uint32_t prop_list_count,
1103 const struct loader_layer_properties *props) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001104 uint32_t i;
1105 struct loader_layer_properties *layer;
1106
1107 if (list->list == NULL || list->capacity == 0) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001108 loader_init_layer_list(inst, list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001109 }
1110
1111 if (list->list == NULL)
Mark Young0ad83132016-06-30 13:02:42 -06001112 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001113
1114 for (i = 0; i < prop_list_count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001115 layer = (struct loader_layer_properties *)&props[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001116
1117 // look for duplicates
1118 if (has_vk_layer_property(&layer->info, list)) {
1119 continue;
1120 }
1121
1122 // add to list at end
1123 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001124 if (list->count * sizeof(struct loader_layer_properties) >=
1125 list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001126
Mark Young0ad83132016-06-30 13:02:42 -06001127 list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001128 inst, list->list, list->capacity, list->capacity * 2,
1129 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06001130 if (NULL == list->list) {
1131 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1132 "realloc failed for layer list when attempting to "
1133 "add new layer");
1134 return VK_ERROR_OUT_OF_HOST_MEMORY;
1135 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001136 // double capacity
1137 list->capacity *= 2;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001138 }
1139
Jon Ashburn23d36b12016-02-02 17:47:28 -07001140 memcpy(&list->list[list->count], layer,
1141 sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001142 list->count++;
1143 }
Mark Young0ad83132016-06-30 13:02:42 -06001144
1145 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001146}
1147
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001148/**
1149 * Search the search_list for any layer with a name
1150 * that matches the given name and a type that matches the given type
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001151 * Add all matching layers to the found_list
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001152 * Do not add if found loader_layer_properties is already
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001153 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001154 */
Jon Ashburncc407a22016-04-15 09:25:03 -06001155void loader_find_layer_name_add_list(
1156 const struct loader_instance *inst, const char *name,
1157 const enum layer_type type, const struct loader_layer_list *search_list,
1158 struct loader_layer_list *found_list) {
Jon Ashburn56151d62015-10-05 09:03:21 -06001159 bool found = false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001160 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001161 struct loader_layer_properties *layer_prop = &search_list->list[i];
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001162 if (0 == strcmp(layer_prop->info.layerName, name) &&
Jon Ashburn23d36b12016-02-02 17:47:28 -07001163 (layer_prop->type & type)) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001164 /* Found a layer with the same name, add to found_list */
Mark Young0153e0b2016-11-03 14:27:13 -06001165 if (VK_SUCCESS ==
1166 loader_add_to_layer_list(inst, found_list, 1, layer_prop)) {
Mark Young0ad83132016-06-30 13:02:42 -06001167 found = true;
1168 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001169 }
1170 }
Jon Ashburn56151d62015-10-05 09:03:21 -06001171 if (!found) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001172 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001173 "Warning, couldn't find layer name %s to activate", name);
Jon Ashburn56151d62015-10-05 09:03:21 -06001174 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001175}
1176
Jon Ashburn23d36b12016-02-02 17:47:28 -07001177static VkExtensionProperties *
1178get_extension_property(const char *name,
1179 const struct loader_extension_list *list) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001180 for (uint32_t i = 0; i < list->count; i++) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +08001181 if (strcmp(name, list->list[i].extensionName) == 0)
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001182 return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001183 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001184 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001185}
1186
Jon Ashburn23d36b12016-02-02 17:47:28 -07001187static VkExtensionProperties *
1188get_dev_extension_property(const char *name,
1189 const struct loader_device_extension_list *list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001190 for (uint32_t i = 0; i < list->count; i++) {
1191 if (strcmp(name, list->list[i].props.extensionName) == 0)
1192 return &list->list[i].props;
1193 }
1194 return NULL;
1195}
1196
Courtney Goeltzenleuchterb39ccd52016-01-15 14:15:00 -07001197/*
Courtney Goeltzenleuchterf538ef72015-12-02 14:00:19 -07001198 * For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001199 * the extension must provide two entry points for the loader to use:
1200 * - "trampoline" entry point - this is the address returned by GetProcAddr
1201 * and will always do what's necessary to support a global call.
1202 * - "terminator" function - this function will be put at the end of the
Jon Ashburn232e3af2015-11-30 17:21:25 -07001203 * instance chain and will contain the necessary logic to call / process
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001204 * the extension for the appropriate ICDs that are available.
1205 * There is no generic mechanism for including these functions, the references
1206 * must be placed into the appropriate loader entry points.
Jon Ashburn23d36b12016-02-02 17:47:28 -07001207 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for
1208 * GetProcAddr requests
1209 * loader_coalesce_extensions(void) - add extension records to the list of
1210 * global
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001211 * extension available to the app.
1212 * instance_disp - add function pointer for terminator function to this array.
1213 * The extension itself should be in a separate file that will be
1214 * linked directly with the loader.
1215 */
Jon Ashburn9a4c6aa2015-08-14 11:57:54 -06001216
Mark Young3a587792016-08-19 15:25:08 -06001217VkResult loader_get_icd_loader_instance_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06001218 const struct loader_instance *inst,
1219 struct loader_icd_tramp_list *icd_tramp_list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001220 struct loader_extension_list *inst_exts) {
Jon Ashburn5c6a46f2015-08-14 14:49:22 -06001221 struct loader_extension_list icd_exts;
Mark Young3a587792016-08-19 15:25:08 -06001222 VkResult res = VK_SUCCESS;
1223
Jon Ashburn23d36b12016-02-02 17:47:28 -07001224 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
1225 "Build ICD instance extension list");
Mark Young3a587792016-08-19 15:25:08 -06001226
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001227 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001228 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
Mark Young3a587792016-08-19 15:25:08 -06001229 res = loader_init_generic_list(inst,
1230 (struct loader_generic_list *)&icd_exts,
1231 sizeof(VkExtensionProperties));
1232 if (VK_SUCCESS != res) {
1233 goto out;
1234 }
1235 res = loader_add_instance_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06001236 inst, icd_tramp_list->scanned_list[i]
1237 .EnumerateInstanceExtensionProperties,
1238 icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001239 if (VK_SUCCESS == res) {
1240 res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count,
1241 icd_exts.list);
1242 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001243 loader_destroy_generic_list(inst,
1244 (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001245 if (VK_SUCCESS != res) {
1246 goto out;
1247 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001248 };
1249
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001250 // Traverse loader's extensions, adding non-duplicate extensions to the list
Jon Ashburne39a4f82015-08-28 13:38:21 -06001251 debug_report_add_instance_extensions(inst, inst_exts);
Mark Young3a587792016-08-19 15:25:08 -06001252
1253out:
1254 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001255}
1256
Mark Young0153e0b2016-11-03 14:27:13 -06001257struct loader_icd_term *
1258loader_get_icd_and_device(const VkDevice device,
1259 struct loader_device **found_dev,
1260 uint32_t *icd_index) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001261 *found_dev = NULL;
Mark Young16573c72016-06-28 10:52:43 -06001262 uint32_t index = 0;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001263 for (struct loader_instance *inst = loader.instances; inst;
1264 inst = inst->next) {
Mark Young0153e0b2016-11-03 14:27:13 -06001265 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term;
1266 icd_term = icd_term->next) {
1267 for (struct loader_device *dev = icd_term->logical_device_list; dev;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001268 dev = dev->next)
Mark Young65cb3662016-11-07 13:27:02 -07001269 // Value comparison of device prevents object wrapping by layers
1270 if (loader_get_dispatch(dev->icd_device) ==
1271 loader_get_dispatch(device) ||
1272 loader_get_dispatch(dev->chain_device) ==
Jon Ashburn23d36b12016-02-02 17:47:28 -07001273 loader_get_dispatch(device)) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001274 *found_dev = dev;
Mark Young16573c72016-06-28 10:52:43 -06001275 if (NULL != icd_index) {
1276 *icd_index = index;
1277 }
Mark Young0153e0b2016-11-03 14:27:13 -06001278 return icd_term;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001279 }
Mark Young16573c72016-06-28 10:52:43 -06001280 index++;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001281 }
1282 }
1283 return NULL;
1284}
1285
Mark Young0ad83132016-06-30 13:02:42 -06001286void loader_destroy_logical_device(const struct loader_instance *inst,
1287 struct loader_device *dev,
1288 const VkAllocationCallbacks *pAllocator) {
1289 if (pAllocator) {
1290 dev->alloc_callbacks = *pAllocator;
1291 }
Mark Young0ad83132016-06-30 13:02:42 -06001292 if (NULL != dev->activated_layer_list.list) {
1293 loader_deactivate_layers(inst, dev, &dev->activated_layer_list);
1294 }
1295 loader_device_heap_free(dev, dev);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001296}
1297
Jon Ashburn1530c342016-02-26 13:14:27 -07001298struct loader_device *
Mark Young0ad83132016-06-30 13:02:42 -06001299loader_create_logical_device(const struct loader_instance *inst,
1300 const VkAllocationCallbacks *pAllocator) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001301 struct loader_device *new_dev;
Mark Young0ad83132016-06-30 13:02:42 -06001302#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
1303 {
1304#else
1305 if (pAllocator) {
1306 new_dev = (struct loader_device *)pAllocator->pfnAllocation(
1307 pAllocator->pUserData, sizeof(struct loader_device), sizeof(int *),
1308 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1309 } else {
1310#endif
1311 new_dev = (struct loader_device *)malloc(sizeof(struct loader_device));
1312 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001313
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001314 if (!new_dev) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001315 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1316 "Failed to alloc struct loader-device");
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001317 return NULL;
1318 }
1319
1320 memset(new_dev, 0, sizeof(struct loader_device));
Mark Young0ad83132016-06-30 13:02:42 -06001321 if (pAllocator) {
1322 new_dev->alloc_callbacks = *pAllocator;
1323 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001324
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001325 return new_dev;
1326}
1327
Piers Daniell295fe402016-03-29 11:51:11 -06001328void loader_add_logical_device(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001329 struct loader_icd_term *icd_term,
Piers Daniell295fe402016-03-29 11:51:11 -06001330 struct loader_device *dev) {
Mark Young0153e0b2016-11-03 14:27:13 -06001331 dev->next = icd_term->logical_device_list;
1332 icd_term->logical_device_list = dev;
Piers Daniell295fe402016-03-29 11:51:11 -06001333}
1334
Jon Ashburn23d36b12016-02-02 17:47:28 -07001335void loader_remove_logical_device(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001336 struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001337 struct loader_device *found_dev,
1338 const VkAllocationCallbacks *pAllocator) {
Jon Ashburn781a7ae2015-11-19 15:43:26 -07001339 struct loader_device *dev, *prev_dev;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001340
Mark Young0153e0b2016-11-03 14:27:13 -06001341 if (!icd_term || !found_dev)
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001342 return;
1343
1344 prev_dev = NULL;
Mark Young0153e0b2016-11-03 14:27:13 -06001345 dev = icd_term->logical_device_list;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001346 while (dev && dev != found_dev) {
1347 prev_dev = dev;
1348 dev = dev->next;
1349 }
1350
1351 if (prev_dev)
1352 prev_dev->next = found_dev->next;
1353 else
Mark Young0153e0b2016-11-03 14:27:13 -06001354 icd_term->logical_device_list = found_dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001355 loader_destroy_logical_device(inst, found_dev, pAllocator);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001356}
1357
Jon Ashburn23d36b12016-02-02 17:47:28 -07001358static void loader_icd_destroy(struct loader_instance *ptr_inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001359 struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001360 const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001361 ptr_inst->total_icd_count--;
Mark Young0153e0b2016-11-03 14:27:13 -06001362 for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001363 struct loader_device *next_dev = dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001364 loader_destroy_logical_device(ptr_inst, dev, pAllocator);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001365 dev = next_dev;
1366 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001367
Mark Young0153e0b2016-11-03 14:27:13 -06001368 loader_instance_heap_free(ptr_inst, icd_term);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001369}
1370
Mark Young0153e0b2016-11-03 14:27:13 -06001371static struct loader_icd_term *
Jon Ashburn23d36b12016-02-02 17:47:28 -07001372loader_icd_create(const struct loader_instance *inst) {
Mark Young0153e0b2016-11-03 14:27:13 -06001373 struct loader_icd_term *icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001374
Mark Young0153e0b2016-11-03 14:27:13 -06001375 icd_term = loader_instance_heap_alloc(inst, sizeof(struct loader_icd_term),
1376 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1377 if (!icd_term) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001378 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001379 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001380
Mark Young0153e0b2016-11-03 14:27:13 -06001381 memset(icd_term, 0, sizeof(struct loader_icd_term));
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -06001382
Mark Young0153e0b2016-11-03 14:27:13 -06001383 return icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001384}
1385
Mark Young0153e0b2016-11-03 14:27:13 -06001386static struct loader_icd_term *
Jon Ashburn23d36b12016-02-02 17:47:28 -07001387loader_icd_add(struct loader_instance *ptr_inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001388 const struct loader_scanned_icd *scanned_icd) {
1389 struct loader_icd_term *icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001390
Mark Young0153e0b2016-11-03 14:27:13 -06001391 icd_term = loader_icd_create(ptr_inst);
1392 if (!icd_term) {
Chia-I Wu13a61a52014-08-04 11:18:20 +08001393 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001394 }
Chia-I Wu13a61a52014-08-04 11:18:20 +08001395
Mark Young0153e0b2016-11-03 14:27:13 -06001396 icd_term->scanned_icd = scanned_icd;
1397 icd_term->this_instance = ptr_inst;
Jon Ashburn3d002332015-08-20 16:35:30 -06001398
Chia-I Wu13a61a52014-08-04 11:18:20 +08001399 /* prepend to the list */
Mark Young0153e0b2016-11-03 14:27:13 -06001400 icd_term->next = ptr_inst->icd_terms;
1401 ptr_inst->icd_terms = icd_term;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001402 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001403
Mark Young0153e0b2016-11-03 14:27:13 -06001404 return icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001405}
Mark Young0153e0b2016-11-03 14:27:13 -06001406
Jon Ashburn17b4c862016-04-25 11:09:37 -06001407/**
1408 * Determine the ICD interface version to use.
1409 * @param icd
1410 * @param pVersion Output parameter indicating which version to use or 0 if
1411 * the negotiation API is not supported by the ICD
1412 * @return bool indicating true if the selected interface version is supported
1413 * by the loader, false indicates the version is not supported
1414 * version 0 doesn't support vk_icdGetInstanceProcAddr nor
1415 * vk_icdNegotiateLoaderICDInterfaceVersion
1416 * version 1 supports vk_icdGetInstanceProcAddr
1417 * version 2 supports vk_icdNegotiateLoaderICDInterfaceVersion
1418 */
1419bool loader_get_icd_interface_version(
Mark Young0153e0b2016-11-03 14:27:13 -06001420 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version,
1421 uint32_t *pVersion) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001422
1423 if (fp_negotiate_icd_version == NULL) {
1424 // ICD does not support the negotiation API, it supports version 0 or 1
1425 // calling code must determine if it is version 0 or 1
1426 *pVersion = 0;
1427 } else {
1428 // ICD supports the negotiation API, so call it with the loader's
1429 // latest version supported
1430 *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1431 VkResult result = fp_negotiate_icd_version(pVersion);
1432
1433 if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1434 // ICD no longer supports the loader's latest interface version so
1435 // fail loading the ICD
1436 return false;
1437 }
1438 }
1439
1440#if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1441 if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1442 // Loader no longer supports the ICD's latest interface version so fail
1443 // loading the ICD
1444 return false;
1445 }
1446#endif
1447 return true;
1448}
Chia-I Wu13a61a52014-08-04 11:18:20 +08001449
Jon Ashburn23d36b12016-02-02 17:47:28 -07001450void loader_scanned_icd_clear(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001451 struct loader_icd_tramp_list *icd_tramp_list) {
1452 if (icd_tramp_list->capacity == 0)
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001453 return;
Mark Young0153e0b2016-11-03 14:27:13 -06001454 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1455 loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1456 loader_instance_heap_free(inst,
1457 icd_tramp_list->scanned_list[i].lib_name);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001458 }
Mark Young0153e0b2016-11-03 14:27:13 -06001459 loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1460 icd_tramp_list->capacity = 0;
1461 icd_tramp_list->count = 0;
1462 icd_tramp_list->scanned_list = NULL;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001463}
1464
Mark Young0153e0b2016-11-03 14:27:13 -06001465static VkResult
1466loader_scanned_icd_init(const struct loader_instance *inst,
1467 struct loader_icd_tramp_list *icd_tramp_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001468 VkResult err = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06001469 loader_scanned_icd_clear(inst, icd_tramp_list);
1470 icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
1471 icd_tramp_list->scanned_list = loader_instance_heap_alloc(
1472 inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1473 if (NULL == icd_tramp_list->scanned_list) {
1474 loader_log(
1475 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young0ad83132016-06-30 13:02:42 -06001476 "realloc failed for layer list when attempting to add new layer");
1477 err = VK_ERROR_OUT_OF_HOST_MEMORY;
1478 }
1479 return err;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001480}
1481
Mark Young0153e0b2016-11-03 14:27:13 -06001482static VkResult
1483loader_scanned_icd_add(const struct loader_instance *inst,
1484 struct loader_icd_tramp_list *icd_tramp_list,
1485 const char *filename, uint32_t api_version) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001486 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06001487 PFN_vkCreateInstance fp_create_inst;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001488 PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
Jon Ashburnc624c882015-07-16 10:17:29 -06001489 PFN_vkGetInstanceProcAddr fp_get_proc_addr;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001490 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
Mark Young0153e0b2016-11-03 14:27:13 -06001491 struct loader_scanned_icd *new_scanned_icd;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001492 uint32_t interface_vers;
Mark Young3a587792016-08-19 15:25:08 -06001493 VkResult res = VK_SUCCESS;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001494
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06001495 /* TODO implement smarter opening/closing of libraries. For now this
1496 * function leaves libraries open and the scanned_icd_clear closes them */
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001497 handle = loader_platform_open_library(filename);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001498 if (!handle) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001499 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001500 loader_platform_open_library_error(filename));
Mark Young3a587792016-08-19 15:25:08 -06001501 goto out;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001502 }
1503
Jon Ashburn17b4c862016-04-25 11:09:37 -06001504 // Get and settle on an ICD interface version
Mark Young0ad83132016-06-30 13:02:42 -06001505 fp_negotiate_icd_version = loader_platform_get_proc_address(
1506 handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
Jon Ashburn17b4c862016-04-25 11:09:37 -06001507
1508 if (!loader_get_icd_interface_version(fp_negotiate_icd_version,
Mark Young0ad83132016-06-30 13:02:42 -06001509 &interface_vers)) {
1510 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1511 "ICD (%s) doesn't support interface version compatible"
1512 "with loader, skip this ICD %s",
1513 filename);
Mark Young3a587792016-08-19 15:25:08 -06001514 goto out;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001515 }
1516
Jon Ashburn23d36b12016-02-02 17:47:28 -07001517 fp_get_proc_addr =
1518 loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001519 if (!fp_get_proc_addr) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001520 assert(interface_vers == 0);
1521 // Use deprecated interface from version 0
Jon Ashburn23d36b12016-02-02 17:47:28 -07001522 fp_get_proc_addr =
1523 loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001524 if (!fp_get_proc_addr) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001525 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1526 loader_platform_get_proc_address_error(
1527 "vk_icdGetInstanceProcAddr"));
Mark Young3a587792016-08-19 15:25:08 -06001528 goto out;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001529 } else {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001530 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001531 "Using deprecated ICD interface of "
1532 "vkGetInstanceProcAddr instead of "
Mark Young0ad83132016-06-30 13:02:42 -06001533 "vk_icdGetInstanceProcAddr for ICD %s",
1534 filename);
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001535 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001536 fp_create_inst =
1537 loader_platform_get_proc_address(handle, "vkCreateInstance");
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001538 if (!fp_create_inst) {
Mark Young0ad83132016-06-30 13:02:42 -06001539 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1540 "Couldn't get vkCreateInstance via dlsym/loadlibrary "
1541 "for ICD %s",
1542 filename);
Mark Young3a587792016-08-19 15:25:08 -06001543 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001544 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001545 fp_get_inst_ext_props = loader_platform_get_proc_address(
1546 handle, "vkEnumerateInstanceExtensionProperties");
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001547 if (!fp_get_inst_ext_props) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001548 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1549 "Couldn't get vkEnumerateInstanceExtensionProperties "
Mark Young0ad83132016-06-30 13:02:42 -06001550 "via dlsym/loadlibrary for ICD %s",
1551 filename);
Mark Young3a587792016-08-19 15:25:08 -06001552 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001553 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001554 } else {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001555 // Use newer interface version 1 or later
1556 if (interface_vers == 0)
1557 interface_vers = 1;
1558
Jon Ashburn23d36b12016-02-02 17:47:28 -07001559 fp_create_inst =
1560 (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001561 if (!fp_create_inst) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001562 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1563 "Couldn't get vkCreateInstance via "
Mark Young0ad83132016-06-30 13:02:42 -06001564 "vk_icdGetInstanceProcAddr for ICD %s",
1565 filename);
Mark Young3a587792016-08-19 15:25:08 -06001566 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001567 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001568 fp_get_inst_ext_props =
1569 (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(
1570 NULL, "vkEnumerateInstanceExtensionProperties");
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001571 if (!fp_get_inst_ext_props) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001572 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1573 "Couldn't get vkEnumerateInstanceExtensionProperties "
Mark Young0ad83132016-06-30 13:02:42 -06001574 "via vk_icdGetInstanceProcAddr for ICD %s",
1575 filename);
Mark Young3a587792016-08-19 15:25:08 -06001576 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001577 }
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001578 }
Jon Ashburn46d1f582015-01-28 11:01:35 -07001579
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001580 // check for enough capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001581 if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >=
1582 icd_tramp_list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001583
Mark Young0153e0b2016-11-03 14:27:13 -06001584 icd_tramp_list->scanned_list = loader_instance_heap_realloc(
1585 inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1586 icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1587 if (NULL == icd_tramp_list->scanned_list) {
Mark Young3a587792016-08-19 15:25:08 -06001588 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001589 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1590 "realloc failed on icd library list");
Mark Young3a587792016-08-19 15:25:08 -06001591 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06001592 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001593 // double capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001594 icd_tramp_list->capacity *= 2;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001595 }
Mark Young0153e0b2016-11-03 14:27:13 -06001596 new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001597
Mark Young0153e0b2016-11-03 14:27:13 -06001598 new_scanned_icd->handle = handle;
1599 new_scanned_icd->api_version = api_version;
1600 new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
1601 new_scanned_icd->EnumerateInstanceExtensionProperties =
1602 fp_get_inst_ext_props;
1603 new_scanned_icd->CreateInstance = fp_create_inst;
1604 new_scanned_icd->interface_version = interface_vers;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001605
Mark Young0153e0b2016-11-03 14:27:13 -06001606 new_scanned_icd->lib_name = (char *)loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001607 inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0153e0b2016-11-03 14:27:13 -06001608 if (NULL == new_scanned_icd->lib_name) {
Mark Young3a587792016-08-19 15:25:08 -06001609 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001610 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001611 "Out of memory can't add icd");
Mark Young3a587792016-08-19 15:25:08 -06001612 goto out;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001613 }
Mark Young0153e0b2016-11-03 14:27:13 -06001614 strcpy(new_scanned_icd->lib_name, filename);
1615 icd_tramp_list->count++;
Mark Young3a587792016-08-19 15:25:08 -06001616
1617out:
1618
1619 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001620}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001621
Mark Young0153e0b2016-11-03 14:27:13 -06001622static bool loader_icd_init_entrys(struct loader_icd_term *icd_term,
1623 VkInstance inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001624 const PFN_vkGetInstanceProcAddr fp_gipa) {
1625/* initialize entrypoint function pointers */
Jon Ashburn3da71f22015-05-14 12:43:38 -06001626
Jon Ashburn23d36b12016-02-02 17:47:28 -07001627#define LOOKUP_GIPA(func, required) \
1628 do { \
Mark Young0153e0b2016-11-03 14:27:13 -06001629 icd_term->func = (PFN_vk##func)fp_gipa(inst, "vk" #func); \
1630 if (!icd_term->func && required) { \
Jon Ashburn23d36b12016-02-02 17:47:28 -07001631 loader_log((struct loader_instance *)inst, \
Jon Ashburn1530c342016-02-26 13:14:27 -07001632 VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07001633 loader_platform_get_proc_address_error("vk" #func)); \
1634 return false; \
1635 } \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001636 } while (0)
1637
Jon Ashburnc624c882015-07-16 10:17:29 -06001638 LOOKUP_GIPA(GetDeviceProcAddr, true);
1639 LOOKUP_GIPA(DestroyInstance, true);
1640 LOOKUP_GIPA(EnumeratePhysicalDevices, true);
1641 LOOKUP_GIPA(GetPhysicalDeviceFeatures, true);
1642 LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true);
Jon Ashburn754864f2015-07-23 18:49:07 -06001643 LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true);
Jon Ashburnc624c882015-07-16 10:17:29 -06001644 LOOKUP_GIPA(CreateDevice, true);
1645 LOOKUP_GIPA(GetPhysicalDeviceProperties, true);
1646 LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true);
Cody Northropd0802882015-08-03 17:04:53 -06001647 LOOKUP_GIPA(GetPhysicalDeviceQueueFamilyProperties, true);
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -06001648 LOOKUP_GIPA(EnumerateDeviceExtensionProperties, true);
Jon Ashburnc624c882015-07-16 10:17:29 -06001649 LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001650 LOOKUP_GIPA(CreateDebugReportCallbackEXT, false);
1651 LOOKUP_GIPA(DestroyDebugReportCallbackEXT, false);
Mark Young65cb3662016-11-07 13:27:02 -07001652 LOOKUP_GIPA(DebugMarkerSetObjectTagEXT, false);
1653 LOOKUP_GIPA(DebugMarkerSetObjectNameEXT, false);
Ian Elliott7e40db92015-08-21 15:09:33 -06001654 LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportKHR, false);
Ian Elliott486c5502015-11-19 16:05:09 -07001655 LOOKUP_GIPA(GetPhysicalDeviceSurfaceCapabilitiesKHR, false);
1656 LOOKUP_GIPA(GetPhysicalDeviceSurfaceFormatsKHR, false);
1657 LOOKUP_GIPA(GetPhysicalDeviceSurfacePresentModesKHR, false);
Petros Bantolas25d27fe2016-04-14 12:50:42 +01001658 LOOKUP_GIPA(GetPhysicalDeviceDisplayPropertiesKHR, false);
1659 LOOKUP_GIPA(GetDisplayModePropertiesKHR, false);
1660 LOOKUP_GIPA(CreateDisplayPlaneSurfaceKHR, false);
1661 LOOKUP_GIPA(GetPhysicalDeviceDisplayPlanePropertiesKHR, false);
1662 LOOKUP_GIPA(GetDisplayPlaneSupportedDisplaysKHR, false);
1663 LOOKUP_GIPA(CreateDisplayModeKHR, false);
1664 LOOKUP_GIPA(GetDisplayPlaneCapabilitiesKHR, false);
1665 LOOKUP_GIPA(DestroySurfaceKHR, false);
Mark Young16573c72016-06-28 10:52:43 -06001666 LOOKUP_GIPA(CreateSwapchainKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001667#ifdef VK_USE_PLATFORM_WIN32_KHR
Mark Young16573c72016-06-28 10:52:43 -06001668 LOOKUP_GIPA(CreateWin32SurfaceKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001669 LOOKUP_GIPA(GetPhysicalDeviceWin32PresentationSupportKHR, false);
1670#endif
1671#ifdef VK_USE_PLATFORM_XCB_KHR
Mark Young16573c72016-06-28 10:52:43 -06001672 LOOKUP_GIPA(CreateXcbSurfaceKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001673 LOOKUP_GIPA(GetPhysicalDeviceXcbPresentationSupportKHR, false);
1674#endif
Karl Schultz65d20182016-03-08 07:55:27 -07001675#ifdef VK_USE_PLATFORM_XLIB_KHR
Mark Young16573c72016-06-28 10:52:43 -06001676 LOOKUP_GIPA(CreateXlibSurfaceKHR, false);
Karl Schultz65d20182016-03-08 07:55:27 -07001677 LOOKUP_GIPA(GetPhysicalDeviceXlibPresentationSupportKHR, false);
1678#endif
Mark Younga7c51fd2016-09-16 10:18:42 -06001679#ifdef VK_USE_PLATFORM_MIR_KHR
1680 LOOKUP_GIPA(CreateMirSurfaceKHR, false);
1681 LOOKUP_GIPA(GetPhysicalDeviceMirPresentationSupportKHR, false);
1682#endif
Jason Ekstranda5ebe8a2016-02-12 17:25:03 -08001683#ifdef VK_USE_PLATFORM_WAYLAND_KHR
Mark Young16573c72016-06-28 10:52:43 -06001684 LOOKUP_GIPA(CreateWaylandSurfaceKHR, false);
Jason Ekstranda5ebe8a2016-02-12 17:25:03 -08001685 LOOKUP_GIPA(GetPhysicalDeviceWaylandPresentationSupportKHR, false);
1686#endif
Mark Youngfa552782016-12-12 16:14:55 -07001687 // NV_external_memory_capabilities
James Jones389dc0c2016-08-18 23:41:19 +01001688 LOOKUP_GIPA(GetPhysicalDeviceExternalImageFormatPropertiesNV, false);
Mark Youngfa552782016-12-12 16:14:55 -07001689 // NVX_device_generated_commands
1690 LOOKUP_GIPA(GetPhysicalDeviceGeneratedCommandsPropertiesNVX, false);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001691
Jon Ashburnc624c882015-07-16 10:17:29 -06001692#undef LOOKUP_GIPA
Ian Elliottd3ef02f2015-07-06 14:36:13 -06001693
Jon Ashburnc624c882015-07-16 10:17:29 -06001694 return true;
Jon Ashburn3da71f22015-05-14 12:43:38 -06001695}
1696
Jon Ashburn23d36b12016-02-02 17:47:28 -07001697static void loader_debug_init(void) {
Mark Young0ad83132016-06-30 13:02:42 -06001698 char *env, *orig;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001699
1700 if (g_loader_debug > 0)
1701 return;
1702
1703 g_loader_debug = 0;
1704
1705 /* parse comma-separated debug options */
Mark Young0ad83132016-06-30 13:02:42 -06001706 orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001707 while (env) {
Mark Young0ad83132016-06-30 13:02:42 -06001708 char *p = strchr(env, ',');
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001709 size_t len;
1710
1711 if (p)
1712 len = p - env;
1713 else
1714 len = strlen(env);
1715
1716 if (len > 0) {
Michael Worcester25c73e72015-12-10 18:06:24 +00001717 if (strncmp(env, "all", len) == 0) {
1718 g_loader_debug = ~0u;
1719 g_loader_log_msgs = ~0u;
1720 } else if (strncmp(env, "warn", len) == 0) {
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001721 g_loader_debug |= LOADER_WARN_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001722 g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001723 } else if (strncmp(env, "info", len) == 0) {
1724 g_loader_debug |= LOADER_INFO_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001725 g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001726 } else if (strncmp(env, "perf", len) == 0) {
1727 g_loader_debug |= LOADER_PERF_BIT;
Jon Ashburn1530c342016-02-26 13:14:27 -07001728 g_loader_log_msgs |=
1729 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001730 } else if (strncmp(env, "error", len) == 0) {
1731 g_loader_debug |= LOADER_ERROR_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001732 g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001733 } else if (strncmp(env, "debug", len) == 0) {
1734 g_loader_debug |= LOADER_DEBUG_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001735 g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001736 }
1737 }
1738
1739 if (!p)
1740 break;
1741
1742 env = p + 1;
1743 }
Jon Ashburn38a497f2016-01-04 14:01:38 -07001744
Mark Young0ad83132016-06-30 13:02:42 -06001745 loader_free_getenv(orig, NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001746}
1747
Jon Ashburn23d36b12016-02-02 17:47:28 -07001748void loader_initialize(void) {
Jon Ashburn6461ef22015-09-22 13:11:00 -06001749 // initialize mutexs
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001750 loader_platform_thread_create_mutex(&loader_lock);
Jon Ashburn6461ef22015-09-22 13:11:00 -06001751 loader_platform_thread_create_mutex(&loader_json_lock);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001752
1753 // initialize logging
1754 loader_debug_init();
Jon Ashburn87d6aa92015-08-28 15:19:27 -06001755
1756 // initial cJSON to use alloc callbacks
1757 cJSON_Hooks alloc_fns = {
Mark Young0ad83132016-06-30 13:02:42 -06001758 .malloc_fn = loader_instance_tls_heap_alloc,
1759 .free_fn = loader_instance_tls_heap_free,
Jon Ashburn87d6aa92015-08-28 15:19:27 -06001760 };
1761 cJSON_InitHooks(&alloc_fns);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001762}
1763
Jon Ashburn2077e382015-06-29 11:25:34 -06001764struct loader_manifest_files {
1765 uint32_t count;
1766 char **filename_list;
1767};
1768
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001769/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001770 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001771 *
1772 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001773 * A pointer to first char in the next path.
1774 * The next path (or NULL) in the list is returned in next_path.
1775 * Note: input string is modified in some cases. PASS IN A COPY!
1776 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001777static char *loader_get_next_path(char *path) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001778 uint32_t len;
1779 char *next;
1780
1781 if (path == NULL)
1782 return NULL;
Frank Henigman57173102016-11-24 22:15:20 -05001783 next = strchr(path, PATH_SEPARATOR);
Jon Ashburn2077e382015-06-29 11:25:34 -06001784 if (next == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001785 len = (uint32_t)strlen(path);
Jon Ashburn2077e382015-06-29 11:25:34 -06001786 next = path + len;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001787 } else {
Jon Ashburn2077e382015-06-29 11:25:34 -06001788 *next = '\0';
1789 next++;
1790 }
1791
1792 return next;
1793}
1794
1795/**
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001796 * Given a path which is absolute or relative, expand the path if relative or
1797 * leave the path unmodified if absolute. The base path to prepend to relative
1798 * paths is given in rel_base.
Jon Ashburn15315172015-07-07 15:06:25 -06001799 *
1800 * \returns
1801 * A string in out_fullpath of the full absolute path
Jon Ashburn15315172015-07-07 15:06:25 -06001802 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001803static void loader_expand_path(const char *path, const char *rel_base,
1804 size_t out_size, char *out_fullpath) {
Jon Ashburn15315172015-07-07 15:06:25 -06001805 if (loader_platform_is_path_absolute(path)) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001806 // do not prepend a base to an absolute path
1807 rel_base = "";
Jon Ashburn15315172015-07-07 15:06:25 -06001808 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001809
1810 loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
Jon Ashburn15315172015-07-07 15:06:25 -06001811}
1812
1813/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001814 * Given a filename (file) and a list of paths (dir), try to find an existing
1815 * file in the paths. If filename already is a path then no
1816 * searching in the given paths.
1817 *
1818 * \returns
1819 * A string in out_fullpath of either the full path or file.
Jon Ashburn2077e382015-06-29 11:25:34 -06001820 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001821static void loader_get_fullpath(const char *file, const char *dirs,
1822 size_t out_size, char *out_fullpath) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001823 if (!loader_platform_is_path(file) && *dirs) {
1824 char *dirs_copy, *dir, *next_dir;
1825
1826 dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
1827 strcpy(dirs_copy, dirs);
1828
Jon Ashburn23d36b12016-02-02 17:47:28 -07001829 // find if file exists after prepending paths in given list
1830 for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir));
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001831 dir = next_dir) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001832 loader_platform_combine_path(out_fullpath, out_size, dir, file,
1833 NULL);
Jon Ashburn2077e382015-06-29 11:25:34 -06001834 if (loader_platform_file_exists(out_fullpath)) {
1835 return;
1836 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001837 }
1838 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001839
Jon Ashburn2077e382015-06-29 11:25:34 -06001840 snprintf(out_fullpath, out_size, "%s", file);
1841}
1842
1843/**
1844 * Read a JSON file into a buffer.
1845 *
1846 * \returns
1847 * A pointer to a cJSON object representing the JSON parse tree.
1848 * This returned buffer should be freed by caller.
1849 */
Mark Young3a587792016-08-19 15:25:08 -06001850static VkResult loader_get_json(const struct loader_instance *inst,
1851 const char *filename, cJSON **json) {
1852 FILE *file = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06001853 char *json_buf;
Mark Young93ecb1d2016-01-13 13:47:16 -07001854 size_t len;
Mark Young3a587792016-08-19 15:25:08 -06001855 VkResult res = VK_SUCCESS;
1856
1857 if (NULL == json) {
1858 res = VK_ERROR_INITIALIZATION_FAILED;
1859 goto out;
1860 }
1861
1862 *json = NULL;
1863
Jon Ashburn23d36b12016-02-02 17:47:28 -07001864 file = fopen(filename, "rb");
Jon Ashburnaa4ea472015-08-27 08:30:50 -06001865 if (!file) {
Mark Young3a587792016-08-19 15:25:08 -06001866 res = VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001867 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1868 "Couldn't open JSON file %s", filename);
Mark Young3a587792016-08-19 15:25:08 -06001869 goto out;
Jon Ashburnaa4ea472015-08-27 08:30:50 -06001870 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001871 fseek(file, 0, SEEK_END);
1872 len = ftell(file);
1873 fseek(file, 0, SEEK_SET);
Jon Ashburn23d36b12016-02-02 17:47:28 -07001874 json_buf = (char *)loader_stack_alloc(len + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06001875 if (json_buf == NULL) {
Mark Young3a587792016-08-19 15:25:08 -06001876 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001877 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1878 "Out of memory can't get JSON file");
Mark Young3a587792016-08-19 15:25:08 -06001879 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06001880 }
1881 if (fread(json_buf, sizeof(char), len, file) != len) {
Mark Young3a587792016-08-19 15:25:08 -06001882 res = VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001883 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1884 "fread failed can't get JSON file");
Mark Young3a587792016-08-19 15:25:08 -06001885 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06001886 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001887 json_buf[len] = '\0';
1888
Jon Ashburn23d36b12016-02-02 17:47:28 -07001889 // parse text from file
Mark Young3a587792016-08-19 15:25:08 -06001890 *json = cJSON_Parse(json_buf);
1891 if (*json == NULL) {
1892 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001893 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1894 "Can't parse JSON file %s", filename);
Mark Young3a587792016-08-19 15:25:08 -06001895 goto out;
1896 }
1897
1898out:
1899 if (NULL != file) {
1900 fclose(file);
1901 }
1902
1903 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06001904}
1905
1906/**
Jon Ashburn3d002332015-08-20 16:35:30 -06001907 * Do a deep copy of the loader_layer_properties structure.
1908 */
Mark Young0ad83132016-06-30 13:02:42 -06001909VkResult loader_copy_layer_properties(const struct loader_instance *inst,
1910 struct loader_layer_properties *dst,
1911 struct loader_layer_properties *src) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001912 uint32_t cnt, i;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001913 memcpy(dst, src, sizeof(*src));
1914 dst->instance_extension_list.list =
Mark Young0ad83132016-06-30 13:02:42 -06001915 loader_instance_heap_alloc(inst, sizeof(VkExtensionProperties) *
1916 src->instance_extension_list.count,
1917 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1918 if (NULL == dst->instance_extension_list.list) {
1919 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1920 "alloc failed for instance extension list");
1921 return VK_ERROR_OUT_OF_HOST_MEMORY;
1922 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001923 dst->instance_extension_list.capacity =
1924 sizeof(VkExtensionProperties) * src->instance_extension_list.count;
Jon Ashburne39a4f82015-08-28 13:38:21 -06001925 memcpy(dst->instance_extension_list.list, src->instance_extension_list.list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001926 dst->instance_extension_list.capacity);
1927 dst->device_extension_list.list =
Mark Young0ad83132016-06-30 13:02:42 -06001928 loader_instance_heap_alloc(inst, sizeof(struct loader_dev_ext_props) *
1929 src->device_extension_list.count,
1930 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1931 if (NULL == dst->device_extension_list.list) {
1932 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1933 "alloc failed for device extension list");
1934 return VK_ERROR_OUT_OF_HOST_MEMORY;
1935 }
Mark Young0153e0b2016-11-03 14:27:13 -06001936 memset(dst->device_extension_list.list, 0,
1937 sizeof(struct loader_dev_ext_props) *
1938 src->device_extension_list.count);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001939
Jon Ashburn23d36b12016-02-02 17:47:28 -07001940 dst->device_extension_list.capacity =
1941 sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
Jon Ashburne39a4f82015-08-28 13:38:21 -06001942 memcpy(dst->device_extension_list.list, src->device_extension_list.list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001943 dst->device_extension_list.capacity);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001944 if (src->device_extension_list.count > 0 &&
Jon Ashburn23d36b12016-02-02 17:47:28 -07001945 src->device_extension_list.list->entrypoint_count > 0) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001946 cnt = src->device_extension_list.list->entrypoint_count;
Mark Young0ad83132016-06-30 13:02:42 -06001947 dst->device_extension_list.list->entrypoints =
1948 loader_instance_heap_alloc(inst, sizeof(char *) * cnt,
1949 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1950 if (NULL == dst->device_extension_list.list->entrypoints) {
1951 loader_log(
1952 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1953 "alloc failed for device extension list entrypoint array");
1954 return VK_ERROR_OUT_OF_HOST_MEMORY;
1955 }
Mark Young0153e0b2016-11-03 14:27:13 -06001956 memset(dst->device_extension_list.list->entrypoints, 0,
1957 sizeof(char *) * cnt);
Mark Young0ad83132016-06-30 13:02:42 -06001958
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001959 for (i = 0; i < cnt; i++) {
Mark Young0ad83132016-06-30 13:02:42 -06001960 dst->device_extension_list.list->entrypoints[i] =
1961 loader_instance_heap_alloc(
1962 inst,
1963 strlen(src->device_extension_list.list->entrypoints[i]) + 1,
1964 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1965 if (NULL == dst->device_extension_list.list->entrypoints[i]) {
1966 loader_log(
1967 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1968 "alloc failed for device extension list entrypoint %d", i);
1969 return VK_ERROR_OUT_OF_HOST_MEMORY;
1970 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001971 strcpy(dst->device_extension_list.list->entrypoints[i],
1972 src->device_extension_list.list->entrypoints[i]);
1973 }
1974 }
Mark Young0ad83132016-06-30 13:02:42 -06001975
1976 return VK_SUCCESS;
Jon Ashburn3d002332015-08-20 16:35:30 -06001977}
1978
Jon Ashburn86a527a2016-02-10 20:59:26 -07001979static bool
1980loader_find_layer_name_list(const char *name,
1981 const struct loader_layer_list *layer_list) {
1982 if (!layer_list)
1983 return false;
1984 for (uint32_t j = 0; j < layer_list->count; j++)
1985 if (!strcmp(name, layer_list->list[j].info.layerName))
1986 return true;
1987 return false;
1988}
1989
1990static bool loader_find_layer_name(const char *name, uint32_t layer_count,
1991 const char **layer_list) {
1992 if (!layer_list)
1993 return false;
1994 for (uint32_t j = 0; j < layer_count; j++)
1995 if (!strcmp(name, layer_list[j]))
1996 return true;
1997 return false;
1998}
1999
Jon Ashburn491cd042016-05-16 14:01:18 -06002000bool loader_find_layer_name_array(
Jon Ashburn86a527a2016-02-10 20:59:26 -07002001 const char *name, uint32_t layer_count,
2002 const char layer_list[][VK_MAX_EXTENSION_NAME_SIZE]) {
2003 if (!layer_list)
2004 return false;
2005 for (uint32_t j = 0; j < layer_count; j++)
2006 if (!strcmp(name, layer_list[j]))
2007 return true;
2008 return false;
2009}
2010
2011/**
2012 * Searches through an array of layer names (ppp_layer_names) looking for a
2013 * layer key_name.
2014 * If not found then simply returns updating nothing.
2015 * Otherwise, it uses expand_count, expand_names adding them to layer names.
Chris Forbes69366472016-04-07 09:04:49 +12002016 * Any duplicate (pre-existing) expand_names in layer names are removed.
2017 * Order is otherwise preserved, with the layer key_name being replaced by the
2018 * expand_names.
Jon Ashburn86a527a2016-02-10 20:59:26 -07002019 * @param inst
2020 * @param layer_count
2021 * @param ppp_layer_names
2022 */
Mark Young0ad83132016-06-30 13:02:42 -06002023VkResult loader_expand_layer_names(
2024 struct loader_instance *inst, const char *key_name, uint32_t expand_count,
Jon Ashburn86a527a2016-02-10 20:59:26 -07002025 const char expand_names[][VK_MAX_EXTENSION_NAME_SIZE],
Jon Ashburncc407a22016-04-15 09:25:03 -06002026 uint32_t *layer_count, char const *const **ppp_layer_names) {
Jon Ashburn71483442016-02-11 18:59:43 -07002027
Jon Ashburncc407a22016-04-15 09:25:03 -06002028 char const *const *pp_src_layers = *ppp_layer_names;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002029
Jon Ashburncc407a22016-04-15 09:25:03 -06002030 if (!loader_find_layer_name(key_name, *layer_count,
Jon Ashburn491cd042016-05-16 14:01:18 -06002031 (char const **)pp_src_layers)) {
2032 inst->activated_layers_are_std_val = false;
Mark Young0ad83132016-06-30 13:02:42 -06002033 return VK_SUCCESS; // didn't find the key_name in the list.
Jon Ashburn491cd042016-05-16 14:01:18 -06002034 }
Jon Ashburn71483442016-02-11 18:59:43 -07002035
Jon Ashburn86a527a2016-02-10 20:59:26 -07002036 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2037 "Found meta layer %s, replacing with actual layer group",
2038 key_name);
Chris Forbesbd9de052016-04-06 20:49:02 +12002039
Jon Ashburn491cd042016-05-16 14:01:18 -06002040 inst->activated_layers_are_std_val = true;
Mark Young0ad83132016-06-30 13:02:42 -06002041 char const **pp_dst_layers = loader_instance_heap_alloc(
Jon Ashburncc407a22016-04-15 09:25:03 -06002042 inst, (expand_count + *layer_count - 1) * sizeof(char const *),
2043 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young0ad83132016-06-30 13:02:42 -06002044 if (NULL == pp_dst_layers) {
2045 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2046 "alloc failed for dst layer array");
2047 return VK_ERROR_OUT_OF_HOST_MEMORY;
2048 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002049
2050 // copy layers from src to dst, stripping key_name and anything in
2051 // expand_names.
2052 uint32_t src_index, dst_index = 0;
2053 for (src_index = 0; src_index < *layer_count; src_index++) {
Jon Ashburncc407a22016-04-15 09:25:03 -06002054 if (loader_find_layer_name_array(pp_src_layers[src_index], expand_count,
2055 expand_names)) {
Chris Forbes69366472016-04-07 09:04:49 +12002056 continue;
2057 }
2058
2059 if (!strcmp(pp_src_layers[src_index], key_name)) {
2060 // insert all expand_names in place of key_name
2061 uint32_t expand_index;
Jon Ashburncc407a22016-04-15 09:25:03 -06002062 for (expand_index = 0; expand_index < expand_count;
2063 expand_index++) {
Chris Forbes69366472016-04-07 09:04:49 +12002064 pp_dst_layers[dst_index++] = expand_names[expand_index];
2065 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002066 continue;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002067 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002068
2069 pp_dst_layers[dst_index++] = pp_src_layers[src_index];
Jon Ashburn86a527a2016-02-10 20:59:26 -07002070 }
2071
Chris Forbesbd9de052016-04-06 20:49:02 +12002072 *ppp_layer_names = pp_dst_layers;
2073 *layer_count = dst_index;
Mark Young0ad83132016-06-30 13:02:42 -06002074
2075 return VK_SUCCESS;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002076}
2077
Chris Forbesbd9de052016-04-06 20:49:02 +12002078void loader_delete_shadow_inst_layer_names(const struct loader_instance *inst,
2079 const VkInstanceCreateInfo *orig,
2080 VkInstanceCreateInfo *ours) {
2081 /* Free the layer names array iff we had to reallocate it */
2082 if (orig->ppEnabledLayerNames != ours->ppEnabledLayerNames) {
Mark Young0ad83132016-06-30 13:02:42 -06002083 loader_instance_heap_free(inst, (void *)ours->ppEnabledLayerNames);
Jon Ashburn86a527a2016-02-10 20:59:26 -07002084 }
2085}
2086
Jon Ashburn491cd042016-05-16 14:01:18 -06002087void loader_init_std_validation_props(struct loader_layer_properties *props) {
2088 memset(props, 0, sizeof(struct loader_layer_properties));
2089 props->type = VK_LAYER_TYPE_META_EXPLICT;
2090 strncpy(props->info.description, "LunarG Standard Validation Layer",
Mark Young0153e0b2016-11-03 14:27:13 -06002091 sizeof(props->info.description));
Jon Ashburn491cd042016-05-16 14:01:18 -06002092 props->info.implementationVersion = 1;
2093 strncpy(props->info.layerName, std_validation_str,
Mark Young0153e0b2016-11-03 14:27:13 -06002094 sizeof(props->info.layerName));
Jon Ashburn491cd042016-05-16 14:01:18 -06002095 // TODO what about specVersion? for now insert loader's built version
2096 props->info.specVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION);
2097}
2098
Jon Ashburn86a527a2016-02-10 20:59:26 -07002099/**
Jon Ashburn491cd042016-05-16 14:01:18 -06002100 * Searches through the existing instance layer lists looking for
Jon Ashburn86a527a2016-02-10 20:59:26 -07002101 * the set of required layer names. If found then it adds a meta property to the
2102 * layer list.
2103 * Assumes the required layers are the same for both instance and device lists.
2104 * @param inst
2105 * @param layer_count number of layers in layer_names
2106 * @param layer_names array of required layer names
2107 * @param layer_instance_list
Jon Ashburn86a527a2016-02-10 20:59:26 -07002108 */
2109static void loader_add_layer_property_meta(
2110 const struct loader_instance *inst, uint32_t layer_count,
2111 const char layer_names[][VK_MAX_EXTENSION_NAME_SIZE],
Jon Ashburn491cd042016-05-16 14:01:18 -06002112 struct loader_layer_list *layer_instance_list) {
2113 uint32_t i;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002114 bool found;
2115 struct loader_layer_list *layer_list;
2116
Jon Ashburn491cd042016-05-16 14:01:18 -06002117 if (0 == layer_count || (!layer_instance_list))
Jon Ashburn888c0502016-02-19 15:22:10 -07002118 return;
Jon Ashburn491cd042016-05-16 14:01:18 -06002119 if (layer_instance_list && (layer_count > layer_instance_list->count))
Jon Ashburn86a527a2016-02-10 20:59:26 -07002120 return;
2121
Jon Ashburn491cd042016-05-16 14:01:18 -06002122 layer_list = layer_instance_list;
2123
2124 found = true;
2125 if (layer_list == NULL)
2126 return;
2127 for (i = 0; i < layer_count; i++) {
2128 if (loader_find_layer_name_list(layer_names[i], layer_list))
Jon Ashburn888c0502016-02-19 15:22:10 -07002129 continue;
Jon Ashburn491cd042016-05-16 14:01:18 -06002130 found = false;
2131 break;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002132 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002133
2134 struct loader_layer_properties *props;
2135 if (found) {
2136 props = loader_get_next_layer_property(inst, layer_list);
Mark Young0ad83132016-06-30 13:02:42 -06002137 if (NULL == props) {
2138 // Error already triggered in loader_get_next_layer_property.
2139 return;
2140 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002141 loader_init_std_validation_props(props);
Jon Ashburn491cd042016-05-16 14:01:18 -06002142 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002143}
2144
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002145static void loader_read_json_layer(
2146 const struct loader_instance *inst,
2147 struct loader_layer_list *layer_instance_list, cJSON *layer_node,
2148 cJSON *item, cJSON *disable_environment, bool is_implicit, char *filename) {
2149 char *temp;
2150 char *name, *type, *library_path, *api_version;
2151 char *implementation_version, *description;
2152 cJSON *ext_item;
2153 VkExtensionProperties ext_prop;
2154
Mark Young0ad83132016-06-30 13:02:42 -06002155/*
2156 * The following are required in the "layer" object:
2157 * (required) "name"
2158 * (required) "type"
2159 * (required) “library_path”
2160 * (required) “api_version”
2161 * (required) “implementation_version”
2162 * (required) “description”
2163 * (required for implicit layers) “disable_environment”
2164 */
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002165
Jon Ashburn23d36b12016-02-02 17:47:28 -07002166#define GET_JSON_OBJECT(node, var) \
2167 { \
2168 var = cJSON_GetObjectItem(node, #var); \
2169 if (var == NULL) { \
2170 layer_node = layer_node->next; \
Jon Ashburn1530c342016-02-26 13:14:27 -07002171 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002172 "Didn't find required layer object %s in manifest " \
2173 "JSON file, skipping this layer", \
2174 #var); \
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002175 return; \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002176 } \
2177 }
2178#define GET_JSON_ITEM(node, var) \
2179 { \
2180 item = cJSON_GetObjectItem(node, #var); \
2181 if (item == NULL) { \
2182 layer_node = layer_node->next; \
Jon Ashburn1530c342016-02-26 13:14:27 -07002183 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002184 "Didn't find required layer value %s in manifest JSON " \
2185 "file, skipping this layer", \
2186 #var); \
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002187 return; \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002188 } \
2189 temp = cJSON_Print(item); \
Mark Young0ad83132016-06-30 13:02:42 -06002190 if (temp == NULL) { \
2191 layer_node = layer_node->next; \
2192 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2193 "Problem accessing layer value %s in manifest JSON " \
2194 "file, skipping this layer", \
2195 #var); \
2196 return; \
2197 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002198 temp[strlen(temp) - 1] = '\0'; \
2199 var = loader_stack_alloc(strlen(temp) + 1); \
2200 strcpy(var, &temp[1]); \
Mark Young0ad83132016-06-30 13:02:42 -06002201 cJSON_Free(temp); \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002202 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002203 GET_JSON_ITEM(layer_node, name)
2204 GET_JSON_ITEM(layer_node, type)
2205 GET_JSON_ITEM(layer_node, library_path)
2206 GET_JSON_ITEM(layer_node, api_version)
2207 GET_JSON_ITEM(layer_node, implementation_version)
2208 GET_JSON_ITEM(layer_node, description)
2209 if (is_implicit) {
2210 GET_JSON_OBJECT(layer_node, disable_environment)
2211 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002212#undef GET_JSON_ITEM
2213#undef GET_JSON_OBJECT
2214
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002215 // add list entry
2216 struct loader_layer_properties *props = NULL;
2217 if (!strcmp(type, "DEVICE")) {
2218 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2219 "Device layers are deprecated skipping this layer");
2220 layer_node = layer_node->next;
2221 return;
2222 }
2223 // Allow either GLOBAL or INSTANCE type interchangeably to handle
2224 // layers that must work with older loaders
2225 if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2226 if (layer_instance_list == NULL) {
Jon Ashburn432d2762015-09-18 12:53:16 -06002227 layer_node = layer_node->next;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002228 return;
Jon Ashburn432d2762015-09-18 12:53:16 -06002229 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002230 props = loader_get_next_layer_property(inst, layer_instance_list);
Mark Young0ad83132016-06-30 13:02:42 -06002231 if (NULL == props) {
2232 // Error already triggered in loader_get_next_layer_property.
2233 return;
2234 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002235 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT
2236 : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
2237 }
Jon Ashburn432d2762015-09-18 12:53:16 -06002238
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002239 if (props == NULL) {
2240 layer_node = layer_node->next;
2241 return;
2242 }
Jon Ashburn15315172015-07-07 15:06:25 -06002243
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002244 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
2245 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
2246
2247 char *fullpath = props->lib_name;
2248 char *rel_base;
2249 if (loader_platform_is_path(library_path)) {
2250 // a relative or absolute path
2251 char *name_copy = loader_stack_alloc(strlen(filename) + 1);
2252 strcpy(name_copy, filename);
2253 rel_base = loader_platform_dirname(name_copy);
2254 loader_expand_path(library_path, rel_base, MAX_STRING_SIZE, fullpath);
2255 } else {
2256 // a filename which is assumed in a system directory
2257 loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH,
2258 MAX_STRING_SIZE, fullpath);
2259 }
2260 props->info.specVersion = loader_make_version(api_version);
2261 props->info.implementationVersion = atoi(implementation_version);
2262 strncpy((char *)props->info.description, description,
2263 sizeof(props->info.description));
2264 props->info.description[sizeof(props->info.description) - 1] = '\0';
2265 if (is_implicit) {
2266 if (!disable_environment || !disable_environment->child) {
2267 loader_log(
2268 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2269 "Didn't find required layer child value disable_environment"
2270 "in manifest JSON file, skipping this layer");
2271 layer_node = layer_node->next;
2272 return;
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002273 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002274 strncpy(props->disable_env_var.name, disable_environment->child->string,
2275 sizeof(props->disable_env_var.name));
2276 props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] =
2277 '\0';
2278 strncpy(props->disable_env_var.value,
2279 disable_environment->child->valuestring,
2280 sizeof(props->disable_env_var.value));
2281 props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] =
2282 '\0';
2283 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002284
Jon Ashburn23d36b12016-02-02 17:47:28 -07002285/**
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002286* Now get all optional items and objects and put in list:
2287* functions
2288* instance_extensions
2289* device_extensions
2290* enable_environment (implicit layers only)
2291*/
Jon Ashburn23d36b12016-02-02 17:47:28 -07002292#define GET_JSON_OBJECT(node, var) \
2293 { var = cJSON_GetObjectItem(node, #var); }
2294#define GET_JSON_ITEM(node, var) \
2295 { \
2296 item = cJSON_GetObjectItem(node, #var); \
2297 if (item != NULL) { \
2298 temp = cJSON_Print(item); \
Mark Young0ad83132016-06-30 13:02:42 -06002299 if (temp != NULL) { \
2300 temp[strlen(temp) - 1] = '\0'; \
2301 var = loader_stack_alloc(strlen(temp) + 1); \
2302 strcpy(var, &temp[1]); \
2303 cJSON_Free(temp); \
2304 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002305 } \
2306 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002307
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002308 cJSON *instance_extensions, *device_extensions, *functions,
2309 *enable_environment;
2310 cJSON *entrypoints;
2311 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *spec_version;
2312 char **entry_array;
2313 vkGetInstanceProcAddr = NULL;
2314 vkGetDeviceProcAddr = NULL;
2315 spec_version = NULL;
2316 entrypoints = NULL;
2317 entry_array = NULL;
2318 int i, j;
Jon Ashburn075ce432015-12-17 17:38:24 -07002319
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002320 /**
2321 * functions
2322 * vkGetInstanceProcAddr
2323 * vkGetDeviceProcAddr
2324 */
2325 GET_JSON_OBJECT(layer_node, functions)
2326 if (functions != NULL) {
2327 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
2328 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
2329 if (vkGetInstanceProcAddr != NULL)
2330 strncpy(props->functions.str_gipa, vkGetInstanceProcAddr,
2331 sizeof(props->functions.str_gipa));
2332 props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
2333 if (vkGetDeviceProcAddr != NULL)
2334 strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr,
2335 sizeof(props->functions.str_gdpa));
2336 props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
2337 }
2338 /**
2339 * instance_extensions
2340 * array of
2341 * name
2342 * spec_version
2343 */
2344 GET_JSON_OBJECT(layer_node, instance_extensions)
2345 if (instance_extensions != NULL) {
2346 int count = cJSON_GetArraySize(instance_extensions);
2347 for (i = 0; i < count; i++) {
2348 ext_item = cJSON_GetArrayItem(instance_extensions, i);
2349 GET_JSON_ITEM(ext_item, name)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002350 if (name != NULL) {
2351 strncpy(ext_prop.extensionName, name,
2352 sizeof(ext_prop.extensionName));
2353 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
2354 '\0';
2355 }
Mark Young0ad83132016-06-30 13:02:42 -06002356 GET_JSON_ITEM(ext_item, spec_version)
2357 if (NULL != spec_version) {
2358 ext_prop.specVersion = atoi(spec_version);
2359 } else {
2360 ext_prop.specVersion = 0;
2361 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002362 bool ext_unsupported =
2363 wsi_unsupported_instance_extension(&ext_prop);
2364 if (!ext_unsupported) {
2365 loader_add_to_ext_list(inst, &props->instance_extension_list, 1,
2366 &ext_prop);
Jon Ashburn075ce432015-12-17 17:38:24 -07002367 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002368 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002369 }
2370 /**
2371 * device_extensions
2372 * array of
2373 * name
2374 * spec_version
2375 * entrypoints
2376 */
2377 GET_JSON_OBJECT(layer_node, device_extensions)
2378 if (device_extensions != NULL) {
2379 int count = cJSON_GetArraySize(device_extensions);
2380 for (i = 0; i < count; i++) {
2381 ext_item = cJSON_GetArrayItem(device_extensions, i);
2382 GET_JSON_ITEM(ext_item, name)
2383 GET_JSON_ITEM(ext_item, spec_version)
2384 if (name != NULL) {
2385 strncpy(ext_prop.extensionName, name,
2386 sizeof(ext_prop.extensionName));
2387 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
2388 '\0';
2389 }
Mark Young0ad83132016-06-30 13:02:42 -06002390 if (NULL != spec_version) {
2391 ext_prop.specVersion = atoi(spec_version);
2392 } else {
2393 ext_prop.specVersion = 0;
2394 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002395 // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
2396 GET_JSON_OBJECT(ext_item, entrypoints)
2397 int entry_count;
2398 if (entrypoints == NULL) {
2399 loader_add_to_dev_ext_list(inst, &props->device_extension_list,
2400 &ext_prop, 0, NULL);
2401 continue;
2402 }
2403 entry_count = cJSON_GetArraySize(entrypoints);
Mark Young0ad83132016-06-30 13:02:42 -06002404 if (entry_count) {
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002405 entry_array =
2406 (char **)loader_stack_alloc(sizeof(char *) * entry_count);
Mark Young0ad83132016-06-30 13:02:42 -06002407 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002408 for (j = 0; j < entry_count; j++) {
2409 ext_item = cJSON_GetArrayItem(entrypoints, j);
2410 if (ext_item != NULL) {
2411 temp = cJSON_Print(ext_item);
Mark Young0ad83132016-06-30 13:02:42 -06002412 if (NULL == temp) {
2413 entry_array[j] = NULL;
2414 continue;
2415 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002416 temp[strlen(temp) - 1] = '\0';
2417 entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
2418 strcpy(entry_array[j], &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06002419 cJSON_Free(temp);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002420 }
2421 }
2422 loader_add_to_dev_ext_list(inst, &props->device_extension_list,
2423 &ext_prop, entry_count, entry_array);
2424 }
2425 }
2426 if (is_implicit) {
2427 GET_JSON_OBJECT(layer_node, enable_environment)
2428
2429 // enable_environment is optional
2430 if (enable_environment) {
2431 strncpy(props->enable_env_var.name,
2432 enable_environment->child->string,
2433 sizeof(props->enable_env_var.name));
2434 props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] =
2435 '\0';
2436 strncpy(props->enable_env_var.value,
2437 enable_environment->child->valuestring,
2438 sizeof(props->enable_env_var.value));
2439 props->enable_env_var
2440 .value[sizeof(props->enable_env_var.value) - 1] = '\0';
2441 }
2442 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002443#undef GET_JSON_ITEM
2444#undef GET_JSON_OBJECT
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002445}
2446
2447/**
2448 * Given a cJSON struct (json) of the top level JSON object from layer manifest
2449 * file, add entry to the layer_list. Fill out the layer_properties in this list
2450 * entry from the input cJSON object.
2451 *
2452 * \returns
2453 * void
2454 * layer_list has a new entry and initialized accordingly.
2455 * If the json input object does not have all the required fields no entry
2456 * is added to the list.
2457 */
2458static void
2459loader_add_layer_properties(const struct loader_instance *inst,
2460 struct loader_layer_list *layer_instance_list,
2461 cJSON *json, bool is_implicit, char *filename) {
2462 /* Fields in layer manifest file that are required:
2463 * (required) “file_format_version”
2464 *
Mark Young0ad83132016-06-30 13:02:42 -06002465 * If more than one "layer" object are to be used, use the "layers" array
2466 * instead.
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002467 *
2468 * First get all required items and if any missing abort
2469 */
2470
2471 cJSON *item, *layers_node, *layer_node;
2472 uint16_t file_major_vers = 0;
2473 uint16_t file_minor_vers = 0;
2474 uint16_t file_patch_vers = 0;
2475 char *vers_tok;
2476 cJSON *disable_environment = NULL;
2477 item = cJSON_GetObjectItem(json, "file_format_version");
2478 if (item == NULL) {
2479 return;
2480 }
2481 char *file_vers = cJSON_PrintUnformatted(item);
Mark Young0ad83132016-06-30 13:02:42 -06002482 if (NULL == file_vers) {
2483 return;
2484 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002485 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2486 "Found manifest file %s, version %s", filename, file_vers);
2487 // Get the major/minor/and patch as integers for easier comparison
2488 vers_tok = strtok(file_vers, ".\"\n\r");
2489 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002490 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002491 vers_tok = strtok(NULL, ".\"\n\r");
2492 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002493 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002494 vers_tok = strtok(NULL, ".\"\n\r");
2495 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002496 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002497 }
2498 }
2499 }
2500 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
2501 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2502 "%s Unexpected manifest file version (expected 1.0.0 or "
2503 "1.0.1), may cause errors",
2504 filename);
2505 }
Mark Young0ad83132016-06-30 13:02:42 -06002506 cJSON_Free(file_vers);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002507 // If "layers" is present, read in the array of layer objects
2508 layers_node = cJSON_GetObjectItem(json, "layers");
2509 if (layers_node != NULL) {
2510 int numItems = cJSON_GetArraySize(layers_node);
2511 if (file_major_vers == 1 && file_minor_vers == 0 &&
2512 file_patch_vers == 0) {
2513 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2514 "\"layers\" tag not officially added until file version "
2515 "1.0.1, but %s is reporting version %s",
2516 filename, file_vers);
2517 }
2518 for (int curLayer = 0; curLayer < numItems; curLayer++) {
2519 layer_node = cJSON_GetArrayItem(layers_node, curLayer);
2520 if (layer_node == NULL) {
2521 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2522 "Can't find \"layers\" array element %d object in "
2523 "manifest JSON file %s, skipping this file",
2524 curLayer, filename);
2525 return;
2526 }
2527 loader_read_json_layer(inst, layer_instance_list, layer_node, item,
2528 disable_environment, is_implicit, filename);
2529 }
2530 } else {
2531 // Otherwise, try to read in individual layers
2532 layer_node = cJSON_GetObjectItem(json, "layer");
2533 if (layer_node == NULL) {
2534 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2535 "Can't find \"layer\" object in manifest JSON file %s, "
2536 "skipping this file",
2537 filename);
2538 return;
2539 }
2540 // Loop through all "layer" objects in the file to get a count of them
2541 // first.
2542 uint16_t layer_count = 0;
2543 cJSON *tempNode = layer_node;
2544 do {
2545 tempNode = tempNode->next;
2546 layer_count++;
2547 } while (tempNode != NULL);
2548 /*
2549 * Throw a warning if we encounter multiple "layer" objects in file
2550 * versions newer than 1.0.0. Having multiple objects with the same
2551 * name at the same level is actually a JSON standard violation.
2552 */
2553 if (layer_count > 1 &&
2554 (file_major_vers > 1 ||
2555 !(file_minor_vers == 0 && file_patch_vers == 0))) {
2556 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2557 "Multiple \"layer\" nodes are deprecated starting in "
2558 "file version \"1.0.1\". Please use \"layers\" : [] "
2559 "array instead in %s.",
2560 filename);
2561 } else {
2562 do {
2563 loader_read_json_layer(inst, layer_instance_list, layer_node,
2564 item, disable_environment, is_implicit,
2565 filename);
2566 layer_node = layer_node->next;
2567 } while (layer_node != NULL);
2568 }
2569 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002570 return;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002571}
2572
2573/**
Jon Ashburn2077e382015-06-29 11:25:34 -06002574 * Find the Vulkan library manifest files.
2575 *
Jon Ashburnb6822212016-02-16 15:34:16 -07002576 * This function scans the "location" or "env_override" directories/files
Jon Ashburn2077e382015-06-29 11:25:34 -06002577 * for a list of JSON manifest files. If env_override is non-NULL
2578 * and has a valid value. Then the location is ignored. Otherwise
2579 * location is used to look for manifest files. The location
2580 * is interpreted as Registry path on Windows and a directory path(s)
Jon Ashburnb6822212016-02-16 15:34:16 -07002581 * on Linux. "home_location" is an additional directory in the users home
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002582 * directory to look at. It is expanded into the dir path
2583 * $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
2584 * on environment variables. This "home_location" is only used on Linux.
Jon Ashburn2077e382015-06-29 11:25:34 -06002585 *
2586 * \returns
Mark Young0ad83132016-06-30 13:02:42 -06002587 * VKResult
Jon Ashburn2077e382015-06-29 11:25:34 -06002588 * A string list of manifest files to be opened in out_files param.
2589 * List has a pointer to string for each manifest filename.
2590 * When done using the list in out_files, pointers should be freed.
Jon Ashburn23d36b12016-02-02 17:47:28 -07002591 * Location or override string lists can be either files or directories as
2592 *follows:
Jon Ashburnffad94d2015-06-30 14:46:22 -07002593 * | location | override
2594 * --------------------------------
2595 * Win ICD | files | files
2596 * Win Layer | files | dirs
2597 * Linux ICD | dirs | files
2598 * Linux Layer| dirs | dirs
Jon Ashburn2077e382015-06-29 11:25:34 -06002599 */
Mark Youngf8c20102016-11-07 16:26:17 -07002600static VkResult
2601loader_get_manifest_files(const struct loader_instance *inst,
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002602 const char *env_override, const char *source_override,
Mark Youngf8c20102016-11-07 16:26:17 -07002603 bool is_layer, bool warn_if_not_present,
2604 const char *location, const char *home_location,
2605 struct loader_manifest_files *out_files) {
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002606 const char *override = NULL;
2607 char *override_getenv = NULL;
Mark Young0ad83132016-06-30 13:02:42 -06002608 char *loc, *orig_loc = NULL;
2609 char *reg = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002610 char *file, *next_file, *name;
2611 size_t alloced_count = 64;
2612 char full_path[2048];
2613 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002614 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06002615 struct dirent *dent;
Mark Young0ad83132016-06-30 13:02:42 -06002616 VkResult res = VK_SUCCESS;
Jon Ashburn2077e382015-06-29 11:25:34 -06002617
2618 out_files->count = 0;
2619 out_files->filename_list = NULL;
2620
Jamie Madill00c3c912016-04-06 18:26:46 -04002621 if (source_override != NULL) {
2622 override = source_override;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002623 } else if (env_override != NULL) {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002624#if !defined(_WIN32)
Jon Ashburncc407a22016-04-15 09:25:03 -06002625 if (geteuid() != getuid() || getegid() != getgid()) {
Jon Ashburnffad94d2015-06-30 14:46:22 -07002626 /* Don't allow setuid apps to use the env var: */
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002627 env_override = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002628 }
2629#endif
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002630 if (env_override != NULL) {
2631 override = override_getenv = loader_getenv(env_override, inst);
2632 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002633 }
2634
Jon Ashburnb6822212016-02-16 15:34:16 -07002635#if !defined(_WIN32)
2636 if (location == NULL && home_location == NULL) {
2637#else
2638 home_location = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002639 if (location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07002640#endif
Jon Ashburn23d36b12016-02-02 17:47:28 -07002641 loader_log(
2642 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburnffad94d2015-06-30 14:46:22 -07002643 "Can't get manifest files with NULL location, env_override=%s",
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002644 (env_override != NULL) ? env_override : "");
Mark Young0ad83132016-06-30 13:02:42 -06002645 res = VK_ERROR_INITIALIZATION_FAILED;
2646 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002647 }
2648
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002649#if defined(_WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -07002650 list_is_dirs = (is_layer && override != NULL) ? true : false;
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002651#else
2652 list_is_dirs = (override == NULL || is_layer) ? true : false;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002653#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06002654 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07002655 // Also handle getting the location(s) from registry on Windows
2656 if (override == NULL) {
Jon Ashburn3b78e462015-07-31 10:11:24 -06002657 loc = loader_stack_alloc(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002658 if (loc == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002659 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2660 "Out of memory can't get manifest files");
Mark Young0ad83132016-06-30 13:02:42 -06002661 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2662 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002663 }
2664 strcpy(loc, location);
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002665#if defined(_WIN32)
Mark Young0ad83132016-06-30 13:02:42 -06002666 reg = loader_get_registry_files(inst, loc);
2667 if (reg == NULL) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002668 if (!is_layer) {
2669 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2670 "Registry lookup failed can't get ICD manifest "
2671 "files, do you have a Vulkan driver installed");
Mark Young0ad83132016-06-30 13:02:42 -06002672 // This typically only fails when out of memory, which is
2673 // critical
2674 // if this is for the loader.
2675 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002676 } else {
Mark Youngf8c20102016-11-07 16:26:17 -07002677 if (warn_if_not_present) {
2678 // warning only for layers
2679 loader_log(
2680 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2681 "Registry lookup failed can't get layer manifest files");
2682 }
Mark Young0ad83132016-06-30 13:02:42 -06002683 // Return success for now since it's not critical for layers
2684 res = VK_SUCCESS;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002685 }
Mark Young0ad83132016-06-30 13:02:42 -06002686 goto out;
Jon Ashburn24265ac2015-07-31 09:33:21 -06002687 }
Mark Young0ad83132016-06-30 13:02:42 -06002688 orig_loc = loc;
2689 loc = reg;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002690#endif
Jon Ashburn23d36b12016-02-02 17:47:28 -07002691 } else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06002692 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002693 if (loc == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002694 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2695 "Out of memory can't get manifest files");
Mark Young0ad83132016-06-30 13:02:42 -06002696 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2697 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002698 }
2699 strcpy(loc, override);
2700 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002701
Liam Middlebrook9b14e892015-07-23 18:32:20 -07002702 // Print out the paths being searched if debugging is enabled
Jon Ashburn23d36b12016-02-02 17:47:28 -07002703 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2704 "Searching the following paths for manifest files: %s\n", loc);
Liam Middlebrook9b14e892015-07-23 18:32:20 -07002705
Jon Ashburn2077e382015-06-29 11:25:34 -06002706 file = loc;
2707 while (*file) {
2708 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002709 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002710 sysdir = opendir(file);
2711 name = NULL;
2712 if (sysdir) {
2713 dent = readdir(sysdir);
2714 if (dent == NULL)
2715 break;
2716 name = &(dent->d_name[0]);
2717 loader_get_fullpath(name, file, sizeof(full_path), full_path);
2718 name = full_path;
2719 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002720 } else {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002721#if defined(_WIN32)
2722 name = file;
2723#else
Jon Ashburnffad94d2015-06-30 14:46:22 -07002724 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06002725 char *dir;
2726 // make a copy of location so it isn't modified
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07002727 dir = loader_stack_alloc(strlen(loc) + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06002728 if (dir == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002729 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2730 "Out of memory can't get manifest files");
Mark Young0ad83132016-06-30 13:02:42 -06002731 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002732 }
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07002733 strcpy(dir, loc);
Jon Ashburn2077e382015-06-29 11:25:34 -06002734
2735 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
2736
2737 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002738#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06002739 }
2740 while (name) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002741 /* Look for files ending with ".json" suffix */
2742 uint32_t nlen = (uint32_t)strlen(name);
2743 const char *suf = name + nlen - 5;
2744 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
2745 if (out_files->count == 0) {
Mark Young0ad83132016-06-30 13:02:42 -06002746 out_files->filename_list = loader_instance_heap_alloc(
2747 inst, alloced_count * sizeof(char *),
2748 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002749 } else if (out_files->count == alloced_count) {
Mark Young0ad83132016-06-30 13:02:42 -06002750 out_files->filename_list = loader_instance_heap_realloc(
2751 inst, out_files->filename_list,
2752 alloced_count * sizeof(char *),
2753 alloced_count * sizeof(char *) * 2,
2754 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002755 alloced_count *= 2;
Jon Ashburn2077e382015-06-29 11:25:34 -06002756 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002757 if (out_files->filename_list == NULL) {
2758 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2759 "Out of memory can't alloc manifest file list");
Mark Young0ad83132016-06-30 13:02:42 -06002760 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2761 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002762 }
Mark Young0ad83132016-06-30 13:02:42 -06002763 out_files->filename_list[out_files->count] =
2764 loader_instance_heap_alloc(
2765 inst, strlen(name) + 1,
2766 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002767 if (out_files->filename_list[out_files->count] == NULL) {
2768 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2769 "Out of memory can't get manifest files");
Mark Young0ad83132016-06-30 13:02:42 -06002770 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2771 goto out;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002772 }
2773 strcpy(out_files->filename_list[out_files->count], name);
2774 out_files->count++;
2775 } else if (!list_is_dirs) {
2776 loader_log(
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002777 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07002778 "Skipping manifest file %s, file name must end in .json",
2779 name);
2780 }
2781 if (list_is_dirs) {
2782 dent = readdir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06002783 if (dent == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002784 break;
Mark Young0ad83132016-06-30 13:02:42 -06002785 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002786 name = &(dent->d_name[0]);
2787 loader_get_fullpath(name, file, sizeof(full_path), full_path);
2788 name = full_path;
2789 } else {
2790 break;
2791 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002792 }
Mark Young0ad83132016-06-30 13:02:42 -06002793 if (sysdir) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002794 closedir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06002795 sysdir = NULL;
2796 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002797 file = next_file;
Jon Ashburn67e262e2016-02-18 12:45:39 -07002798#if !defined(_WIN32)
Jon Ashburn1530c342016-02-26 13:14:27 -07002799 if (home_location != NULL &&
2800 (next_file == NULL || *next_file == '\0') && override == NULL) {
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002801 char *xdgdatahome = secure_getenv("XDG_DATA_HOME");
2802 size_t len;
2803 if (xdgdatahome != NULL) {
2804
2805 char *home_loc = loader_stack_alloc(strlen(xdgdatahome) + 2 +
Jon Ashburn67e262e2016-02-18 12:45:39 -07002806 strlen(home_location));
2807 if (home_loc == NULL) {
2808 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburn1530c342016-02-26 13:14:27 -07002809 "Out of memory can't get manifest files");
Mark Young0ad83132016-06-30 13:02:42 -06002810 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2811 goto out;
Jon Ashburn67e262e2016-02-18 12:45:39 -07002812 }
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002813 strcpy(home_loc, xdgdatahome);
Jon Ashburn67e262e2016-02-18 12:45:39 -07002814 // Add directory separator if needed
2815 if (home_location[0] != DIRECTORY_SYMBOL) {
2816 len = strlen(home_loc);
2817 home_loc[len] = DIRECTORY_SYMBOL;
Jon Ashburn1530c342016-02-26 13:14:27 -07002818 home_loc[len + 1] = '\0';
Jon Ashburn67e262e2016-02-18 12:45:39 -07002819 }
2820 strcat(home_loc, home_location);
2821 file = home_loc;
2822 next_file = loader_get_next_path(file);
2823 home_location = NULL;
2824
Jon Ashburn1530c342016-02-26 13:14:27 -07002825 loader_log(
2826 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002827 "Searching the following path for manifest files: %s\n",
Jon Ashburn1530c342016-02-26 13:14:27 -07002828 home_loc);
Jon Ashburn67e262e2016-02-18 12:45:39 -07002829 list_is_dirs = true;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002830
2831 } else {
2832
2833 char *home = secure_getenv("HOME");
2834 if (home != NULL) {
2835 char *home_loc = loader_stack_alloc(strlen(home) + 16 +
2836 strlen(home_location));
2837 if (home_loc == NULL) {
2838 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young0153e0b2016-11-03 14:27:13 -06002839 "Out of memory can't get manifest files");
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002840 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2841 goto out;
2842 }
2843 strcpy(home_loc, home);
2844
2845 len = strlen(home);
2846 if (home[len] != DIRECTORY_SYMBOL) {
2847 home_loc[len] = DIRECTORY_SYMBOL;
2848 home_loc[len + 1] = '\0';
2849 }
2850 strcat(home_loc, ".local/share");
2851
2852 if (home_location[0] != DIRECTORY_SYMBOL) {
2853 len = strlen(home_loc);
2854 home_loc[len] = DIRECTORY_SYMBOL;
2855 home_loc[len + 1] = '\0';
2856 }
2857 strcat(home_loc, home_location);
2858 file = home_loc;
2859 next_file = loader_get_next_path(file);
2860 home_location = NULL;
2861
2862 loader_log(
2863 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2864 "Searching the following path for manifest files: %s\n",
2865 home_loc);
2866 list_is_dirs = true;
2867 } else {
2868 // without knowing HOME, we just.. give up
2869 }
Jon Ashburn67e262e2016-02-18 12:45:39 -07002870 }
2871 }
2872#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06002873 }
Mark Young0ad83132016-06-30 13:02:42 -06002874
2875out:
2876 if (VK_SUCCESS != res && NULL != out_files->filename_list) {
2877 for (uint32_t remove = 0; remove < out_files->count; remove++) {
2878 loader_instance_heap_free(inst, out_files->filename_list[remove]);
2879 }
2880 loader_instance_heap_free(inst, out_files->filename_list);
2881 out_files->count = 0;
2882 out_files->filename_list = NULL;
2883 }
2884
2885 if (NULL != sysdir) {
2886 closedir(sysdir);
2887 }
2888
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002889 if (override_getenv != NULL) {
2890 loader_free_getenv(override_getenv, inst);
2891 }
2892
Mark Young0ad83132016-06-30 13:02:42 -06002893 if (NULL != reg && reg != orig_loc) {
2894 loader_instance_heap_free(inst, reg);
2895 }
2896 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06002897}
2898
Jon Ashburn23d36b12016-02-02 17:47:28 -07002899void loader_init_icd_lib_list() {}
Jon Ashburn8810c5f2015-08-18 18:04:47 -06002900
Jon Ashburn23d36b12016-02-02 17:47:28 -07002901void loader_destroy_icd_lib_list() {}
Jon Ashburn2077e382015-06-29 11:25:34 -06002902/**
2903 * Try to find the Vulkan ICD driver(s).
2904 *
2905 * This function scans the default system loader path(s) or path
2906 * specified by the \c VK_ICD_FILENAMES environment variable in
2907 * order to find loadable VK ICDs manifest files. From these
2908 * manifest files it finds the ICD libraries.
2909 *
2910 * \returns
Mark Young0ad83132016-06-30 13:02:42 -06002911 * Vulkan result
2912 * (on result == VK_SUCCESS) a list of icds that were discovered
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06002913 */
Mark Young0ad83132016-06-30 13:02:42 -06002914VkResult loader_icd_scan(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06002915 struct loader_icd_tramp_list *icd_tramp_list) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002916 char *file_str;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002917 uint16_t file_major_vers = 0;
2918 uint16_t file_minor_vers = 0;
2919 uint16_t file_patch_vers = 0;
2920 char *vers_tok;
Jon Ashburn2077e382015-06-29 11:25:34 -06002921 struct loader_manifest_files manifest_files;
Mark Young0ad83132016-06-30 13:02:42 -06002922 VkResult res = VK_SUCCESS;
2923 bool lockedMutex = false;
2924 cJSON *json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06002925 uint32_t num_good_icds = 0;
Jon Ashburn2077e382015-06-29 11:25:34 -06002926
Mark Young0ad83132016-06-30 13:02:42 -06002927 memset(&manifest_files, 0, sizeof(struct loader_manifest_files));
2928
Mark Young0153e0b2016-11-03 14:27:13 -06002929 res = loader_scanned_icd_init(inst, icd_tramp_list);
Mark Young0ad83132016-06-30 13:02:42 -06002930 if (VK_SUCCESS != res) {
2931 goto out;
2932 }
2933
Jon Ashburn2077e382015-06-29 11:25:34 -06002934 // Get a list of manifest files for ICDs
Mark Young0ad83132016-06-30 13:02:42 -06002935 res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false,
Mark Youngf8c20102016-11-07 16:26:17 -07002936 true, DEFAULT_VK_DRIVERS_INFO,
Mark Young0ad83132016-06-30 13:02:42 -06002937 HOME_VK_DRIVERS_INFO, &manifest_files);
2938 if (VK_SUCCESS != res || manifest_files.count == 0) {
2939 goto out;
2940 }
Jon Ashburn6461ef22015-09-22 13:11:00 -06002941 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06002942 lockedMutex = true;
Jon Ashburn2077e382015-06-29 11:25:34 -06002943 for (uint32_t i = 0; i < manifest_files.count; i++) {
2944 file_str = manifest_files.filename_list[i];
Mark Young0ad83132016-06-30 13:02:42 -06002945 if (file_str == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002946 continue;
Mark Young0ad83132016-06-30 13:02:42 -06002947 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002948
Mark Young3a587792016-08-19 15:25:08 -06002949 res = loader_get_json(inst, file_str, &json);
2950 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
2951 break;
2952 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002953 continue;
Mark Young0ad83132016-06-30 13:02:42 -06002954 }
Mark Young3a587792016-08-19 15:25:08 -06002955
Jon Ashburn005617f2015-11-17 17:35:40 -07002956 cJSON *item, *itemICD;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002957 item = cJSON_GetObjectItem(json, "file_format_version");
Jon Ashburn6461ef22015-09-22 13:11:00 -06002958 if (item == NULL) {
Mark Young3a587792016-08-19 15:25:08 -06002959 if (num_good_icds == 0) {
2960 res = VK_ERROR_INITIALIZATION_FAILED;
2961 }
Derrick Owens62e16ef2016-09-09 15:49:07 -04002962 cJSON_Delete(json);
2963 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06002964 continue;
Jon Ashburn6461ef22015-09-22 13:11:00 -06002965 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002966 char *file_vers = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06002967 if (NULL == file_vers) {
2968 // Only reason the print can fail is if there was an allocation
2969 // issue
Mark Young3a587792016-08-19 15:25:08 -06002970 if (num_good_icds == 0) {
2971 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2972 }
Derrick Owenscd92b8b2016-09-09 15:45:13 -04002973 cJSON_Delete(json);
2974 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06002975 continue;
Mark Young0ad83132016-06-30 13:02:42 -06002976 }
Mark Youngcbcbf892016-06-22 15:25:00 -06002977 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2978 "Found manifest file %s, version %s", file_str, file_vers);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002979 // Get the major/minor/and patch as integers for easier comparison
2980 vers_tok = strtok(file_vers, ".\"\n\r");
2981 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002982 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002983 vers_tok = strtok(NULL, ".\"\n\r");
2984 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002985 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002986 vers_tok = strtok(NULL, ".\"\n\r");
2987 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002988 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002989 }
2990 }
2991 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002992 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1)
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002993 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Young0ad83132016-06-30 13:02:42 -06002994 "Unexpected manifest file version (expected 1.0.0 or "
2995 "1.0.1), may "
Jon Ashburn23d36b12016-02-02 17:47:28 -07002996 "cause errors");
Mark Young0ad83132016-06-30 13:02:42 -06002997 cJSON_Free(file_vers);
Jon Ashburn005617f2015-11-17 17:35:40 -07002998 itemICD = cJSON_GetObjectItem(json, "ICD");
2999 if (itemICD != NULL) {
3000 item = cJSON_GetObjectItem(itemICD, "library_path");
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003001 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003002 char *temp = cJSON_Print(item);
Jon Ashburn86251302015-08-25 16:48:24 -06003003 if (!temp || strlen(temp) == 0) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003004 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003005 "Can't find \"library_path\" in ICD JSON file "
3006 "%s, skipping",
3007 file_str);
Mark Young3a587792016-08-19 15:25:08 -06003008 if (num_good_icds == 0) {
3009 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3010 }
Mark Young0ad83132016-06-30 13:02:42 -06003011 cJSON_Free(temp);
Jon Ashburn86251302015-08-25 16:48:24 -06003012 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003013 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003014 continue;
Jon Ashburn2077e382015-06-29 11:25:34 -06003015 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003016 // strip out extra quotes
Jon Ashburn86251302015-08-25 16:48:24 -06003017 temp[strlen(temp) - 1] = '\0';
3018 char *library_path = loader_stack_alloc(strlen(temp) + 1);
Mark Young3a587792016-08-19 15:25:08 -06003019 if (NULL == library_path) {
3020 loader_log(
3021 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3022 "Can't allocate space for \"library_path\" in ICD "
3023 "JSON file %s, skipping",
3024 file_str);
3025 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3026 cJSON_Free(temp);
3027 cJSON_Delete(json);
3028 json = NULL;
3029 goto out;
3030 }
Jon Ashburn86251302015-08-25 16:48:24 -06003031 strcpy(library_path, &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06003032 cJSON_Free(temp);
Mark Young3a587792016-08-19 15:25:08 -06003033 if (strlen(library_path) == 0) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003034 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003035 "Can't find \"library_path\" in ICD JSON file "
3036 "%s, skipping",
3037 file_str);
Jon Ashburn86251302015-08-25 16:48:24 -06003038 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003039 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003040 continue;
3041 }
Jamie Madill2fcbd152016-04-27 16:33:23 -04003042 char fullpath[MAX_STRING_SIZE];
Jon Ashburn86251302015-08-25 16:48:24 -06003043 // Print out the paths being searched if debugging is enabled
Jon Ashburn23d36b12016-02-02 17:47:28 -07003044 loader_log(
3045 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Jamie Madill2fcbd152016-04-27 16:33:23 -04003046 "Searching for ICD drivers named %s default dir %s\n",
3047 library_path, DEFAULT_VK_DRIVERS_PATH);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003048 if (loader_platform_is_path(library_path)) {
Jon Ashburn86251302015-08-25 16:48:24 -06003049 // a relative or absolute path
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003050 char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
3051 char *rel_base;
Jon Ashburn86251302015-08-25 16:48:24 -06003052 strcpy(name_copy, file_str);
3053 rel_base = loader_platform_dirname(name_copy);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003054 loader_expand_path(library_path, rel_base, sizeof(fullpath),
3055 fullpath);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003056 } else {
Jamie Madill2fcbd152016-04-27 16:33:23 -04003057 // a filename which is assumed in a system directory
3058 loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH,
3059 sizeof(fullpath), fullpath);
Jon Ashburn86251302015-08-25 16:48:24 -06003060 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003061
3062 uint32_t vers = 0;
3063 item = cJSON_GetObjectItem(itemICD, "api_version");
3064 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003065 temp = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003066 if (NULL == temp) {
3067 // Only reason the print can fail is if there was an
3068 // allocation issue
3069 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3070 goto out;
3071 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003072 vers = loader_make_version(temp);
Mark Young0ad83132016-06-30 13:02:42 -06003073 cJSON_Free(temp);
Jon Ashburn005617f2015-11-17 17:35:40 -07003074 }
Mark Young0153e0b2016-11-03 14:27:13 -06003075 res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath,
3076 vers);
Mark Young3a587792016-08-19 15:25:08 -06003077 if (VK_SUCCESS != res) {
3078 goto out;
3079 }
3080 num_good_icds++;
Mark Young0ad83132016-06-30 13:02:42 -06003081 } else {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003082 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003083 "Can't find \"library_path\" object in ICD JSON "
3084 "file %s, skipping",
3085 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003086 }
3087 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003088 loader_log(
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003089 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003090 "Can't find \"ICD\" object in ICD JSON file %s, skipping",
3091 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003092 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003093
Mark Young0ad83132016-06-30 13:02:42 -06003094 cJSON_Delete(json);
3095 json = NULL;
3096 }
3097
3098out:
3099 if (NULL != json) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003100 cJSON_Delete(json);
3101 }
Mark Young0ad83132016-06-30 13:02:42 -06003102 if (NULL != manifest_files.filename_list) {
3103 for (uint32_t i = 0; i < manifest_files.count; i++) {
3104 if (NULL != manifest_files.filename_list[i]) {
3105 loader_instance_heap_free(inst,
3106 manifest_files.filename_list[i]);
3107 }
3108 }
3109 loader_instance_heap_free(inst, manifest_files.filename_list);
3110 }
3111 if (lockedMutex) {
3112 loader_platform_thread_unlock_mutex(&loader_json_lock);
3113 }
3114 return res;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003115}
3116
Jon Ashburn23d36b12016-02-02 17:47:28 -07003117void loader_layer_scan(const struct loader_instance *inst,
Jon Ashburn491cd042016-05-16 14:01:18 -06003118 struct loader_layer_list *instance_layers) {
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003119 char *file_str;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003120 struct loader_manifest_files
3121 manifest_files[2]; // [0] = explicit, [1] = implicit
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003122 cJSON *json;
Jon Ashburn075ce432015-12-17 17:38:24 -07003123 uint32_t implicit;
Mark Young0ad83132016-06-30 13:02:42 -06003124 bool lockedMutex = false;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003125
Mark Young0ad83132016-06-30 13:02:42 -06003126 memset(manifest_files, 0, sizeof(struct loader_manifest_files) * 2);
3127
3128 // Get a list of manifest files for explicit layers
3129 if (VK_SUCCESS !=
3130 loader_get_manifest_files(inst, LAYERS_PATH_ENV, LAYERS_SOURCE_PATH,
Mark Youngf8c20102016-11-07 16:26:17 -07003131 true, true, DEFAULT_VK_ELAYERS_INFO,
Mark Young0ad83132016-06-30 13:02:42 -06003132 HOME_VK_ELAYERS_INFO, &manifest_files[0])) {
3133 goto out;
3134 }
3135
3136 // Get a list of manifest files for any implicit layers
Jon Ashburn23d36b12016-02-02 17:47:28 -07003137 // Pass NULL for environment variable override - implicit layers are not
3138 // overridden by LAYERS_PATH_ENV
Mark Youngf8c20102016-11-07 16:26:17 -07003139 if (VK_SUCCESS != loader_get_manifest_files(inst, NULL, NULL, true, false,
3140 DEFAULT_VK_ILAYERS_INFO,
3141 HOME_VK_ILAYERS_INFO,
3142 &manifest_files[1])) {
Mark Young0ad83132016-06-30 13:02:42 -06003143 goto out;
3144 }
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06003145
Mark Young0ad83132016-06-30 13:02:42 -06003146 // Make sure we have at least one layer, if not, go ahead and return
3147 if (manifest_files[0].count == 0 && manifest_files[1].count == 0) {
3148 goto out;
3149 }
3150
3151 // cleanup any previously scanned libraries
Jon Ashburne39a4f82015-08-28 13:38:21 -06003152 loader_delete_layer_properties(inst, instance_layers);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06003153
Jon Ashburn6461ef22015-09-22 13:11:00 -06003154 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003155 lockedMutex = true;
Jon Ashburn075ce432015-12-17 17:38:24 -07003156 for (implicit = 0; implicit < 2; implicit++) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003157 for (uint32_t i = 0; i < manifest_files[implicit].count; i++) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003158 file_str = manifest_files[implicit].filename_list[i];
3159 if (file_str == NULL)
3160 continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06003161
Jon Ashburn075ce432015-12-17 17:38:24 -07003162 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003163 VkResult res = loader_get_json(inst, file_str, &json);
3164 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3165 break;
3166 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003167 continue;
3168 }
3169
Jon Ashburn491cd042016-05-16 14:01:18 -06003170 loader_add_layer_properties(inst, instance_layers, json,
3171 (implicit == 1), file_str);
Jon Ashburn075ce432015-12-17 17:38:24 -07003172 cJSON_Delete(json);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003173 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003174 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07003175
3176 // add a meta layer for validation if the validation layers are all present
Mark Young0ad83132016-06-30 13:02:42 -06003177 loader_add_layer_property_meta(inst, sizeof(std_validation_names) /
3178 sizeof(std_validation_names[0]),
3179 std_validation_names, instance_layers);
Jon Ashburn86a527a2016-02-10 20:59:26 -07003180
Mark Young0ad83132016-06-30 13:02:42 -06003181out:
3182
3183 for (uint32_t manFile = 0; manFile < 2; manFile++) {
3184 if (NULL != manifest_files[manFile].filename_list) {
3185 for (uint32_t i = 0; i < manifest_files[manFile].count; i++) {
3186 if (NULL != manifest_files[manFile].filename_list[i]) {
3187 loader_instance_heap_free(
3188 inst, manifest_files[manFile].filename_list[i]);
3189 }
3190 }
3191 loader_instance_heap_free(inst,
3192 manifest_files[manFile].filename_list);
3193 }
3194 }
3195 if (lockedMutex) {
3196 loader_platform_thread_unlock_mutex(&loader_json_lock);
3197 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003198}
3199
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003200void loader_implicit_layer_scan(const struct loader_instance *inst,
Jon Ashburn491cd042016-05-16 14:01:18 -06003201 struct loader_layer_list *instance_layers) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003202 char *file_str;
3203 struct loader_manifest_files manifest_files;
3204 cJSON *json;
3205 uint32_t i;
3206
3207 // Pass NULL for environment variable override - implicit layers are not
3208 // overridden by LAYERS_PATH_ENV
Mark Young0ad83132016-06-30 13:02:42 -06003209 VkResult res = loader_get_manifest_files(
Mark Youngf8c20102016-11-07 16:26:17 -07003210 inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO,
3211 HOME_VK_ILAYERS_INFO, &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003212 if (VK_SUCCESS != res || manifest_files.count == 0) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003213 return;
3214 }
3215
3216 /* cleanup any previously scanned libraries */
3217 loader_delete_layer_properties(inst, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003218
3219 loader_platform_thread_lock_mutex(&loader_json_lock);
3220
3221 for (i = 0; i < manifest_files.count; i++) {
3222 file_str = manifest_files.filename_list[i];
3223 if (file_str == NULL) {
3224 continue;
3225 }
3226
3227 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003228 res = loader_get_json(inst, file_str, &json);
3229 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3230 break;
3231 } else if (VK_SUCCESS != res || NULL == json) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003232 continue;
3233 }
3234
Mark Young0ad83132016-06-30 13:02:42 -06003235 loader_add_layer_properties(inst, instance_layers, json, true,
3236 file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003237
Mark Young0ad83132016-06-30 13:02:42 -06003238 loader_instance_heap_free(inst, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003239 cJSON_Delete(json);
3240 }
Mark Young0ad83132016-06-30 13:02:42 -06003241 loader_instance_heap_free(inst, manifest_files.filename_list);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003242
3243 // add a meta layer for validation if the validation layers are all present
Mark Young0ad83132016-06-30 13:02:42 -06003244 loader_add_layer_property_meta(inst, sizeof(std_validation_names) /
3245 sizeof(std_validation_names[0]),
3246 std_validation_names, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003247
3248 loader_platform_thread_unlock_mutex(&loader_json_lock);
3249}
3250
Jon Ashburn23d36b12016-02-02 17:47:28 -07003251static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
3252loader_gpa_instance_internal(VkInstance inst, const char *pName) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003253 if (!strcmp(pName, "vkGetInstanceProcAddr"))
Jon Ashburn23d36b12016-02-02 17:47:28 -07003254 return (void *)loader_gpa_instance_internal;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003255 if (!strcmp(pName, "vkCreateInstance"))
Jon Ashburn1530c342016-02-26 13:14:27 -07003256 return (void *)terminator_CreateInstance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003257 if (!strcmp(pName, "vkCreateDevice"))
Jon Ashburn1530c342016-02-26 13:14:27 -07003258 return (void *)terminator_CreateDevice;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003259
Jon Ashburn27cd5842015-05-12 17:26:48 -06003260 // inst is not wrapped
3261 if (inst == VK_NULL_HANDLE) {
3262 return NULL;
3263 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003264 VkLayerInstanceDispatchTable *disp_table =
3265 *(VkLayerInstanceDispatchTable **)inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003266 void *addr;
3267
3268 if (disp_table == NULL)
3269 return NULL;
3270
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003271 bool found_name;
Jon Ashburncc407a22016-04-15 09:25:03 -06003272 addr =
3273 loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003274 if (found_name) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06003275 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003276 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003277
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003278 // Don't call down the chain, this would be an infinite loop
3279 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburncc407a22016-04-15 09:25:03 -06003280 "loader_gpa_instance_internal() unrecognized name %s", pName);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003281 return NULL;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003282}
3283
Piers Daniellf9262be2016-09-14 11:24:36 -06003284VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
Jon Ashburncc407a22016-04-15 09:25:03 -06003285loader_gpa_device_internal(VkDevice device, const char *pName) {
3286 struct loader_device *dev;
Mark Young0153e0b2016-11-03 14:27:13 -06003287 struct loader_icd_term *icd_term =
3288 loader_get_icd_and_device(device, &dev, NULL);
Mark Young16573c72016-06-28 10:52:43 -06003289
Mark Young65cb3662016-11-07 13:27:02 -07003290 // NOTE: Device Funcs needing Trampoline/Terminator.
3291 // Overrides for device functions needing a trampoline and
3292 // a terminator because certain device entry-points still need to go
3293 // through a terminator before hitting the ICD. This could be for
3294 // several reasons, but the main one is currently unwrapping an
3295 // object before passing the appropriate info along to the ICD.
3296 // This is why we also have to override the direct ICD call to
3297 // vkGetDeviceProcAddr to intercept those calls.
3298 if (!strcmp(pName, "vkGetDeviceProcAddr")) {
3299 return (PFN_vkVoidFunction)loader_gpa_device_internal;
3300 } else if (!strcmp(pName, "vkCreateSwapchainKHR")) {
Mark Young16573c72016-06-28 10:52:43 -06003301 return (PFN_vkVoidFunction)terminator_vkCreateSwapchainKHR;
Mark Young65cb3662016-11-07 13:27:02 -07003302 } else if (!strcmp(pName, "vkDebugMarkerSetObjectTagEXT")) {
3303 return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectTagEXT;
3304 } else if (!strcmp(pName, "vkDebugMarkerSetObjectNameEXT")) {
3305 return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectNameEXT;
Mark Young16573c72016-06-28 10:52:43 -06003306 }
3307
Mark Young0153e0b2016-11-03 14:27:13 -06003308 return icd_term->GetDeviceProcAddr(device, pName);
Piers Daniell295fe402016-03-29 11:51:11 -06003309}
3310
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003311/**
3312 * Initialize device_ext dispatch table entry as follows:
3313 * If dev == NULL find all logical devices created within this instance and
3314 * init the entry (given by idx) in the ext dispatch table.
3315 * If dev != NULL only initialize the entry in the given dev's dispatch table.
Jon Ashburn23d36b12016-02-02 17:47:28 -07003316 * The initialization value is gotten by calling down the device chain with
3317 * GDPA.
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003318 * If GDPA returns NULL then don't initialize the dispatch table entry.
3319 */
3320static void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003321 struct loader_device *dev,
3322 uint32_t idx,
3323 const char *funcName)
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003324
Jon Ashburn23d36b12016-02-02 17:47:28 -07003325{
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003326 void *gdpa_value;
3327 if (dev != NULL) {
3328 gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
Mark Young65cb3662016-11-07 13:27:02 -07003329 dev->chain_device, funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003330 if (gdpa_value != NULL)
Mark Young8191d9f2016-09-02 11:41:28 -06003331 dev->loader_dispatch.ext_dispatch.dev_ext[idx] =
Jon Ashburn23d36b12016-02-02 17:47:28 -07003332 (PFN_vkDevExt)gdpa_value;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003333 } else {
Mark Young0153e0b2016-11-03 14:27:13 -06003334 for (struct loader_icd_term *icd_term = inst->icd_terms;
3335 icd_term != NULL; icd_term = icd_term->next) {
3336 struct loader_device *ldev = icd_term->logical_device_list;
Karl Schultz2558bd32016-02-24 14:39:39 -07003337 while (ldev) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003338 gdpa_value =
Karl Schultz2558bd32016-02-24 14:39:39 -07003339 ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
Mark Young65cb3662016-11-07 13:27:02 -07003340 ldev->chain_device, funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003341 if (gdpa_value != NULL)
Mark Young8191d9f2016-09-02 11:41:28 -06003342 ldev->loader_dispatch.ext_dispatch.dev_ext[idx] =
Jon Ashburn23d36b12016-02-02 17:47:28 -07003343 (PFN_vkDevExt)gdpa_value;
Karl Schultz2558bd32016-02-24 14:39:39 -07003344 ldev = ldev->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003345 }
3346 }
3347 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003348}
3349
3350/**
3351 * Find all dev extension in the hash table and initialize the dispatch table
3352 * for dev for each of those extension entrypoints found in hash table.
3353
3354 */
Jon Ashburn1530c342016-02-26 13:14:27 -07003355void loader_init_dispatch_dev_ext(struct loader_instance *inst,
3356 struct loader_device *dev) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003357 for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
3358 if (inst->disp_hash[i].func_name != NULL)
3359 loader_init_dispatch_dev_ext_entry(inst, dev, i,
3360 inst->disp_hash[i].func_name);
3361 }
3362}
3363
3364static bool loader_check_icds_for_address(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003365 const char *funcName) {
Mark Young0153e0b2016-11-03 14:27:13 -06003366 struct loader_icd_term *icd_term;
3367 icd_term = inst->icd_terms;
3368 while (NULL != icd_term) {
3369 if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance,
3370 funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003371 // this icd supports funcName
3372 return true;
Mark Young0153e0b2016-11-03 14:27:13 -06003373 icd_term = icd_term->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003374 }
3375
3376 return false;
3377}
3378
Jon Ashburncc407a22016-04-15 09:25:03 -06003379static bool loader_check_layer_list_for_address(
3380 const struct loader_layer_list *const layers, const char *funcName) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003381 // Iterate over the layers.
Jon Ashburncc407a22016-04-15 09:25:03 -06003382 for (uint32_t layer = 0; layer < layers->count; ++layer) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003383 // Iterate over the extensions.
Jon Ashburncc407a22016-04-15 09:25:03 -06003384 const struct loader_device_extension_list *const extensions =
3385 &(layers->list[layer].device_extension_list);
3386 for (uint32_t extension = 0; extension < extensions->count;
3387 ++extension) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003388 // Iterate over the entry points.
Jon Ashburncc407a22016-04-15 09:25:03 -06003389 const struct loader_dev_ext_props *const property =
3390 &(extensions->list[extension]);
3391 for (uint32_t entry = 0; entry < property->entrypoint_count;
3392 ++entry) {
3393 if (strcmp(property->entrypoints[entry], funcName) == 0) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003394 return true;
3395 }
3396 }
3397 }
3398 }
3399
3400 return false;
3401}
3402
Jon Ashburn23d36b12016-02-02 17:47:28 -07003403static void loader_free_dev_ext_table(struct loader_instance *inst) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003404 for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
Mark Young0ad83132016-06-30 13:02:42 -06003405 loader_instance_heap_free(inst, inst->disp_hash[i].func_name);
3406 loader_instance_heap_free(inst, inst->disp_hash[i].list.index);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003407 }
3408 memset(inst->disp_hash, 0, sizeof(inst->disp_hash));
3409}
3410
3411static bool loader_add_dev_ext_table(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003412 uint32_t *ptr_idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003413 uint32_t i;
3414 uint32_t idx = *ptr_idx;
3415 struct loader_dispatch_hash_list *list = &inst->disp_hash[idx].list;
3416
3417 if (!inst->disp_hash[idx].func_name) {
3418 // no entry here at this idx, so use it
3419 assert(list->capacity == 0);
Mark Young0ad83132016-06-30 13:02:42 -06003420 inst->disp_hash[idx].func_name = (char *)loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07003421 inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003422 if (inst->disp_hash[idx].func_name == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003423 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003424 "loader_add_dev_ext_table() can't allocate memory for "
3425 "func_name");
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003426 return false;
3427 }
3428 strncpy(inst->disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
3429 return true;
3430 }
3431
3432 // check for enough capacity
3433 if (list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -06003434 list->index =
3435 loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)),
3436 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003437 if (list->index == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003438 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003439 "loader_add_dev_ext_table() can't allocate list memory");
3440 return false;
3441 }
3442 list->capacity = 8 * sizeof(*(list->index));
3443 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Young0153e0b2016-11-03 14:27:13 -06003444 list->index = loader_instance_heap_realloc(
3445 inst, list->index, list->capacity, list->capacity * 2,
3446 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003447 if (list->index == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003448 loader_log(
3449 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3450 "loader_add_dev_ext_table() can't reallocate list memory");
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003451 return false;
3452 }
3453 list->capacity *= 2;
3454 }
3455
Jon Ashburn23d36b12016-02-02 17:47:28 -07003456 // find an unused index in the hash table and use it
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003457 i = (idx + 1) % MAX_NUM_DEV_EXTS;
3458 do {
3459 if (!inst->disp_hash[i].func_name) {
3460 assert(inst->disp_hash[i].list.capacity == 0);
Mark Young0153e0b2016-11-03 14:27:13 -06003461 inst->disp_hash[i].func_name = (char *)loader_instance_heap_alloc(
3462 inst, strlen(funcName) + 1,
3463 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003464 if (inst->disp_hash[i].func_name == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003465 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003466 "loader_add_dev_ext_table() can't rallocate "
3467 "func_name memory");
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003468 return false;
3469 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003470 strncpy(inst->disp_hash[i].func_name, funcName,
3471 strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003472 list->index[list->count] = i;
3473 list->count++;
3474 *ptr_idx = i;
3475 return true;
3476 }
3477 i = (i + 1) % MAX_NUM_DEV_EXTS;
3478 } while (i != idx);
3479
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003480 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003481 "loader_add_dev_ext_table() couldn't insert into hash table; is "
3482 "it full?");
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003483 return false;
3484}
3485
3486static bool loader_name_in_dev_ext_table(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003487 uint32_t *idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003488 uint32_t alt_idx;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003489 if (inst->disp_hash[*idx].func_name &&
3490 !strcmp(inst->disp_hash[*idx].func_name, funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003491 return true;
3492
3493 // funcName wasn't at the primary spot in the hash table
3494 // search the list of secondary locations (shallow search, not deep search)
3495 for (uint32_t i = 0; i < inst->disp_hash[*idx].list.count; i++) {
3496 alt_idx = inst->disp_hash[*idx].list.index[i];
3497 if (!strcmp(inst->disp_hash[*idx].func_name, funcName)) {
3498 *idx = alt_idx;
3499 return true;
3500 }
3501 }
3502
3503 return false;
3504}
3505
3506/**
Jon Ashburn23d36b12016-02-02 17:47:28 -07003507 * This function returns generic trampoline code address for unknown entry
3508 * points.
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003509 * Presumably, these unknown entry points (as given by funcName) are device
3510 * extension entrypoints. A hash table is used to keep a list of unknown entry
3511 * points and their mapping to the device extension dispatch table
3512 * (struct loader_dev_ext_dispatch_table).
3513 * \returns
Jon Ashburn23d36b12016-02-02 17:47:28 -07003514 * For a given entry point string (funcName), if an existing mapping is found
3515 * the
3516 * trampoline address for that mapping is returned. Otherwise, this unknown
3517 * entry point
3518 * has not been seen yet. Next check if a layer or ICD supports it. If so then
3519 * a
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003520 * new entry in the hash table is initialized and that trampoline address for
3521 * the new entry is returned. Null is returned if the hash table is full or
3522 * if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
3523 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003524void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003525 uint32_t idx;
3526 uint32_t seed = 0;
3527
3528 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_DEV_EXTS;
3529
3530 if (loader_name_in_dev_ext_table(inst, &idx, funcName))
3531 // found funcName already in hash
3532 return loader_get_dev_ext_trampoline(idx);
3533
3534 // Check if funcName is supported in either ICDs or a layer library
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003535 if (!loader_check_icds_for_address(inst, funcName) &&
Mark Young0153e0b2016-11-03 14:27:13 -06003536 !loader_check_layer_list_for_address(&inst->instance_layer_list,
3537 funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003538 // if support found in layers continue on
3539 return NULL;
3540 }
3541
3542 if (loader_add_dev_ext_table(inst, &idx, funcName)) {
3543 // successfully added new table entry
3544 // init any dev dispatch table entrys as needed
3545 loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
3546 return loader_get_dev_ext_trampoline(idx);
3547 }
3548
3549 return NULL;
3550}
3551
Jon Ashburn23d36b12016-02-02 17:47:28 -07003552struct loader_instance *loader_get_instance(const VkInstance instance) {
Jon Ashburne0e64572015-09-30 12:56:42 -06003553 /* look up the loader_instance in our list by comparing dispatch tables, as
3554 * there is no guarantee the instance is still a loader_instance* after any
3555 * layers which wrap the instance object.
3556 */
3557 const VkLayerInstanceDispatchTable *disp;
3558 struct loader_instance *ptr_instance = NULL;
3559 disp = loader_get_instance_dispatch(instance);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003560 for (struct loader_instance *inst = loader.instances; inst;
3561 inst = inst->next) {
Jon Ashburne0e64572015-09-30 12:56:42 -06003562 if (inst->disp == disp) {
3563 ptr_instance = inst;
3564 break;
3565 }
3566 }
3567 return ptr_instance;
3568}
3569
Jon Ashburn23d36b12016-02-02 17:47:28 -07003570static loader_platform_dl_handle
Mark Young0153e0b2016-11-03 14:27:13 -06003571loader_open_layer_lib(const struct loader_instance *inst,
3572 const char *chain_type,
3573 struct loader_layer_properties *prop) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003574
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003575 if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) ==
Jon Ashburn23d36b12016-02-02 17:47:28 -07003576 NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003577 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003578 loader_platform_open_library_error(prop->lib_name));
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003579 } else {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003580 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003581 "Chain: %s: Loading layer library %s", chain_type,
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003582 prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003583 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003584
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003585 return prop->lib_handle;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003586}
3587
Mark Young0153e0b2016-11-03 14:27:13 -06003588static void loader_close_layer_lib(const struct loader_instance *inst,
3589 struct loader_layer_properties *prop) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003590
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003591 if (prop->lib_handle) {
3592 loader_platform_close_library(prop->lib_handle);
3593 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3594 "Unloading layer library %s", prop->lib_name);
3595 prop->lib_handle = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003596 }
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003597}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003598
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003599void loader_deactivate_layers(const struct loader_instance *instance,
Mark Young0ad83132016-06-30 13:02:42 -06003600 struct loader_device *device,
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003601 struct loader_layer_list *list) {
3602 /* delete instance list of enabled layers and close any layer libraries */
3603 for (uint32_t i = 0; i < list->count; i++) {
3604 struct loader_layer_properties *layer_prop = &list->list[i];
Courtney Goeltzenleuchter80bfd0e2015-12-17 09:51:22 -07003605
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003606 loader_close_layer_lib(instance, layer_prop);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003607 }
Mark Young0ad83132016-06-30 13:02:42 -06003608 loader_destroy_layer_list(instance, device, list);
Jon Ashburnb8358052014-11-18 09:06:04 -07003609}
3610
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003611/**
3612 * Go through the search_list and find any layers which match type. If layer
3613 * type match is found in then add it to ext_list.
3614 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003615static void
3616loader_add_layer_implicit(const struct loader_instance *inst,
3617 const enum layer_type type,
3618 struct loader_layer_list *list,
3619 const struct loader_layer_list *search_list) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003620 bool enable;
3621 char *env_value;
Jon Ashburn0c26e712015-07-02 16:10:32 -06003622 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003623 for (i = 0; i < search_list->count; i++) {
3624 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06003625 if (prop->type & type) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003626 /* Found an implicit layer, see if it should be enabled */
3627 enable = false;
3628
Jon Ashburn23d36b12016-02-02 17:47:28 -07003629 // if no enable_environment variable is specified, this implicit
3630 // layer
Jon Ashburn075ce432015-12-17 17:38:24 -07003631 // should always be enabled. Otherwise check if the variable is set
3632 if (prop->enable_env_var.name[0] == 0) {
3633 enable = true;
3634 } else {
Mark Young0ad83132016-06-30 13:02:42 -06003635 env_value = loader_getenv(prop->enable_env_var.name, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003636 if (env_value && !strcmp(prop->enable_env_var.value, env_value))
3637 enable = true;
Mark Young0ad83132016-06-30 13:02:42 -06003638 loader_free_getenv(env_value, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003639 }
3640
3641 // disable_environment has priority, i.e. if both enable and disable
Jon Ashburn23d36b12016-02-02 17:47:28 -07003642 // environment variables are set, the layer is disabled. Implicit
3643 // layers
Jon Ashburn075ce432015-12-17 17:38:24 -07003644 // are required to have a disable_environment variables
Mark Young0ad83132016-06-30 13:02:42 -06003645 env_value = loader_getenv(prop->disable_env_var.name, inst);
3646 if (env_value) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003647 enable = false;
Mark Young0ad83132016-06-30 13:02:42 -06003648 }
3649 loader_free_getenv(env_value, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003650
Mark Young0ad83132016-06-30 13:02:42 -06003651 if (enable) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003652 loader_add_to_layer_list(inst, list, 1, prop);
Mark Young0ad83132016-06-30 13:02:42 -06003653 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06003654 }
3655 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06003656}
3657
3658/**
3659 * Get the layer name(s) from the env_name environment variable. If layer
Jon Ashburnbd332cc2015-07-07 10:27:45 -06003660 * is found in search_list then add it to layer_list. But only add it to
3661 * layer_list if type matches.
Jon Ashburn0c26e712015-07-02 16:10:32 -06003662 */
Jon Ashburn491cd042016-05-16 14:01:18 -06003663static void loader_add_layer_env(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003664 const enum layer_type type,
3665 const char *env_name,
3666 struct loader_layer_list *layer_list,
3667 const struct loader_layer_list *search_list) {
Ian Elliott4470a302015-02-17 10:33:47 -07003668 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06003669 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003670
Mark Young0ad83132016-06-30 13:02:42 -06003671 layerEnv = loader_getenv(env_name, inst);
Ian Elliott4470a302015-02-17 10:33:47 -07003672 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003673 return;
Ian Elliott4470a302015-02-17 10:33:47 -07003674 }
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06003675 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06003676 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003677 return;
Ian Elliott4470a302015-02-17 10:33:47 -07003678 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06003679 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003680
Mark Young0ad83132016-06-30 13:02:42 -06003681 loader_free_getenv(layerEnv, inst);
Jon Ashburn38a497f2016-01-04 14:01:38 -07003682
Jon Ashburn23d36b12016-02-02 17:47:28 -07003683 while (name && *name) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06003684 next = loader_get_next_path(name);
Jon Ashburn71483442016-02-11 18:59:43 -07003685 if (!strcmp(std_validation_str, name)) {
3686 /* add meta list of layers
3687 don't attempt to remove duplicate layers already added by app or
3688 env var
3689 */
3690 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
3691 "Expanding meta layer %s found in environment variable",
3692 std_validation_str);
Jon Ashburn491cd042016-05-16 14:01:18 -06003693 if (type == VK_LAYER_TYPE_INSTANCE_EXPLICIT)
3694 inst->activated_layers_are_std_val = true;
Jon Ashburn71483442016-02-11 18:59:43 -07003695 for (uint32_t i = 0; i < sizeof(std_validation_names) /
3696 sizeof(std_validation_names[0]);
3697 i++) {
3698 loader_find_layer_name_add_list(inst, std_validation_names[i],
3699 type, search_list, layer_list);
3700 }
3701 } else {
3702 loader_find_layer_name_add_list(inst, name, type, search_list,
3703 layer_list);
3704 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06003705 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003706 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003707
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003708 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003709}
3710
Jon Ashburn23d36b12016-02-02 17:47:28 -07003711VkResult
3712loader_enable_instance_layers(struct loader_instance *inst,
3713 const VkInstanceCreateInfo *pCreateInfo,
3714 const struct loader_layer_list *instance_layers) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003715 VkResult err;
3716
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06003717 assert(inst && "Cannot have null instance");
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003718
Jon Ashburne39a4f82015-08-28 13:38:21 -06003719 if (!loader_init_layer_list(inst, &inst->activated_layer_list)) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003720 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3721 "Failed to alloc Instance activated layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003722 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06003723 }
3724
Jon Ashburn0c26e712015-07-02 16:10:32 -06003725 /* Add any implicit layers first */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003726 loader_add_layer_implicit(inst, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
3727 &inst->activated_layer_list, instance_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06003728
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003729 /* Add any layers specified via environment variable next */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003730 loader_add_layer_env(inst, VK_LAYER_TYPE_INSTANCE_EXPLICIT,
3731 "VK_INSTANCE_LAYERS", &inst->activated_layer_list,
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003732 instance_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06003733
3734 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003735 err = loader_add_layer_names_to_list(
Jon Ashburn23d36b12016-02-02 17:47:28 -07003736 inst, &inst->activated_layer_list, pCreateInfo->enabledLayerCount,
3737 pCreateInfo->ppEnabledLayerNames, instance_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003738
3739 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003740}
3741
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003742/*
3743 * Given the list of layers to activate in the loader_instance
3744 * structure. This function will add a VkLayerInstanceCreateInfo
3745 * structure to the VkInstanceCreateInfo.pNext pointer.
3746 * Each activated layer will have it's own VkLayerInstanceLink
3747 * structure that tells the layer what Get*ProcAddr to call to
3748 * get function pointers to the next layer down.
3749 * Once the chain info has been created this function will
3750 * execute the CreateInstance call chain. Each layer will
3751 * then have an opportunity in it's CreateInstance function
3752 * to setup it's dispatch table when the lower layer returns
3753 * successfully.
3754 * Each layer can wrap or not-wrap the returned VkInstance object
3755 * as it sees fit.
3756 * The instance chain is terminated by a loader function
3757 * that will call CreateInstance on all available ICD's and
3758 * cache those VkInstance objects for future use.
3759 */
3760VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003761 const VkAllocationCallbacks *pAllocator,
Jon Ashburn373c1802016-01-20 08:08:25 -07003762 struct loader_instance *inst,
Jon Ashburn6e0a2132016-02-03 12:37:30 -07003763 VkInstance *created_instance) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003764 uint32_t activated_layers = 0;
3765 VkLayerInstanceCreateInfo chain_info;
3766 VkLayerInstanceLink *layer_instance_link_info = NULL;
3767 VkInstanceCreateInfo loader_create_info;
3768 VkResult res;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003769
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003770 PFN_vkGetInstanceProcAddr nextGIPA = loader_gpa_instance_internal;
3771 PFN_vkGetInstanceProcAddr fpGIPA = loader_gpa_instance_internal;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003772
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003773 memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
Jon Ashburn27cd5842015-05-12 17:26:48 -06003774
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003775 if (inst->activated_layer_list.count > 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003776
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003777 chain_info.u.pLayerInfo = NULL;
3778 chain_info.pNext = pCreateInfo->pNext;
3779 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
3780 chain_info.function = VK_LAYER_LINK_INFO;
3781 loader_create_info.pNext = &chain_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003782
Jon Ashburn23d36b12016-02-02 17:47:28 -07003783 layer_instance_link_info = loader_stack_alloc(
3784 sizeof(VkLayerInstanceLink) * inst->activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003785 if (!layer_instance_link_info) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003786 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3787 "Failed to alloc Instance objects for layer");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003788 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003789 }
3790
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003791 /* Create instance chain of enabled layers */
3792 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003793 struct loader_layer_properties *layer_prop =
3794 &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003795 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003796
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003797 lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003798 if (!lib_handle)
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07003799 continue;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003800 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
3801 NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05003802 if (strlen(layer_prop->functions.str_gipa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003803 fpGIPA = (PFN_vkGetInstanceProcAddr)
3804 loader_platform_get_proc_address(
3805 lib_handle, "vkGetInstanceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003806 layer_prop->functions.get_instance_proc_addr = fpGIPA;
3807 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07003808 fpGIPA = (PFN_vkGetInstanceProcAddr)
3809 loader_platform_get_proc_address(
3810 lib_handle, layer_prop->functions.str_gipa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003811 if (!fpGIPA) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003812 loader_log(
3813 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3814 "Failed to find vkGetInstanceProcAddr in layer %s",
3815 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003816 continue;
3817 }
3818 }
3819
Jon Ashburn23d36b12016-02-02 17:47:28 -07003820 layer_instance_link_info[activated_layers].pNext =
3821 chain_info.u.pLayerInfo;
3822 layer_instance_link_info[activated_layers]
3823 .pfnNextGetInstanceProcAddr = nextGIPA;
3824 chain_info.u.pLayerInfo =
3825 &layer_instance_link_info[activated_layers];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003826 nextGIPA = fpGIPA;
3827
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003828 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003829 "Insert instance layer %s (%s)",
3830 layer_prop->info.layerName, layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003831
3832 activated_layers++;
3833 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06003834 }
3835
Jon Ashburn23d36b12016-02-02 17:47:28 -07003836 PFN_vkCreateInstance fpCreateInstance =
Jon Ashburn6e0a2132016-02-03 12:37:30 -07003837 (PFN_vkCreateInstance)nextGIPA(*created_instance, "vkCreateInstance");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003838 if (fpCreateInstance) {
Jon Ashburnc3c58772016-03-29 11:16:01 -06003839 VkLayerInstanceCreateInfo create_info_disp;
3840
Jon Ashburncc407a22016-04-15 09:25:03 -06003841 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06003842 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
Jon Ashburnc3c58772016-03-29 11:16:01 -06003843
3844 create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
3845
3846 create_info_disp.pNext = loader_create_info.pNext;
3847 loader_create_info.pNext = &create_info_disp;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07003848 res =
3849 fpCreateInstance(&loader_create_info, pAllocator, created_instance);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003850 } else {
3851 // Couldn't find CreateInstance function!
3852 res = VK_ERROR_INITIALIZATION_FAILED;
3853 }
3854
3855 if (res != VK_SUCCESS) {
3856 // TODO: Need to clean up here
3857 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003858 loader_init_instance_core_dispatch_table(inst->disp, nextGIPA,
Jon Ashburn6e0a2132016-02-03 12:37:30 -07003859 *created_instance);
Jon Ashburn4e8c4162016-03-08 15:21:30 -07003860 inst->instance = *created_instance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003861 }
3862
3863 return res;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003864}
3865
Jon Ashburn23d36b12016-02-02 17:47:28 -07003866void loader_activate_instance_layer_extensions(struct loader_instance *inst,
3867 VkInstance created_inst) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003868
Jon Ashburn23d36b12016-02-02 17:47:28 -07003869 loader_init_instance_extension_dispatch_table(
3870 inst->disp, inst->disp->GetInstanceProcAddr, created_inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06003871}
3872
Jon Ashburn1530c342016-02-26 13:14:27 -07003873VkResult
Jon Ashburncc407a22016-04-15 09:25:03 -06003874loader_create_device_chain(const struct loader_physical_device_tramp *pd,
3875 const VkDeviceCreateInfo *pCreateInfo,
3876 const VkAllocationCallbacks *pAllocator,
3877 const struct loader_instance *inst,
3878 struct loader_device *dev) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003879 uint32_t activated_layers = 0;
3880 VkLayerDeviceLink *layer_device_link_info;
3881 VkLayerDeviceCreateInfo chain_info;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003882 VkDeviceCreateInfo loader_create_info;
3883 VkResult res;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06003884
Piers Daniell295fe402016-03-29 11:51:11 -06003885 PFN_vkGetDeviceProcAddr fpGDPA, nextGDPA = loader_gpa_device_internal;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003886 PFN_vkGetInstanceProcAddr fpGIPA, nextGIPA = loader_gpa_instance_internal;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06003887
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003888 memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
3889
Jon Ashburn23d36b12016-02-02 17:47:28 -07003890 layer_device_link_info = loader_stack_alloc(
3891 sizeof(VkLayerDeviceLink) * dev->activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003892 if (!layer_device_link_info) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003893 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3894 "Failed to alloc Device objects for layer");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003895 return VK_ERROR_OUT_OF_HOST_MEMORY;
David Pinedoa0a8a242015-06-24 15:29:18 -06003896 }
Jon Ashburn94e70492015-06-10 10:13:10 -06003897
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003898 if (dev->activated_layer_list.count > 0) {
Jon Ashburn72690f22016-03-29 12:52:13 -06003899 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
3900 chain_info.function = VK_LAYER_LINK_INFO;
3901 chain_info.u.pLayerInfo = NULL;
3902 chain_info.pNext = pCreateInfo->pNext;
3903 loader_create_info.pNext = &chain_info;
3904
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003905 /* Create instance chain of enabled layers */
3906 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003907 struct loader_layer_properties *layer_prop =
3908 &dev->activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003909 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06003910
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003911 lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003912 if (!lib_handle)
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07003913 continue;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003914 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
3915 NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05003916 if (strlen(layer_prop->functions.str_gipa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003917 fpGIPA = (PFN_vkGetInstanceProcAddr)
3918 loader_platform_get_proc_address(
3919 lib_handle, "vkGetInstanceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003920 layer_prop->functions.get_instance_proc_addr = fpGIPA;
3921 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07003922 fpGIPA = (PFN_vkGetInstanceProcAddr)
3923 loader_platform_get_proc_address(
3924 lib_handle, layer_prop->functions.str_gipa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003925 if (!fpGIPA) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003926 loader_log(
3927 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3928 "Failed to find vkGetInstanceProcAddr in layer %s",
3929 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003930 continue;
3931 }
Jon Ashburn21c21ee2015-09-09 11:29:24 -06003932 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003933 if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05003934 if (strlen(layer_prop->functions.str_gdpa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003935 fpGDPA = (PFN_vkGetDeviceProcAddr)
3936 loader_platform_get_proc_address(lib_handle,
3937 "vkGetDeviceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003938 layer_prop->functions.get_device_proc_addr = fpGDPA;
3939 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07003940 fpGDPA = (PFN_vkGetDeviceProcAddr)
3941 loader_platform_get_proc_address(
3942 lib_handle, layer_prop->functions.str_gdpa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003943 if (!fpGDPA) {
Jon Ashburnc0dc07c2016-05-16 17:35:43 -06003944 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003945 "Failed to find vkGetDeviceProcAddr in layer %s",
3946 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003947 continue;
3948 }
3949 }
3950
Jon Ashburn23d36b12016-02-02 17:47:28 -07003951 layer_device_link_info[activated_layers].pNext =
3952 chain_info.u.pLayerInfo;
3953 layer_device_link_info[activated_layers]
3954 .pfnNextGetInstanceProcAddr = nextGIPA;
3955 layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr =
3956 nextGDPA;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003957 chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
3958 nextGIPA = fpGIPA;
3959 nextGDPA = fpGDPA;
3960
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003961 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003962 "Insert device layer %s (%s)",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003963 layer_prop->info.layerName, layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003964
3965 activated_layers++;
Jon Ashburn94e70492015-06-10 10:13:10 -06003966 }
Jon Ashburn94e70492015-06-10 10:13:10 -06003967 }
3968
Jon Ashburncc407a22016-04-15 09:25:03 -06003969 VkDevice created_device = (VkDevice)dev;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003970 PFN_vkCreateDevice fpCreateDevice =
Jon Ashburn4e8c4162016-03-08 15:21:30 -07003971 (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003972 if (fpCreateDevice) {
Jon Ashburned8f2312016-03-31 10:52:22 -06003973 VkLayerDeviceCreateInfo create_info_disp;
3974
Jon Ashburncc407a22016-04-15 09:25:03 -06003975 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06003976 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
3977
3978 create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
3979
3980 create_info_disp.pNext = loader_create_info.pNext;
3981 loader_create_info.pNext = &create_info_disp;
Jon Ashburn014438f2016-03-01 19:51:07 -07003982 res = fpCreateDevice(pd->phys_dev, &loader_create_info, pAllocator,
Jon Ashburn72690f22016-03-29 12:52:13 -06003983 &created_device);
Piers Daniellefbbfc12016-04-05 17:28:06 -06003984 if (res != VK_SUCCESS) {
3985 return res;
3986 }
Mark Young65cb3662016-11-07 13:27:02 -07003987 dev->chain_device = created_device;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003988 } else {
3989 // Couldn't find CreateDevice function!
3990 return VK_ERROR_INITIALIZATION_FAILED;
3991 }
Jon Ashburn94e70492015-06-10 10:13:10 -06003992
Mark Young65cb3662016-11-07 13:27:02 -07003993 // Initialize device dispatch table
Jon Ashburn23d36b12016-02-02 17:47:28 -07003994 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA,
Mark Young65cb3662016-11-07 13:27:02 -07003995 dev->chain_device);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003996
3997 return res;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06003998}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003999
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004000VkResult loader_validate_layers(const struct loader_instance *inst,
4001 const uint32_t layer_count,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004002 const char *const *ppEnabledLayerNames,
4003 const struct loader_layer_list *list) {
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004004 struct loader_layer_properties *prop;
4005
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004006 for (uint32_t i = 0; i < layer_count; i++) {
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004007 VkStringErrorFlags result =
4008 vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004009 if (result != VK_STRING_ERROR_NONE) {
4010 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004011 "Loader: Device ppEnabledLayerNames contains string "
4012 "that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004013 return VK_ERROR_LAYER_NOT_PRESENT;
4014 }
4015
Jon Ashburn23d36b12016-02-02 17:47:28 -07004016 prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004017 if (!prop) {
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004018 return VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004019 }
4020 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004021 return VK_SUCCESS;
4022}
4023
4024VkResult loader_validate_instance_extensions(
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004025 const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004026 const struct loader_extension_list *icd_exts,
4027 const struct loader_layer_list *instance_layer,
4028 const VkInstanceCreateInfo *pCreateInfo) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004029
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004030 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004031 struct loader_layer_properties *layer_prop;
4032
Jon Ashburnf19916e2016-01-11 13:12:43 -07004033 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004034 VkStringErrorFlags result = vk_string_validate(
4035 MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004036 if (result != VK_STRING_ERROR_NONE) {
4037 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004038 "Loader: Instance ppEnabledExtensionNames contains "
4039 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004040 return VK_ERROR_EXTENSION_NOT_PRESENT;
4041 }
4042
Jon Ashburn23d36b12016-02-02 17:47:28 -07004043 extension_prop = get_extension_property(
4044 pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004045
4046 if (extension_prop) {
4047 continue;
4048 }
4049
4050 extension_prop = NULL;
4051
4052 /* Not in global list, search layer extension lists */
Jon Ashburnf19916e2016-01-11 13:12:43 -07004053 for (uint32_t j = 0; j < pCreateInfo->enabledLayerCount; j++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004054 layer_prop = loader_get_layer_property(
Jan-Harald Fredriksene812a642016-09-28 12:10:24 +02004055 pCreateInfo->ppEnabledLayerNames[j], instance_layer);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004056 if (!layer_prop) {
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06004057 /* Should NOT get here, loader_validate_layers
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004058 * should have already filtered this case out.
4059 */
4060 continue;
4061 }
4062
Jon Ashburn23d36b12016-02-02 17:47:28 -07004063 extension_prop =
4064 get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
4065 &layer_prop->instance_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004066 if (extension_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004067 /* Found the extension in one of the layers enabled by the app.
4068 */
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004069 break;
4070 }
4071 }
4072
4073 if (!extension_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004074 /* Didn't find extension name in any of the global layers, error out
4075 */
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004076 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004077 }
4078 }
4079 return VK_SUCCESS;
4080}
4081
4082VkResult loader_validate_device_extensions(
Jon Ashburn787eb252016-03-24 15:49:57 -06004083 struct loader_physical_device_tramp *phys_dev,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004084 const struct loader_layer_list *activated_device_layers,
Jon Ashburn014438f2016-03-01 19:51:07 -07004085 const struct loader_extension_list *icd_exts,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004086 const VkDeviceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004087 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004088 struct loader_layer_properties *layer_prop;
4089
Jon Ashburnf19916e2016-01-11 13:12:43 -07004090 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004091
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004092 VkStringErrorFlags result = vk_string_validate(
4093 MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004094 if (result != VK_STRING_ERROR_NONE) {
Jon Ashburncc407a22016-04-15 09:25:03 -06004095 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4096 0, "Loader: Device ppEnabledExtensionNames contains "
4097 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004098 return VK_ERROR_EXTENSION_NOT_PRESENT;
4099 }
4100
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004101 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07004102 extension_prop = get_extension_property(extension_name, icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004103
4104 if (extension_prop) {
4105 continue;
4106 }
4107
Jon Ashburn471f44c2016-01-13 12:51:43 -07004108 /* Not in global list, search activated layer extension lists */
4109 for (uint32_t j = 0; j < activated_device_layers->count; j++) {
4110 layer_prop = &activated_device_layers->list[j];
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004111
Jon Ashburn23d36b12016-02-02 17:47:28 -07004112 extension_prop = get_dev_extension_property(
4113 extension_name, &layer_prop->device_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004114 if (extension_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004115 /* Found the extension in one of the layers enabled by the app.
4116 */
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004117 break;
4118 }
4119 }
4120
4121 if (!extension_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004122 /* Didn't find extension name in any of the device layers, error out
4123 */
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004124 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004125 }
4126 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004127 return VK_SUCCESS;
4128}
4129
Jon Ashburn1530c342016-02-26 13:14:27 -07004130/**
4131 * Terminator functions for the Instance chain
4132 * All named terminator_<Vulakn API name>
4133 */
Mark Young0ad83132016-06-30 13:02:42 -06004134VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(
4135 const VkInstanceCreateInfo *pCreateInfo,
4136 const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
Mark Young0153e0b2016-11-03 14:27:13 -06004137 struct loader_icd_term *icd_term;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004138 VkExtensionProperties *prop;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004139 char **filtered_extension_names = NULL;
4140 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004141 VkResult res = VK_SUCCESS;
Mark Young8b4edb52016-11-11 09:31:55 -07004142 bool one_icd_successful = false;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004143
Jon Ashburncc407a22016-04-15 09:25:03 -06004144 struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
Tony Barbour3c78ff42015-12-04 13:24:39 -07004145 memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
4146
Jon Ashburnf19916e2016-01-11 13:12:43 -07004147 icd_create_info.enabledLayerCount = 0;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004148 icd_create_info.ppEnabledLayerNames = NULL;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004149
4150 /*
4151 * NOTE: Need to filter the extensions to only those
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004152 * supported by the ICD.
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004153 * No ICD will advertise support for layers. An ICD
4154 * library could support a layer, but it would be
4155 * independent of the actual ICD, just in the same library.
4156 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07004157 filtered_extension_names =
4158 loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004159 if (!filtered_extension_names) {
Mark Young3a587792016-08-19 15:25:08 -06004160 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4161 goto out;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004162 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07004163 icd_create_info.ppEnabledExtensionNames =
4164 (const char *const *)filtered_extension_names;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004165
Mark Young0153e0b2016-11-03 14:27:13 -06004166 for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
4167 icd_term = loader_icd_add(
4168 ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
4169 if (NULL == icd_term) {
Mark Young3a587792016-08-19 15:25:08 -06004170 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4171 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06004172 }
4173 icd_create_info.enabledExtensionCount = 0;
4174 struct loader_extension_list icd_exts;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004175
Mark Young0ad83132016-06-30 13:02:42 -06004176 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
4177 "Build ICD instance extension list");
4178 // traverse scanned icd list adding non-duplicate extensions to the
4179 // list
Mark Young3a587792016-08-19 15:25:08 -06004180 res = loader_init_generic_list(ptr_instance,
Mark Young0153e0b2016-11-03 14:27:13 -06004181 (struct loader_generic_list *)&icd_exts,
4182 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06004183 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4184 // If out of memory, bail immediately.
4185 goto out;
4186 } else if (VK_SUCCESS != res) {
Mark Young7e471292016-09-06 09:53:45 -06004187 // Something bad happened with this ICD, so free it and try the
4188 // next.
Mark Young0153e0b2016-11-03 14:27:13 -06004189 ptr_instance->icd_terms = icd_term->next;
4190 icd_term->next = NULL;
4191 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004192 continue;
4193 }
4194
4195 res = loader_add_instance_extensions(
Mark Young0ad83132016-06-30 13:02:42 -06004196 ptr_instance,
Mark Young0153e0b2016-11-03 14:27:13 -06004197 icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
4198 icd_term->scanned_icd->lib_name, &icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004199 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06004200 loader_destroy_generic_list(
4201 ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004202 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4203 // If out of memory, bail immediately.
4204 goto out;
4205 } else {
4206 // Something bad happened with this ICD, so free it and try
4207 // the next.
Mark Young0153e0b2016-11-03 14:27:13 -06004208 ptr_instance->icd_terms = icd_term->next;
4209 icd_term->next = NULL;
4210 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004211 continue;
4212 }
Mark Young3a587792016-08-19 15:25:08 -06004213 }
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -07004214
Mark Young0ad83132016-06-30 13:02:42 -06004215 for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
4216 prop = get_extension_property(
4217 pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
4218 if (prop) {
4219 filtered_extension_names[icd_create_info
4220 .enabledExtensionCount] =
4221 (char *)pCreateInfo->ppEnabledExtensionNames[j];
4222 icd_create_info.enabledExtensionCount++;
Jon Ashburn46888392015-01-29 15:45:51 -07004223 }
4224 }
Mark Young0ad83132016-06-30 13:02:42 -06004225
4226 loader_destroy_generic_list(ptr_instance,
4227 (struct loader_generic_list *)&icd_exts);
4228
Mark Young8b4edb52016-11-11 09:31:55 -07004229 VkResult icd_result =
4230 ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(
4231 &icd_create_info, pAllocator, &(icd_term->instance));
4232 if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06004233 // If out of memory, bail immediately.
Mark Young8b4edb52016-11-11 09:31:55 -07004234 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06004235 goto out;
Mark Young8b4edb52016-11-11 09:31:55 -07004236 } else if (VK_SUCCESS != icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06004237 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
4238 "ICD ignored: failed to CreateInstance in ICD %d", i);
Mark Young0153e0b2016-11-03 14:27:13 -06004239 ptr_instance->icd_terms = icd_term->next;
4240 icd_term->next = NULL;
4241 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004242 continue;
4243 }
Mark Young0ad83132016-06-30 13:02:42 -06004244
Mark Young0153e0b2016-11-03 14:27:13 -06004245 if (!loader_icd_init_entrys(icd_term, icd_term->instance,
4246 ptr_instance->icd_tramp_list.scanned_list[i]
4247 .GetInstanceProcAddr)) {
Mark Young3a587792016-08-19 15:25:08 -06004248 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Young0ad83132016-06-30 13:02:42 -06004249 "ICD ignored: failed to CreateInstance and find "
4250 "entrypoints with ICD");
Mark Young3a587792016-08-19 15:25:08 -06004251 continue;
Mark Young0ad83132016-06-30 13:02:42 -06004252 }
Mark Young8b4edb52016-11-11 09:31:55 -07004253
4254 // If we made it this far, at least one ICD was successful
4255 one_icd_successful = true;
Jon Ashburn46888392015-01-29 15:45:51 -07004256 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004257
Mark Young8b4edb52016-11-11 09:31:55 -07004258 // If no ICDs were added to instance list and res is unchanged
4259 // from it's initial value, the loader was unable to find
4260 // a suitable ICD.
4261 if (VK_SUCCESS == res &&
4262 (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
Mark Young3a587792016-08-19 15:25:08 -06004263 res = VK_ERROR_INCOMPATIBLE_DRIVER;
4264 }
4265
4266out:
4267
4268 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06004269 while (NULL != ptr_instance->icd_terms) {
4270 icd_term = ptr_instance->icd_terms;
4271 ptr_instance->icd_terms = icd_term->next;
4272 if (NULL != icd_term->instance) {
4273 icd_term->DestroyInstance(icd_term->instance, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004274 }
Mark Young0153e0b2016-11-03 14:27:13 -06004275 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004276 }
Ian Elliotteb450762015-02-05 15:19:15 -07004277 }
Jon Ashburn46888392015-01-29 15:45:51 -07004278
Mark Young3a587792016-08-19 15:25:08 -06004279 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004280}
4281
Mark Young0ad83132016-06-30 13:02:42 -06004282VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(
4283 VkInstance instance, const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06004284 struct loader_instance *ptr_instance = loader_instance(instance);
Mark Young0153e0b2016-11-03 14:27:13 -06004285 struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
4286 struct loader_icd_term *next_icd_term;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004287
4288 // Remove this instance from the list of instances:
4289 struct loader_instance *prev = NULL;
4290 struct loader_instance *next = loader.instances;
4291 while (next != NULL) {
4292 if (next == ptr_instance) {
4293 // Remove this instance from the list:
4294 if (prev)
4295 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07004296 else
4297 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004298 break;
4299 }
4300 prev = next;
4301 next = next->next;
4302 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004303
Mark Young0153e0b2016-11-03 14:27:13 -06004304 while (NULL != icd_terms) {
4305 if (icd_terms->instance) {
4306 icd_terms->DestroyInstance(icd_terms->instance, pAllocator);
Tony Barbourf20f87b2015-04-22 09:02:32 -06004307 }
Mark Young0153e0b2016-11-03 14:27:13 -06004308 next_icd_term = icd_terms->next;
4309 icd_terms->instance = VK_NULL_HANDLE;
4310 loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
Jon Ashburna6fd2612015-06-16 14:43:19 -06004311
Mark Young0153e0b2016-11-03 14:27:13 -06004312 icd_terms = next_icd_term;
Jon Ashburn46888392015-01-29 15:45:51 -07004313 }
Jon Ashburn491cd042016-05-16 14:01:18 -06004314
Jon Ashburn23d36b12016-02-02 17:47:28 -07004315 loader_delete_layer_properties(ptr_instance,
4316 &ptr_instance->instance_layer_list);
Mark Young0153e0b2016-11-03 14:27:13 -06004317 loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
Jon Ashburn23d36b12016-02-02 17:47:28 -07004318 loader_destroy_generic_list(
4319 ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
Jon Ashburn014438f2016-03-01 19:51:07 -07004320 if (ptr_instance->phys_devs_term)
Mark Young0ad83132016-06-30 13:02:42 -06004321 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004322 loader_free_dev_ext_table(ptr_instance);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004323}
4324
Mark Young0ad83132016-06-30 13:02:42 -06004325VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(
4326 VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
4327 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
4328 VkResult res = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06004329 struct loader_physical_device_term *phys_dev_term;
4330 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
4331 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004332
Jon Ashburncc407a22016-04-15 09:25:03 -06004333 struct loader_device *dev = (struct loader_device *)*pDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06004334 PFN_vkCreateDevice fpCreateDevice = icd_term->CreateDevice;
Mark Young0ad83132016-06-30 13:02:42 -06004335 struct loader_extension_list icd_exts;
4336
Mark Young65cb3662016-11-07 13:27:02 -07004337 dev->phys_dev_term = phys_dev_term;
4338
Mark Young0ad83132016-06-30 13:02:42 -06004339 icd_exts.list = NULL;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004340
Jon Ashburn1530c342016-02-26 13:14:27 -07004341 if (fpCreateDevice == NULL) {
Mark Young0153e0b2016-11-03 14:27:13 -06004342 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young9a3ddd42016-10-21 16:25:47 -06004343 "No vkCreateDevice command exposed by ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06004344 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06004345 res = VK_ERROR_INITIALIZATION_FAILED;
4346 goto out;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004347 }
4348
Jon Ashburn1530c342016-02-26 13:14:27 -07004349 VkDeviceCreateInfo localCreateInfo;
4350 memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
Jon Ashburn1530c342016-02-26 13:14:27 -07004351
4352 /*
4353 * NOTE: Need to filter the extensions to only those
4354 * supported by the ICD.
4355 * No ICD will advertise support for layers. An ICD
4356 * library could support a layer, but it would be
4357 * independent of the actual ICD, just in the same library.
4358 */
4359 char **filtered_extension_names = NULL;
4360 filtered_extension_names =
4361 loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
4362 if (!filtered_extension_names) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004363 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004364 }
4365
Jon Ashburn1530c342016-02-26 13:14:27 -07004366 localCreateInfo.enabledLayerCount = 0;
4367 localCreateInfo.ppEnabledLayerNames = NULL;
4368
4369 localCreateInfo.enabledExtensionCount = 0;
4370 localCreateInfo.ppEnabledExtensionNames =
4371 (const char *const *)filtered_extension_names;
4372
Jon Ashburn014438f2016-03-01 19:51:07 -07004373 /* Get the physical device (ICD) extensions */
Mark Young0153e0b2016-11-03 14:27:13 -06004374 res = loader_init_generic_list(icd_term->this_instance,
4375 (struct loader_generic_list *)&icd_exts,
4376 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06004377 if (VK_SUCCESS != res) {
Mark Young0ad83132016-06-30 13:02:42 -06004378 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07004379 }
4380
4381 res = loader_add_device_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06004382 icd_term->this_instance, icd_term->EnumerateDeviceExtensionProperties,
4383 phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
Jon Ashburn014438f2016-03-01 19:51:07 -07004384 if (res != VK_SUCCESS) {
Mark Young0ad83132016-06-30 13:02:42 -06004385 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07004386 }
4387
Jon Ashburn1530c342016-02-26 13:14:27 -07004388 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4389 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07004390 VkExtensionProperties *prop =
4391 get_extension_property(extension_name, &icd_exts);
Jon Ashburn1530c342016-02-26 13:14:27 -07004392 if (prop) {
4393 filtered_extension_names[localCreateInfo.enabledExtensionCount] =
4394 (char *)extension_name;
4395 localCreateInfo.enabledExtensionCount++;
Mark Young9a3ddd42016-10-21 16:25:47 -06004396 } else {
Mark Young0153e0b2016-11-03 14:27:13 -06004397 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT,
4398 0, "vkCreateDevice extension %s not available for "
4399 "devices associated with ICD %s",
4400 extension_name, icd_term->scanned_icd->lib_name);
Jon Ashburn1530c342016-02-26 13:14:27 -07004401 }
4402 }
4403
Mark Young0153e0b2016-11-03 14:27:13 -06004404 res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator,
Mark Young65cb3662016-11-07 13:27:02 -07004405 &dev->icd_device);
Jon Ashburn1530c342016-02-26 13:14:27 -07004406 if (res != VK_SUCCESS) {
Mark Young0153e0b2016-11-03 14:27:13 -06004407 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young9a3ddd42016-10-21 16:25:47 -06004408 "vkCreateDevice call failed in ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06004409 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06004410 goto out;
Jon Ashburn1530c342016-02-26 13:14:27 -07004411 }
4412
Mark Young65cb3662016-11-07 13:27:02 -07004413 *pDevice = dev->icd_device;
Mark Young0153e0b2016-11-03 14:27:13 -06004414 loader_add_logical_device(icd_term->this_instance, icd_term, dev);
Jon Ashburn1530c342016-02-26 13:14:27 -07004415
4416 /* Init dispatch pointer in new device object */
4417 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
4418
Mark Young0ad83132016-06-30 13:02:42 -06004419out:
4420 if (NULL != icd_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06004421 loader_destroy_generic_list(icd_term->this_instance,
Mark Young0ad83132016-06-30 13:02:42 -06004422 (struct loader_generic_list *)&icd_exts);
4423 }
4424
Jon Ashburn1530c342016-02-26 13:14:27 -07004425 return res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004426}
4427
Mark Young0153e0b2016-11-03 14:27:13 -06004428VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(
4429 VkInstance instance, uint32_t *pPhysicalDeviceCount,
4430 VkPhysicalDevice *pPhysicalDevices) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004431 uint32_t i;
Jon Ashburn014438f2016-03-01 19:51:07 -07004432 struct loader_instance *inst = (struct loader_instance *)instance;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004433 VkResult res = VK_SUCCESS;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07004434
Mark Young0153e0b2016-11-03 14:27:13 -06004435 struct loader_icd_term *icd_term;
Jon Ashburn014438f2016-03-01 19:51:07 -07004436 struct loader_phys_dev_per_icd *phys_devs;
4437
4438 inst->total_gpu_count = 0;
4439 phys_devs = (struct loader_phys_dev_per_icd *)loader_stack_alloc(
4440 sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
4441 if (!phys_devs)
4442 return VK_ERROR_OUT_OF_HOST_MEMORY;
4443
Mark Young0153e0b2016-11-03 14:27:13 -06004444 icd_term = inst->icd_terms;
Jon Ashburn014438f2016-03-01 19:51:07 -07004445 for (i = 0; i < inst->total_icd_count; i++) {
Mark Young0153e0b2016-11-03 14:27:13 -06004446 assert(icd_term);
4447 res = icd_term->EnumeratePhysicalDevices(icd_term->instance,
4448 &phys_devs[i].count, NULL);
Jon Ashburn014438f2016-03-01 19:51:07 -07004449 if (res != VK_SUCCESS)
4450 return res;
Mark Young0153e0b2016-11-03 14:27:13 -06004451 icd_term = icd_term->next;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07004452 }
4453
Mark Young0153e0b2016-11-03 14:27:13 -06004454 icd_term = inst->icd_terms;
Jon Ashburn014438f2016-03-01 19:51:07 -07004455 for (i = 0; i < inst->total_icd_count; i++) {
Mark Young0153e0b2016-11-03 14:27:13 -06004456 assert(icd_term);
Jon Ashburn014438f2016-03-01 19:51:07 -07004457 phys_devs[i].phys_devs = (VkPhysicalDevice *)loader_stack_alloc(
4458 phys_devs[i].count * sizeof(VkPhysicalDevice));
4459 if (!phys_devs[i].phys_devs) {
4460 return VK_ERROR_OUT_OF_HOST_MEMORY;
4461 }
Mark Young0153e0b2016-11-03 14:27:13 -06004462 res = icd_term->EnumeratePhysicalDevices(
4463 icd_term->instance, &(phys_devs[i].count), phys_devs[i].phys_devs);
Jamie Madillc3d3f072016-12-14 17:21:43 -05004464 if (res == VK_SUCCESS) {
Jon Ashburn014438f2016-03-01 19:51:07 -07004465 inst->total_gpu_count += phys_devs[i].count;
4466 } else {
4467 return res;
4468 }
Mark Young0153e0b2016-11-03 14:27:13 -06004469 phys_devs[i].this_icd_term = icd_term;
4470 icd_term = icd_term->next;
Jon Ashburn014438f2016-03-01 19:51:07 -07004471 }
Mark Young76a24632016-10-27 15:32:08 -06004472 if (inst->total_gpu_count == 0) {
4473 return VK_ERROR_INITIALIZATION_FAILED;
4474 }
Jon Ashburn014438f2016-03-01 19:51:07 -07004475
Mark Young559d7502016-09-26 11:38:46 -06004476 uint32_t copy_count = inst->total_gpu_count;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07004477
Mark Young559d7502016-09-26 11:38:46 -06004478 if (NULL != pPhysicalDevices) {
4479 // Initialize the output pPhysicalDevices with wrapped loader
4480 // terminator physicalDevice objects; save this list of
4481 // wrapped objects in instance struct for later cleanup and
4482 // use by trampoline code
4483 uint32_t j, idx = 0;
Jon Ashburn014438f2016-03-01 19:51:07 -07004484
Mark Young559d7502016-09-26 11:38:46 -06004485 if (copy_count > *pPhysicalDeviceCount) {
4486 copy_count = *pPhysicalDeviceCount;
4487 }
Jon Ashburn014438f2016-03-01 19:51:07 -07004488
Mark Young76a24632016-10-27 15:32:08 -06004489 if (NULL == inst->phys_devs_term) {
Mark Young559d7502016-09-26 11:38:46 -06004490 inst->phys_devs_term = loader_instance_heap_alloc(
Mark Young0153e0b2016-11-03 14:27:13 -06004491 inst, sizeof(struct loader_physical_device_term) *
4492 inst->total_gpu_count,
Mark Young559d7502016-09-26 11:38:46 -06004493 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young76a24632016-10-27 15:32:08 -06004494 if (NULL == inst->phys_devs_term) {
Mark Young559d7502016-09-26 11:38:46 -06004495 return VK_ERROR_OUT_OF_HOST_MEMORY;
4496 }
4497 }
Jon Ashburn1a02c2f2016-03-11 14:43:57 -07004498
Mark Young76a24632016-10-27 15:32:08 -06004499 for (i = 0; idx < inst->total_gpu_count && i < inst->total_icd_count;
4500 i++) {
4501 for (j = 0; j < phys_devs[i].count && idx < inst->total_gpu_count;
4502 j++) {
Mark Young559d7502016-09-26 11:38:46 -06004503 loader_set_dispatch((void *)&inst->phys_devs_term[idx],
4504 inst->disp);
Mark Young0153e0b2016-11-03 14:27:13 -06004505 inst->phys_devs_term[idx].this_icd_term =
4506 phys_devs[i].this_icd_term;
Jamie Madilld29fc092016-10-24 16:54:40 -04004507 inst->phys_devs_term[idx].icd_index = (uint8_t)(i);
Mark Young559d7502016-09-26 11:38:46 -06004508 inst->phys_devs_term[idx].phys_dev = phys_devs[i].phys_devs[j];
Slawomir Cyganeb610df2016-10-05 18:38:02 +02004509 if (idx < copy_count) {
4510 pPhysicalDevices[idx] =
4511 (VkPhysicalDevice)&inst->phys_devs_term[idx];
4512 }
Mark Young559d7502016-09-26 11:38:46 -06004513 idx++;
4514 }
4515 }
4516
4517 if (copy_count < inst->total_gpu_count) {
Mark Young559d7502016-09-26 11:38:46 -06004518 res = VK_INCOMPLETE;
Jon Ashburn014438f2016-03-01 19:51:07 -07004519 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004520 }
Mark Young559d7502016-09-26 11:38:46 -06004521
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004522 *pPhysicalDeviceCount = copy_count;
4523
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004524 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004525}
4526
Jon Ashburn1530c342016-02-26 13:14:27 -07004527VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(
4528 VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06004529 struct loader_physical_device_term *phys_dev_term =
4530 (struct loader_physical_device_term *)physicalDevice;
4531 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburn3da71f22015-05-14 12:43:38 -06004532
Mark Young0153e0b2016-11-03 14:27:13 -06004533 if (icd_term->GetPhysicalDeviceProperties)
4534 icd_term->GetPhysicalDeviceProperties(phys_dev_term->phys_dev,
4535 pProperties);
Tony Barbour59a47322015-06-24 16:06:58 -06004536}
4537
Jon Ashburn1530c342016-02-26 13:14:27 -07004538VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07004539 VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
4540 VkQueueFamilyProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06004541 struct loader_physical_device_term *phys_dev_term =
4542 (struct loader_physical_device_term *)physicalDevice;
4543 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Tony Barbour59a47322015-06-24 16:06:58 -06004544
Mark Young0153e0b2016-11-03 14:27:13 -06004545 if (icd_term->GetPhysicalDeviceQueueFamilyProperties)
4546 icd_term->GetPhysicalDeviceQueueFamilyProperties(
4547 phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
Tony Barbour59a47322015-06-24 16:06:58 -06004548}
4549
Jon Ashburn1530c342016-02-26 13:14:27 -07004550VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07004551 VkPhysicalDevice physicalDevice,
4552 VkPhysicalDeviceMemoryProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06004553 struct loader_physical_device_term *phys_dev_term =
4554 (struct loader_physical_device_term *)physicalDevice;
4555 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Tony Barbour59a47322015-06-24 16:06:58 -06004556
Mark Young0153e0b2016-11-03 14:27:13 -06004557 if (icd_term->GetPhysicalDeviceMemoryProperties)
4558 icd_term->GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev,
4559 pProperties);
Jon Ashburn3da71f22015-05-14 12:43:38 -06004560}
4561
Mark Young0153e0b2016-11-03 14:27:13 -06004562VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(
4563 VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures) {
4564 struct loader_physical_device_term *phys_dev_term =
4565 (struct loader_physical_device_term *)physicalDevice;
4566 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Chris Forbesbc0bb772015-06-21 22:55:02 +12004567
Mark Young0153e0b2016-11-03 14:27:13 -06004568 if (icd_term->GetPhysicalDeviceFeatures)
4569 icd_term->GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
Chris Forbesbc0bb772015-06-21 22:55:02 +12004570}
4571
Mark Young0153e0b2016-11-03 14:27:13 -06004572VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(
4573 VkPhysicalDevice physicalDevice, VkFormat format,
4574 VkFormatProperties *pFormatInfo) {
4575 struct loader_physical_device_term *phys_dev_term =
4576 (struct loader_physical_device_term *)physicalDevice;
4577 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Chris Forbesbc0bb772015-06-21 22:55:02 +12004578
Mark Young0153e0b2016-11-03 14:27:13 -06004579 if (icd_term->GetPhysicalDeviceFormatProperties)
4580 icd_term->GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev,
4581 format, pFormatInfo);
Chris Forbesbc0bb772015-06-21 22:55:02 +12004582}
4583
Jon Ashburn1530c342016-02-26 13:14:27 -07004584VKAPI_ATTR VkResult VKAPI_CALL
4585terminator_GetPhysicalDeviceImageFormatProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07004586 VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
4587 VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
4588 VkImageFormatProperties *pImageFormatProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06004589 struct loader_physical_device_term *phys_dev_term =
4590 (struct loader_physical_device_term *)physicalDevice;
4591 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburn754864f2015-07-23 18:49:07 -06004592
Mark Young0153e0b2016-11-03 14:27:13 -06004593 if (!icd_term->GetPhysicalDeviceImageFormatProperties)
Chia-I Wu17241042015-10-31 00:31:16 +08004594 return VK_ERROR_INITIALIZATION_FAILED;
4595
Mark Young0153e0b2016-11-03 14:27:13 -06004596 return icd_term->GetPhysicalDeviceImageFormatProperties(
4597 phys_dev_term->phys_dev, format, type, tiling, usage, flags,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004598 pImageFormatProperties);
Jon Ashburn754864f2015-07-23 18:49:07 -06004599}
4600
Jon Ashburn1530c342016-02-26 13:14:27 -07004601VKAPI_ATTR void VKAPI_CALL
4602terminator_GetPhysicalDeviceSparseImageFormatProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07004603 VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
4604 VkSampleCountFlagBits samples, VkImageUsageFlags usage,
4605 VkImageTiling tiling, uint32_t *pNumProperties,
4606 VkSparseImageFormatProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06004607 struct loader_physical_device_term *phys_dev_term =
4608 (struct loader_physical_device_term *)physicalDevice;
4609 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06004610
Mark Young0153e0b2016-11-03 14:27:13 -06004611 if (icd_term->GetPhysicalDeviceSparseImageFormatProperties)
4612 icd_term->GetPhysicalDeviceSparseImageFormatProperties(
4613 phys_dev_term->phys_dev, format, type, samples, usage, tiling,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004614 pNumProperties, pProperties);
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06004615}
4616
Jon Ashburn1530c342016-02-26 13:14:27 -07004617VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(
4618 VkPhysicalDevice physicalDevice, const char *pLayerName,
4619 uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06004620 struct loader_physical_device_term *phys_dev_term;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07004621
Mark Young3a587792016-08-19 15:25:08 -06004622 struct loader_layer_list implicit_layer_list = {0};
4623 struct loader_extension_list all_exts = {0};
4624 struct loader_extension_list icd_exts = {0};
Jon Ashburn471f44c2016-01-13 12:51:43 -07004625
Jon Ashburndc5d9202016-02-29 13:00:51 -07004626 assert(pLayerName == NULL || strlen(pLayerName) == 0);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06004627
Jon Ashburndc5d9202016-02-29 13:00:51 -07004628 /* Any layer or trampoline wrapping should be removed at this point in time
4629 * can just cast to the expected type for VkPhysicalDevice. */
Mark Young0153e0b2016-11-03 14:27:13 -06004630 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Jon Ashburn471f44c2016-01-13 12:51:43 -07004631
Jon Ashburndc5d9202016-02-29 13:00:51 -07004632 /* this case is during the call down the instance chain with pLayerName
4633 * == NULL*/
Mark Young0153e0b2016-11-03 14:27:13 -06004634 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburndc5d9202016-02-29 13:00:51 -07004635 uint32_t icd_ext_count = *pPropertyCount;
4636 VkResult res;
Jon Ashburn471f44c2016-01-13 12:51:43 -07004637
Jon Ashburndc5d9202016-02-29 13:00:51 -07004638 /* get device extensions */
Mark Young0153e0b2016-11-03 14:27:13 -06004639 res = icd_term->EnumerateDeviceExtensionProperties(
4640 phys_dev_term->phys_dev, NULL, &icd_ext_count, pProperties);
Mark Young3a587792016-08-19 15:25:08 -06004641 if (res != VK_SUCCESS) {
4642 goto out;
4643 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07004644
Mark Young0153e0b2016-11-03 14:27:13 -06004645 if (!loader_init_layer_list(icd_term->this_instance,
4646 &implicit_layer_list)) {
Mark Young3a587792016-08-19 15:25:08 -06004647 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4648 goto out;
4649 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07004650
Jon Ashburndc5d9202016-02-29 13:00:51 -07004651 loader_add_layer_implicit(
Mark Young0153e0b2016-11-03 14:27:13 -06004652 icd_term->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
4653 &implicit_layer_list, &icd_term->this_instance->instance_layer_list);
Jon Ashburndc5d9202016-02-29 13:00:51 -07004654 /* we need to determine which implicit layers are active,
4655 * and then add their extensions. This can't be cached as
4656 * it depends on results of environment variables (which can change).
4657 */
4658 if (pProperties != NULL) {
4659 /* initialize dev_extension list within the physicalDevice object */
Mark Young0153e0b2016-11-03 14:27:13 -06004660 res = loader_init_device_extensions(icd_term->this_instance,
4661 phys_dev_term, icd_ext_count,
4662 pProperties, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06004663 if (res != VK_SUCCESS) {
4664 goto out;
4665 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07004666
Jon Ashburndc5d9202016-02-29 13:00:51 -07004667 /* we need to determine which implicit layers are active,
4668 * and then add their extensions. This can't be cached as
4669 * it depends on results of environment variables (which can
4670 * change).
4671 */
Mark Young0153e0b2016-11-03 14:27:13 -06004672 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts,
Mark Young3a587792016-08-19 15:25:08 -06004673 icd_exts.count, icd_exts.list);
4674 if (res != VK_SUCCESS) {
4675 goto out;
4676 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07004677
Jon Ashburndc5d9202016-02-29 13:00:51 -07004678 loader_add_layer_implicit(
Mark Young0153e0b2016-11-03 14:27:13 -06004679 icd_term->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
4680 &implicit_layer_list,
4681 &icd_term->this_instance->instance_layer_list);
Jon Ashburn471f44c2016-01-13 12:51:43 -07004682
Jon Ashburndc5d9202016-02-29 13:00:51 -07004683 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
4684 for (uint32_t j = 0;
Jon Ashburn014438f2016-03-01 19:51:07 -07004685 j < implicit_layer_list.list[i].device_extension_list.count;
4686 j++) {
Mark Young0153e0b2016-11-03 14:27:13 -06004687 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts,
4688 1,
Mark Young3a587792016-08-19 15:25:08 -06004689 &implicit_layer_list.list[i]
4690 .device_extension_list.list[j]
4691 .props);
4692 if (res != VK_SUCCESS) {
4693 goto out;
4694 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07004695 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07004696 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07004697 uint32_t capacity = *pPropertyCount;
4698 VkExtensionProperties *props = pProperties;
Jon Ashburn471f44c2016-01-13 12:51:43 -07004699
Jon Ashburndc5d9202016-02-29 13:00:51 -07004700 for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
4701 props[i] = all_exts.list[i];
4702 }
4703 /* wasn't enough space for the extensions, we did partial copy now
4704 * return VK_INCOMPLETE */
4705 if (capacity < all_exts.count) {
4706 res = VK_INCOMPLETE;
4707 } else {
4708 *pPropertyCount = all_exts.count;
4709 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07004710 } else {
4711 /* just return the count; need to add in the count of implicit layer
4712 * extensions
4713 * don't worry about duplicates being added in the count */
4714 *pPropertyCount = icd_ext_count;
4715
4716 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
4717 *pPropertyCount +=
Jon Ashburn014438f2016-03-01 19:51:07 -07004718 implicit_layer_list.list[i].device_extension_list.count;
Jon Ashburndc5d9202016-02-29 13:00:51 -07004719 }
4720 res = VK_SUCCESS;
Jon Ashburnb82c1852015-08-11 14:49:54 -06004721 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07004722
Mark Young3a587792016-08-19 15:25:08 -06004723out:
4724
4725 if (NULL != implicit_layer_list.list) {
4726 loader_destroy_generic_list(
Mark Young0153e0b2016-11-03 14:27:13 -06004727 icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06004728 (struct loader_generic_list *)&implicit_layer_list);
4729 }
4730 if (NULL != all_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06004731 loader_destroy_generic_list(icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06004732 (struct loader_generic_list *)&all_exts);
4733 }
4734 if (NULL != icd_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06004735 loader_destroy_generic_list(icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06004736 (struct loader_generic_list *)&icd_exts);
4737 }
4738
Jon Ashburndc5d9202016-02-29 13:00:51 -07004739 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06004740}
4741
Mark Young0153e0b2016-11-03 14:27:13 -06004742VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(
4743 VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
4744 VkLayerProperties *pProperties) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06004745
Jon Ashburndc5d9202016-02-29 13:00:51 -07004746 // should never get here this call isn't dispatched down the chain
4747 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06004748}
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004749
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004750VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004751 VkStringErrorFlags result = VK_STRING_ERROR_NONE;
Karl Schultz2558bd32016-02-24 14:39:39 -07004752 int num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004753 int i, j;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004754
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004755 for (i = 0; i < max_length; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004756 if (utf8[i] == 0) {
4757 break;
Mark Lobodzinski36b4de22016-02-12 11:30:14 -07004758 } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004759 num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004760 } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004761 num_char_bytes = 1;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004762 } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004763 num_char_bytes = 2;
4764 } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
4765 num_char_bytes = 3;
4766 } else {
4767 result = VK_STRING_ERROR_BAD_DATA;
4768 }
4769
4770 // Validate the following num_char_bytes of data
4771 for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
4772 if (++i == max_length) {
4773 result |= VK_STRING_ERROR_LENGTH;
4774 break;
4775 }
4776 if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
4777 result |= VK_STRING_ERROR_BAD_DATA;
4778 }
4779 }
4780 }
4781 return result;
4782}