blob: 351bf2ec675326030e45baea998e3b3ba7a7ffca [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
Lenny Komow4053b812016-12-29 16:27:28 -0700167// A null-terminated list of all of the instance extensions supported by the
168// loader
169static const char *const LOADER_INSTANCE_EXTENSIONS[] = {
170 VK_KHR_SURFACE_EXTENSION_NAME,
171 VK_KHR_DISPLAY_EXTENSION_NAME,
172#ifdef VK_USE_PLATFORM_XLIB_KHR
173 VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
174#endif
175#ifdef VK_USE_PLATFORM_XCB_KHR
176 VK_KHR_XCB_SURFACE_EXTENSION_NAME,
177#endif
178#ifdef VK_USE_PLATFORM_WAYLAND_KHR
179 VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
180#endif
181#ifdef VK_USE_PLATFORM_MIR_KHR
182 VK_KHR_MIR_SURFACE_EXTENSION_NAME,
183#endif
184#ifdef VK_USE_PLATFORM_ANDROID_KHR
185 VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
186#endif
187#ifdef VK_USE_PLATFORM_WIN32_KHR
188 VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
189#endif
190 VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
191 VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
192 VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME,
193 NULL};
194
Jon Ashburn8810c5f2015-08-18 18:04:47 -0600195LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
Ian Elliott2d4ab1e2015-01-13 17:52:38 -0700196
Mark Young0ad83132016-06-30 13:02:42 -0600197void *loader_instance_heap_alloc(const struct loader_instance *instance,
198 size_t size,
199 VkSystemAllocationScope alloc_scope) {
200 void *pMemory = NULL;
201#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
202 {
203#else
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800204 if (instance && instance->alloc_callbacks.pfnAllocation) {
Mark Young0ad83132016-06-30 13:02:42 -0600205 /* These are internal structures, so it's best to align everything to
206 * the largest unit size which is the size of a uint64_t.
207 */
208 pMemory = instance->alloc_callbacks.pfnAllocation(
209 instance->alloc_callbacks.pUserData, size, sizeof(uint64_t),
Jon Ashburn23d36b12016-02-02 17:47:28 -0700210 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600211 } else {
212#endif
213 pMemory = malloc(size);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600214 }
Mark Young0ad83132016-06-30 13:02:42 -0600215 return pMemory;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600216}
217
Mark Young0ad83132016-06-30 13:02:42 -0600218void loader_instance_heap_free(const struct loader_instance *instance,
219 void *pMemory) {
220 if (pMemory != NULL) {
221#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
222 {
223#else
224 if (instance && instance->alloc_callbacks.pfnFree) {
225 instance->alloc_callbacks.pfnFree(
226 instance->alloc_callbacks.pUserData, pMemory);
227 } else {
228#endif
229 free(pMemory);
Mark Youngd077f992016-06-30 11:03:59 -0600230 }
Mark Young4b0b9222016-06-29 18:33:53 -0600231 }
Mark Young4b0b9222016-06-29 18:33:53 -0600232}
233
Mark Young0ad83132016-06-30 13:02:42 -0600234void *loader_instance_heap_realloc(const struct loader_instance *instance,
235 void *pMemory, size_t orig_size, size_t size,
236 VkSystemAllocationScope alloc_scope) {
237 void *pNewMem = NULL;
238 if (pMemory == NULL || orig_size == 0) {
239 pNewMem = loader_instance_heap_alloc(instance, size, alloc_scope);
240 } else if (size == 0) {
241 loader_instance_heap_free(instance, pMemory);
242#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
243#else
244 } else if (instance && instance->alloc_callbacks.pfnReallocation) {
245 /* These are internal structures, so it's best to align everything to
246 * the largest unit size which is the size of a uint64_t.
247 */
248 pNewMem = instance->alloc_callbacks.pfnReallocation(
249 instance->alloc_callbacks.pUserData, pMemory, size,
250 sizeof(uint64_t), alloc_scope);
251#endif
252 } else {
253 pNewMem = realloc(pMemory, size);
254 }
255 return pNewMem;
Mark Young4b0b9222016-06-29 18:33:53 -0600256}
257
Mark Young0ad83132016-06-30 13:02:42 -0600258void *loader_instance_tls_heap_alloc(size_t size) {
259 return loader_instance_heap_alloc(tls_instance, size,
260 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young4b0b9222016-06-29 18:33:53 -0600261}
Mark Young4b0b9222016-06-29 18:33:53 -0600262
Mark Young0ad83132016-06-30 13:02:42 -0600263void loader_instance_tls_heap_free(void *pMemory) {
264 loader_instance_heap_free(tls_instance, pMemory);
265}
266
267void *loader_device_heap_alloc(const struct loader_device *device, size_t size,
268 VkSystemAllocationScope alloc_scope) {
269 void *pMemory = NULL;
270#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
271 {
272#else
273 if (device && device->alloc_callbacks.pfnAllocation) {
274 /* These are internal structures, so it's best to align everything to
275 * the largest unit size which is the size of a uint64_t.
276 */
277 pMemory = device->alloc_callbacks.pfnAllocation(
278 device->alloc_callbacks.pUserData, size, sizeof(uint64_t),
279 alloc_scope);
280 } else {
281#endif
282 pMemory = malloc(size);
283 }
284 return pMemory;
285}
286
287void loader_device_heap_free(const struct loader_device *device,
288 void *pMemory) {
289 if (pMemory != NULL) {
290#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
291 {
292#else
293 if (device && device->alloc_callbacks.pfnFree) {
294 device->alloc_callbacks.pfnFree(device->alloc_callbacks.pUserData,
295 pMemory);
296 } else {
297#endif
298 free(pMemory);
299 }
300 }
301}
302
303void *loader_device_heap_realloc(const struct loader_device *device,
304 void *pMemory, size_t orig_size, size_t size,
305 VkSystemAllocationScope alloc_scope) {
306 void *pNewMem = NULL;
307 if (pMemory == NULL || orig_size == 0) {
308 pNewMem = loader_device_heap_alloc(device, size, alloc_scope);
309 } else if (size == 0) {
310 loader_device_heap_free(device, pMemory);
311#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
312#else
313 } else if (device && device->alloc_callbacks.pfnReallocation) {
314 /* These are internal structures, so it's best to align everything to
315 * the largest unit size which is the size of a uint64_t.
316 */
317 pNewMem = device->alloc_callbacks.pfnReallocation(
318 device->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
319 alloc_scope);
320#endif
321 } else {
322 pNewMem = realloc(pMemory, size);
323 }
324 return pNewMem;
325}
326
327// Environment variables
328#if defined(__linux__)
329
330static inline char *loader_getenv(const char *name,
331 const struct loader_instance *inst) {
332 // No allocation of memory necessary for Linux, but we should at least touch
333 // the inst pointer to get rid of compiler warnings.
334 (void)inst;
335 return getenv(name);
336}
Frank Henigmanb1c27cb2016-11-24 20:02:09 -0500337static inline void loader_free_getenv(char *val,
Mark Young0ad83132016-06-30 13:02:42 -0600338 const struct loader_instance *inst) {
339 // No freeing of memory necessary for Linux, but we should at least touch
340 // the val and inst pointers to get rid of compiler warnings.
341 (void)val;
342 (void)inst;
343}
344
345#elif defined(WIN32)
346
347static inline char *loader_getenv(const char *name,
348 const struct loader_instance *inst) {
349 char *retVal;
350 DWORD valSize;
351
352 valSize = GetEnvironmentVariableA(name, NULL, 0);
353
354 // valSize DOES include the null terminator, so for any set variable
355 // will always be at least 1. If it's 0, the variable wasn't set.
356 if (valSize == 0)
357 return NULL;
358
359 // Allocate the space necessary for the registry entry
360 if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) {
361 retVal = (char *)inst->alloc_callbacks.pfnAllocation(
362 inst->alloc_callbacks.pUserData, valSize, sizeof(char *),
363 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
364 } else {
365 retVal = (char *)malloc(valSize);
366 }
367
368 if (NULL != retVal) {
369 GetEnvironmentVariableA(name, retVal, valSize);
370 }
371
372 return retVal;
373}
374
375static inline void loader_free_getenv(char *val,
376 const struct loader_instance *inst) {
377 if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) {
378 inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val);
379 } else {
380 free((void *)val);
381 }
382}
383
384#else
385
386static inline char *loader_getenv(const char *name,
Mark Young0153e0b2016-11-03 14:27:13 -0600387 const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600388 // stub func
389 (void)inst;
390 (void)name;
391 return NULL;
392}
Frank Henigmanb1c27cb2016-11-24 20:02:09 -0500393static inline void loader_free_getenv(char *val,
Mark Young0153e0b2016-11-03 14:27:13 -0600394 const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600395 // stub func
396 (void)val;
397 (void)inst;
398}
399
400#endif
401
Jon Ashburn2e37d752016-02-12 08:20:06 -0700402void loader_log(const struct loader_instance *inst, VkFlags msg_type,
Jon Ashburn1530c342016-02-26 13:14:27 -0700403 int32_t msg_code, const char *format, ...) {
Jon Ashburn86723b02015-07-31 15:47:59 -0600404 char msg[512];
Mark Young2c84c0c2017-01-13 10:27:03 -0700405 char cmd_line_msg[512];
406 uint16_t cmd_line_size = sizeof(cmd_line_msg);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700407 va_list ap;
408 int ret;
409
Jon Ashburnffad94d2015-06-30 14:46:22 -0700410 va_start(ap, format);
411 ret = vsnprintf(msg, sizeof(msg), format, ap);
Jon Ashburn23d36b12016-02-02 17:47:28 -0700412 if ((ret >= (int)sizeof(msg)) || ret < 0) {
413 msg[sizeof(msg) - 1] = '\0';
Jon Ashburnffad94d2015-06-30 14:46:22 -0700414 }
415 va_end(ap);
416
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700417 if (inst) {
Karl Schultz94971292016-11-19 09:02:27 -0700418 util_DebugReportMessage(
419 inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
420 (uint64_t)(uintptr_t)inst, 0, msg_code, "loader", msg);
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700421 }
422
423 if (!(msg_type & g_loader_log_msgs)) {
424 return;
425 }
426
Mark Young2c84c0c2017-01-13 10:27:03 -0700427 cmd_line_msg[0] = '\0';
428
429 va_start(ap, format);
430 if ((msg_type & LOADER_INFO_BIT) != 0) {
431 strcat(cmd_line_msg, "INFO");
432 cmd_line_size -= 4;
433 }
434 if ((msg_type & LOADER_WARN_BIT) != 0) {
435 if (cmd_line_size != sizeof(cmd_line_msg)) {
436 strcat(cmd_line_msg, " | ");
437 cmd_line_size -= 3;
438 }
439 strcat(cmd_line_msg, "WARNING");
440 cmd_line_size -= 7;
441 }
442 if ((msg_type & LOADER_PERF_BIT) != 0) {
443 if (cmd_line_size != sizeof(cmd_line_msg)) {
444 strcat(cmd_line_msg, " | ");
445 cmd_line_size -= 3;
446 }
447 strcat(cmd_line_msg, "PERF");
448 cmd_line_size -= 4;
449 }
450 if ((msg_type & LOADER_ERROR_BIT) != 0) {
451 if (cmd_line_size != sizeof(cmd_line_msg)) {
452 strcat(cmd_line_msg, " | ");
453 cmd_line_size -= 3;
454 }
455 strcat(cmd_line_msg, "ERROR");
456 cmd_line_size -= 5;
457 }
458 if ((msg_type & LOADER_DEBUG_BIT) != 0) {
459 if (cmd_line_size != sizeof(cmd_line_msg)) {
460 strcat(cmd_line_msg, " | ");
461 cmd_line_size -= 3;
462 }
463 strcat(cmd_line_msg, "DEBUG");
464 cmd_line_size -= 5;
465 }
466 if (cmd_line_size != sizeof(cmd_line_msg)) {
467 strcat(cmd_line_msg, ": ");
468 cmd_line_size -= 2;
469 }
470 strncat(cmd_line_msg, msg, cmd_line_size);
471
Ian Elliott4470a302015-02-17 10:33:47 -0700472#if defined(WIN32)
Mark Young2c84c0c2017-01-13 10:27:03 -0700473 OutputDebugString(cmd_line_msg);
mschottb9cdb782015-07-22 14:11:29 +0200474 OutputDebugString("\n");
Jon Ashburnffad94d2015-06-30 14:46:22 -0700475#endif
Mark Young2c84c0c2017-01-13 10:27:03 -0700476 fputs(cmd_line_msg, stderr);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700477 fputc('\n', stderr);
478}
479
Mark Young0153e0b2016-11-03 14:27:13 -0600480VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance,
481 void *object) {
Jon Ashburnc3c58772016-03-29 11:16:01 -0600482
483 struct loader_instance *inst = loader_get_instance(instance);
484 if (!inst) {
Mark Youngb6399312017-01-10 14:22:15 -0700485 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
486 "vkSetInstanceDispatch: Can not retrieve Instance "
487 "dispatch table.");
Jon Ashburnc3c58772016-03-29 11:16:01 -0600488 return VK_ERROR_INITIALIZATION_FAILED;
489 }
490 loader_set_dispatch(object, inst->disp);
491 return VK_SUCCESS;
492}
493
Mark Young0153e0b2016-11-03 14:27:13 -0600494VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device,
495 void *object) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600496 struct loader_device *dev;
Mark Young0153e0b2016-11-03 14:27:13 -0600497 struct loader_icd_term *icd_term =
498 loader_get_icd_and_device(device, &dev, NULL);
Jon Ashburned8f2312016-03-31 10:52:22 -0600499
Mark Young0153e0b2016-11-03 14:27:13 -0600500 if (NULL == icd_term) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600501 return VK_ERROR_INITIALIZATION_FAILED;
502 }
503 loader_set_dispatch(object, &dev->loader_dispatch);
504 return VK_SUCCESS;
505}
506
Jon Ashburnffad94d2015-06-30 14:46:22 -0700507#if defined(WIN32)
Tony Barbourea968902015-07-29 14:26:21 -0600508static char *loader_get_next_path(char *path);
Mark Young2c84c0c2017-01-13 10:27:03 -0700509
510// Find the list of registry files (names within a key) in key "location".
511//
512// This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
513// given in "location"
514// for a list or name/values which are added to a returned list (function return
515// value).
516// The DWORD values within the key must be 0 or they are skipped.
517// Function return is a string with a ';' separated list of filenames.
518// Function return is NULL if no valid name/value pairs are found in the key,
519// or the key is not found.
520//
521// *reg_data contains a string list of filenames as pointer.
522// When done using the returned string list, the caller should free the pointer.
523VkResult loaderGetRegistryFiles(const struct loader_instance *inst,
524 char *location, char **reg_data) {
Jon Ashburnffad94d2015-06-30 14:46:22 -0700525 LONG rtn_value;
526 HKEY hive, key;
Piers Daniell524ec732015-11-05 16:58:26 -0700527 DWORD access_flags;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700528 char name[2048];
Tony Barbourea968902015-07-29 14:26:21 -0600529 char *loc = location;
530 char *next;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700531 DWORD idx = 0;
532 DWORD name_size = sizeof(name);
533 DWORD value;
534 DWORD total_size = 4096;
535 DWORD value_size = sizeof(value);
Mark Young2c84c0c2017-01-13 10:27:03 -0700536 VkResult result = VK_SUCCESS;
537 bool found = false;
538
539 if (NULL == reg_data) {
540 result = VK_ERROR_INITIALIZATION_FAILED;
541 goto out;
542 }
Tony Barbourea968902015-07-29 14:26:21 -0600543
Jon Ashburn23d36b12016-02-02 17:47:28 -0700544 while (*loc) {
Tony Barbourea968902015-07-29 14:26:21 -0600545 next = loader_get_next_path(loc);
546 hive = DEFAULT_VK_REGISTRY_HIVE;
Piers Daniell524ec732015-11-05 16:58:26 -0700547 access_flags = KEY_QUERY_VALUE;
Tony Barbourea968902015-07-29 14:26:21 -0600548 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
Mark Young2c84c0c2017-01-13 10:27:03 -0700549 if (ERROR_SUCCESS != rtn_value) {
Mark Young93ecb1d2016-01-13 13:47:16 -0700550 // We still couldn't find the key, so give up:
551 loc = next;
552 continue;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700553 }
Tony Barbourea968902015-07-29 14:26:21 -0600554
Jon Ashburn23d36b12016-02-02 17:47:28 -0700555 while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL,
556 NULL, (LPBYTE)&value, &value_size)) ==
557 ERROR_SUCCESS) {
Tony Barbourea968902015-07-29 14:26:21 -0600558 if (value_size == sizeof(value) && value == 0) {
Mark Young2c84c0c2017-01-13 10:27:03 -0700559 if (NULL == *reg_data) {
560 *reg_data = loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700561 inst, total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young2c84c0c2017-01-13 10:27:03 -0700562 if (NULL == *reg_data) {
Mark Young0ad83132016-06-30 13:02:42 -0600563 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young2c84c0c2017-01-13 10:27:03 -0700564 "loaderGetRegistryFiles: Failed to allocate "
565 "space for registry data for key %s",
566 name);
567 result = VK_ERROR_OUT_OF_HOST_MEMORY;
568 goto out;
Mark Young0ad83132016-06-30 13:02:42 -0600569 }
Mark Young2c84c0c2017-01-13 10:27:03 -0700570 *reg_data[0] = '\0';
571 } else if (strlen(*reg_data) + name_size + 1 > total_size) {
572 *reg_data = loader_instance_heap_realloc(
573 inst, *reg_data, total_size, total_size * 2,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700574 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young2c84c0c2017-01-13 10:27:03 -0700575 if (NULL == *reg_data) {
576 loader_log(
577 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
578 "loaderGetRegistryFiles: Failed to reallocate "
579 "space for registry value of size %d for key %s",
580 total_size * 2, name);
581 result = VK_ERROR_OUT_OF_HOST_MEMORY;
582 goto out;
Mark Young0ad83132016-06-30 13:02:42 -0600583 }
Tony Barbourea968902015-07-29 14:26:21 -0600584 total_size *= 2;
585 }
Mark Young2c84c0c2017-01-13 10:27:03 -0700586 if (strlen(*reg_data) == 0) {
Karl Schultze2ef9e62017-01-13 14:01:35 -0700587 (void)snprintf(*reg_data, name_size + 1, "%s", name);
Mark Young2c84c0c2017-01-13 10:27:03 -0700588 } else {
Karl Schultze2ef9e62017-01-13 14:01:35 -0700589 (void)snprintf(*reg_data + strlen(*reg_data), name_size + 2,
590 "%c%s", PATH_SEPARATOR, name);
Mark Young2c84c0c2017-01-13 10:27:03 -0700591 }
592 found = true;
Tony Barbourea968902015-07-29 14:26:21 -0600593 }
594 name_size = 2048;
595 }
596 loc = next;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700597 }
Tony Barbourea968902015-07-29 14:26:21 -0600598
Mark Young2c84c0c2017-01-13 10:27:03 -0700599 if (!found) {
600 result = VK_ERROR_INITIALIZATION_FAILED;
601 }
602
603out:
604
605 return result;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700606}
607
Ian Elliott4470a302015-02-17 10:33:47 -0700608#endif // WIN32
609
Jon Ashburnc7237a72015-08-03 09:08:46 -0600610/**
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500611 * Combine path elements, separating each element with the platform-specific
612 * directory separator, and save the combined string to a destination buffer,
613 * not exceeding the given length. Path elements are given as variadic args,
614 * with a NULL element terminating the list.
615 *
616 * \returns the total length of the combined string, not including an ASCII
617 * NUL termination character. This length may exceed the available storage:
618 * in this case, the written string will be truncated to avoid a buffer
619 * overrun, and the return value will greater than or equal to the storage
620 * size. A NULL argument may be provided as the destination buffer in order
621 * to determine the required string length without actually writing a string.
622 */
623
Jon Ashburn23d36b12016-02-02 17:47:28 -0700624static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -0700625 size_t required_len = 0;
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500626 va_list ap;
627 const char *component;
628
629 va_start(ap, len);
630
Jon Ashburn23d36b12016-02-02 17:47:28 -0700631 while ((component = va_arg(ap, const char *))) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500632 if (required_len > 0) {
633 // This path element is not the first non-empty element; prepend
634 // a directory separator if space allows
635 if (dest && required_len + 1 < len) {
Karl Schultze2ef9e62017-01-13 14:01:35 -0700636 (void)snprintf(dest + required_len, len - required_len, "%c",
637 DIRECTORY_SYMBOL);
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500638 }
639 required_len++;
640 }
641
642 if (dest && required_len < len) {
643 strncpy(dest + required_len, component, len - required_len);
644 }
645 required_len += strlen(component);
646 }
647
648 va_end(ap);
649
650 // strncpy(3) won't add a NUL terminating byte in the event of truncation.
651 if (dest && required_len >= len) {
652 dest[len - 1] = '\0';
653 }
654
655 return required_len;
656}
657
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500658/**
Jon Ashburnc7237a72015-08-03 09:08:46 -0600659 * Given string of three part form "maj.min.pat" convert to a vulkan version
660 * number.
661 */
Mark Young60861ac2016-09-02 11:39:26 -0600662static uint32_t loader_make_version(char *vers_str) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700663 uint32_t vers = 0, major = 0, minor = 0, patch = 0;
Mark Young60861ac2016-09-02 11:39:26 -0600664 char *vers_tok;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600665
Mark Young60861ac2016-09-02 11:39:26 -0600666 if (!vers_str) {
Jon Ashburnc7237a72015-08-03 09:08:46 -0600667 return vers;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600668 }
Mark Young60861ac2016-09-02 11:39:26 -0600669
670 vers_tok = strtok(vers_str, ".\"\n\r");
671 if (NULL != vers_tok) {
672 major = (uint16_t)atoi(vers_tok);
673 vers_tok = strtok(NULL, ".\"\n\r");
674 if (NULL != vers_tok) {
675 minor = (uint16_t)atoi(vers_tok);
676 vers_tok = strtok(NULL, ".\"\n\r");
677 if (NULL != vers_tok) {
678 patch = (uint16_t)atoi(vers_tok);
679 }
680 }
681 }
Jon Ashburnc7237a72015-08-03 09:08:46 -0600682
683 return VK_MAKE_VERSION(major, minor, patch);
Jon Ashburnc7237a72015-08-03 09:08:46 -0600684}
685
Jon Ashburn23d36b12016-02-02 17:47:28 -0700686bool compare_vk_extension_properties(const VkExtensionProperties *op1,
687 const VkExtensionProperties *op2) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800688 return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600689}
690
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600691/**
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600692 * Search the given ext_array for an extension
693 * matching the given vk_ext_prop
694 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700695bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop,
696 const uint32_t count,
697 const VkExtensionProperties *ext_array) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600698 for (uint32_t i = 0; i < count; i++) {
699 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
700 return true;
701 }
702 return false;
703}
704
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600705/**
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600706 * Search the given ext_list for an extension
707 * matching the given vk_ext_prop
708 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700709bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop,
710 const struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600711 for (uint32_t i = 0; i < ext_list->count; i++) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600712 if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop))
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600713 return true;
714 }
715 return false;
716}
717
Jon Ashburnb8726962016-04-08 15:03:35 -0600718/**
719 * Search the given ext_list for a device extension matching the given ext_prop
720 */
Jon Ashburncc407a22016-04-15 09:25:03 -0600721bool has_vk_dev_ext_property(
722 const VkExtensionProperties *ext_prop,
723 const struct loader_device_extension_list *ext_list) {
Jon Ashburnb8726962016-04-08 15:03:35 -0600724 for (uint32_t i = 0; i < ext_list->count; i++) {
725 if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop))
726 return true;
727 }
728 return false;
729}
730
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600731/*
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -0600732 * Search the given layer list for a layer matching the given layer name
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600733 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700734static struct loader_layer_properties *
735loader_get_layer_property(const char *name,
736 const struct loader_layer_list *layer_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600737 for (uint32_t i = 0; i < layer_list->count; i++) {
738 const VkLayerProperties *item = &layer_list->list[i].info;
739 if (strcmp(name, item->layerName) == 0)
740 return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600741 }
742 return NULL;
743}
744
Jon Ashburne13ecc92015-08-03 17:19:30 -0600745/**
746 * Get the next unused layer property in the list. Init the property to zero.
747 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700748static struct loader_layer_properties *
749loader_get_next_layer_property(const struct loader_instance *inst,
750 struct loader_layer_list *layer_list) {
Jon Ashburne13ecc92015-08-03 17:19:30 -0600751 if (layer_list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -0600752 layer_list->list = loader_instance_heap_alloc(
753 inst, sizeof(struct loader_layer_properties) * 64,
754 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600755 if (layer_list->list == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700756 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -0700757 "loader_get_next_layer_property: Out of memory can "
758 "not add any layer properties to list");
Jon Ashburne13ecc92015-08-03 17:19:30 -0600759 return NULL;
760 }
Jon Ashburn23d36b12016-02-02 17:47:28 -0700761 memset(layer_list->list, 0,
762 sizeof(struct loader_layer_properties) * 64);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600763 layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
764 }
765
766 // ensure enough room to add an entry
Jon Ashburn23d36b12016-02-02 17:47:28 -0700767 if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) >
768 layer_list->capacity) {
Mark Young0ad83132016-06-30 13:02:42 -0600769 layer_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700770 inst, layer_list->list, layer_list->capacity,
771 layer_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600772 if (layer_list->list == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -0700773 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -0700774 "loader_get_next_layer_property: realloc failed for "
775 "layer list");
Mark Young0ad83132016-06-30 13:02:42 -0600776 return NULL;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600777 }
778 layer_list->capacity *= 2;
779 }
780
781 layer_list->count++;
782 return &(layer_list->list[layer_list->count - 1]);
783}
784
785/**
786 * Remove all layer properties entrys from the list
787 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700788void loader_delete_layer_properties(const struct loader_instance *inst,
789 struct loader_layer_list *layer_list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700790 uint32_t i, j;
791 struct loader_device_extension_list *dev_ext_list;
Jon Ashburnb82c1852015-08-11 14:49:54 -0600792 if (!layer_list)
793 return;
794
Jon Ashburne13ecc92015-08-03 17:19:30 -0600795 for (i = 0; i < layer_list->count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700796 loader_destroy_generic_list(
797 inst, (struct loader_generic_list *)&layer_list->list[i]
798 .instance_extension_list);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700799 dev_ext_list = &layer_list->list[i].device_extension_list;
Mark Young0153e0b2016-11-03 14:27:13 -0600800 if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list &&
Jon Ashburn23d36b12016-02-02 17:47:28 -0700801 dev_ext_list->list->entrypoint_count > 0) {
802 for (j = 0; j < dev_ext_list->list->entrypoint_count; j++) {
Mark Young0153e0b2016-11-03 14:27:13 -0600803 loader_instance_heap_free(inst,
804 dev_ext_list->list->entrypoints[j]);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700805 }
Mark Young0ad83132016-06-30 13:02:42 -0600806 loader_instance_heap_free(inst, dev_ext_list->list->entrypoints);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700807 }
Jon Ashburn23d36b12016-02-02 17:47:28 -0700808 loader_destroy_generic_list(inst,
809 (struct loader_generic_list *)dev_ext_list);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600810 }
811 layer_list->count = 0;
812
Jon Ashburnb82c1852015-08-11 14:49:54 -0600813 if (layer_list->capacity > 0) {
814 layer_list->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -0600815 loader_instance_heap_free(inst, layer_list->list);
Jon Ashburnb82c1852015-08-11 14:49:54 -0600816 }
Jon Ashburne13ecc92015-08-03 17:19:30 -0600817}
818
Mark Young3a587792016-08-19 15:25:08 -0600819static VkResult loader_add_instance_extensions(
Jon Ashburn23d36b12016-02-02 17:47:28 -0700820 const struct loader_instance *inst,
821 const PFN_vkEnumerateInstanceExtensionProperties fp_get_props,
822 const char *lib_name, struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -0700823 uint32_t i, count = 0;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600824 VkExtensionProperties *ext_props;
Mark Young3a587792016-08-19 15:25:08 -0600825 VkResult res = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600826
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600827 if (!fp_get_props) {
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -0600828 /* No EnumerateInstanceExtensionProperties defined */
Mark Young3a587792016-08-19 15:25:08 -0600829 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600830 }
831
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600832 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600833 if (res != VK_SUCCESS) {
Mark Youngb6399312017-01-10 14:22:15 -0700834 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
835 "loader_add_instance_extensions: Error getting Instance "
836 "extension count from %s",
837 lib_name);
Mark Young3a587792016-08-19 15:25:08 -0600838 goto out;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600839 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600840
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600841 if (count == 0) {
842 /* No ExtensionProperties to report */
Mark Young3a587792016-08-19 15:25:08 -0600843 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600844 }
845
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600846 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600847
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600848 res = fp_get_props(NULL, &count, ext_props);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600849 if (res != VK_SUCCESS) {
Mark Youngb6399312017-01-10 14:22:15 -0700850 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
851 "loader_add_instance_extensions: Error getting Instance "
852 "extensions from %s",
853 lib_name);
Mark Young3a587792016-08-19 15:25:08 -0600854 goto out;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600855 }
Tony Barbour59a47322015-06-24 16:06:58 -0600856
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600857 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600858 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600859
Jon Ashburncc407a22016-04-15 09:25:03 -0600860 bool ext_unsupported =
861 wsi_unsupported_instance_extension(&ext_props[i]);
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600862 if (!ext_unsupported) {
Karl Schultze2ef9e62017-01-13 14:01:35 -0700863 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
864 VK_MAJOR(ext_props[i].specVersion),
865 VK_MINOR(ext_props[i].specVersion),
866 VK_PATCH(ext_props[i].specVersion));
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600867 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
868 "Instance Extension: %s (%s) version %s",
869 ext_props[i].extensionName, lib_name, spec_version);
Mark Young6267ae62017-01-12 12:27:19 -0700870
Mark Young3a587792016-08-19 15:25:08 -0600871 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
872 if (res != VK_SUCCESS) {
Mark Youngb6399312017-01-10 14:22:15 -0700873 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
874 "loader_add_instance_extensions: Failed to add %s "
875 "to Instance extension list",
Mark Young3a587792016-08-19 15:25:08 -0600876 lib_name);
877 goto out;
878 }
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600879 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600880 }
Mark Young6267ae62017-01-12 12:27:19 -0700881
Mark Young3a587792016-08-19 15:25:08 -0600882out:
883 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600884}
885
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700886/*
887 * Initialize ext_list with the physical device extensions.
888 * The extension properties are passed as inputs in count and ext_props.
889 */
Jon Ashburn23d36b12016-02-02 17:47:28 -0700890static VkResult
891loader_init_device_extensions(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -0600892 struct loader_physical_device_term *phys_dev_term,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700893 uint32_t count, VkExtensionProperties *ext_props,
894 struct loader_extension_list *ext_list) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700895 VkResult res;
896 uint32_t i;
897
Mark Young3a587792016-08-19 15:25:08 -0600898 res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list,
899 sizeof(VkExtensionProperties));
900 if (VK_SUCCESS != res) {
901 return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700902 }
903
904 for (i = 0; i < count; i++) {
905 char spec_version[64];
906
Karl Schultze2ef9e62017-01-13 14:01:35 -0700907 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
908 VK_MAJOR(ext_props[i].specVersion),
909 VK_MINOR(ext_props[i].specVersion),
910 VK_PATCH(ext_props[i].specVersion));
Mark Young0153e0b2016-11-03 14:27:13 -0600911 loader_log(
912 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
913 "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
914 phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700915 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
916 if (res != VK_SUCCESS)
917 return res;
918 }
919
920 return VK_SUCCESS;
921}
922
Jon Ashburn1530c342016-02-26 13:14:27 -0700923VkResult loader_add_device_extensions(const struct loader_instance *inst,
Jon Ashburncc407a22016-04-15 09:25:03 -0600924 PFN_vkEnumerateDeviceExtensionProperties
925 fpEnumerateDeviceExtensionProperties,
Jon Ashburn1530c342016-02-26 13:14:27 -0700926 VkPhysicalDevice physical_device,
927 const char *lib_name,
928 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600929 uint32_t i, count;
930 VkResult res;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600931 VkExtensionProperties *ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600932
Piers Daniell295fe402016-03-29 11:51:11 -0600933 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count,
934 NULL);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700935 if (res == VK_SUCCESS && count > 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700936 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young9a3ddd42016-10-21 16:25:47 -0600937 if (!ext_props) {
Mark Youngb6399312017-01-10 14:22:15 -0700938 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
939 "loader_add_device_extensions: Failed to allocate space"
940 " for device extension properties.");
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700941 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young9a3ddd42016-10-21 16:25:47 -0600942 }
Piers Daniell295fe402016-03-29 11:51:11 -0600943 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL,
944 &count, ext_props);
Mark Young9a3ddd42016-10-21 16:25:47 -0600945 if (res != VK_SUCCESS) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700946 return res;
Mark Young9a3ddd42016-10-21 16:25:47 -0600947 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700948 for (i = 0; i < count; i++) {
949 char spec_version[64];
950
Karl Schultze2ef9e62017-01-13 14:01:35 -0700951 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
952 VK_MAJOR(ext_props[i].specVersion),
953 VK_MINOR(ext_props[i].specVersion),
954 VK_PATCH(ext_props[i].specVersion));
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -0700955 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700956 "Device Extension: %s (%s) version %s",
957 ext_props[i].extensionName, lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700958 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
Mark Youngb6399312017-01-10 14:22:15 -0700959 if (res != VK_SUCCESS) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700960 return res;
Mark Youngb6399312017-01-10 14:22:15 -0700961 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600962 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700963 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700964 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -0700965 "loader_add_device_extensions: Error getting physical "
966 "device extension info count from library %s",
Jon Ashburn23d36b12016-02-02 17:47:28 -0700967 lib_name);
Jon Ashburn00eb6c02015-11-02 17:40:01 -0700968 return res;
969 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600970
Jon Ashburn24cd4be2015-11-01 14:04:06 -0700971 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600972}
973
Mark Young3a587792016-08-19 15:25:08 -0600974VkResult loader_init_generic_list(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -0600975 struct loader_generic_list *list_info,
976 size_t element_size) {
Mark Young84ba0482016-09-02 11:45:00 -0600977 size_t capacity = 32 * element_size;
978 list_info->count = 0;
979 list_info->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -0600980 list_info->list = loader_instance_heap_alloc(
Mark Young84ba0482016-09-02 11:45:00 -0600981 inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700982 if (list_info->list == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -0700983 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
984 "loader_init_generic_list: Failed to allocate space "
985 "for generic list");
Mark Young3a587792016-08-19 15:25:08 -0600986 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600987 }
Mark Young84ba0482016-09-02 11:45:00 -0600988 memset(list_info->list, 0, capacity);
989 list_info->capacity = capacity;
Mark Young3a587792016-08-19 15:25:08 -0600990 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600991}
992
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700993void loader_destroy_generic_list(const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700994 struct loader_generic_list *list) {
Mark Young0ad83132016-06-30 13:02:42 -0600995 loader_instance_heap_free(inst, list->list);
Jon Ashburn6e6a2162015-12-10 08:51:10 -0700996 list->count = 0;
997 list->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600998}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600999
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001000/*
1001 * Append non-duplicate extension properties defined in props
1002 * to the given ext_list.
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001003 * Return
1004 * Vk_SUCCESS on success
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001005 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001006VkResult loader_add_to_ext_list(const struct loader_instance *inst,
1007 struct loader_extension_list *ext_list,
1008 uint32_t prop_list_count,
1009 const VkExtensionProperties *props) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001010 uint32_t i;
1011 const VkExtensionProperties *cur_ext;
1012
1013 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -06001014 VkResult res = loader_init_generic_list(
1015 inst, (struct loader_generic_list *)ext_list,
1016 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001017 if (VK_SUCCESS != res) {
1018 return res;
1019 }
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001020 }
1021
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001022 for (i = 0; i < prop_list_count; i++) {
1023 cur_ext = &props[i];
1024
1025 // look for duplicates
1026 if (has_vk_extension_property(cur_ext, ext_list)) {
1027 continue;
1028 }
1029
1030 // add to list at end
1031 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001032 if (ext_list->count * sizeof(VkExtensionProperties) >=
1033 ext_list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001034
Mark Young0ad83132016-06-30 13:02:42 -06001035 ext_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001036 inst, ext_list->list, ext_list->capacity,
1037 ext_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001038
Mark Youngb6399312017-01-10 14:22:15 -07001039 if (ext_list->list == NULL) {
1040 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1041 "loader_add_to_ext_list: Failed to reallocate "
1042 "space for extension list");
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001043 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -07001044 }
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001045
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001046 // double capacity
1047 ext_list->capacity *= 2;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001048 }
1049
Jon Ashburn23d36b12016-02-02 17:47:28 -07001050 memcpy(&ext_list->list[ext_list->count], cur_ext,
1051 sizeof(VkExtensionProperties));
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001052 ext_list->count++;
1053 }
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001054 return VK_SUCCESS;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001055}
1056
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001057/*
1058 * Append one extension property defined in props with entrypoints
Jon Ashburnb8726962016-04-08 15:03:35 -06001059 * defined in entrys to the given ext_list. Do not append if a duplicate
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001060 * Return
1061 * Vk_SUCCESS on success
1062 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001063VkResult
1064loader_add_to_dev_ext_list(const struct loader_instance *inst,
1065 struct loader_device_extension_list *ext_list,
1066 const VkExtensionProperties *props,
1067 uint32_t entry_count, char **entrys) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001068 uint32_t idx;
1069 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Young3a587792016-08-19 15:25:08 -06001070 VkResult res = loader_init_generic_list(
1071 inst, (struct loader_generic_list *)ext_list,
1072 sizeof(struct loader_dev_ext_props));
1073 if (VK_SUCCESS != res) {
1074 return res;
1075 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001076 }
1077
Jon Ashburnb8726962016-04-08 15:03:35 -06001078 // look for duplicates
1079 if (has_vk_dev_ext_property(props, ext_list)) {
1080 return VK_SUCCESS;
1081 }
1082
Jon Ashburn23d36b12016-02-02 17:47:28 -07001083 idx = ext_list->count;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001084 // add to list at end
1085 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001086 if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001087
Mark Young0ad83132016-06-30 13:02:42 -06001088 ext_list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001089 inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1090 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001091
Mark Youngb6399312017-01-10 14:22:15 -07001092 if (ext_list->list == NULL) {
1093 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1094 "loader_add_to_dev_ext_list: Failed to reallocate "
1095 "space for device extension list");
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001096 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -07001097 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001098
1099 // double capacity
1100 ext_list->capacity *= 2;
1101 }
1102
Jon Ashburn23d36b12016-02-02 17:47:28 -07001103 memcpy(&ext_list->list[idx].props, props,
1104 sizeof(struct loader_dev_ext_props));
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001105 ext_list->list[idx].entrypoint_count = entry_count;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001106 ext_list->list[idx].entrypoints =
Mark Young0ad83132016-06-30 13:02:42 -06001107 loader_instance_heap_alloc(inst, sizeof(char *) * entry_count,
1108 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1109 if (ext_list->list[idx].entrypoints == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07001110 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1111 "loader_add_to_dev_ext_list: Failed to allocate space "
1112 "for device extension entrypoint list in list %d",
1113 idx);
Mark Young0ad83132016-06-30 13:02:42 -06001114 ext_list->list[idx].entrypoint_count = 0;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001115 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001116 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001117 for (uint32_t i = 0; i < entry_count; i++) {
Mark Young0ad83132016-06-30 13:02:42 -06001118 ext_list->list[idx].entrypoints[i] = loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001119 inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06001120 if (ext_list->list[idx].entrypoints[i] == NULL) {
1121 for (uint32_t j = 0; j < i; j++) {
1122 loader_instance_heap_free(inst,
1123 ext_list->list[idx].entrypoints[j]);
1124 }
1125 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints);
1126 ext_list->list[idx].entrypoint_count = 0;
1127 ext_list->list[idx].entrypoints = NULL;
Mark Youngb6399312017-01-10 14:22:15 -07001128 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1129 "loader_add_to_dev_ext_list: Failed to allocate space "
1130 "for device extension entrypoint %d name",
1131 i);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001132 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001133 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001134 strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
1135 }
1136 ext_list->count++;
1137
1138 return VK_SUCCESS;
1139}
1140
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001141/**
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001142 * Search the given search_list for any layers in the props list.
Jon Ashburn23d36b12016-02-02 17:47:28 -07001143 * Add these to the output layer_list. Don't add duplicates to the output
1144 * layer_list.
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001145 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001146static VkResult
1147loader_add_layer_names_to_list(const struct loader_instance *inst,
1148 struct loader_layer_list *output_list,
1149 uint32_t name_count, const char *const *names,
1150 const struct loader_layer_list *search_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001151 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001152 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001153
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001154 for (uint32_t i = 0; i < name_count; i++) {
1155 const char *search_target = names[i];
Jon Ashburne13ecc92015-08-03 17:19:30 -06001156 layer_prop = loader_get_layer_property(search_target, search_list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001157 if (!layer_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001158 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001159 "loader_add_layer_names_to_list: Unable to find layer"
1160 " %s",
1161 search_target);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06001162 err = VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001163 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001164 }
1165
Mark Young0ad83132016-06-30 13:02:42 -06001166 err = loader_add_to_layer_list(inst, output_list, 1, layer_prop);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001167 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001168
1169 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001170}
1171
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06001172/*
1173 * Manage lists of VkLayerProperties
1174 */
Jon Ashburne39a4f82015-08-28 13:38:21 -06001175static bool loader_init_layer_list(const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001176 struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001177 list->capacity = 32 * sizeof(struct loader_layer_properties);
Mark Young0ad83132016-06-30 13:02:42 -06001178 list->list = loader_instance_heap_alloc(
1179 inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001180 if (list->list == NULL) {
1181 return false;
1182 }
1183 memset(list->list, 0, list->capacity);
1184 list->count = 0;
1185 return true;
1186}
1187
Jon Ashburne39a4f82015-08-28 13:38:21 -06001188void loader_destroy_layer_list(const struct loader_instance *inst,
Mark Young0ad83132016-06-30 13:02:42 -06001189 struct loader_device *device,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001190 struct loader_layer_list *layer_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001191 if (device) {
1192 loader_device_heap_free(device, layer_list->list);
1193 } else {
1194 loader_instance_heap_free(inst, layer_list->list);
1195 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001196 layer_list->count = 0;
1197 layer_list->capacity = 0;
1198}
1199
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001200/*
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001201 * Search the given layer list for a list
1202 * matching the given VkLayerProperties
1203 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001204bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop,
1205 const struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001206 for (uint32_t i = 0; i < list->count; i++) {
1207 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
1208 return true;
1209 }
1210 return false;
1211}
1212
1213/*
1214 * Search the given layer list for a layer
1215 * matching the given name
1216 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001217bool has_layer_name(const char *name, const struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001218 for (uint32_t i = 0; i < list->count; i++) {
1219 if (strcmp(name, list->list[i].info.layerName) == 0)
1220 return true;
1221 }
1222 return false;
1223}
1224
1225/*
1226 * Append non-duplicate layer properties defined in prop_list
1227 * to the given layer_info list
1228 */
Mark Young0ad83132016-06-30 13:02:42 -06001229VkResult loader_add_to_layer_list(const struct loader_instance *inst,
1230 struct loader_layer_list *list,
1231 uint32_t prop_list_count,
1232 const struct loader_layer_properties *props) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001233 uint32_t i;
1234 struct loader_layer_properties *layer;
1235
1236 if (list->list == NULL || list->capacity == 0) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001237 loader_init_layer_list(inst, list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001238 }
1239
1240 if (list->list == NULL)
Mark Young0ad83132016-06-30 13:02:42 -06001241 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001242
1243 for (i = 0; i < prop_list_count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001244 layer = (struct loader_layer_properties *)&props[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001245
1246 // look for duplicates
1247 if (has_vk_layer_property(&layer->info, list)) {
1248 continue;
1249 }
1250
1251 // add to list at end
1252 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001253 if (list->count * sizeof(struct loader_layer_properties) >=
1254 list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001255
Mark Young0ad83132016-06-30 13:02:42 -06001256 list->list = loader_instance_heap_realloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001257 inst, list->list, list->capacity, list->capacity * 2,
1258 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06001259 if (NULL == list->list) {
1260 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001261 "loader_add_to_layer_list: Realloc failed for "
1262 "when attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001263 return VK_ERROR_OUT_OF_HOST_MEMORY;
1264 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001265 // double capacity
1266 list->capacity *= 2;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001267 }
1268
Jon Ashburn23d36b12016-02-02 17:47:28 -07001269 memcpy(&list->list[list->count], layer,
1270 sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001271 list->count++;
1272 }
Mark Young0ad83132016-06-30 13:02:42 -06001273
1274 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001275}
1276
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001277/**
1278 * Search the search_list for any layer with a name
1279 * that matches the given name and a type that matches the given type
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001280 * Add all matching layers to the found_list
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001281 * Do not add if found loader_layer_properties is already
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001282 * on the found_list.
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001283 */
Jon Ashburncc407a22016-04-15 09:25:03 -06001284void loader_find_layer_name_add_list(
1285 const struct loader_instance *inst, const char *name,
1286 const enum layer_type type, const struct loader_layer_list *search_list,
1287 struct loader_layer_list *found_list) {
Jon Ashburn56151d62015-10-05 09:03:21 -06001288 bool found = false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001289 for (uint32_t i = 0; i < search_list->count; i++) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001290 struct loader_layer_properties *layer_prop = &search_list->list[i];
Jon Ashburnbd332cc2015-07-07 10:27:45 -06001291 if (0 == strcmp(layer_prop->info.layerName, name) &&
Jon Ashburn23d36b12016-02-02 17:47:28 -07001292 (layer_prop->type & type)) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001293 /* Found a layer with the same name, add to found_list */
Mark Young0153e0b2016-11-03 14:27:13 -06001294 if (VK_SUCCESS ==
1295 loader_add_to_layer_list(inst, found_list, 1, layer_prop)) {
Mark Young0ad83132016-06-30 13:02:42 -06001296 found = true;
1297 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001298 }
1299 }
Jon Ashburn56151d62015-10-05 09:03:21 -06001300 if (!found) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001301 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001302 "loader_find_layer_name_add_list: Failed to find layer name "
1303 "%s to activate",
1304 name);
Jon Ashburn56151d62015-10-05 09:03:21 -06001305 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001306}
1307
Jon Ashburn23d36b12016-02-02 17:47:28 -07001308static VkExtensionProperties *
1309get_extension_property(const char *name,
1310 const struct loader_extension_list *list) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001311 for (uint32_t i = 0; i < list->count; i++) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +08001312 if (strcmp(name, list->list[i].extensionName) == 0)
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001313 return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001314 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001315 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001316}
1317
Jon Ashburn23d36b12016-02-02 17:47:28 -07001318static VkExtensionProperties *
1319get_dev_extension_property(const char *name,
1320 const struct loader_device_extension_list *list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001321 for (uint32_t i = 0; i < list->count; i++) {
1322 if (strcmp(name, list->list[i].props.extensionName) == 0)
1323 return &list->list[i].props;
1324 }
1325 return NULL;
1326}
1327
Courtney Goeltzenleuchterb39ccd52016-01-15 14:15:00 -07001328/*
Courtney Goeltzenleuchterf538ef72015-12-02 14:00:19 -07001329 * For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001330 * the extension must provide two entry points for the loader to use:
1331 * - "trampoline" entry point - this is the address returned by GetProcAddr
1332 * and will always do what's necessary to support a global call.
1333 * - "terminator" function - this function will be put at the end of the
Jon Ashburn232e3af2015-11-30 17:21:25 -07001334 * instance chain and will contain the necessary logic to call / process
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001335 * the extension for the appropriate ICDs that are available.
1336 * There is no generic mechanism for including these functions, the references
1337 * must be placed into the appropriate loader entry points.
Jon Ashburn23d36b12016-02-02 17:47:28 -07001338 * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for
1339 * GetProcAddr requests
1340 * loader_coalesce_extensions(void) - add extension records to the list of
1341 * global
Jon Ashburnbd6c4882015-07-02 12:59:25 -06001342 * extension available to the app.
1343 * instance_disp - add function pointer for terminator function to this array.
1344 * The extension itself should be in a separate file that will be
1345 * linked directly with the loader.
1346 */
Jon Ashburn9a4c6aa2015-08-14 11:57:54 -06001347
Mark Young3a587792016-08-19 15:25:08 -06001348VkResult loader_get_icd_loader_instance_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06001349 const struct loader_instance *inst,
1350 struct loader_icd_tramp_list *icd_tramp_list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001351 struct loader_extension_list *inst_exts) {
Jon Ashburn5c6a46f2015-08-14 14:49:22 -06001352 struct loader_extension_list icd_exts;
Mark Young3a587792016-08-19 15:25:08 -06001353 VkResult res = VK_SUCCESS;
1354
Jon Ashburn23d36b12016-02-02 17:47:28 -07001355 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
1356 "Build ICD instance extension list");
Mark Young3a587792016-08-19 15:25:08 -06001357
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001358 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001359 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
Mark Young3a587792016-08-19 15:25:08 -06001360 res = loader_init_generic_list(inst,
1361 (struct loader_generic_list *)&icd_exts,
1362 sizeof(VkExtensionProperties));
1363 if (VK_SUCCESS != res) {
1364 goto out;
1365 }
1366 res = loader_add_instance_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06001367 inst, icd_tramp_list->scanned_list[i]
1368 .EnumerateInstanceExtensionProperties,
1369 icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001370 if (VK_SUCCESS == res) {
Lenny Komow4053b812016-12-29 16:27:28 -07001371 // Remove any extensions not recognized by the loader
1372 for (int32_t j = 0; j < (int32_t)icd_exts.count; j++) {
1373
1374 // See if the extension is in the list of supported extensions
1375 bool found = false;
1376 for (uint32_t k = 0; LOADER_INSTANCE_EXTENSIONS[k] != NULL;
1377 k++) {
1378 if (strcmp(icd_exts.list[j].extensionName,
1379 LOADER_INSTANCE_EXTENSIONS[k]) == 0) {
1380 found = true;
1381 break;
1382 }
1383 }
1384
1385 // If it isn't in the list, remove it
1386 if (!found) {
1387 for (uint32_t k = j + 1; k < icd_exts.count; k++) {
1388 icd_exts.list[k - 1] = icd_exts.list[k];
1389 }
1390 --icd_exts.count;
1391 --j;
1392 }
1393 }
1394
Mark Young3a587792016-08-19 15:25:08 -06001395 res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count,
1396 icd_exts.list);
1397 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001398 loader_destroy_generic_list(inst,
1399 (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001400 if (VK_SUCCESS != res) {
1401 goto out;
1402 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001403 };
1404
Mark Young6267ae62017-01-12 12:27:19 -07001405
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001406 // Traverse loader's extensions, adding non-duplicate extensions to the list
Jon Ashburne39a4f82015-08-28 13:38:21 -06001407 debug_report_add_instance_extensions(inst, inst_exts);
Mark Young3a587792016-08-19 15:25:08 -06001408
1409out:
1410 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001411}
1412
Mark Young0153e0b2016-11-03 14:27:13 -06001413struct loader_icd_term *
1414loader_get_icd_and_device(const VkDevice device,
1415 struct loader_device **found_dev,
1416 uint32_t *icd_index) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001417 *found_dev = NULL;
Mark Young16573c72016-06-28 10:52:43 -06001418 uint32_t index = 0;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001419 for (struct loader_instance *inst = loader.instances; inst;
1420 inst = inst->next) {
Mark Young0153e0b2016-11-03 14:27:13 -06001421 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term;
1422 icd_term = icd_term->next) {
1423 for (struct loader_device *dev = icd_term->logical_device_list; dev;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001424 dev = dev->next)
Mark Young65cb3662016-11-07 13:27:02 -07001425 // Value comparison of device prevents object wrapping by layers
1426 if (loader_get_dispatch(dev->icd_device) ==
1427 loader_get_dispatch(device) ||
1428 loader_get_dispatch(dev->chain_device) ==
Jon Ashburn23d36b12016-02-02 17:47:28 -07001429 loader_get_dispatch(device)) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001430 *found_dev = dev;
Mark Young16573c72016-06-28 10:52:43 -06001431 if (NULL != icd_index) {
1432 *icd_index = index;
1433 }
Mark Young0153e0b2016-11-03 14:27:13 -06001434 return icd_term;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001435 }
Mark Young16573c72016-06-28 10:52:43 -06001436 index++;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001437 }
1438 }
1439 return NULL;
1440}
1441
Mark Young0ad83132016-06-30 13:02:42 -06001442void loader_destroy_logical_device(const struct loader_instance *inst,
1443 struct loader_device *dev,
1444 const VkAllocationCallbacks *pAllocator) {
1445 if (pAllocator) {
1446 dev->alloc_callbacks = *pAllocator;
1447 }
Mark Young0ad83132016-06-30 13:02:42 -06001448 if (NULL != dev->activated_layer_list.list) {
1449 loader_deactivate_layers(inst, dev, &dev->activated_layer_list);
1450 }
1451 loader_device_heap_free(dev, dev);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001452}
1453
Jon Ashburn1530c342016-02-26 13:14:27 -07001454struct loader_device *
Mark Young0ad83132016-06-30 13:02:42 -06001455loader_create_logical_device(const struct loader_instance *inst,
1456 const VkAllocationCallbacks *pAllocator) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001457 struct loader_device *new_dev;
Mark Young0ad83132016-06-30 13:02:42 -06001458#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
1459 {
1460#else
1461 if (pAllocator) {
1462 new_dev = (struct loader_device *)pAllocator->pfnAllocation(
1463 pAllocator->pUserData, sizeof(struct loader_device), sizeof(int *),
1464 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1465 } else {
1466#endif
1467 new_dev = (struct loader_device *)malloc(sizeof(struct loader_device));
1468 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001469
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001470 if (!new_dev) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001471 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001472 "loader_create_logical_device: Failed to alloc struct "
1473 "loader_device");
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001474 return NULL;
1475 }
1476
1477 memset(new_dev, 0, sizeof(struct loader_device));
Mark Young0ad83132016-06-30 13:02:42 -06001478 if (pAllocator) {
1479 new_dev->alloc_callbacks = *pAllocator;
1480 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001481
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001482 return new_dev;
1483}
1484
Piers Daniell295fe402016-03-29 11:51:11 -06001485void loader_add_logical_device(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001486 struct loader_icd_term *icd_term,
Piers Daniell295fe402016-03-29 11:51:11 -06001487 struct loader_device *dev) {
Mark Young0153e0b2016-11-03 14:27:13 -06001488 dev->next = icd_term->logical_device_list;
1489 icd_term->logical_device_list = dev;
Piers Daniell295fe402016-03-29 11:51:11 -06001490}
1491
Jon Ashburn23d36b12016-02-02 17:47:28 -07001492void loader_remove_logical_device(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001493 struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001494 struct loader_device *found_dev,
1495 const VkAllocationCallbacks *pAllocator) {
Jon Ashburn781a7ae2015-11-19 15:43:26 -07001496 struct loader_device *dev, *prev_dev;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001497
Mark Young0153e0b2016-11-03 14:27:13 -06001498 if (!icd_term || !found_dev)
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001499 return;
1500
1501 prev_dev = NULL;
Mark Young0153e0b2016-11-03 14:27:13 -06001502 dev = icd_term->logical_device_list;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001503 while (dev && dev != found_dev) {
1504 prev_dev = dev;
1505 dev = dev->next;
1506 }
1507
1508 if (prev_dev)
1509 prev_dev->next = found_dev->next;
1510 else
Mark Young0153e0b2016-11-03 14:27:13 -06001511 icd_term->logical_device_list = found_dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001512 loader_destroy_logical_device(inst, found_dev, pAllocator);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001513}
1514
Jon Ashburn23d36b12016-02-02 17:47:28 -07001515static void loader_icd_destroy(struct loader_instance *ptr_inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001516 struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001517 const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001518 ptr_inst->total_icd_count--;
Mark Young0153e0b2016-11-03 14:27:13 -06001519 for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001520 struct loader_device *next_dev = dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001521 loader_destroy_logical_device(ptr_inst, dev, pAllocator);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001522 dev = next_dev;
1523 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001524
Mark Young0153e0b2016-11-03 14:27:13 -06001525 loader_instance_heap_free(ptr_inst, icd_term);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001526}
1527
Mark Young0153e0b2016-11-03 14:27:13 -06001528static struct loader_icd_term *
Jon Ashburn23d36b12016-02-02 17:47:28 -07001529loader_icd_create(const struct loader_instance *inst) {
Mark Young0153e0b2016-11-03 14:27:13 -06001530 struct loader_icd_term *icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001531
Mark Young0153e0b2016-11-03 14:27:13 -06001532 icd_term = loader_instance_heap_alloc(inst, sizeof(struct loader_icd_term),
1533 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1534 if (!icd_term) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001535 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001536 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001537
Mark Young0153e0b2016-11-03 14:27:13 -06001538 memset(icd_term, 0, sizeof(struct loader_icd_term));
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -06001539
Mark Young0153e0b2016-11-03 14:27:13 -06001540 return icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001541}
1542
Mark Young0153e0b2016-11-03 14:27:13 -06001543static struct loader_icd_term *
Jon Ashburn23d36b12016-02-02 17:47:28 -07001544loader_icd_add(struct loader_instance *ptr_inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001545 const struct loader_scanned_icd *scanned_icd) {
1546 struct loader_icd_term *icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001547
Mark Young0153e0b2016-11-03 14:27:13 -06001548 icd_term = loader_icd_create(ptr_inst);
1549 if (!icd_term) {
Chia-I Wu13a61a52014-08-04 11:18:20 +08001550 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001551 }
Chia-I Wu13a61a52014-08-04 11:18:20 +08001552
Mark Young0153e0b2016-11-03 14:27:13 -06001553 icd_term->scanned_icd = scanned_icd;
1554 icd_term->this_instance = ptr_inst;
Jon Ashburn3d002332015-08-20 16:35:30 -06001555
Chia-I Wu13a61a52014-08-04 11:18:20 +08001556 /* prepend to the list */
Mark Young0153e0b2016-11-03 14:27:13 -06001557 icd_term->next = ptr_inst->icd_terms;
1558 ptr_inst->icd_terms = icd_term;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001559 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001560
Mark Young0153e0b2016-11-03 14:27:13 -06001561 return icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001562}
Mark Young0153e0b2016-11-03 14:27:13 -06001563
Jon Ashburn17b4c862016-04-25 11:09:37 -06001564/**
1565 * Determine the ICD interface version to use.
1566 * @param icd
1567 * @param pVersion Output parameter indicating which version to use or 0 if
1568 * the negotiation API is not supported by the ICD
1569 * @return bool indicating true if the selected interface version is supported
1570 * by the loader, false indicates the version is not supported
1571 * version 0 doesn't support vk_icdGetInstanceProcAddr nor
1572 * vk_icdNegotiateLoaderICDInterfaceVersion
1573 * version 1 supports vk_icdGetInstanceProcAddr
1574 * version 2 supports vk_icdNegotiateLoaderICDInterfaceVersion
1575 */
1576bool loader_get_icd_interface_version(
Mark Young0153e0b2016-11-03 14:27:13 -06001577 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version,
1578 uint32_t *pVersion) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001579
1580 if (fp_negotiate_icd_version == NULL) {
1581 // ICD does not support the negotiation API, it supports version 0 or 1
1582 // calling code must determine if it is version 0 or 1
1583 *pVersion = 0;
1584 } else {
1585 // ICD supports the negotiation API, so call it with the loader's
1586 // latest version supported
1587 *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1588 VkResult result = fp_negotiate_icd_version(pVersion);
1589
1590 if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1591 // ICD no longer supports the loader's latest interface version so
1592 // fail loading the ICD
1593 return false;
1594 }
1595 }
1596
1597#if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1598 if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1599 // Loader no longer supports the ICD's latest interface version so fail
1600 // loading the ICD
1601 return false;
1602 }
1603#endif
1604 return true;
1605}
Chia-I Wu13a61a52014-08-04 11:18:20 +08001606
Jon Ashburn23d36b12016-02-02 17:47:28 -07001607void loader_scanned_icd_clear(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06001608 struct loader_icd_tramp_list *icd_tramp_list) {
1609 if (icd_tramp_list->capacity == 0)
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001610 return;
Mark Young0153e0b2016-11-03 14:27:13 -06001611 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1612 loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1613 loader_instance_heap_free(inst,
1614 icd_tramp_list->scanned_list[i].lib_name);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001615 }
Mark Young0153e0b2016-11-03 14:27:13 -06001616 loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1617 icd_tramp_list->capacity = 0;
1618 icd_tramp_list->count = 0;
1619 icd_tramp_list->scanned_list = NULL;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001620}
1621
Mark Young0153e0b2016-11-03 14:27:13 -06001622static VkResult
1623loader_scanned_icd_init(const struct loader_instance *inst,
1624 struct loader_icd_tramp_list *icd_tramp_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001625 VkResult err = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06001626 loader_scanned_icd_clear(inst, icd_tramp_list);
1627 icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
1628 icd_tramp_list->scanned_list = loader_instance_heap_alloc(
1629 inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1630 if (NULL == icd_tramp_list->scanned_list) {
1631 loader_log(
1632 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001633 "loader_scanned_icd_init: Realloc failed for layer list when "
1634 "attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001635 err = VK_ERROR_OUT_OF_HOST_MEMORY;
1636 }
1637 return err;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001638}
1639
Mark Young0153e0b2016-11-03 14:27:13 -06001640static VkResult
1641loader_scanned_icd_add(const struct loader_instance *inst,
1642 struct loader_icd_tramp_list *icd_tramp_list,
1643 const char *filename, uint32_t api_version) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001644 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06001645 PFN_vkCreateInstance fp_create_inst;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001646 PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
Jon Ashburnc624c882015-07-16 10:17:29 -06001647 PFN_vkGetInstanceProcAddr fp_get_proc_addr;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001648 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
Mark Young0153e0b2016-11-03 14:27:13 -06001649 struct loader_scanned_icd *new_scanned_icd;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001650 uint32_t interface_vers;
Mark Young3a587792016-08-19 15:25:08 -06001651 VkResult res = VK_SUCCESS;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001652
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06001653 /* TODO implement smarter opening/closing of libraries. For now this
1654 * function leaves libraries open and the scanned_icd_clear closes them */
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001655 handle = loader_platform_open_library(filename);
Mark Youngb6399312017-01-10 14:22:15 -07001656 if (NULL == handle) {
1657 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001658 loader_platform_open_library_error(filename));
Mark Young3a587792016-08-19 15:25:08 -06001659 goto out;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001660 }
1661
Jon Ashburn17b4c862016-04-25 11:09:37 -06001662 // Get and settle on an ICD interface version
Mark Young0ad83132016-06-30 13:02:42 -06001663 fp_negotiate_icd_version = loader_platform_get_proc_address(
1664 handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
Jon Ashburn17b4c862016-04-25 11:09:37 -06001665
1666 if (!loader_get_icd_interface_version(fp_negotiate_icd_version,
Mark Young0ad83132016-06-30 13:02:42 -06001667 &interface_vers)) {
1668 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001669 "loader_scanned_icd_add: ICD %s doesn't support interface"
1670 " version compatible with loader, skip this ICD.",
Mark Young0ad83132016-06-30 13:02:42 -06001671 filename);
Mark Young3a587792016-08-19 15:25:08 -06001672 goto out;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001673 }
1674
Jon Ashburn23d36b12016-02-02 17:47:28 -07001675 fp_get_proc_addr =
1676 loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001677 if (NULL == fp_get_proc_addr) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001678 assert(interface_vers == 0);
1679 // Use deprecated interface from version 0
Jon Ashburn23d36b12016-02-02 17:47:28 -07001680 fp_get_proc_addr =
1681 loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001682 if (NULL == fp_get_proc_addr) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001683 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001684 "loader_scanned_icd_add: Attempt to retreive either "
Mark Young2c84c0c2017-01-13 10:27:03 -07001685 "\'vkGetInstanceProcAddr\' or "
Mark Youngb6399312017-01-10 14:22:15 -07001686 "\'vk_icdGetInstanceProcAddr\' from ICD %s failed.",
1687 filename);
Mark Young3a587792016-08-19 15:25:08 -06001688 goto out;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001689 } else {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001690 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001691 "loader_scanned_icd_add: Using deprecated ICD "
1692 "interface of \'vkGetInstanceProcAddr\' instead of "
1693 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001694 filename);
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001695 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001696 fp_create_inst =
1697 loader_platform_get_proc_address(handle, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001698 if (NULL == fp_create_inst) {
Mark Young0ad83132016-06-30 13:02:42 -06001699 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001700 "loader_scanned_icd_add: Failed querying "
1701 "\'vkCreateInstance\' via dlsym/loadlibrary for "
1702 "ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001703 filename);
Mark Young3a587792016-08-19 15:25:08 -06001704 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001705 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001706 fp_get_inst_ext_props = loader_platform_get_proc_address(
1707 handle, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001708 if (NULL == fp_get_inst_ext_props) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001709 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001710 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1711 "InstanceExtensionProperties\' via dlsym/loadlibrary "
1712 "for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001713 filename);
Mark Young3a587792016-08-19 15:25:08 -06001714 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001715 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001716 } else {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001717 // Use newer interface version 1 or later
1718 if (interface_vers == 0)
1719 interface_vers = 1;
1720
Jon Ashburn23d36b12016-02-02 17:47:28 -07001721 fp_create_inst =
1722 (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001723 if (NULL == fp_create_inst) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001724 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001725 "loader_scanned_icd_add: Could not get "
1726 "\'vkCreateInstance\' via \'vk_icdGetInstanceProcAddr\'"
1727 " for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001728 filename);
Mark Young3a587792016-08-19 15:25:08 -06001729 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001730 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001731 fp_get_inst_ext_props =
1732 (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(
1733 NULL, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001734 if (NULL == fp_get_inst_ext_props) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001735 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001736 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1737 "InstanceExtensionProperties\' via "
1738 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001739 filename);
Mark Young3a587792016-08-19 15:25:08 -06001740 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001741 }
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001742 }
Jon Ashburn46d1f582015-01-28 11:01:35 -07001743
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001744 // check for enough capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001745 if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >=
1746 icd_tramp_list->capacity) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001747
Mark Young0153e0b2016-11-03 14:27:13 -06001748 icd_tramp_list->scanned_list = loader_instance_heap_realloc(
1749 inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1750 icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1751 if (NULL == icd_tramp_list->scanned_list) {
Mark Young3a587792016-08-19 15:25:08 -06001752 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001753 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07001754 "loader_scanned_icd_add: Realloc failed on icd library"
1755 " list for ICD %s",
1756 filename);
Mark Young3a587792016-08-19 15:25:08 -06001757 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06001758 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001759 // double capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001760 icd_tramp_list->capacity *= 2;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001761 }
Mark Young0153e0b2016-11-03 14:27:13 -06001762 new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
Jon Ashburn46d1f582015-01-28 11:01:35 -07001763
Mark Young0153e0b2016-11-03 14:27:13 -06001764 new_scanned_icd->handle = handle;
1765 new_scanned_icd->api_version = api_version;
1766 new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
1767 new_scanned_icd->EnumerateInstanceExtensionProperties =
1768 fp_get_inst_ext_props;
1769 new_scanned_icd->CreateInstance = fp_create_inst;
1770 new_scanned_icd->interface_version = interface_vers;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001771
Mark Young0153e0b2016-11-03 14:27:13 -06001772 new_scanned_icd->lib_name = (char *)loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07001773 inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0153e0b2016-11-03 14:27:13 -06001774 if (NULL == new_scanned_icd->lib_name) {
Mark Youngb6399312017-01-10 14:22:15 -07001775 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1776 "loader_scanned_icd_add: Out of memory can't add ICD %s",
1777 filename);
Mark Young3a587792016-08-19 15:25:08 -06001778 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06001779 goto out;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001780 }
Mark Young0153e0b2016-11-03 14:27:13 -06001781 strcpy(new_scanned_icd->lib_name, filename);
1782 icd_tramp_list->count++;
Mark Young3a587792016-08-19 15:25:08 -06001783
1784out:
1785
1786 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001787}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001788
Mark Young0153e0b2016-11-03 14:27:13 -06001789static bool loader_icd_init_entrys(struct loader_icd_term *icd_term,
1790 VkInstance inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001791 const PFN_vkGetInstanceProcAddr fp_gipa) {
1792/* initialize entrypoint function pointers */
Jon Ashburn3da71f22015-05-14 12:43:38 -06001793
Jon Ashburn23d36b12016-02-02 17:47:28 -07001794#define LOOKUP_GIPA(func, required) \
1795 do { \
Mark Young0153e0b2016-11-03 14:27:13 -06001796 icd_term->func = (PFN_vk##func)fp_gipa(inst, "vk" #func); \
1797 if (!icd_term->func && required) { \
Jon Ashburn23d36b12016-02-02 17:47:28 -07001798 loader_log((struct loader_instance *)inst, \
Jon Ashburn1530c342016-02-26 13:14:27 -07001799 VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07001800 loader_platform_get_proc_address_error("vk" #func)); \
1801 return false; \
1802 } \
Jon Ashburn3da71f22015-05-14 12:43:38 -06001803 } while (0)
1804
Jon Ashburnc624c882015-07-16 10:17:29 -06001805 LOOKUP_GIPA(GetDeviceProcAddr, true);
1806 LOOKUP_GIPA(DestroyInstance, true);
1807 LOOKUP_GIPA(EnumeratePhysicalDevices, true);
1808 LOOKUP_GIPA(GetPhysicalDeviceFeatures, true);
1809 LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true);
Jon Ashburn754864f2015-07-23 18:49:07 -06001810 LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true);
Jon Ashburnc624c882015-07-16 10:17:29 -06001811 LOOKUP_GIPA(CreateDevice, true);
1812 LOOKUP_GIPA(GetPhysicalDeviceProperties, true);
1813 LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true);
Cody Northropd0802882015-08-03 17:04:53 -06001814 LOOKUP_GIPA(GetPhysicalDeviceQueueFamilyProperties, true);
Courtney Goeltzenleuchter35985f62015-09-14 17:22:16 -06001815 LOOKUP_GIPA(EnumerateDeviceExtensionProperties, true);
Jon Ashburnc624c882015-07-16 10:17:29 -06001816 LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001817 LOOKUP_GIPA(CreateDebugReportCallbackEXT, false);
1818 LOOKUP_GIPA(DestroyDebugReportCallbackEXT, false);
Mark Young65cb3662016-11-07 13:27:02 -07001819 LOOKUP_GIPA(DebugMarkerSetObjectTagEXT, false);
1820 LOOKUP_GIPA(DebugMarkerSetObjectNameEXT, false);
Ian Elliott7e40db92015-08-21 15:09:33 -06001821 LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportKHR, false);
Ian Elliott486c5502015-11-19 16:05:09 -07001822 LOOKUP_GIPA(GetPhysicalDeviceSurfaceCapabilitiesKHR, false);
1823 LOOKUP_GIPA(GetPhysicalDeviceSurfaceFormatsKHR, false);
1824 LOOKUP_GIPA(GetPhysicalDeviceSurfacePresentModesKHR, false);
Petros Bantolas25d27fe2016-04-14 12:50:42 +01001825 LOOKUP_GIPA(GetPhysicalDeviceDisplayPropertiesKHR, false);
1826 LOOKUP_GIPA(GetDisplayModePropertiesKHR, false);
1827 LOOKUP_GIPA(CreateDisplayPlaneSurfaceKHR, false);
1828 LOOKUP_GIPA(GetPhysicalDeviceDisplayPlanePropertiesKHR, false);
1829 LOOKUP_GIPA(GetDisplayPlaneSupportedDisplaysKHR, false);
1830 LOOKUP_GIPA(CreateDisplayModeKHR, false);
1831 LOOKUP_GIPA(GetDisplayPlaneCapabilitiesKHR, false);
1832 LOOKUP_GIPA(DestroySurfaceKHR, false);
Mark Young16573c72016-06-28 10:52:43 -06001833 LOOKUP_GIPA(CreateSwapchainKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001834#ifdef VK_USE_PLATFORM_WIN32_KHR
Mark Young16573c72016-06-28 10:52:43 -06001835 LOOKUP_GIPA(CreateWin32SurfaceKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001836 LOOKUP_GIPA(GetPhysicalDeviceWin32PresentationSupportKHR, false);
1837#endif
1838#ifdef VK_USE_PLATFORM_XCB_KHR
Mark Young16573c72016-06-28 10:52:43 -06001839 LOOKUP_GIPA(CreateXcbSurfaceKHR, false);
Ian Elliott919fa302015-11-24 15:39:10 -07001840 LOOKUP_GIPA(GetPhysicalDeviceXcbPresentationSupportKHR, false);
1841#endif
Karl Schultz65d20182016-03-08 07:55:27 -07001842#ifdef VK_USE_PLATFORM_XLIB_KHR
Mark Young16573c72016-06-28 10:52:43 -06001843 LOOKUP_GIPA(CreateXlibSurfaceKHR, false);
Karl Schultz65d20182016-03-08 07:55:27 -07001844 LOOKUP_GIPA(GetPhysicalDeviceXlibPresentationSupportKHR, false);
1845#endif
Mark Younga7c51fd2016-09-16 10:18:42 -06001846#ifdef VK_USE_PLATFORM_MIR_KHR
1847 LOOKUP_GIPA(CreateMirSurfaceKHR, false);
1848 LOOKUP_GIPA(GetPhysicalDeviceMirPresentationSupportKHR, false);
1849#endif
Jason Ekstranda5ebe8a2016-02-12 17:25:03 -08001850#ifdef VK_USE_PLATFORM_WAYLAND_KHR
Mark Young16573c72016-06-28 10:52:43 -06001851 LOOKUP_GIPA(CreateWaylandSurfaceKHR, false);
Jason Ekstranda5ebe8a2016-02-12 17:25:03 -08001852 LOOKUP_GIPA(GetPhysicalDeviceWaylandPresentationSupportKHR, false);
1853#endif
Mark Youngfa552782016-12-12 16:14:55 -07001854 // NV_external_memory_capabilities
James Jones389dc0c2016-08-18 23:41:19 +01001855 LOOKUP_GIPA(GetPhysicalDeviceExternalImageFormatPropertiesNV, false);
Mark Youngfa552782016-12-12 16:14:55 -07001856 // NVX_device_generated_commands
1857 LOOKUP_GIPA(GetPhysicalDeviceGeneratedCommandsPropertiesNVX, false);
Jon Ashburn3da71f22015-05-14 12:43:38 -06001858
Jon Ashburnc624c882015-07-16 10:17:29 -06001859#undef LOOKUP_GIPA
Ian Elliottd3ef02f2015-07-06 14:36:13 -06001860
Jon Ashburnc624c882015-07-16 10:17:29 -06001861 return true;
Jon Ashburn3da71f22015-05-14 12:43:38 -06001862}
1863
Jon Ashburn23d36b12016-02-02 17:47:28 -07001864static void loader_debug_init(void) {
Mark Young0ad83132016-06-30 13:02:42 -06001865 char *env, *orig;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001866
1867 if (g_loader_debug > 0)
1868 return;
1869
1870 g_loader_debug = 0;
1871
1872 /* parse comma-separated debug options */
Mark Young0ad83132016-06-30 13:02:42 -06001873 orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001874 while (env) {
Mark Young0ad83132016-06-30 13:02:42 -06001875 char *p = strchr(env, ',');
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001876 size_t len;
1877
1878 if (p)
1879 len = p - env;
1880 else
1881 len = strlen(env);
1882
1883 if (len > 0) {
Michael Worcester25c73e72015-12-10 18:06:24 +00001884 if (strncmp(env, "all", len) == 0) {
1885 g_loader_debug = ~0u;
1886 g_loader_log_msgs = ~0u;
1887 } else if (strncmp(env, "warn", len) == 0) {
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001888 g_loader_debug |= LOADER_WARN_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001889 g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001890 } else if (strncmp(env, "info", len) == 0) {
1891 g_loader_debug |= LOADER_INFO_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001892 g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001893 } else if (strncmp(env, "perf", len) == 0) {
1894 g_loader_debug |= LOADER_PERF_BIT;
Jon Ashburn1530c342016-02-26 13:14:27 -07001895 g_loader_log_msgs |=
1896 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001897 } else if (strncmp(env, "error", len) == 0) {
1898 g_loader_debug |= LOADER_ERROR_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001899 g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001900 } else if (strncmp(env, "debug", len) == 0) {
1901 g_loader_debug |= LOADER_DEBUG_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001902 g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001903 }
1904 }
1905
1906 if (!p)
1907 break;
1908
1909 env = p + 1;
1910 }
Jon Ashburn38a497f2016-01-04 14:01:38 -07001911
Mark Young0ad83132016-06-30 13:02:42 -06001912 loader_free_getenv(orig, NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001913}
1914
Jon Ashburn23d36b12016-02-02 17:47:28 -07001915void loader_initialize(void) {
Jon Ashburn6461ef22015-09-22 13:11:00 -06001916 // initialize mutexs
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001917 loader_platform_thread_create_mutex(&loader_lock);
Jon Ashburn6461ef22015-09-22 13:11:00 -06001918 loader_platform_thread_create_mutex(&loader_json_lock);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001919
1920 // initialize logging
1921 loader_debug_init();
Jon Ashburn87d6aa92015-08-28 15:19:27 -06001922
1923 // initial cJSON to use alloc callbacks
1924 cJSON_Hooks alloc_fns = {
Mark Young0ad83132016-06-30 13:02:42 -06001925 .malloc_fn = loader_instance_tls_heap_alloc,
1926 .free_fn = loader_instance_tls_heap_free,
Jon Ashburn87d6aa92015-08-28 15:19:27 -06001927 };
1928 cJSON_InitHooks(&alloc_fns);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001929}
1930
Jon Ashburn2077e382015-06-29 11:25:34 -06001931struct loader_manifest_files {
1932 uint32_t count;
1933 char **filename_list;
1934};
1935
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001936/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001937 * Get next file or dirname given a string list or registry key path
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06001938 *
1939 * \returns
Jon Ashburn2077e382015-06-29 11:25:34 -06001940 * A pointer to first char in the next path.
1941 * The next path (or NULL) in the list is returned in next_path.
1942 * Note: input string is modified in some cases. PASS IN A COPY!
1943 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001944static char *loader_get_next_path(char *path) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001945 uint32_t len;
1946 char *next;
1947
1948 if (path == NULL)
1949 return NULL;
Frank Henigman57173102016-11-24 22:15:20 -05001950 next = strchr(path, PATH_SEPARATOR);
Jon Ashburn2077e382015-06-29 11:25:34 -06001951 if (next == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001952 len = (uint32_t)strlen(path);
Jon Ashburn2077e382015-06-29 11:25:34 -06001953 next = path + len;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001954 } else {
Jon Ashburn2077e382015-06-29 11:25:34 -06001955 *next = '\0';
1956 next++;
1957 }
1958
1959 return next;
1960}
1961
1962/**
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001963 * Given a path which is absolute or relative, expand the path if relative or
1964 * leave the path unmodified if absolute. The base path to prepend to relative
1965 * paths is given in rel_base.
Jon Ashburn15315172015-07-07 15:06:25 -06001966 *
1967 * \returns
1968 * A string in out_fullpath of the full absolute path
Jon Ashburn15315172015-07-07 15:06:25 -06001969 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001970static void loader_expand_path(const char *path, const char *rel_base,
1971 size_t out_size, char *out_fullpath) {
Jon Ashburn15315172015-07-07 15:06:25 -06001972 if (loader_platform_is_path_absolute(path)) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001973 // do not prepend a base to an absolute path
1974 rel_base = "";
Jon Ashburn15315172015-07-07 15:06:25 -06001975 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001976
1977 loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
Jon Ashburn15315172015-07-07 15:06:25 -06001978}
1979
1980/**
Jon Ashburn2077e382015-06-29 11:25:34 -06001981 * Given a filename (file) and a list of paths (dir), try to find an existing
1982 * file in the paths. If filename already is a path then no
1983 * searching in the given paths.
1984 *
1985 * \returns
1986 * A string in out_fullpath of either the full path or file.
Jon Ashburn2077e382015-06-29 11:25:34 -06001987 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07001988static void loader_get_fullpath(const char *file, const char *dirs,
1989 size_t out_size, char *out_fullpath) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001990 if (!loader_platform_is_path(file) && *dirs) {
1991 char *dirs_copy, *dir, *next_dir;
1992
1993 dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
1994 strcpy(dirs_copy, dirs);
1995
Jon Ashburn23d36b12016-02-02 17:47:28 -07001996 // find if file exists after prepending paths in given list
1997 for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir));
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001998 dir = next_dir) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001999 loader_platform_combine_path(out_fullpath, out_size, dir, file,
2000 NULL);
Jon Ashburn2077e382015-06-29 11:25:34 -06002001 if (loader_platform_file_exists(out_fullpath)) {
2002 return;
2003 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002004 }
2005 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05002006
Karl Schultze2ef9e62017-01-13 14:01:35 -07002007 (void)snprintf(out_fullpath, out_size, "%s", file);
Jon Ashburn2077e382015-06-29 11:25:34 -06002008}
2009
2010/**
2011 * Read a JSON file into a buffer.
2012 *
2013 * \returns
2014 * A pointer to a cJSON object representing the JSON parse tree.
2015 * This returned buffer should be freed by caller.
2016 */
Mark Young3a587792016-08-19 15:25:08 -06002017static VkResult loader_get_json(const struct loader_instance *inst,
2018 const char *filename, cJSON **json) {
2019 FILE *file = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002020 char *json_buf;
Mark Young93ecb1d2016-01-13 13:47:16 -07002021 size_t len;
Mark Young3a587792016-08-19 15:25:08 -06002022 VkResult res = VK_SUCCESS;
2023
2024 if (NULL == json) {
Mark Youngb6399312017-01-10 14:22:15 -07002025 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2026 "loader_get_json: Received invalid JSON file");
Mark Young3a587792016-08-19 15:25:08 -06002027 res = VK_ERROR_INITIALIZATION_FAILED;
2028 goto out;
2029 }
2030
2031 *json = NULL;
2032
Jon Ashburn23d36b12016-02-02 17:47:28 -07002033 file = fopen(filename, "rb");
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002034 if (!file) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002035 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002036 "loader_get_json: Failed to open JSON file %s", filename);
2037 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06002038 goto out;
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002039 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002040 fseek(file, 0, SEEK_END);
2041 len = ftell(file);
2042 fseek(file, 0, SEEK_SET);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002043 json_buf = (char *)loader_stack_alloc(len + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06002044 if (json_buf == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002045 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002046 "loader_get_json: Failed to allocate space for "
Mark Young2c84c0c2017-01-13 10:27:03 -07002047 "JSON file %s buffer of length %d",
Mark Youngb6399312017-01-10 14:22:15 -07002048 filename, len);
2049 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002050 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002051 }
2052 if (fread(json_buf, sizeof(char), len, file) != len) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002053 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002054 "loader_get_json: Failed to read JSON file %s.", filename);
2055 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06002056 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002057 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002058 json_buf[len] = '\0';
2059
Jon Ashburn23d36b12016-02-02 17:47:28 -07002060 // parse text from file
Mark Young3a587792016-08-19 15:25:08 -06002061 *json = cJSON_Parse(json_buf);
2062 if (*json == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002063 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002064 "loader_get_json: Failed to parse JSON file %s, "
Mark Young2c84c0c2017-01-13 10:27:03 -07002065 "this is usually because something ran out of "
2066 "memory.",
Mark Youngb6399312017-01-10 14:22:15 -07002067 filename);
2068 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002069 goto out;
2070 }
2071
2072out:
2073 if (NULL != file) {
2074 fclose(file);
2075 }
2076
2077 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06002078}
2079
2080/**
Jon Ashburn3d002332015-08-20 16:35:30 -06002081 * Do a deep copy of the loader_layer_properties structure.
2082 */
Mark Young0ad83132016-06-30 13:02:42 -06002083VkResult loader_copy_layer_properties(const struct loader_instance *inst,
2084 struct loader_layer_properties *dst,
2085 struct loader_layer_properties *src) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002086 uint32_t cnt, i;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002087 memcpy(dst, src, sizeof(*src));
Mark Youngb6399312017-01-10 14:22:15 -07002088 dst->instance_extension_list.list = loader_instance_heap_alloc(
2089 inst,
2090 sizeof(VkExtensionProperties) * src->instance_extension_list.count,
2091 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002092 if (NULL == dst->instance_extension_list.list) {
2093 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002094 "loader_copy_layer_properties: Failed to allocate space "
Mark Young2c84c0c2017-01-13 10:27:03 -07002095 "for instance extension list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002096 src->instance_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002097 return VK_ERROR_OUT_OF_HOST_MEMORY;
2098 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002099 dst->instance_extension_list.capacity =
2100 sizeof(VkExtensionProperties) * src->instance_extension_list.count;
Jon Ashburne39a4f82015-08-28 13:38:21 -06002101 memcpy(dst->instance_extension_list.list, src->instance_extension_list.list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07002102 dst->instance_extension_list.capacity);
Mark Youngb6399312017-01-10 14:22:15 -07002103 dst->device_extension_list.list = loader_instance_heap_alloc(
2104 inst,
2105 sizeof(struct loader_dev_ext_props) * src->device_extension_list.count,
2106 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002107 if (NULL == dst->device_extension_list.list) {
2108 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002109 "loader_copy_layer_properties: Failed to allocate space "
Mark Young2c84c0c2017-01-13 10:27:03 -07002110 "for device extension list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002111 src->device_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002112 return VK_ERROR_OUT_OF_HOST_MEMORY;
2113 }
Mark Young0153e0b2016-11-03 14:27:13 -06002114 memset(dst->device_extension_list.list, 0,
2115 sizeof(struct loader_dev_ext_props) *
2116 src->device_extension_list.count);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002117
Jon Ashburn23d36b12016-02-02 17:47:28 -07002118 dst->device_extension_list.capacity =
2119 sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
Jon Ashburne39a4f82015-08-28 13:38:21 -06002120 memcpy(dst->device_extension_list.list, src->device_extension_list.list,
Jon Ashburn23d36b12016-02-02 17:47:28 -07002121 dst->device_extension_list.capacity);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002122 if (src->device_extension_list.count > 0 &&
Jon Ashburn23d36b12016-02-02 17:47:28 -07002123 src->device_extension_list.list->entrypoint_count > 0) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002124 cnt = src->device_extension_list.list->entrypoint_count;
Mark Young0ad83132016-06-30 13:02:42 -06002125 dst->device_extension_list.list->entrypoints =
2126 loader_instance_heap_alloc(inst, sizeof(char *) * cnt,
2127 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2128 if (NULL == dst->device_extension_list.list->entrypoints) {
Mark Youngb6399312017-01-10 14:22:15 -07002129 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2130 "loader_copy_layer_properties: Failed to allocate space "
Mark Young2c84c0c2017-01-13 10:27:03 -07002131 "for device extension entrypoint list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002132 cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002133 return VK_ERROR_OUT_OF_HOST_MEMORY;
2134 }
Mark Young0153e0b2016-11-03 14:27:13 -06002135 memset(dst->device_extension_list.list->entrypoints, 0,
2136 sizeof(char *) * cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002137
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002138 for (i = 0; i < cnt; i++) {
Mark Young0ad83132016-06-30 13:02:42 -06002139 dst->device_extension_list.list->entrypoints[i] =
2140 loader_instance_heap_alloc(
2141 inst,
2142 strlen(src->device_extension_list.list->entrypoints[i]) + 1,
2143 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2144 if (NULL == dst->device_extension_list.list->entrypoints[i]) {
Mark Youngb6399312017-01-10 14:22:15 -07002145 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2146 "loader_copy_layer_properties: Failed to "
2147 "allocate space for device extension entrypoint "
2148 "%d name of length",
2149 i);
Mark Young0ad83132016-06-30 13:02:42 -06002150 return VK_ERROR_OUT_OF_HOST_MEMORY;
2151 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002152 strcpy(dst->device_extension_list.list->entrypoints[i],
2153 src->device_extension_list.list->entrypoints[i]);
2154 }
2155 }
Mark Young0ad83132016-06-30 13:02:42 -06002156
2157 return VK_SUCCESS;
Jon Ashburn3d002332015-08-20 16:35:30 -06002158}
2159
Jon Ashburn86a527a2016-02-10 20:59:26 -07002160static bool
2161loader_find_layer_name_list(const char *name,
2162 const struct loader_layer_list *layer_list) {
2163 if (!layer_list)
2164 return false;
2165 for (uint32_t j = 0; j < layer_list->count; j++)
2166 if (!strcmp(name, layer_list->list[j].info.layerName))
2167 return true;
2168 return false;
2169}
2170
2171static bool loader_find_layer_name(const char *name, uint32_t layer_count,
2172 const char **layer_list) {
2173 if (!layer_list)
2174 return false;
2175 for (uint32_t j = 0; j < layer_count; j++)
2176 if (!strcmp(name, layer_list[j]))
2177 return true;
2178 return false;
2179}
2180
Jon Ashburn491cd042016-05-16 14:01:18 -06002181bool loader_find_layer_name_array(
Jon Ashburn86a527a2016-02-10 20:59:26 -07002182 const char *name, uint32_t layer_count,
2183 const char layer_list[][VK_MAX_EXTENSION_NAME_SIZE]) {
2184 if (!layer_list)
2185 return false;
2186 for (uint32_t j = 0; j < layer_count; j++)
2187 if (!strcmp(name, layer_list[j]))
2188 return true;
2189 return false;
2190}
2191
2192/**
2193 * Searches through an array of layer names (ppp_layer_names) looking for a
2194 * layer key_name.
2195 * If not found then simply returns updating nothing.
2196 * Otherwise, it uses expand_count, expand_names adding them to layer names.
Chris Forbes69366472016-04-07 09:04:49 +12002197 * Any duplicate (pre-existing) expand_names in layer names are removed.
2198 * Order is otherwise preserved, with the layer key_name being replaced by the
2199 * expand_names.
Jon Ashburn86a527a2016-02-10 20:59:26 -07002200 * @param inst
2201 * @param layer_count
2202 * @param ppp_layer_names
2203 */
Mark Young0ad83132016-06-30 13:02:42 -06002204VkResult loader_expand_layer_names(
2205 struct loader_instance *inst, const char *key_name, uint32_t expand_count,
Jon Ashburn86a527a2016-02-10 20:59:26 -07002206 const char expand_names[][VK_MAX_EXTENSION_NAME_SIZE],
Jon Ashburncc407a22016-04-15 09:25:03 -06002207 uint32_t *layer_count, char const *const **ppp_layer_names) {
Jon Ashburn71483442016-02-11 18:59:43 -07002208
Jon Ashburncc407a22016-04-15 09:25:03 -06002209 char const *const *pp_src_layers = *ppp_layer_names;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002210
Jon Ashburncc407a22016-04-15 09:25:03 -06002211 if (!loader_find_layer_name(key_name, *layer_count,
Jon Ashburn491cd042016-05-16 14:01:18 -06002212 (char const **)pp_src_layers)) {
2213 inst->activated_layers_are_std_val = false;
Mark Young0ad83132016-06-30 13:02:42 -06002214 return VK_SUCCESS; // didn't find the key_name in the list.
Jon Ashburn491cd042016-05-16 14:01:18 -06002215 }
Jon Ashburn71483442016-02-11 18:59:43 -07002216
Jon Ashburn86a527a2016-02-10 20:59:26 -07002217 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2218 "Found meta layer %s, replacing with actual layer group",
2219 key_name);
Chris Forbesbd9de052016-04-06 20:49:02 +12002220
Jon Ashburn491cd042016-05-16 14:01:18 -06002221 inst->activated_layers_are_std_val = true;
Mark Young0ad83132016-06-30 13:02:42 -06002222 char const **pp_dst_layers = loader_instance_heap_alloc(
Jon Ashburncc407a22016-04-15 09:25:03 -06002223 inst, (expand_count + *layer_count - 1) * sizeof(char const *),
2224 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young0ad83132016-06-30 13:02:42 -06002225 if (NULL == pp_dst_layers) {
2226 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002227 "loader_expand_layer_names:: Failed to allocate space for "
2228 "std_validation layer names in pp_dst_layers.");
Mark Young0ad83132016-06-30 13:02:42 -06002229 return VK_ERROR_OUT_OF_HOST_MEMORY;
2230 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002231
2232 // copy layers from src to dst, stripping key_name and anything in
2233 // expand_names.
2234 uint32_t src_index, dst_index = 0;
2235 for (src_index = 0; src_index < *layer_count; src_index++) {
Jon Ashburncc407a22016-04-15 09:25:03 -06002236 if (loader_find_layer_name_array(pp_src_layers[src_index], expand_count,
2237 expand_names)) {
Chris Forbes69366472016-04-07 09:04:49 +12002238 continue;
2239 }
2240
2241 if (!strcmp(pp_src_layers[src_index], key_name)) {
2242 // insert all expand_names in place of key_name
2243 uint32_t expand_index;
Jon Ashburncc407a22016-04-15 09:25:03 -06002244 for (expand_index = 0; expand_index < expand_count;
2245 expand_index++) {
Chris Forbes69366472016-04-07 09:04:49 +12002246 pp_dst_layers[dst_index++] = expand_names[expand_index];
2247 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002248 continue;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002249 }
Chris Forbesbd9de052016-04-06 20:49:02 +12002250
2251 pp_dst_layers[dst_index++] = pp_src_layers[src_index];
Jon Ashburn86a527a2016-02-10 20:59:26 -07002252 }
2253
Chris Forbesbd9de052016-04-06 20:49:02 +12002254 *ppp_layer_names = pp_dst_layers;
2255 *layer_count = dst_index;
Mark Young0ad83132016-06-30 13:02:42 -06002256
2257 return VK_SUCCESS;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002258}
2259
Chris Forbesbd9de052016-04-06 20:49:02 +12002260void loader_delete_shadow_inst_layer_names(const struct loader_instance *inst,
2261 const VkInstanceCreateInfo *orig,
2262 VkInstanceCreateInfo *ours) {
2263 /* Free the layer names array iff we had to reallocate it */
2264 if (orig->ppEnabledLayerNames != ours->ppEnabledLayerNames) {
Mark Young0ad83132016-06-30 13:02:42 -06002265 loader_instance_heap_free(inst, (void *)ours->ppEnabledLayerNames);
Jon Ashburn86a527a2016-02-10 20:59:26 -07002266 }
2267}
2268
Jon Ashburn491cd042016-05-16 14:01:18 -06002269void loader_init_std_validation_props(struct loader_layer_properties *props) {
2270 memset(props, 0, sizeof(struct loader_layer_properties));
2271 props->type = VK_LAYER_TYPE_META_EXPLICT;
2272 strncpy(props->info.description, "LunarG Standard Validation Layer",
Mark Young0153e0b2016-11-03 14:27:13 -06002273 sizeof(props->info.description));
Jon Ashburn491cd042016-05-16 14:01:18 -06002274 props->info.implementationVersion = 1;
2275 strncpy(props->info.layerName, std_validation_str,
Mark Young0153e0b2016-11-03 14:27:13 -06002276 sizeof(props->info.layerName));
Jon Ashburn491cd042016-05-16 14:01:18 -06002277 // TODO what about specVersion? for now insert loader's built version
2278 props->info.specVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION);
2279}
2280
Jon Ashburn86a527a2016-02-10 20:59:26 -07002281/**
Jon Ashburn491cd042016-05-16 14:01:18 -06002282 * Searches through the existing instance layer lists looking for
Jon Ashburn86a527a2016-02-10 20:59:26 -07002283 * the set of required layer names. If found then it adds a meta property to the
2284 * layer list.
2285 * Assumes the required layers are the same for both instance and device lists.
2286 * @param inst
2287 * @param layer_count number of layers in layer_names
2288 * @param layer_names array of required layer names
2289 * @param layer_instance_list
Jon Ashburn86a527a2016-02-10 20:59:26 -07002290 */
2291static void loader_add_layer_property_meta(
2292 const struct loader_instance *inst, uint32_t layer_count,
2293 const char layer_names[][VK_MAX_EXTENSION_NAME_SIZE],
Jon Ashburn491cd042016-05-16 14:01:18 -06002294 struct loader_layer_list *layer_instance_list) {
2295 uint32_t i;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002296 bool found;
2297 struct loader_layer_list *layer_list;
2298
Jon Ashburn491cd042016-05-16 14:01:18 -06002299 if (0 == layer_count || (!layer_instance_list))
Jon Ashburn888c0502016-02-19 15:22:10 -07002300 return;
Jon Ashburn491cd042016-05-16 14:01:18 -06002301 if (layer_instance_list && (layer_count > layer_instance_list->count))
Jon Ashburn86a527a2016-02-10 20:59:26 -07002302 return;
2303
Jon Ashburn491cd042016-05-16 14:01:18 -06002304 layer_list = layer_instance_list;
2305
2306 found = true;
2307 if (layer_list == NULL)
2308 return;
2309 for (i = 0; i < layer_count; i++) {
2310 if (loader_find_layer_name_list(layer_names[i], layer_list))
Jon Ashburn888c0502016-02-19 15:22:10 -07002311 continue;
Jon Ashburn491cd042016-05-16 14:01:18 -06002312 found = false;
2313 break;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002314 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002315
2316 struct loader_layer_properties *props;
2317 if (found) {
2318 props = loader_get_next_layer_property(inst, layer_list);
Mark Young0ad83132016-06-30 13:02:42 -06002319 if (NULL == props) {
2320 // Error already triggered in loader_get_next_layer_property.
2321 return;
2322 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002323 loader_init_std_validation_props(props);
Jon Ashburn491cd042016-05-16 14:01:18 -06002324 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002325}
2326
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002327static void loader_read_json_layer(
2328 const struct loader_instance *inst,
2329 struct loader_layer_list *layer_instance_list, cJSON *layer_node,
2330 cJSON *item, cJSON *disable_environment, bool is_implicit, char *filename) {
2331 char *temp;
2332 char *name, *type, *library_path, *api_version;
2333 char *implementation_version, *description;
2334 cJSON *ext_item;
2335 VkExtensionProperties ext_prop;
2336
Mark Young0ad83132016-06-30 13:02:42 -06002337/*
2338 * The following are required in the "layer" object:
2339 * (required) "name"
2340 * (required) "type"
2341 * (required) “library_path”
2342 * (required) “api_version”
2343 * (required) “implementation_version”
2344 * (required) “description”
2345 * (required for implicit layers) “disable_environment”
2346 */
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002347
Jon Ashburn23d36b12016-02-02 17:47:28 -07002348#define GET_JSON_OBJECT(node, var) \
2349 { \
2350 var = cJSON_GetObjectItem(node, #var); \
2351 if (var == NULL) { \
2352 layer_node = layer_node->next; \
Jon Ashburn1530c342016-02-26 13:14:27 -07002353 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002354 "Didn't find required layer object %s in manifest " \
2355 "JSON file, skipping this layer", \
2356 #var); \
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002357 return; \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002358 } \
2359 }
2360#define GET_JSON_ITEM(node, var) \
2361 { \
2362 item = cJSON_GetObjectItem(node, #var); \
2363 if (item == NULL) { \
2364 layer_node = layer_node->next; \
Jon Ashburn1530c342016-02-26 13:14:27 -07002365 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002366 "Didn't find required layer value %s in manifest JSON " \
2367 "file, skipping this layer", \
2368 #var); \
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002369 return; \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002370 } \
2371 temp = cJSON_Print(item); \
Mark Young0ad83132016-06-30 13:02:42 -06002372 if (temp == NULL) { \
2373 layer_node = layer_node->next; \
2374 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2375 "Problem accessing layer value %s in manifest JSON " \
2376 "file, skipping this layer", \
2377 #var); \
2378 return; \
2379 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002380 temp[strlen(temp) - 1] = '\0'; \
2381 var = loader_stack_alloc(strlen(temp) + 1); \
2382 strcpy(var, &temp[1]); \
Mark Young0ad83132016-06-30 13:02:42 -06002383 cJSON_Free(temp); \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002384 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002385 GET_JSON_ITEM(layer_node, name)
2386 GET_JSON_ITEM(layer_node, type)
2387 GET_JSON_ITEM(layer_node, library_path)
2388 GET_JSON_ITEM(layer_node, api_version)
2389 GET_JSON_ITEM(layer_node, implementation_version)
2390 GET_JSON_ITEM(layer_node, description)
2391 if (is_implicit) {
2392 GET_JSON_OBJECT(layer_node, disable_environment)
2393 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002394#undef GET_JSON_ITEM
2395#undef GET_JSON_OBJECT
2396
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002397 // add list entry
2398 struct loader_layer_properties *props = NULL;
2399 if (!strcmp(type, "DEVICE")) {
2400 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2401 "Device layers are deprecated skipping this layer");
2402 layer_node = layer_node->next;
2403 return;
2404 }
2405 // Allow either GLOBAL or INSTANCE type interchangeably to handle
2406 // layers that must work with older loaders
2407 if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2408 if (layer_instance_list == NULL) {
Jon Ashburn432d2762015-09-18 12:53:16 -06002409 layer_node = layer_node->next;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002410 return;
Jon Ashburn432d2762015-09-18 12:53:16 -06002411 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002412 props = loader_get_next_layer_property(inst, layer_instance_list);
Mark Young0ad83132016-06-30 13:02:42 -06002413 if (NULL == props) {
2414 // Error already triggered in loader_get_next_layer_property.
2415 return;
2416 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002417 props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT
2418 : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
2419 }
Jon Ashburn432d2762015-09-18 12:53:16 -06002420
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002421 if (props == NULL) {
2422 layer_node = layer_node->next;
2423 return;
2424 }
Jon Ashburn15315172015-07-07 15:06:25 -06002425
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002426 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
2427 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
2428
2429 char *fullpath = props->lib_name;
2430 char *rel_base;
2431 if (loader_platform_is_path(library_path)) {
2432 // a relative or absolute path
2433 char *name_copy = loader_stack_alloc(strlen(filename) + 1);
2434 strcpy(name_copy, filename);
2435 rel_base = loader_platform_dirname(name_copy);
2436 loader_expand_path(library_path, rel_base, MAX_STRING_SIZE, fullpath);
2437 } else {
2438 // a filename which is assumed in a system directory
2439 loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH,
2440 MAX_STRING_SIZE, fullpath);
2441 }
2442 props->info.specVersion = loader_make_version(api_version);
2443 props->info.implementationVersion = atoi(implementation_version);
2444 strncpy((char *)props->info.description, description,
2445 sizeof(props->info.description));
2446 props->info.description[sizeof(props->info.description) - 1] = '\0';
2447 if (is_implicit) {
2448 if (!disable_environment || !disable_environment->child) {
2449 loader_log(
2450 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2451 "Didn't find required layer child value disable_environment"
2452 "in manifest JSON file, skipping this layer");
2453 layer_node = layer_node->next;
2454 return;
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002455 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002456 strncpy(props->disable_env_var.name, disable_environment->child->string,
2457 sizeof(props->disable_env_var.name));
2458 props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] =
2459 '\0';
2460 strncpy(props->disable_env_var.value,
2461 disable_environment->child->valuestring,
2462 sizeof(props->disable_env_var.value));
2463 props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] =
2464 '\0';
2465 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002466
Jon Ashburn23d36b12016-02-02 17:47:28 -07002467/**
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002468* Now get all optional items and objects and put in list:
2469* functions
2470* instance_extensions
2471* device_extensions
2472* enable_environment (implicit layers only)
2473*/
Jon Ashburn23d36b12016-02-02 17:47:28 -07002474#define GET_JSON_OBJECT(node, var) \
2475 { var = cJSON_GetObjectItem(node, #var); }
2476#define GET_JSON_ITEM(node, var) \
2477 { \
2478 item = cJSON_GetObjectItem(node, #var); \
2479 if (item != NULL) { \
2480 temp = cJSON_Print(item); \
Mark Young0ad83132016-06-30 13:02:42 -06002481 if (temp != NULL) { \
2482 temp[strlen(temp) - 1] = '\0'; \
2483 var = loader_stack_alloc(strlen(temp) + 1); \
2484 strcpy(var, &temp[1]); \
2485 cJSON_Free(temp); \
2486 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002487 } \
2488 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002489
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002490 cJSON *instance_extensions, *device_extensions, *functions,
2491 *enable_environment;
2492 cJSON *entrypoints;
2493 char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *spec_version;
2494 char **entry_array;
2495 vkGetInstanceProcAddr = NULL;
2496 vkGetDeviceProcAddr = NULL;
2497 spec_version = NULL;
2498 entrypoints = NULL;
2499 entry_array = NULL;
2500 int i, j;
Jon Ashburn075ce432015-12-17 17:38:24 -07002501
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002502 /**
2503 * functions
2504 * vkGetInstanceProcAddr
2505 * vkGetDeviceProcAddr
2506 */
2507 GET_JSON_OBJECT(layer_node, functions)
2508 if (functions != NULL) {
2509 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
2510 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
2511 if (vkGetInstanceProcAddr != NULL)
2512 strncpy(props->functions.str_gipa, vkGetInstanceProcAddr,
2513 sizeof(props->functions.str_gipa));
2514 props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
2515 if (vkGetDeviceProcAddr != NULL)
2516 strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr,
2517 sizeof(props->functions.str_gdpa));
2518 props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
2519 }
2520 /**
2521 * instance_extensions
2522 * array of
2523 * name
2524 * spec_version
2525 */
2526 GET_JSON_OBJECT(layer_node, instance_extensions)
2527 if (instance_extensions != NULL) {
2528 int count = cJSON_GetArraySize(instance_extensions);
2529 for (i = 0; i < count; i++) {
2530 ext_item = cJSON_GetArrayItem(instance_extensions, i);
2531 GET_JSON_ITEM(ext_item, name)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002532 if (name != NULL) {
2533 strncpy(ext_prop.extensionName, name,
2534 sizeof(ext_prop.extensionName));
2535 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
2536 '\0';
2537 }
Mark Young0ad83132016-06-30 13:02:42 -06002538 GET_JSON_ITEM(ext_item, spec_version)
2539 if (NULL != spec_version) {
2540 ext_prop.specVersion = atoi(spec_version);
2541 } else {
2542 ext_prop.specVersion = 0;
2543 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002544 bool ext_unsupported =
2545 wsi_unsupported_instance_extension(&ext_prop);
2546 if (!ext_unsupported) {
2547 loader_add_to_ext_list(inst, &props->instance_extension_list, 1,
2548 &ext_prop);
Jon Ashburn075ce432015-12-17 17:38:24 -07002549 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002550 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002551 }
2552 /**
2553 * device_extensions
2554 * array of
2555 * name
2556 * spec_version
2557 * entrypoints
2558 */
2559 GET_JSON_OBJECT(layer_node, device_extensions)
2560 if (device_extensions != NULL) {
2561 int count = cJSON_GetArraySize(device_extensions);
2562 for (i = 0; i < count; i++) {
2563 ext_item = cJSON_GetArrayItem(device_extensions, i);
2564 GET_JSON_ITEM(ext_item, name)
2565 GET_JSON_ITEM(ext_item, spec_version)
2566 if (name != NULL) {
2567 strncpy(ext_prop.extensionName, name,
2568 sizeof(ext_prop.extensionName));
2569 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
2570 '\0';
2571 }
Mark Young0ad83132016-06-30 13:02:42 -06002572 if (NULL != spec_version) {
2573 ext_prop.specVersion = atoi(spec_version);
2574 } else {
2575 ext_prop.specVersion = 0;
2576 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002577 // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
2578 GET_JSON_OBJECT(ext_item, entrypoints)
2579 int entry_count;
2580 if (entrypoints == NULL) {
2581 loader_add_to_dev_ext_list(inst, &props->device_extension_list,
2582 &ext_prop, 0, NULL);
2583 continue;
2584 }
2585 entry_count = cJSON_GetArraySize(entrypoints);
Mark Young0ad83132016-06-30 13:02:42 -06002586 if (entry_count) {
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002587 entry_array =
2588 (char **)loader_stack_alloc(sizeof(char *) * entry_count);
Mark Young0ad83132016-06-30 13:02:42 -06002589 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002590 for (j = 0; j < entry_count; j++) {
2591 ext_item = cJSON_GetArrayItem(entrypoints, j);
2592 if (ext_item != NULL) {
2593 temp = cJSON_Print(ext_item);
Mark Young0ad83132016-06-30 13:02:42 -06002594 if (NULL == temp) {
2595 entry_array[j] = NULL;
2596 continue;
2597 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002598 temp[strlen(temp) - 1] = '\0';
2599 entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
2600 strcpy(entry_array[j], &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06002601 cJSON_Free(temp);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002602 }
2603 }
2604 loader_add_to_dev_ext_list(inst, &props->device_extension_list,
2605 &ext_prop, entry_count, entry_array);
2606 }
2607 }
2608 if (is_implicit) {
2609 GET_JSON_OBJECT(layer_node, enable_environment)
2610
2611 // enable_environment is optional
2612 if (enable_environment) {
2613 strncpy(props->enable_env_var.name,
2614 enable_environment->child->string,
2615 sizeof(props->enable_env_var.name));
2616 props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] =
2617 '\0';
2618 strncpy(props->enable_env_var.value,
2619 enable_environment->child->valuestring,
2620 sizeof(props->enable_env_var.value));
2621 props->enable_env_var
2622 .value[sizeof(props->enable_env_var.value) - 1] = '\0';
2623 }
2624 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002625#undef GET_JSON_ITEM
2626#undef GET_JSON_OBJECT
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002627}
2628
2629/**
2630 * Given a cJSON struct (json) of the top level JSON object from layer manifest
2631 * file, add entry to the layer_list. Fill out the layer_properties in this list
2632 * entry from the input cJSON object.
2633 *
2634 * \returns
2635 * void
2636 * layer_list has a new entry and initialized accordingly.
2637 * If the json input object does not have all the required fields no entry
2638 * is added to the list.
2639 */
2640static void
2641loader_add_layer_properties(const struct loader_instance *inst,
2642 struct loader_layer_list *layer_instance_list,
2643 cJSON *json, bool is_implicit, char *filename) {
2644 /* Fields in layer manifest file that are required:
2645 * (required) “file_format_version”
2646 *
Mark Young0ad83132016-06-30 13:02:42 -06002647 * If more than one "layer" object are to be used, use the "layers" array
2648 * instead.
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002649 *
2650 * First get all required items and if any missing abort
2651 */
2652
2653 cJSON *item, *layers_node, *layer_node;
2654 uint16_t file_major_vers = 0;
2655 uint16_t file_minor_vers = 0;
2656 uint16_t file_patch_vers = 0;
2657 char *vers_tok;
2658 cJSON *disable_environment = NULL;
2659 item = cJSON_GetObjectItem(json, "file_format_version");
2660 if (item == NULL) {
2661 return;
2662 }
2663 char *file_vers = cJSON_PrintUnformatted(item);
Mark Young0ad83132016-06-30 13:02:42 -06002664 if (NULL == file_vers) {
2665 return;
2666 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002667 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2668 "Found manifest file %s, version %s", filename, file_vers);
2669 // Get the major/minor/and patch as integers for easier comparison
2670 vers_tok = strtok(file_vers, ".\"\n\r");
2671 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002672 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002673 vers_tok = strtok(NULL, ".\"\n\r");
2674 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002675 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002676 vers_tok = strtok(NULL, ".\"\n\r");
2677 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04002678 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002679 }
2680 }
2681 }
2682 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
2683 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002684 "loader_add_layer_properties: Unexpected manifest file "
Mark Young2c84c0c2017-01-13 10:27:03 -07002685 "version (expected 1.0.0 or 1.0.1) in %s, may cause "
Mark Youngb6399312017-01-10 14:22:15 -07002686 "errors",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002687 filename);
2688 }
Mark Young0ad83132016-06-30 13:02:42 -06002689 cJSON_Free(file_vers);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002690 // If "layers" is present, read in the array of layer objects
2691 layers_node = cJSON_GetObjectItem(json, "layers");
2692 if (layers_node != NULL) {
2693 int numItems = cJSON_GetArraySize(layers_node);
2694 if (file_major_vers == 1 && file_minor_vers == 0 &&
2695 file_patch_vers == 0) {
2696 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Young2c84c0c2017-01-13 10:27:03 -07002697 "loader_add_layer_properties: \'layers\' tag not "
Mark Youngb6399312017-01-10 14:22:15 -07002698 "supported until file version 1.0.1, but %s is "
2699 "reporting version %s",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002700 filename, file_vers);
2701 }
2702 for (int curLayer = 0; curLayer < numItems; curLayer++) {
2703 layer_node = cJSON_GetArrayItem(layers_node, curLayer);
2704 if (layer_node == NULL) {
2705 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002706 "loader_add_layer_properties: Can not find "
Mark Young2c84c0c2017-01-13 10:27:03 -07002707 "\'layers\' array element %d object in manifest "
Mark Youngb6399312017-01-10 14:22:15 -07002708 "JSON file %s. Skipping this file",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002709 curLayer, filename);
2710 return;
2711 }
2712 loader_read_json_layer(inst, layer_instance_list, layer_node, item,
2713 disable_environment, is_implicit, filename);
2714 }
2715 } else {
2716 // Otherwise, try to read in individual layers
2717 layer_node = cJSON_GetObjectItem(json, "layer");
2718 if (layer_node == NULL) {
2719 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Young2c84c0c2017-01-13 10:27:03 -07002720 "loader_add_layer_properties: Can not find \'layer\' "
Mark Youngb6399312017-01-10 14:22:15 -07002721 "object in manifest JSON file %s. Skipping this file.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002722 filename);
2723 return;
2724 }
2725 // Loop through all "layer" objects in the file to get a count of them
2726 // first.
2727 uint16_t layer_count = 0;
2728 cJSON *tempNode = layer_node;
2729 do {
2730 tempNode = tempNode->next;
2731 layer_count++;
2732 } while (tempNode != NULL);
2733 /*
2734 * Throw a warning if we encounter multiple "layer" objects in file
2735 * versions newer than 1.0.0. Having multiple objects with the same
2736 * name at the same level is actually a JSON standard violation.
2737 */
2738 if (layer_count > 1 &&
2739 (file_major_vers > 1 ||
2740 !(file_minor_vers == 0 && file_patch_vers == 0))) {
2741 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young2c84c0c2017-01-13 10:27:03 -07002742 "loader_add_layer_properties: Multiple \'layer\' nodes"
Mark Youngb6399312017-01-10 14:22:15 -07002743 " are deprecated starting in file version \"1.0.1\". "
Mark Young2c84c0c2017-01-13 10:27:03 -07002744 "Please use \'layers\' : [] array instead in %s.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002745 filename);
2746 } else {
2747 do {
2748 loader_read_json_layer(inst, layer_instance_list, layer_node,
2749 item, disable_environment, is_implicit,
2750 filename);
2751 layer_node = layer_node->next;
2752 } while (layer_node != NULL);
2753 }
2754 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002755 return;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002756}
2757
2758/**
Jon Ashburn2077e382015-06-29 11:25:34 -06002759 * Find the Vulkan library manifest files.
2760 *
Jon Ashburnb6822212016-02-16 15:34:16 -07002761 * This function scans the "location" or "env_override" directories/files
Jon Ashburn2077e382015-06-29 11:25:34 -06002762 * for a list of JSON manifest files. If env_override is non-NULL
2763 * and has a valid value. Then the location is ignored. Otherwise
2764 * location is used to look for manifest files. The location
2765 * is interpreted as Registry path on Windows and a directory path(s)
Jon Ashburnb6822212016-02-16 15:34:16 -07002766 * on Linux. "home_location" is an additional directory in the users home
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01002767 * directory to look at. It is expanded into the dir path
2768 * $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
2769 * on environment variables. This "home_location" is only used on Linux.
Jon Ashburn2077e382015-06-29 11:25:34 -06002770 *
2771 * \returns
Mark Young0ad83132016-06-30 13:02:42 -06002772 * VKResult
Jon Ashburn2077e382015-06-29 11:25:34 -06002773 * A string list of manifest files to be opened in out_files param.
2774 * List has a pointer to string for each manifest filename.
2775 * When done using the list in out_files, pointers should be freed.
Jon Ashburn23d36b12016-02-02 17:47:28 -07002776 * Location or override string lists can be either files or directories as
2777 *follows:
Jon Ashburnffad94d2015-06-30 14:46:22 -07002778 * | location | override
2779 * --------------------------------
2780 * Win ICD | files | files
2781 * Win Layer | files | dirs
2782 * Linux ICD | dirs | files
2783 * Linux Layer| dirs | dirs
Jon Ashburn2077e382015-06-29 11:25:34 -06002784 */
Mark Youngf8c20102016-11-07 16:26:17 -07002785static VkResult
2786loader_get_manifest_files(const struct loader_instance *inst,
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002787 const char *env_override, const char *source_override,
Mark Youngf8c20102016-11-07 16:26:17 -07002788 bool is_layer, bool warn_if_not_present,
2789 const char *location, const char *home_location,
2790 struct loader_manifest_files *out_files) {
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002791 const char *override = NULL;
2792 char *override_getenv = NULL;
Mark Young0ad83132016-06-30 13:02:42 -06002793 char *loc, *orig_loc = NULL;
2794 char *reg = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002795 char *file, *next_file, *name;
2796 size_t alloced_count = 64;
2797 char full_path[2048];
2798 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002799 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06002800 struct dirent *dent;
Mark Young0ad83132016-06-30 13:02:42 -06002801 VkResult res = VK_SUCCESS;
Jon Ashburn2077e382015-06-29 11:25:34 -06002802
2803 out_files->count = 0;
2804 out_files->filename_list = NULL;
2805
Jamie Madill00c3c912016-04-06 18:26:46 -04002806 if (source_override != NULL) {
2807 override = source_override;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002808 } else if (env_override != NULL) {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002809#if !defined(_WIN32)
Jon Ashburncc407a22016-04-15 09:25:03 -06002810 if (geteuid() != getuid() || getegid() != getgid()) {
Jon Ashburnffad94d2015-06-30 14:46:22 -07002811 /* Don't allow setuid apps to use the env var: */
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002812 env_override = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002813 }
2814#endif
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002815 if (env_override != NULL) {
2816 override = override_getenv = loader_getenv(env_override, inst);
2817 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002818 }
2819
Jon Ashburnb6822212016-02-16 15:34:16 -07002820#if !defined(_WIN32)
2821 if (location == NULL && home_location == NULL) {
2822#else
2823 home_location = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002824 if (location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07002825#endif
Mark Youngb6399312017-01-10 14:22:15 -07002826 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2827 "loader_get_manifest_files: Can not get manifest files with "
2828 "NULL location, env_override=%s",
2829 (env_override != NULL) ? env_override : "");
Mark Young0ad83132016-06-30 13:02:42 -06002830 res = VK_ERROR_INITIALIZATION_FAILED;
2831 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002832 }
2833
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002834#if defined(_WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -07002835 list_is_dirs = (is_layer && override != NULL) ? true : false;
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002836#else
2837 list_is_dirs = (override == NULL || is_layer) ? true : false;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002838#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06002839 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07002840 // Also handle getting the location(s) from registry on Windows
2841 if (override == NULL) {
Jon Ashburn3b78e462015-07-31 10:11:24 -06002842 loc = loader_stack_alloc(strlen(location) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002843 if (loc == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002844 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002845 "loader_get_manifest_files: Failed to allocate "
Mark Young2c84c0c2017-01-13 10:27:03 -07002846 "%d bytes for manifest file location.",
Mark Youngb6399312017-01-10 14:22:15 -07002847 strlen(location));
Mark Young0ad83132016-06-30 13:02:42 -06002848 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2849 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002850 }
2851 strcpy(loc, location);
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002852#if defined(_WIN32)
Mark Young2c84c0c2017-01-13 10:27:03 -07002853 VkResult reg_result = loaderGetRegistryFiles(inst, loc, &reg);
2854 if (VK_SUCCESS != reg_result || NULL == reg) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002855 if (!is_layer) {
Mark Young2c84c0c2017-01-13 10:27:03 -07002856 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2857 "loader_get_manifest_files: Registry lookup failed "
2858 "to get ICD manifest files. Possibly missing Vulkan"
2859 " driver?");
2860 if (VK_SUCCESS == reg_result ||
2861 VK_ERROR_OUT_OF_HOST_MEMORY == reg_result) {
2862 res = reg_result;
2863 } else {
2864 res = VK_ERROR_INCOMPATIBLE_DRIVER;
2865 }
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002866 } else {
Mark Youngf8c20102016-11-07 16:26:17 -07002867 if (warn_if_not_present) {
Mark Young2c84c0c2017-01-13 10:27:03 -07002868 // This is only a warning for layers
Mark Youngf8c20102016-11-07 16:26:17 -07002869 loader_log(
2870 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002871 "loader_get_manifest_files: Registry lookup failed "
Mark Young2c84c0c2017-01-13 10:27:03 -07002872 "to get layer manifest files.");
Mark Youngf8c20102016-11-07 16:26:17 -07002873 }
Mark Young2c84c0c2017-01-13 10:27:03 -07002874 if (reg_result == VK_ERROR_OUT_OF_HOST_MEMORY) {
2875 res = reg_result;
2876 } else {
2877 // Return success for now since it's not critical for layers
2878 res = VK_SUCCESS;
2879 }
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002880 }
Mark Young0ad83132016-06-30 13:02:42 -06002881 goto out;
Jon Ashburn24265ac2015-07-31 09:33:21 -06002882 }
Mark Young0ad83132016-06-30 13:02:42 -06002883 orig_loc = loc;
2884 loc = reg;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002885#endif
Jon Ashburn23d36b12016-02-02 17:47:28 -07002886 } else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06002887 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002888 if (loc == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07002889 loader_log(
2890 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2891 "loader_get_manifest_files: Failed to allocate space for "
Mark Young2c84c0c2017-01-13 10:27:03 -07002892 "override environment variable of length %d",
Mark Youngb6399312017-01-10 14:22:15 -07002893 strlen(override) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06002894 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2895 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002896 }
2897 strcpy(loc, override);
2898 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002899
Liam Middlebrook9b14e892015-07-23 18:32:20 -07002900 // Print out the paths being searched if debugging is enabled
Jon Ashburn23d36b12016-02-02 17:47:28 -07002901 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2902 "Searching the following paths for manifest files: %s\n", loc);
Liam Middlebrook9b14e892015-07-23 18:32:20 -07002903
Jon Ashburn2077e382015-06-29 11:25:34 -06002904 file = loc;
2905 while (*file) {
2906 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002907 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002908 sysdir = opendir(file);
2909 name = NULL;
2910 if (sysdir) {
2911 dent = readdir(sysdir);
2912 if (dent == NULL)
2913 break;
2914 name = &(dent->d_name[0]);
2915 loader_get_fullpath(name, file, sizeof(full_path), full_path);
2916 name = full_path;
2917 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002918 } else {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002919#if defined(_WIN32)
2920 name = file;
2921#else
Jon Ashburnffad94d2015-06-30 14:46:22 -07002922 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06002923 char *dir;
2924 // make a copy of location so it isn't modified
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07002925 dir = loader_stack_alloc(strlen(loc) + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06002926 if (dir == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002927 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002928 "loader_get_manifest_files: Failed to allocate "
Mark Young2c84c0c2017-01-13 10:27:03 -07002929 "space for relative location path length %d",
Mark Youngb6399312017-01-10 14:22:15 -07002930 strlen(loc) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06002931 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002932 }
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07002933 strcpy(dir, loc);
Jon Ashburn2077e382015-06-29 11:25:34 -06002934
2935 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
2936
2937 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002938#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06002939 }
2940 while (name) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07002941 /* Look for files ending with ".json" suffix */
2942 uint32_t nlen = (uint32_t)strlen(name);
2943 const char *suf = name + nlen - 5;
2944 if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
2945 if (out_files->count == 0) {
Mark Young0ad83132016-06-30 13:02:42 -06002946 out_files->filename_list = loader_instance_heap_alloc(
2947 inst, alloced_count * sizeof(char *),
2948 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002949 } else if (out_files->count == alloced_count) {
Mark Young0ad83132016-06-30 13:02:42 -06002950 out_files->filename_list = loader_instance_heap_realloc(
2951 inst, out_files->filename_list,
2952 alloced_count * sizeof(char *),
2953 alloced_count * sizeof(char *) * 2,
2954 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002955 alloced_count *= 2;
Jon Ashburn2077e382015-06-29 11:25:34 -06002956 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002957 if (out_files->filename_list == NULL) {
2958 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002959 "loader_get_manifest_files: Failed to allocate "
Mark Young2c84c0c2017-01-13 10:27:03 -07002960 "space for manifest file name list");
Mark Young0ad83132016-06-30 13:02:42 -06002961 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2962 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002963 }
Mark Young0ad83132016-06-30 13:02:42 -06002964 out_files->filename_list[out_files->count] =
2965 loader_instance_heap_alloc(
2966 inst, strlen(name) + 1,
2967 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002968 if (out_files->filename_list[out_files->count] == NULL) {
2969 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07002970 "loader_get_manifest_files: Failed to allocate "
Mark Young2c84c0c2017-01-13 10:27:03 -07002971 "space for manifest file %d list",
Mark Youngb6399312017-01-10 14:22:15 -07002972 out_files->count);
Mark Young0ad83132016-06-30 13:02:42 -06002973 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2974 goto out;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002975 }
2976 strcpy(out_files->filename_list[out_files->count], name);
2977 out_files->count++;
2978 } else if (!list_is_dirs) {
2979 loader_log(
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07002980 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07002981 "Skipping manifest file %s, file name must end in .json",
2982 name);
2983 }
2984 if (list_is_dirs) {
2985 dent = readdir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06002986 if (dent == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002987 break;
Mark Young0ad83132016-06-30 13:02:42 -06002988 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07002989 name = &(dent->d_name[0]);
2990 loader_get_fullpath(name, file, sizeof(full_path), full_path);
2991 name = full_path;
2992 } else {
2993 break;
2994 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002995 }
Mark Young0ad83132016-06-30 13:02:42 -06002996 if (sysdir) {
Jon Ashburn2077e382015-06-29 11:25:34 -06002997 closedir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06002998 sysdir = NULL;
2999 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003000 file = next_file;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003001#if !defined(_WIN32)
Jon Ashburn1530c342016-02-26 13:14:27 -07003002 if (home_location != NULL &&
3003 (next_file == NULL || *next_file == '\0') && override == NULL) {
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003004 char *xdgdatahome = secure_getenv("XDG_DATA_HOME");
3005 size_t len;
3006 if (xdgdatahome != NULL) {
3007
3008 char *home_loc = loader_stack_alloc(strlen(xdgdatahome) + 2 +
Jon Ashburn67e262e2016-02-18 12:45:39 -07003009 strlen(home_location));
3010 if (home_loc == NULL) {
3011 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003012 "loader_get_manifest_files: Failed to allocate "
Mark Young2c84c0c2017-01-13 10:27:03 -07003013 "space for manifest file XDG Home location");
Mark Young0ad83132016-06-30 13:02:42 -06003014 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3015 goto out;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003016 }
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003017 strcpy(home_loc, xdgdatahome);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003018 // Add directory separator if needed
3019 if (home_location[0] != DIRECTORY_SYMBOL) {
3020 len = strlen(home_loc);
3021 home_loc[len] = DIRECTORY_SYMBOL;
Jon Ashburn1530c342016-02-26 13:14:27 -07003022 home_loc[len + 1] = '\0';
Jon Ashburn67e262e2016-02-18 12:45:39 -07003023 }
3024 strcat(home_loc, home_location);
3025 file = home_loc;
3026 next_file = loader_get_next_path(file);
3027 home_location = NULL;
3028
Jon Ashburn1530c342016-02-26 13:14:27 -07003029 loader_log(
3030 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003031 "Searching the following path for manifest files: %s\n",
Jon Ashburn1530c342016-02-26 13:14:27 -07003032 home_loc);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003033 list_is_dirs = true;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003034
3035 } else {
3036
3037 char *home = secure_getenv("HOME");
3038 if (home != NULL) {
3039 char *home_loc = loader_stack_alloc(strlen(home) + 16 +
3040 strlen(home_location));
3041 if (home_loc == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07003042 loader_log(
3043 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3044 "loader_get_manifest_files: Failed to allocate "
Mark Young2c84c0c2017-01-13 10:27:03 -07003045 "space for manifest file Home location");
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003046 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3047 goto out;
3048 }
3049 strcpy(home_loc, home);
3050
3051 len = strlen(home);
3052 if (home[len] != DIRECTORY_SYMBOL) {
3053 home_loc[len] = DIRECTORY_SYMBOL;
3054 home_loc[len + 1] = '\0';
3055 }
3056 strcat(home_loc, ".local/share");
3057
3058 if (home_location[0] != DIRECTORY_SYMBOL) {
3059 len = strlen(home_loc);
3060 home_loc[len] = DIRECTORY_SYMBOL;
3061 home_loc[len + 1] = '\0';
3062 }
3063 strcat(home_loc, home_location);
3064 file = home_loc;
3065 next_file = loader_get_next_path(file);
3066 home_location = NULL;
3067
3068 loader_log(
3069 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3070 "Searching the following path for manifest files: %s\n",
3071 home_loc);
3072 list_is_dirs = true;
3073 } else {
3074 // without knowing HOME, we just.. give up
3075 }
Jon Ashburn67e262e2016-02-18 12:45:39 -07003076 }
3077 }
3078#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003079 }
Mark Young0ad83132016-06-30 13:02:42 -06003080
3081out:
3082 if (VK_SUCCESS != res && NULL != out_files->filename_list) {
3083 for (uint32_t remove = 0; remove < out_files->count; remove++) {
3084 loader_instance_heap_free(inst, out_files->filename_list[remove]);
3085 }
3086 loader_instance_heap_free(inst, out_files->filename_list);
3087 out_files->count = 0;
3088 out_files->filename_list = NULL;
3089 }
3090
3091 if (NULL != sysdir) {
3092 closedir(sysdir);
3093 }
3094
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003095 if (override_getenv != NULL) {
3096 loader_free_getenv(override_getenv, inst);
3097 }
3098
Mark Young0ad83132016-06-30 13:02:42 -06003099 if (NULL != reg && reg != orig_loc) {
3100 loader_instance_heap_free(inst, reg);
3101 }
3102 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06003103}
3104
Jon Ashburn23d36b12016-02-02 17:47:28 -07003105void loader_init_icd_lib_list() {}
Jon Ashburn8810c5f2015-08-18 18:04:47 -06003106
Jon Ashburn23d36b12016-02-02 17:47:28 -07003107void loader_destroy_icd_lib_list() {}
Jon Ashburn2077e382015-06-29 11:25:34 -06003108/**
3109 * Try to find the Vulkan ICD driver(s).
3110 *
3111 * This function scans the default system loader path(s) or path
3112 * specified by the \c VK_ICD_FILENAMES environment variable in
3113 * order to find loadable VK ICDs manifest files. From these
3114 * manifest files it finds the ICD libraries.
3115 *
3116 * \returns
Mark Young0ad83132016-06-30 13:02:42 -06003117 * Vulkan result
3118 * (on result == VK_SUCCESS) a list of icds that were discovered
Courtney Goeltzenleuchter4af9bd12014-08-01 14:18:11 -06003119 */
Mark Young0ad83132016-06-30 13:02:42 -06003120VkResult loader_icd_scan(const struct loader_instance *inst,
Mark Young0153e0b2016-11-03 14:27:13 -06003121 struct loader_icd_tramp_list *icd_tramp_list) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003122 char *file_str;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003123 uint16_t file_major_vers = 0;
3124 uint16_t file_minor_vers = 0;
3125 uint16_t file_patch_vers = 0;
3126 char *vers_tok;
Jon Ashburn2077e382015-06-29 11:25:34 -06003127 struct loader_manifest_files manifest_files;
Mark Young0ad83132016-06-30 13:02:42 -06003128 VkResult res = VK_SUCCESS;
3129 bool lockedMutex = false;
3130 cJSON *json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003131 uint32_t num_good_icds = 0;
Jon Ashburn2077e382015-06-29 11:25:34 -06003132
Mark Young0ad83132016-06-30 13:02:42 -06003133 memset(&manifest_files, 0, sizeof(struct loader_manifest_files));
3134
Mark Young0153e0b2016-11-03 14:27:13 -06003135 res = loader_scanned_icd_init(inst, icd_tramp_list);
Mark Young0ad83132016-06-30 13:02:42 -06003136 if (VK_SUCCESS != res) {
3137 goto out;
3138 }
3139
Jon Ashburn2077e382015-06-29 11:25:34 -06003140 // Get a list of manifest files for ICDs
Mark Young0ad83132016-06-30 13:02:42 -06003141 res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false,
Mark Youngf8c20102016-11-07 16:26:17 -07003142 true, DEFAULT_VK_DRIVERS_INFO,
Mark Young0ad83132016-06-30 13:02:42 -06003143 HOME_VK_DRIVERS_INFO, &manifest_files);
3144 if (VK_SUCCESS != res || manifest_files.count == 0) {
3145 goto out;
3146 }
Jon Ashburn6461ef22015-09-22 13:11:00 -06003147 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003148 lockedMutex = true;
Jon Ashburn2077e382015-06-29 11:25:34 -06003149 for (uint32_t i = 0; i < manifest_files.count; i++) {
3150 file_str = manifest_files.filename_list[i];
Mark Young0ad83132016-06-30 13:02:42 -06003151 if (file_str == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003152 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003153 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003154
Mark Young3a587792016-08-19 15:25:08 -06003155 res = loader_get_json(inst, file_str, &json);
3156 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3157 break;
3158 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburnaa4ea472015-08-27 08:30:50 -06003159 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003160 }
Mark Young3a587792016-08-19 15:25:08 -06003161
Jon Ashburn005617f2015-11-17 17:35:40 -07003162 cJSON *item, *itemICD;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003163 item = cJSON_GetObjectItem(json, "file_format_version");
Jon Ashburn6461ef22015-09-22 13:11:00 -06003164 if (item == NULL) {
Mark Young3a587792016-08-19 15:25:08 -06003165 if (num_good_icds == 0) {
3166 res = VK_ERROR_INITIALIZATION_FAILED;
3167 }
Mark Youngb6399312017-01-10 14:22:15 -07003168 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3169 "loader_icd_scan: ICD JSON %s does not have a"
3170 " \'file_format_version\' field. Skipping ICD JSON.",
3171 file_str);
Derrick Owens62e16ef2016-09-09 15:49:07 -04003172 cJSON_Delete(json);
3173 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003174 continue;
Jon Ashburn6461ef22015-09-22 13:11:00 -06003175 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003176 char *file_vers = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003177 if (NULL == file_vers) {
3178 // Only reason the print can fail is if there was an allocation
3179 // issue
Mark Young3a587792016-08-19 15:25:08 -06003180 if (num_good_icds == 0) {
3181 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3182 }
Mark Youngb6399312017-01-10 14:22:15 -07003183 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3184 "loader_icd_scan: Failed retrieving ICD JSON %s"
3185 " \'file_format_version\' field. Skipping ICD JSON",
3186 file_str);
Derrick Owenscd92b8b2016-09-09 15:45:13 -04003187 cJSON_Delete(json);
3188 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003189 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003190 }
Mark Youngcbcbf892016-06-22 15:25:00 -06003191 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003192 "Found ICD manifest file %s, version %s", file_str,
3193 file_vers);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003194 // Get the major/minor/and patch as integers for easier comparison
3195 vers_tok = strtok(file_vers, ".\"\n\r");
3196 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003197 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003198 vers_tok = strtok(NULL, ".\"\n\r");
3199 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003200 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003201 vers_tok = strtok(NULL, ".\"\n\r");
3202 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003203 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003204 }
3205 }
3206 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003207 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1)
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003208 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003209 "loader_icd_scan: Unexpected manifest file version "
3210 "(expected 1.0.0 or 1.0.1), may cause errors");
Mark Young0ad83132016-06-30 13:02:42 -06003211 cJSON_Free(file_vers);
Jon Ashburn005617f2015-11-17 17:35:40 -07003212 itemICD = cJSON_GetObjectItem(json, "ICD");
3213 if (itemICD != NULL) {
3214 item = cJSON_GetObjectItem(itemICD, "library_path");
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003215 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003216 char *temp = cJSON_Print(item);
Jon Ashburn86251302015-08-25 16:48:24 -06003217 if (!temp || strlen(temp) == 0) {
Mark Young3a587792016-08-19 15:25:08 -06003218 if (num_good_icds == 0) {
3219 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3220 }
Mark Youngb6399312017-01-10 14:22:15 -07003221 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3222 "loader_icd_scan: Failed retrieving ICD JSON %s"
3223 " \'library_path\' field. Skipping ICD JSON.",
3224 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003225 cJSON_Free(temp);
Jon Ashburn86251302015-08-25 16:48:24 -06003226 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003227 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003228 continue;
Jon Ashburn2077e382015-06-29 11:25:34 -06003229 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003230 // strip out extra quotes
Jon Ashburn86251302015-08-25 16:48:24 -06003231 temp[strlen(temp) - 1] = '\0';
3232 char *library_path = loader_stack_alloc(strlen(temp) + 1);
Mark Young3a587792016-08-19 15:25:08 -06003233 if (NULL == library_path) {
Mark Youngb6399312017-01-10 14:22:15 -07003234 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3235 "loader_icd_scan: Failed to allocate space for "
3236 "ICD JSON %s \'library_path\' value. Skipping "
Mark Young2c84c0c2017-01-13 10:27:03 -07003237 "ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003238 file_str);
Mark Young3a587792016-08-19 15:25:08 -06003239 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3240 cJSON_Free(temp);
3241 cJSON_Delete(json);
3242 json = NULL;
3243 goto out;
3244 }
Jon Ashburn86251302015-08-25 16:48:24 -06003245 strcpy(library_path, &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06003246 cJSON_Free(temp);
Mark Young3a587792016-08-19 15:25:08 -06003247 if (strlen(library_path) == 0) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003248 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003249 "loader_icd_scan: ICD JSON %s \'library_path\'"
3250 " field is empty. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003251 file_str);
Jon Ashburn86251302015-08-25 16:48:24 -06003252 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003253 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003254 continue;
3255 }
Jamie Madill2fcbd152016-04-27 16:33:23 -04003256 char fullpath[MAX_STRING_SIZE];
Jon Ashburn86251302015-08-25 16:48:24 -06003257 // Print out the paths being searched if debugging is enabled
Jon Ashburn23d36b12016-02-02 17:47:28 -07003258 loader_log(
3259 inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003260 "Searching for ICD drivers named %s, using default dir %s",
Jamie Madill2fcbd152016-04-27 16:33:23 -04003261 library_path, DEFAULT_VK_DRIVERS_PATH);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003262 if (loader_platform_is_path(library_path)) {
Jon Ashburn86251302015-08-25 16:48:24 -06003263 // a relative or absolute path
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003264 char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
3265 char *rel_base;
Jon Ashburn86251302015-08-25 16:48:24 -06003266 strcpy(name_copy, file_str);
3267 rel_base = loader_platform_dirname(name_copy);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003268 loader_expand_path(library_path, rel_base, sizeof(fullpath),
3269 fullpath);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003270 } else {
Jamie Madill2fcbd152016-04-27 16:33:23 -04003271 // a filename which is assumed in a system directory
3272 loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH,
3273 sizeof(fullpath), fullpath);
Jon Ashburn86251302015-08-25 16:48:24 -06003274 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003275
3276 uint32_t vers = 0;
3277 item = cJSON_GetObjectItem(itemICD, "api_version");
3278 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003279 temp = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003280 if (NULL == temp) {
Mark Youngb6399312017-01-10 14:22:15 -07003281 loader_log(
3282 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3283 "loader_icd_scan: Failed retrieving ICD JSON %s"
3284 " \'api_version\' field. Skipping ICD JSON.",
3285 file_str);
3286
Mark Young0ad83132016-06-30 13:02:42 -06003287 // Only reason the print can fail is if there was an
3288 // allocation issue
Mark Youngb6399312017-01-10 14:22:15 -07003289 if (num_good_icds == 0) {
3290 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3291 }
3292
3293 cJSON_Free(temp);
3294 cJSON_Delete(json);
3295 json = NULL;
3296 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003297 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003298 vers = loader_make_version(temp);
Mark Young0ad83132016-06-30 13:02:42 -06003299 cJSON_Free(temp);
Mark Youngb6399312017-01-10 14:22:15 -07003300 } else {
3301 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3302 "loader_icd_scan: ICD JSON %s does not have an"
3303 " \'api_version\' field.",
3304 file_str);
Jon Ashburn005617f2015-11-17 17:35:40 -07003305 }
Mark Youngb6399312017-01-10 14:22:15 -07003306
Mark Young0153e0b2016-11-03 14:27:13 -06003307 res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath,
3308 vers);
Mark Young3a587792016-08-19 15:25:08 -06003309 if (VK_SUCCESS != res) {
Mark Youngb6399312017-01-10 14:22:15 -07003310 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3311 "loader_icd_scan: Failed to add ICD JSON %s. "
3312 " Skipping ICD JSON.",
3313 fullpath);
Mark Youngb6399312017-01-10 14:22:15 -07003314 continue;
Mark Young3a587792016-08-19 15:25:08 -06003315 }
3316 num_good_icds++;
Mark Young0ad83132016-06-30 13:02:42 -06003317 } else {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003318 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003319 "loader_icd_scan: Failed to find \'library_path\' "
3320 "object in ICD JSON file %s. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003321 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003322 }
3323 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003324 loader_log(
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003325 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003326 "loader_icd_scan: Can not find \'ICD\' object in ICD JSON "
3327 "file %s. Skipping ICD JSON",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003328 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003329 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003330
Mark Young0ad83132016-06-30 13:02:42 -06003331 cJSON_Delete(json);
3332 json = NULL;
3333 }
3334
3335out:
Mark Youngb6399312017-01-10 14:22:15 -07003336
Mark Young0ad83132016-06-30 13:02:42 -06003337 if (NULL != json) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003338 cJSON_Delete(json);
3339 }
Mark Young0ad83132016-06-30 13:02:42 -06003340 if (NULL != manifest_files.filename_list) {
3341 for (uint32_t i = 0; i < manifest_files.count; i++) {
3342 if (NULL != manifest_files.filename_list[i]) {
3343 loader_instance_heap_free(inst,
3344 manifest_files.filename_list[i]);
3345 }
3346 }
3347 loader_instance_heap_free(inst, manifest_files.filename_list);
3348 }
3349 if (lockedMutex) {
3350 loader_platform_thread_unlock_mutex(&loader_json_lock);
3351 }
3352 return res;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003353}
3354
Jon Ashburn23d36b12016-02-02 17:47:28 -07003355void loader_layer_scan(const struct loader_instance *inst,
Jon Ashburn491cd042016-05-16 14:01:18 -06003356 struct loader_layer_list *instance_layers) {
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003357 char *file_str;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003358 struct loader_manifest_files
3359 manifest_files[2]; // [0] = explicit, [1] = implicit
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003360 cJSON *json;
Jon Ashburn075ce432015-12-17 17:38:24 -07003361 uint32_t implicit;
Mark Young0ad83132016-06-30 13:02:42 -06003362 bool lockedMutex = false;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003363
Mark Young0ad83132016-06-30 13:02:42 -06003364 memset(manifest_files, 0, sizeof(struct loader_manifest_files) * 2);
3365
3366 // Get a list of manifest files for explicit layers
3367 if (VK_SUCCESS !=
3368 loader_get_manifest_files(inst, LAYERS_PATH_ENV, LAYERS_SOURCE_PATH,
Mark Youngf8c20102016-11-07 16:26:17 -07003369 true, true, DEFAULT_VK_ELAYERS_INFO,
Mark Young0ad83132016-06-30 13:02:42 -06003370 HOME_VK_ELAYERS_INFO, &manifest_files[0])) {
3371 goto out;
3372 }
3373
3374 // Get a list of manifest files for any implicit layers
Jon Ashburn23d36b12016-02-02 17:47:28 -07003375 // Pass NULL for environment variable override - implicit layers are not
3376 // overridden by LAYERS_PATH_ENV
Mark Youngf8c20102016-11-07 16:26:17 -07003377 if (VK_SUCCESS != loader_get_manifest_files(inst, NULL, NULL, true, false,
3378 DEFAULT_VK_ILAYERS_INFO,
3379 HOME_VK_ILAYERS_INFO,
3380 &manifest_files[1])) {
Mark Young0ad83132016-06-30 13:02:42 -06003381 goto out;
3382 }
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06003383
Mark Young0ad83132016-06-30 13:02:42 -06003384 // Make sure we have at least one layer, if not, go ahead and return
3385 if (manifest_files[0].count == 0 && manifest_files[1].count == 0) {
3386 goto out;
3387 }
3388
3389 // cleanup any previously scanned libraries
Jon Ashburne39a4f82015-08-28 13:38:21 -06003390 loader_delete_layer_properties(inst, instance_layers);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06003391
Jon Ashburn6461ef22015-09-22 13:11:00 -06003392 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003393 lockedMutex = true;
Jon Ashburn075ce432015-12-17 17:38:24 -07003394 for (implicit = 0; implicit < 2; implicit++) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003395 for (uint32_t i = 0; i < manifest_files[implicit].count; i++) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003396 file_str = manifest_files[implicit].filename_list[i];
3397 if (file_str == NULL)
3398 continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06003399
Jon Ashburn075ce432015-12-17 17:38:24 -07003400 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003401 VkResult res = loader_get_json(inst, file_str, &json);
3402 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3403 break;
3404 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003405 continue;
3406 }
3407
Jon Ashburn491cd042016-05-16 14:01:18 -06003408 loader_add_layer_properties(inst, instance_layers, json,
3409 (implicit == 1), file_str);
Jon Ashburn075ce432015-12-17 17:38:24 -07003410 cJSON_Delete(json);
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003411 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003412 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07003413
3414 // add a meta layer for validation if the validation layers are all present
Mark Young0ad83132016-06-30 13:02:42 -06003415 loader_add_layer_property_meta(inst, sizeof(std_validation_names) /
3416 sizeof(std_validation_names[0]),
3417 std_validation_names, instance_layers);
Jon Ashburn86a527a2016-02-10 20:59:26 -07003418
Mark Young0ad83132016-06-30 13:02:42 -06003419out:
3420
3421 for (uint32_t manFile = 0; manFile < 2; manFile++) {
3422 if (NULL != manifest_files[manFile].filename_list) {
3423 for (uint32_t i = 0; i < manifest_files[manFile].count; i++) {
3424 if (NULL != manifest_files[manFile].filename_list[i]) {
3425 loader_instance_heap_free(
3426 inst, manifest_files[manFile].filename_list[i]);
3427 }
3428 }
3429 loader_instance_heap_free(inst,
3430 manifest_files[manFile].filename_list);
3431 }
3432 }
3433 if (lockedMutex) {
3434 loader_platform_thread_unlock_mutex(&loader_json_lock);
3435 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003436}
3437
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003438void loader_implicit_layer_scan(const struct loader_instance *inst,
Jon Ashburn491cd042016-05-16 14:01:18 -06003439 struct loader_layer_list *instance_layers) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003440 char *file_str;
3441 struct loader_manifest_files manifest_files;
3442 cJSON *json;
3443 uint32_t i;
3444
3445 // Pass NULL for environment variable override - implicit layers are not
3446 // overridden by LAYERS_PATH_ENV
Mark Young0ad83132016-06-30 13:02:42 -06003447 VkResult res = loader_get_manifest_files(
Mark Youngf8c20102016-11-07 16:26:17 -07003448 inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO,
3449 HOME_VK_ILAYERS_INFO, &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003450 if (VK_SUCCESS != res || manifest_files.count == 0) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003451 return;
3452 }
3453
3454 /* cleanup any previously scanned libraries */
3455 loader_delete_layer_properties(inst, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003456
3457 loader_platform_thread_lock_mutex(&loader_json_lock);
3458
3459 for (i = 0; i < manifest_files.count; i++) {
3460 file_str = manifest_files.filename_list[i];
3461 if (file_str == NULL) {
3462 continue;
3463 }
3464
3465 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003466 res = loader_get_json(inst, file_str, &json);
3467 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3468 break;
3469 } else if (VK_SUCCESS != res || NULL == json) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003470 continue;
3471 }
3472
Mark Young0ad83132016-06-30 13:02:42 -06003473 loader_add_layer_properties(inst, instance_layers, json, true,
3474 file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003475
Mark Young0ad83132016-06-30 13:02:42 -06003476 loader_instance_heap_free(inst, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003477 cJSON_Delete(json);
3478 }
Mark Young0ad83132016-06-30 13:02:42 -06003479 loader_instance_heap_free(inst, manifest_files.filename_list);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003480
3481 // add a meta layer for validation if the validation layers are all present
Mark Young0ad83132016-06-30 13:02:42 -06003482 loader_add_layer_property_meta(inst, sizeof(std_validation_names) /
3483 sizeof(std_validation_names[0]),
3484 std_validation_names, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003485
3486 loader_platform_thread_unlock_mutex(&loader_json_lock);
3487}
3488
Jon Ashburn23d36b12016-02-02 17:47:28 -07003489static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
3490loader_gpa_instance_internal(VkInstance inst, const char *pName) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003491 if (!strcmp(pName, "vkGetInstanceProcAddr"))
Jon Ashburn23d36b12016-02-02 17:47:28 -07003492 return (void *)loader_gpa_instance_internal;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003493 if (!strcmp(pName, "vkCreateInstance"))
Jon Ashburn1530c342016-02-26 13:14:27 -07003494 return (void *)terminator_CreateInstance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003495 if (!strcmp(pName, "vkCreateDevice"))
Jon Ashburn1530c342016-02-26 13:14:27 -07003496 return (void *)terminator_CreateDevice;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003497
Jon Ashburn27cd5842015-05-12 17:26:48 -06003498 // inst is not wrapped
3499 if (inst == VK_NULL_HANDLE) {
3500 return NULL;
3501 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003502 VkLayerInstanceDispatchTable *disp_table =
3503 *(VkLayerInstanceDispatchTable **)inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003504 void *addr;
3505
3506 if (disp_table == NULL)
3507 return NULL;
3508
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003509 bool found_name;
Jon Ashburncc407a22016-04-15 09:25:03 -06003510 addr =
3511 loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003512 if (found_name) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06003513 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003514 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003515
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003516 // Don't call down the chain, this would be an infinite loop
3517 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Jon Ashburncc407a22016-04-15 09:25:03 -06003518 "loader_gpa_instance_internal() unrecognized name %s", pName);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003519 return NULL;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003520}
3521
Piers Daniellf9262be2016-09-14 11:24:36 -06003522VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
Jon Ashburncc407a22016-04-15 09:25:03 -06003523loader_gpa_device_internal(VkDevice device, const char *pName) {
3524 struct loader_device *dev;
Mark Young0153e0b2016-11-03 14:27:13 -06003525 struct loader_icd_term *icd_term =
3526 loader_get_icd_and_device(device, &dev, NULL);
Mark Young16573c72016-06-28 10:52:43 -06003527
Mark Young65cb3662016-11-07 13:27:02 -07003528 // NOTE: Device Funcs needing Trampoline/Terminator.
3529 // Overrides for device functions needing a trampoline and
3530 // a terminator because certain device entry-points still need to go
3531 // through a terminator before hitting the ICD. This could be for
3532 // several reasons, but the main one is currently unwrapping an
3533 // object before passing the appropriate info along to the ICD.
3534 // This is why we also have to override the direct ICD call to
3535 // vkGetDeviceProcAddr to intercept those calls.
3536 if (!strcmp(pName, "vkGetDeviceProcAddr")) {
3537 return (PFN_vkVoidFunction)loader_gpa_device_internal;
3538 } else if (!strcmp(pName, "vkCreateSwapchainKHR")) {
Mark Young16573c72016-06-28 10:52:43 -06003539 return (PFN_vkVoidFunction)terminator_vkCreateSwapchainKHR;
Mark Young65cb3662016-11-07 13:27:02 -07003540 } else if (!strcmp(pName, "vkDebugMarkerSetObjectTagEXT")) {
3541 return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectTagEXT;
3542 } else if (!strcmp(pName, "vkDebugMarkerSetObjectNameEXT")) {
3543 return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectNameEXT;
Mark Young16573c72016-06-28 10:52:43 -06003544 }
3545
Mark Young0153e0b2016-11-03 14:27:13 -06003546 return icd_term->GetDeviceProcAddr(device, pName);
Piers Daniell295fe402016-03-29 11:51:11 -06003547}
3548
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003549/**
3550 * Initialize device_ext dispatch table entry as follows:
3551 * If dev == NULL find all logical devices created within this instance and
3552 * init the entry (given by idx) in the ext dispatch table.
3553 * If dev != NULL only initialize the entry in the given dev's dispatch table.
Jon Ashburn23d36b12016-02-02 17:47:28 -07003554 * The initialization value is gotten by calling down the device chain with
3555 * GDPA.
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003556 * If GDPA returns NULL then don't initialize the dispatch table entry.
3557 */
3558static void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003559 struct loader_device *dev,
3560 uint32_t idx,
3561 const char *funcName)
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003562
Jon Ashburn23d36b12016-02-02 17:47:28 -07003563{
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003564 void *gdpa_value;
3565 if (dev != NULL) {
3566 gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
Mark Young65cb3662016-11-07 13:27:02 -07003567 dev->chain_device, funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003568 if (gdpa_value != NULL)
Mark Young8191d9f2016-09-02 11:41:28 -06003569 dev->loader_dispatch.ext_dispatch.dev_ext[idx] =
Jon Ashburn23d36b12016-02-02 17:47:28 -07003570 (PFN_vkDevExt)gdpa_value;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003571 } else {
Mark Young0153e0b2016-11-03 14:27:13 -06003572 for (struct loader_icd_term *icd_term = inst->icd_terms;
3573 icd_term != NULL; icd_term = icd_term->next) {
3574 struct loader_device *ldev = icd_term->logical_device_list;
Karl Schultz2558bd32016-02-24 14:39:39 -07003575 while (ldev) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003576 gdpa_value =
Karl Schultz2558bd32016-02-24 14:39:39 -07003577 ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
Mark Young65cb3662016-11-07 13:27:02 -07003578 ldev->chain_device, funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003579 if (gdpa_value != NULL)
Mark Young8191d9f2016-09-02 11:41:28 -06003580 ldev->loader_dispatch.ext_dispatch.dev_ext[idx] =
Jon Ashburn23d36b12016-02-02 17:47:28 -07003581 (PFN_vkDevExt)gdpa_value;
Karl Schultz2558bd32016-02-24 14:39:39 -07003582 ldev = ldev->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003583 }
3584 }
3585 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003586}
3587
3588/**
3589 * Find all dev extension in the hash table and initialize the dispatch table
3590 * for dev for each of those extension entrypoints found in hash table.
3591
3592 */
Jon Ashburn1530c342016-02-26 13:14:27 -07003593void loader_init_dispatch_dev_ext(struct loader_instance *inst,
3594 struct loader_device *dev) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003595 for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
3596 if (inst->disp_hash[i].func_name != NULL)
3597 loader_init_dispatch_dev_ext_entry(inst, dev, i,
3598 inst->disp_hash[i].func_name);
3599 }
3600}
3601
3602static bool loader_check_icds_for_address(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003603 const char *funcName) {
Mark Young0153e0b2016-11-03 14:27:13 -06003604 struct loader_icd_term *icd_term;
3605 icd_term = inst->icd_terms;
3606 while (NULL != icd_term) {
3607 if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance,
3608 funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003609 // this icd supports funcName
3610 return true;
Mark Young0153e0b2016-11-03 14:27:13 -06003611 icd_term = icd_term->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003612 }
3613
3614 return false;
3615}
3616
Jon Ashburncc407a22016-04-15 09:25:03 -06003617static bool loader_check_layer_list_for_address(
3618 const struct loader_layer_list *const layers, const char *funcName) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003619 // Iterate over the layers.
Jon Ashburncc407a22016-04-15 09:25:03 -06003620 for (uint32_t layer = 0; layer < layers->count; ++layer) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003621 // Iterate over the extensions.
Jon Ashburncc407a22016-04-15 09:25:03 -06003622 const struct loader_device_extension_list *const extensions =
3623 &(layers->list[layer].device_extension_list);
3624 for (uint32_t extension = 0; extension < extensions->count;
3625 ++extension) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003626 // Iterate over the entry points.
Jon Ashburncc407a22016-04-15 09:25:03 -06003627 const struct loader_dev_ext_props *const property =
3628 &(extensions->list[extension]);
3629 for (uint32_t entry = 0; entry < property->entrypoint_count;
3630 ++entry) {
3631 if (strcmp(property->entrypoints[entry], funcName) == 0) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003632 return true;
3633 }
3634 }
3635 }
3636 }
3637
3638 return false;
3639}
3640
Jon Ashburn23d36b12016-02-02 17:47:28 -07003641static void loader_free_dev_ext_table(struct loader_instance *inst) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003642 for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
Mark Young0ad83132016-06-30 13:02:42 -06003643 loader_instance_heap_free(inst, inst->disp_hash[i].func_name);
3644 loader_instance_heap_free(inst, inst->disp_hash[i].list.index);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003645 }
3646 memset(inst->disp_hash, 0, sizeof(inst->disp_hash));
3647}
3648
3649static bool loader_add_dev_ext_table(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003650 uint32_t *ptr_idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003651 uint32_t i;
3652 uint32_t idx = *ptr_idx;
3653 struct loader_dispatch_hash_list *list = &inst->disp_hash[idx].list;
3654
3655 if (!inst->disp_hash[idx].func_name) {
3656 // no entry here at this idx, so use it
3657 assert(list->capacity == 0);
Mark Young0ad83132016-06-30 13:02:42 -06003658 inst->disp_hash[idx].func_name = (char *)loader_instance_heap_alloc(
Jon Ashburn23d36b12016-02-02 17:47:28 -07003659 inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003660 if (inst->disp_hash[idx].func_name == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003661 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003662 "loader_add_dev_ext_table: Failed to allocate memory "
3663 "for func_name %s",
3664 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003665 return false;
3666 }
3667 strncpy(inst->disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
3668 return true;
3669 }
3670
3671 // check for enough capacity
3672 if (list->capacity == 0) {
Mark Young0153e0b2016-11-03 14:27:13 -06003673 list->index =
3674 loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)),
3675 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003676 if (list->index == NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003677 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003678 "loader_add_dev_ext_table: Failed to allocate memory "
3679 "for list index",
3680 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003681 return false;
3682 }
3683 list->capacity = 8 * sizeof(*(list->index));
3684 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Young0153e0b2016-11-03 14:27:13 -06003685 list->index = loader_instance_heap_realloc(
3686 inst, list->index, list->capacity, list->capacity * 2,
3687 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003688 if (list->index == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07003689 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3690 "loader_add_dev_ext_table: Failed to reallocate memory "
3691 "for list index",
3692 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003693 return false;
3694 }
3695 list->capacity *= 2;
3696 }
3697
Jon Ashburn23d36b12016-02-02 17:47:28 -07003698 // find an unused index in the hash table and use it
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003699 i = (idx + 1) % MAX_NUM_DEV_EXTS;
3700 do {
3701 if (!inst->disp_hash[i].func_name) {
3702 assert(inst->disp_hash[i].list.capacity == 0);
Mark Young0153e0b2016-11-03 14:27:13 -06003703 inst->disp_hash[i].func_name = (char *)loader_instance_heap_alloc(
3704 inst, strlen(funcName) + 1,
3705 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003706 if (inst->disp_hash[i].func_name == NULL) {
Mark Youngb6399312017-01-10 14:22:15 -07003707 loader_log(
3708 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3709 "loader_add_dev_ext_table: Failed to allocate memory "
3710 "for func_name %s",
3711 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003712 return false;
3713 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003714 strncpy(inst->disp_hash[i].func_name, funcName,
3715 strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003716 list->index[list->count] = i;
3717 list->count++;
3718 *ptr_idx = i;
3719 return true;
3720 }
3721 i = (i + 1) % MAX_NUM_DEV_EXTS;
3722 } while (i != idx);
3723
Mark Youngb6399312017-01-10 14:22:15 -07003724 loader_log(
3725 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3726 "loader_add_dev_ext_table: Could not insert into hash table; is "
3727 "it full?");
3728
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003729 return false;
3730}
3731
3732static bool loader_name_in_dev_ext_table(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003733 uint32_t *idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003734 uint32_t alt_idx;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003735 if (inst->disp_hash[*idx].func_name &&
3736 !strcmp(inst->disp_hash[*idx].func_name, funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003737 return true;
3738
3739 // funcName wasn't at the primary spot in the hash table
3740 // search the list of secondary locations (shallow search, not deep search)
3741 for (uint32_t i = 0; i < inst->disp_hash[*idx].list.count; i++) {
3742 alt_idx = inst->disp_hash[*idx].list.index[i];
Karl Schultze2ef9e62017-01-13 14:01:35 -07003743 if (inst->disp_hash[*idx].func_name &&
3744 !strcmp(inst->disp_hash[*idx].func_name, funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003745 *idx = alt_idx;
3746 return true;
3747 }
3748 }
3749
3750 return false;
3751}
3752
3753/**
Jon Ashburn23d36b12016-02-02 17:47:28 -07003754 * This function returns generic trampoline code address for unknown entry
3755 * points.
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003756 * Presumably, these unknown entry points (as given by funcName) are device
3757 * extension entrypoints. A hash table is used to keep a list of unknown entry
3758 * points and their mapping to the device extension dispatch table
3759 * (struct loader_dev_ext_dispatch_table).
3760 * \returns
Jon Ashburn23d36b12016-02-02 17:47:28 -07003761 * For a given entry point string (funcName), if an existing mapping is found
3762 * the
3763 * trampoline address for that mapping is returned. Otherwise, this unknown
3764 * entry point
3765 * has not been seen yet. Next check if a layer or ICD supports it. If so then
3766 * a
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003767 * new entry in the hash table is initialized and that trampoline address for
3768 * the new entry is returned. Null is returned if the hash table is full or
3769 * if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
3770 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003771void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003772 uint32_t idx;
3773 uint32_t seed = 0;
3774
3775 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_DEV_EXTS;
3776
3777 if (loader_name_in_dev_ext_table(inst, &idx, funcName))
3778 // found funcName already in hash
3779 return loader_get_dev_ext_trampoline(idx);
3780
3781 // Check if funcName is supported in either ICDs or a layer library
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003782 if (!loader_check_icds_for_address(inst, funcName) &&
Mark Young0153e0b2016-11-03 14:27:13 -06003783 !loader_check_layer_list_for_address(&inst->instance_layer_list,
3784 funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003785 // if support found in layers continue on
3786 return NULL;
3787 }
3788
3789 if (loader_add_dev_ext_table(inst, &idx, funcName)) {
3790 // successfully added new table entry
3791 // init any dev dispatch table entrys as needed
3792 loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
3793 return loader_get_dev_ext_trampoline(idx);
3794 }
3795
3796 return NULL;
3797}
3798
Jon Ashburn23d36b12016-02-02 17:47:28 -07003799struct loader_instance *loader_get_instance(const VkInstance instance) {
Jon Ashburne0e64572015-09-30 12:56:42 -06003800 /* look up the loader_instance in our list by comparing dispatch tables, as
3801 * there is no guarantee the instance is still a loader_instance* after any
3802 * layers which wrap the instance object.
3803 */
3804 const VkLayerInstanceDispatchTable *disp;
3805 struct loader_instance *ptr_instance = NULL;
3806 disp = loader_get_instance_dispatch(instance);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003807 for (struct loader_instance *inst = loader.instances; inst;
3808 inst = inst->next) {
Jon Ashburne0e64572015-09-30 12:56:42 -06003809 if (inst->disp == disp) {
3810 ptr_instance = inst;
3811 break;
3812 }
3813 }
3814 return ptr_instance;
3815}
3816
Jon Ashburn23d36b12016-02-02 17:47:28 -07003817static loader_platform_dl_handle
Mark Young0153e0b2016-11-03 14:27:13 -06003818loader_open_layer_lib(const struct loader_instance *inst,
3819 const char *chain_type,
3820 struct loader_layer_properties *prop) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003821
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003822 if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) ==
Jon Ashburn23d36b12016-02-02 17:47:28 -07003823 NULL) {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003824 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003825 "loader_open_layer_lib: Failed to open library %s",
3826 prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003827 } else {
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07003828 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003829 "Loading layer library %s", prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003830 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003831
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003832 return prop->lib_handle;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003833}
3834
Mark Young0153e0b2016-11-03 14:27:13 -06003835static void loader_close_layer_lib(const struct loader_instance *inst,
3836 struct loader_layer_properties *prop) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003837
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003838 if (prop->lib_handle) {
3839 loader_platform_close_library(prop->lib_handle);
3840 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3841 "Unloading layer library %s", prop->lib_name);
3842 prop->lib_handle = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003843 }
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003844}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003845
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003846void loader_deactivate_layers(const struct loader_instance *instance,
Mark Young0ad83132016-06-30 13:02:42 -06003847 struct loader_device *device,
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003848 struct loader_layer_list *list) {
3849 /* delete instance list of enabled layers and close any layer libraries */
3850 for (uint32_t i = 0; i < list->count; i++) {
3851 struct loader_layer_properties *layer_prop = &list->list[i];
Courtney Goeltzenleuchter80bfd0e2015-12-17 09:51:22 -07003852
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06003853 loader_close_layer_lib(instance, layer_prop);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003854 }
Mark Young0ad83132016-06-30 13:02:42 -06003855 loader_destroy_layer_list(instance, device, list);
Jon Ashburnb8358052014-11-18 09:06:04 -07003856}
3857
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003858/**
3859 * Go through the search_list and find any layers which match type. If layer
3860 * type match is found in then add it to ext_list.
3861 */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003862static void
3863loader_add_layer_implicit(const struct loader_instance *inst,
3864 const enum layer_type type,
3865 struct loader_layer_list *list,
3866 const struct loader_layer_list *search_list) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003867 bool enable;
3868 char *env_value;
Jon Ashburn0c26e712015-07-02 16:10:32 -06003869 uint32_t i;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06003870 for (i = 0; i < search_list->count; i++) {
3871 const struct loader_layer_properties *prop = &search_list->list[i];
Jon Ashburn0c26e712015-07-02 16:10:32 -06003872 if (prop->type & type) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003873 /* Found an implicit layer, see if it should be enabled */
3874 enable = false;
3875
Jon Ashburn23d36b12016-02-02 17:47:28 -07003876 // if no enable_environment variable is specified, this implicit
3877 // layer
Jon Ashburn075ce432015-12-17 17:38:24 -07003878 // should always be enabled. Otherwise check if the variable is set
3879 if (prop->enable_env_var.name[0] == 0) {
3880 enable = true;
3881 } else {
Mark Young0ad83132016-06-30 13:02:42 -06003882 env_value = loader_getenv(prop->enable_env_var.name, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003883 if (env_value && !strcmp(prop->enable_env_var.value, env_value))
3884 enable = true;
Mark Young0ad83132016-06-30 13:02:42 -06003885 loader_free_getenv(env_value, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003886 }
3887
3888 // disable_environment has priority, i.e. if both enable and disable
Jon Ashburn23d36b12016-02-02 17:47:28 -07003889 // environment variables are set, the layer is disabled. Implicit
3890 // layers
Jon Ashburn075ce432015-12-17 17:38:24 -07003891 // are required to have a disable_environment variables
Mark Young0ad83132016-06-30 13:02:42 -06003892 env_value = loader_getenv(prop->disable_env_var.name, inst);
3893 if (env_value) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003894 enable = false;
Mark Young0ad83132016-06-30 13:02:42 -06003895 }
3896 loader_free_getenv(env_value, inst);
Jon Ashburn075ce432015-12-17 17:38:24 -07003897
Mark Young0ad83132016-06-30 13:02:42 -06003898 if (enable) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003899 loader_add_to_layer_list(inst, list, 1, prop);
Mark Young0ad83132016-06-30 13:02:42 -06003900 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06003901 }
3902 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06003903}
3904
3905/**
3906 * Get the layer name(s) from the env_name environment variable. If layer
Jon Ashburnbd332cc2015-07-07 10:27:45 -06003907 * is found in search_list then add it to layer_list. But only add it to
3908 * layer_list if type matches.
Jon Ashburn0c26e712015-07-02 16:10:32 -06003909 */
Jon Ashburn491cd042016-05-16 14:01:18 -06003910static void loader_add_layer_env(struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003911 const enum layer_type type,
3912 const char *env_name,
3913 struct loader_layer_list *layer_list,
3914 const struct loader_layer_list *search_list) {
Ian Elliott4470a302015-02-17 10:33:47 -07003915 char *layerEnv;
Jon Ashburneb6d5682015-07-02 14:10:53 -06003916 char *next, *name;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003917
Mark Young0ad83132016-06-30 13:02:42 -06003918 layerEnv = loader_getenv(env_name, inst);
Ian Elliott4470a302015-02-17 10:33:47 -07003919 if (layerEnv == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003920 return;
Ian Elliott4470a302015-02-17 10:33:47 -07003921 }
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06003922 name = loader_stack_alloc(strlen(layerEnv) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06003923 if (name == NULL) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003924 return;
Ian Elliott4470a302015-02-17 10:33:47 -07003925 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06003926 strcpy(name, layerEnv);
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003927
Mark Young0ad83132016-06-30 13:02:42 -06003928 loader_free_getenv(layerEnv, inst);
Jon Ashburn38a497f2016-01-04 14:01:38 -07003929
Jon Ashburn23d36b12016-02-02 17:47:28 -07003930 while (name && *name) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06003931 next = loader_get_next_path(name);
Jon Ashburn71483442016-02-11 18:59:43 -07003932 if (!strcmp(std_validation_str, name)) {
3933 /* add meta list of layers
3934 don't attempt to remove duplicate layers already added by app or
3935 env var
3936 */
3937 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
3938 "Expanding meta layer %s found in environment variable",
3939 std_validation_str);
Jon Ashburn491cd042016-05-16 14:01:18 -06003940 if (type == VK_LAYER_TYPE_INSTANCE_EXPLICIT)
3941 inst->activated_layers_are_std_val = true;
Jon Ashburn71483442016-02-11 18:59:43 -07003942 for (uint32_t i = 0; i < sizeof(std_validation_names) /
3943 sizeof(std_validation_names[0]);
3944 i++) {
3945 loader_find_layer_name_add_list(inst, std_validation_names[i],
3946 type, search_list, layer_list);
3947 }
3948 } else {
3949 loader_find_layer_name_add_list(inst, name, type, search_list,
3950 layer_list);
3951 }
Jon Ashburneb6d5682015-07-02 14:10:53 -06003952 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07003953 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003954
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003955 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003956}
3957
Jon Ashburn23d36b12016-02-02 17:47:28 -07003958VkResult
3959loader_enable_instance_layers(struct loader_instance *inst,
3960 const VkInstanceCreateInfo *pCreateInfo,
3961 const struct loader_layer_list *instance_layers) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003962 VkResult err;
3963
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06003964 assert(inst && "Cannot have null instance");
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003965
Jon Ashburne39a4f82015-08-28 13:38:21 -06003966 if (!loader_init_layer_list(inst, &inst->activated_layer_list)) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003967 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07003968 "loader_enable_instance_layers: Failed to initialize"
3969 " the layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003970 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06003971 }
3972
Jon Ashburn0c26e712015-07-02 16:10:32 -06003973 /* Add any implicit layers first */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003974 loader_add_layer_implicit(inst, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
3975 &inst->activated_layer_list, instance_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06003976
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003977 /* Add any layers specified via environment variable next */
Jon Ashburn23d36b12016-02-02 17:47:28 -07003978 loader_add_layer_env(inst, VK_LAYER_TYPE_INSTANCE_EXPLICIT,
3979 "VK_INSTANCE_LAYERS", &inst->activated_layer_list,
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003980 instance_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06003981
3982 /* Add layers specified by the application */
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003983 err = loader_add_layer_names_to_list(
Jon Ashburn23d36b12016-02-02 17:47:28 -07003984 inst, &inst->activated_layer_list, pCreateInfo->enabledLayerCount,
3985 pCreateInfo->ppEnabledLayerNames, instance_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06003986
3987 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003988}
3989
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003990/*
3991 * Given the list of layers to activate in the loader_instance
3992 * structure. This function will add a VkLayerInstanceCreateInfo
3993 * structure to the VkInstanceCreateInfo.pNext pointer.
3994 * Each activated layer will have it's own VkLayerInstanceLink
3995 * structure that tells the layer what Get*ProcAddr to call to
3996 * get function pointers to the next layer down.
3997 * Once the chain info has been created this function will
3998 * execute the CreateInstance call chain. Each layer will
3999 * then have an opportunity in it's CreateInstance function
4000 * to setup it's dispatch table when the lower layer returns
4001 * successfully.
4002 * Each layer can wrap or not-wrap the returned VkInstance object
4003 * as it sees fit.
4004 * The instance chain is terminated by a loader function
4005 * that will call CreateInstance on all available ICD's and
4006 * cache those VkInstance objects for future use.
4007 */
4008VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004009 const VkAllocationCallbacks *pAllocator,
Jon Ashburn373c1802016-01-20 08:08:25 -07004010 struct loader_instance *inst,
Jon Ashburn6e0a2132016-02-03 12:37:30 -07004011 VkInstance *created_instance) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004012 uint32_t activated_layers = 0;
4013 VkLayerInstanceCreateInfo chain_info;
4014 VkLayerInstanceLink *layer_instance_link_info = NULL;
4015 VkInstanceCreateInfo loader_create_info;
4016 VkResult res;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004017
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004018 PFN_vkGetInstanceProcAddr nextGIPA = loader_gpa_instance_internal;
4019 PFN_vkGetInstanceProcAddr fpGIPA = loader_gpa_instance_internal;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004020
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004021 memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
Jon Ashburn27cd5842015-05-12 17:26:48 -06004022
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004023 if (inst->activated_layer_list.count > 0) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004024
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004025 chain_info.u.pLayerInfo = NULL;
4026 chain_info.pNext = pCreateInfo->pNext;
4027 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4028 chain_info.function = VK_LAYER_LINK_INFO;
4029 loader_create_info.pNext = &chain_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004030
Jon Ashburn23d36b12016-02-02 17:47:28 -07004031 layer_instance_link_info = loader_stack_alloc(
4032 sizeof(VkLayerInstanceLink) * inst->activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004033 if (!layer_instance_link_info) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004034 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004035 "loader_create_instance_chain: Failed to alloc Instance"
4036 " objects for layer");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004037 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004038 }
4039
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004040 /* Create instance chain of enabled layers */
4041 for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004042 struct loader_layer_properties *layer_prop =
4043 &inst->activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004044 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004045
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004046 lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004047 if (!lib_handle)
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004048 continue;
Jon Ashburn23d36b12016-02-02 17:47:28 -07004049 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
4050 NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05004051 if (strlen(layer_prop->functions.str_gipa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004052 fpGIPA = (PFN_vkGetInstanceProcAddr)
4053 loader_platform_get_proc_address(
4054 lib_handle, "vkGetInstanceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004055 layer_prop->functions.get_instance_proc_addr = fpGIPA;
4056 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07004057 fpGIPA = (PFN_vkGetInstanceProcAddr)
4058 loader_platform_get_proc_address(
4059 lib_handle, layer_prop->functions.str_gipa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004060 if (!fpGIPA) {
Mark Youngb6399312017-01-10 14:22:15 -07004061 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4062 "loader_create_instance_chain: Failed to find "
4063 "\'vkGetInstanceProcAddr\' in layer %s",
4064 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004065 continue;
4066 }
4067 }
4068
Jon Ashburn23d36b12016-02-02 17:47:28 -07004069 layer_instance_link_info[activated_layers].pNext =
4070 chain_info.u.pLayerInfo;
4071 layer_instance_link_info[activated_layers]
4072 .pfnNextGetInstanceProcAddr = nextGIPA;
4073 chain_info.u.pLayerInfo =
4074 &layer_instance_link_info[activated_layers];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004075 nextGIPA = fpGIPA;
4076
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07004077 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004078 "Insert instance layer %s (%s)",
4079 layer_prop->info.layerName, layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004080
4081 activated_layers++;
4082 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06004083 }
4084
Jon Ashburn23d36b12016-02-02 17:47:28 -07004085 PFN_vkCreateInstance fpCreateInstance =
Jon Ashburn6e0a2132016-02-03 12:37:30 -07004086 (PFN_vkCreateInstance)nextGIPA(*created_instance, "vkCreateInstance");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004087 if (fpCreateInstance) {
Jon Ashburnc3c58772016-03-29 11:16:01 -06004088 VkLayerInstanceCreateInfo create_info_disp;
4089
Jon Ashburncc407a22016-04-15 09:25:03 -06004090 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004091 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
Jon Ashburnc3c58772016-03-29 11:16:01 -06004092
4093 create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
4094
4095 create_info_disp.pNext = loader_create_info.pNext;
4096 loader_create_info.pNext = &create_info_disp;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004097 res =
4098 fpCreateInstance(&loader_create_info, pAllocator, created_instance);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004099 } else {
Mark Youngb6399312017-01-10 14:22:15 -07004100 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4101 "loader_create_instance_chain: Failed to find "
4102 "\'vkCreateInstance\'");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004103 // Couldn't find CreateInstance function!
4104 res = VK_ERROR_INITIALIZATION_FAILED;
4105 }
4106
4107 if (res != VK_SUCCESS) {
4108 // TODO: Need to clean up here
4109 } else {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004110 loader_init_instance_core_dispatch_table(inst->disp, nextGIPA,
Jon Ashburn6e0a2132016-02-03 12:37:30 -07004111 *created_instance);
Jon Ashburn4e8c4162016-03-08 15:21:30 -07004112 inst->instance = *created_instance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004113 }
4114
4115 return res;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004116}
4117
Jon Ashburn23d36b12016-02-02 17:47:28 -07004118void loader_activate_instance_layer_extensions(struct loader_instance *inst,
4119 VkInstance created_inst) {
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004120
Jon Ashburn23d36b12016-02-02 17:47:28 -07004121 loader_init_instance_extension_dispatch_table(
4122 inst->disp, inst->disp->GetInstanceProcAddr, created_inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004123}
4124
Jon Ashburn1530c342016-02-26 13:14:27 -07004125VkResult
Jon Ashburncc407a22016-04-15 09:25:03 -06004126loader_create_device_chain(const struct loader_physical_device_tramp *pd,
4127 const VkDeviceCreateInfo *pCreateInfo,
4128 const VkAllocationCallbacks *pAllocator,
4129 const struct loader_instance *inst,
4130 struct loader_device *dev) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004131 uint32_t activated_layers = 0;
4132 VkLayerDeviceLink *layer_device_link_info;
4133 VkLayerDeviceCreateInfo chain_info;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004134 VkDeviceCreateInfo loader_create_info;
4135 VkResult res;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004136
Piers Daniell295fe402016-03-29 11:51:11 -06004137 PFN_vkGetDeviceProcAddr fpGDPA, nextGDPA = loader_gpa_device_internal;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004138 PFN_vkGetInstanceProcAddr fpGIPA, nextGIPA = loader_gpa_instance_internal;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004139
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004140 memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
4141
Jon Ashburn23d36b12016-02-02 17:47:28 -07004142 layer_device_link_info = loader_stack_alloc(
4143 sizeof(VkLayerDeviceLink) * dev->activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004144 if (!layer_device_link_info) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004145 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004146 "loader_create_device_chain: Failed to alloc Device objects"
4147 " for layer. Skipping Layer.");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004148 return VK_ERROR_OUT_OF_HOST_MEMORY;
David Pinedoa0a8a242015-06-24 15:29:18 -06004149 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004150
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004151 if (dev->activated_layer_list.count > 0) {
Jon Ashburn72690f22016-03-29 12:52:13 -06004152 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
4153 chain_info.function = VK_LAYER_LINK_INFO;
4154 chain_info.u.pLayerInfo = NULL;
4155 chain_info.pNext = pCreateInfo->pNext;
4156 loader_create_info.pNext = &chain_info;
4157
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004158 /* Create instance chain of enabled layers */
4159 for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004160 struct loader_layer_properties *layer_prop =
4161 &dev->activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004162 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004163
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004164 lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004165 if (!lib_handle)
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004166 continue;
Jon Ashburn23d36b12016-02-02 17:47:28 -07004167 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
4168 NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05004169 if (strlen(layer_prop->functions.str_gipa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004170 fpGIPA = (PFN_vkGetInstanceProcAddr)
4171 loader_platform_get_proc_address(
4172 lib_handle, "vkGetInstanceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004173 layer_prop->functions.get_instance_proc_addr = fpGIPA;
4174 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07004175 fpGIPA = (PFN_vkGetInstanceProcAddr)
4176 loader_platform_get_proc_address(
4177 lib_handle, layer_prop->functions.str_gipa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004178 if (!fpGIPA) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004179 loader_log(
4180 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004181 "loader_create_device_chain: Failed to find "
4182 "\'vkGetInstanceProcAddr\' in layer %s. Skipping"
4183 " layer.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07004184 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004185 continue;
4186 }
Jon Ashburn21c21ee2015-09-09 11:29:24 -06004187 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004188 if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
Jamie Madillc3d3f072016-12-14 17:21:43 -05004189 if (strlen(layer_prop->functions.str_gdpa) == 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004190 fpGDPA = (PFN_vkGetDeviceProcAddr)
4191 loader_platform_get_proc_address(lib_handle,
4192 "vkGetDeviceProcAddr");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004193 layer_prop->functions.get_device_proc_addr = fpGDPA;
4194 } else
Jon Ashburn23d36b12016-02-02 17:47:28 -07004195 fpGDPA = (PFN_vkGetDeviceProcAddr)
4196 loader_platform_get_proc_address(
4197 lib_handle, layer_prop->functions.str_gdpa);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004198 if (!fpGDPA) {
Jon Ashburnc0dc07c2016-05-16 17:35:43 -06004199 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004200 "Failed to find vkGetDeviceProcAddr in layer %s",
4201 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004202 continue;
4203 }
4204 }
4205
Jon Ashburn23d36b12016-02-02 17:47:28 -07004206 layer_device_link_info[activated_layers].pNext =
4207 chain_info.u.pLayerInfo;
4208 layer_device_link_info[activated_layers]
4209 .pfnNextGetInstanceProcAddr = nextGIPA;
4210 layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr =
4211 nextGDPA;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004212 chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
4213 nextGIPA = fpGIPA;
4214 nextGDPA = fpGDPA;
4215
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07004216 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004217 "Insert device layer %s (%s)",
Jon Ashburn23d36b12016-02-02 17:47:28 -07004218 layer_prop->info.layerName, layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004219
4220 activated_layers++;
Jon Ashburn94e70492015-06-10 10:13:10 -06004221 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004222 }
4223
Jon Ashburncc407a22016-04-15 09:25:03 -06004224 VkDevice created_device = (VkDevice)dev;
Jon Ashburn23d36b12016-02-02 17:47:28 -07004225 PFN_vkCreateDevice fpCreateDevice =
Jon Ashburn4e8c4162016-03-08 15:21:30 -07004226 (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004227 if (fpCreateDevice) {
Jon Ashburned8f2312016-03-31 10:52:22 -06004228 VkLayerDeviceCreateInfo create_info_disp;
4229
Jon Ashburncc407a22016-04-15 09:25:03 -06004230 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004231 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
4232
4233 create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
4234
4235 create_info_disp.pNext = loader_create_info.pNext;
4236 loader_create_info.pNext = &create_info_disp;
Jon Ashburn014438f2016-03-01 19:51:07 -07004237 res = fpCreateDevice(pd->phys_dev, &loader_create_info, pAllocator,
Jon Ashburn72690f22016-03-29 12:52:13 -06004238 &created_device);
Piers Daniellefbbfc12016-04-05 17:28:06 -06004239 if (res != VK_SUCCESS) {
4240 return res;
4241 }
Mark Young65cb3662016-11-07 13:27:02 -07004242 dev->chain_device = created_device;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004243 } else {
Mark Youngb6399312017-01-10 14:22:15 -07004244 loader_log(
4245 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4246 "loader_create_device_chain: Failed to find \'vkCreateDevice\' "
4247 "in layer %s");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004248 // Couldn't find CreateDevice function!
4249 return VK_ERROR_INITIALIZATION_FAILED;
4250 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004251
Mark Young65cb3662016-11-07 13:27:02 -07004252 // Initialize device dispatch table
Jon Ashburn23d36b12016-02-02 17:47:28 -07004253 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA,
Mark Young65cb3662016-11-07 13:27:02 -07004254 dev->chain_device);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004255
4256 return res;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06004257}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004258
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004259VkResult loader_validate_layers(const struct loader_instance *inst,
4260 const uint32_t layer_count,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004261 const char *const *ppEnabledLayerNames,
4262 const struct loader_layer_list *list) {
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004263 struct loader_layer_properties *prop;
4264
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004265 for (uint32_t i = 0; i < layer_count; i++) {
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004266 VkStringErrorFlags result =
4267 vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004268 if (result != VK_STRING_ERROR_NONE) {
4269 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004270 "loader_validate_layers: Device ppEnabledLayerNames "
Mark Young2c84c0c2017-01-13 10:27:03 -07004271 "contains string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004272 return VK_ERROR_LAYER_NOT_PRESENT;
4273 }
4274
Jon Ashburn23d36b12016-02-02 17:47:28 -07004275 prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004276 if (!prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004277 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4278 "loader_validate_layers: Layer %d does not exist in "
4279 "the list of available layers",
4280 i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004281 return VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004282 }
4283 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004284 return VK_SUCCESS;
4285}
4286
4287VkResult loader_validate_instance_extensions(
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004288 const struct loader_instance *inst,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004289 const struct loader_extension_list *icd_exts,
Michael Jurka5c16c002016-12-19 16:31:43 +01004290 const struct loader_layer_list *instance_layers,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004291 const VkInstanceCreateInfo *pCreateInfo) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004292
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004293 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004294 struct loader_layer_properties *layer_prop;
4295
Jon Ashburnf19916e2016-01-11 13:12:43 -07004296 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004297 VkStringErrorFlags result = vk_string_validate(
4298 MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004299 if (result != VK_STRING_ERROR_NONE) {
4300 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004301 "loader_validate_instance_extensions: Instance "
4302 "ppEnabledExtensionNames contains "
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004303 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004304 return VK_ERROR_EXTENSION_NOT_PRESENT;
4305 }
4306
Lenny Komow4053b812016-12-29 16:27:28 -07004307 // See if the extension is in the list of supported extensions
4308 bool found = false;
4309 for (uint32_t j = 0; LOADER_INSTANCE_EXTENSIONS[j] != NULL; j++) {
4310 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i],
4311 LOADER_INSTANCE_EXTENSIONS[j]) == 0) {
4312 found = true;
4313 break;
4314 }
4315 }
4316
4317 // If it isn't in the list, return an error
4318 if (!found) {
Mark Youngb6399312017-01-10 14:22:15 -07004319 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4320 "loader_validate_instance_extensions: Extension %d "
4321 "not found in list of available extensions.",
4322 i);
Lenny Komow4053b812016-12-29 16:27:28 -07004323 return VK_ERROR_EXTENSION_NOT_PRESENT;
4324 }
4325
Jon Ashburn23d36b12016-02-02 17:47:28 -07004326 extension_prop = get_extension_property(
4327 pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004328
4329 if (extension_prop) {
4330 continue;
4331 }
4332
4333 extension_prop = NULL;
4334
4335 /* Not in global list, search layer extension lists */
Jon Ashburnf19916e2016-01-11 13:12:43 -07004336 for (uint32_t j = 0; j < pCreateInfo->enabledLayerCount; j++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004337 layer_prop = loader_get_layer_property(
Michael Jurka5c16c002016-12-19 16:31:43 +01004338 pCreateInfo->ppEnabledLayerNames[j], instance_layers);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004339 if (!layer_prop) {
Courtney Goeltzenleuchter6f5b00c2015-07-06 20:46:50 -06004340 /* Should NOT get here, loader_validate_layers
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004341 * should have already filtered this case out.
4342 */
4343 continue;
4344 }
4345
Jon Ashburn23d36b12016-02-02 17:47:28 -07004346 extension_prop =
4347 get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
4348 &layer_prop->instance_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004349 if (extension_prop) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07004350 /* Found the extension in one of the layers enabled by the app.
4351 */
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004352 break;
4353 }
4354 }
4355
4356 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004357 // Didn't find extension name in any of the global layers, error out
4358 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4359 "loader_validate_instance_extensions: Extension %d "
4360 "not found in enabled layer list extensions.",
4361 i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004362 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004363 }
4364 }
4365 return VK_SUCCESS;
4366}
4367
4368VkResult loader_validate_device_extensions(
Jon Ashburn787eb252016-03-24 15:49:57 -06004369 struct loader_physical_device_tramp *phys_dev,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004370 const struct loader_layer_list *activated_device_layers,
Jon Ashburn014438f2016-03-01 19:51:07 -07004371 const struct loader_extension_list *icd_exts,
Jon Ashburn23d36b12016-02-02 17:47:28 -07004372 const VkDeviceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004373 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004374 struct loader_layer_properties *layer_prop;
4375
Jon Ashburnf19916e2016-01-11 13:12:43 -07004376 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004377
Jon Ashburnf2b4e382016-02-10 20:50:19 -07004378 VkStringErrorFlags result = vk_string_validate(
4379 MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004380 if (result != VK_STRING_ERROR_NONE) {
Jon Ashburncc407a22016-04-15 09:25:03 -06004381 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
Mark Youngb6399312017-01-10 14:22:15 -07004382 0, "loader_validate_device_extensions: Device "
4383 "ppEnabledExtensionNames contains "
Jon Ashburncc407a22016-04-15 09:25:03 -06004384 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004385 return VK_ERROR_EXTENSION_NOT_PRESENT;
4386 }
4387
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004388 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07004389 extension_prop = get_extension_property(extension_name, icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004390
4391 if (extension_prop) {
4392 continue;
4393 }
4394
Mark Youngb6399312017-01-10 14:22:15 -07004395 // Not in global list, search activated layer extension lists
Jon Ashburn471f44c2016-01-13 12:51:43 -07004396 for (uint32_t j = 0; j < activated_device_layers->count; j++) {
4397 layer_prop = &activated_device_layers->list[j];
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004398
Jon Ashburn23d36b12016-02-02 17:47:28 -07004399 extension_prop = get_dev_extension_property(
4400 extension_name, &layer_prop->device_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004401 if (extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004402 // Found the extension in one of the layers enabled by the app.
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004403 break;
4404 }
4405 }
4406
4407 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004408 // Didn't find extension name in any of the device layers, error out
4409 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4410 0, "loader_validate_device_extensions: Extension %d "
4411 "not found in enabled layer list extensions.",
4412 i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004413 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004414 }
4415 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004416 return VK_SUCCESS;
4417}
4418
Mark Youngb6399312017-01-10 14:22:15 -07004419// Terminator functions for the Instance chain
4420// All named terminator_<Vulakn API name>
Mark Young0ad83132016-06-30 13:02:42 -06004421VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(
4422 const VkInstanceCreateInfo *pCreateInfo,
4423 const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
Mark Young0153e0b2016-11-03 14:27:13 -06004424 struct loader_icd_term *icd_term;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004425 VkExtensionProperties *prop;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004426 char **filtered_extension_names = NULL;
4427 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004428 VkResult res = VK_SUCCESS;
Mark Young8b4edb52016-11-11 09:31:55 -07004429 bool one_icd_successful = false;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004430
Jon Ashburncc407a22016-04-15 09:25:03 -06004431 struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
Tony Barbour3c78ff42015-12-04 13:24:39 -07004432 memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
4433
Jon Ashburnf19916e2016-01-11 13:12:43 -07004434 icd_create_info.enabledLayerCount = 0;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004435 icd_create_info.ppEnabledLayerNames = NULL;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004436
Mark Youngb6399312017-01-10 14:22:15 -07004437 // NOTE: Need to filter the extensions to only those supported by the ICD.
4438 // No ICD will advertise support for layers. An ICD library could
4439 // support a layer, but it would be independent of the actual ICD,
4440 // just in the same library.
Jon Ashburn23d36b12016-02-02 17:47:28 -07004441 filtered_extension_names =
4442 loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004443 if (!filtered_extension_names) {
Mark Youngb6399312017-01-10 14:22:15 -07004444 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4445 "terminator_CreateInstance: Failed create extension name "
4446 "array for %d extensions",
4447 pCreateInfo->enabledExtensionCount);
Mark Young3a587792016-08-19 15:25:08 -06004448 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4449 goto out;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004450 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07004451 icd_create_info.ppEnabledExtensionNames =
4452 (const char *const *)filtered_extension_names;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004453
Mark Young0153e0b2016-11-03 14:27:13 -06004454 for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
4455 icd_term = loader_icd_add(
4456 ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
4457 if (NULL == icd_term) {
Mark Young2c84c0c2017-01-13 10:27:03 -07004458 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
Mark Youngb6399312017-01-10 14:22:15 -07004459 0,
4460 "terminator_CreateInstance: Failed to add ICD %d to ICD "
4461 "trampoline list.",
4462 i);
Mark Young3a587792016-08-19 15:25:08 -06004463 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4464 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06004465 }
Mark Young6267ae62017-01-12 12:27:19 -07004466
Mark Young0ad83132016-06-30 13:02:42 -06004467 icd_create_info.enabledExtensionCount = 0;
4468 struct loader_extension_list icd_exts;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004469
Mark Young0ad83132016-06-30 13:02:42 -06004470 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
4471 "Build ICD instance extension list");
4472 // traverse scanned icd list adding non-duplicate extensions to the
4473 // list
Mark Young3a587792016-08-19 15:25:08 -06004474 res = loader_init_generic_list(ptr_instance,
Mark Young0153e0b2016-11-03 14:27:13 -06004475 (struct loader_generic_list *)&icd_exts,
4476 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06004477 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4478 // If out of memory, bail immediately.
4479 goto out;
4480 } else if (VK_SUCCESS != res) {
Mark Young7e471292016-09-06 09:53:45 -06004481 // Something bad happened with this ICD, so free it and try the
4482 // next.
Mark Young0153e0b2016-11-03 14:27:13 -06004483 ptr_instance->icd_terms = icd_term->next;
4484 icd_term->next = NULL;
4485 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004486 continue;
4487 }
4488
4489 res = loader_add_instance_extensions(
Mark Young0ad83132016-06-30 13:02:42 -06004490 ptr_instance,
Mark Young0153e0b2016-11-03 14:27:13 -06004491 icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
4492 icd_term->scanned_icd->lib_name, &icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004493 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06004494 loader_destroy_generic_list(
4495 ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004496 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4497 // If out of memory, bail immediately.
4498 goto out;
4499 } else {
4500 // Something bad happened with this ICD, so free it and try
4501 // the next.
Mark Young0153e0b2016-11-03 14:27:13 -06004502 ptr_instance->icd_terms = icd_term->next;
4503 icd_term->next = NULL;
4504 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Youngdb13a2a2016-09-06 13:53:03 -06004505 continue;
4506 }
Mark Young3a587792016-08-19 15:25:08 -06004507 }
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -07004508
Mark Young0ad83132016-06-30 13:02:42 -06004509 for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
4510 prop = get_extension_property(
4511 pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
4512 if (prop) {
4513 filtered_extension_names[icd_create_info
4514 .enabledExtensionCount] =
4515 (char *)pCreateInfo->ppEnabledExtensionNames[j];
4516 icd_create_info.enabledExtensionCount++;
Jon Ashburn46888392015-01-29 15:45:51 -07004517 }
4518 }
Mark Young0ad83132016-06-30 13:02:42 -06004519
4520 loader_destroy_generic_list(ptr_instance,
4521 (struct loader_generic_list *)&icd_exts);
4522
Mark Young8b4edb52016-11-11 09:31:55 -07004523 VkResult icd_result =
4524 ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(
4525 &icd_create_info, pAllocator, &(icd_term->instance));
4526 if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06004527 // If out of memory, bail immediately.
Mark Young8b4edb52016-11-11 09:31:55 -07004528 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06004529 goto out;
Mark Young8b4edb52016-11-11 09:31:55 -07004530 } else if (VK_SUCCESS != icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06004531 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004532 "terminator_CreateInstance: Failed to CreateInstance in "
4533 "ICD %d. Skipping ICD.",
4534 i);
Mark Young0153e0b2016-11-03 14:27:13 -06004535 ptr_instance->icd_terms = icd_term->next;
4536 icd_term->next = NULL;
4537 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004538 continue;
4539 }
Mark Young0ad83132016-06-30 13:02:42 -06004540
Mark Young0153e0b2016-11-03 14:27:13 -06004541 if (!loader_icd_init_entrys(icd_term, icd_term->instance,
4542 ptr_instance->icd_tramp_list.scanned_list[i]
4543 .GetInstanceProcAddr)) {
Mark Youngb6399312017-01-10 14:22:15 -07004544 loader_log(
4545 ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
4546 "terminator_CreateInstance: Failed to CreateInstance and find "
4547 "entrypoints with ICD. Skipping ICD.");
Mark Young3a587792016-08-19 15:25:08 -06004548 continue;
Mark Young0ad83132016-06-30 13:02:42 -06004549 }
Mark Young8b4edb52016-11-11 09:31:55 -07004550
4551 // If we made it this far, at least one ICD was successful
4552 one_icd_successful = true;
Jon Ashburn46888392015-01-29 15:45:51 -07004553 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004554
Mark Young8b4edb52016-11-11 09:31:55 -07004555 // If no ICDs were added to instance list and res is unchanged
4556 // from it's initial value, the loader was unable to find
4557 // a suitable ICD.
4558 if (VK_SUCCESS == res &&
4559 (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
Mark Young3a587792016-08-19 15:25:08 -06004560 res = VK_ERROR_INCOMPATIBLE_DRIVER;
4561 }
4562
4563out:
4564
4565 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06004566 while (NULL != ptr_instance->icd_terms) {
4567 icd_term = ptr_instance->icd_terms;
4568 ptr_instance->icd_terms = icd_term->next;
4569 if (NULL != icd_term->instance) {
4570 icd_term->DestroyInstance(icd_term->instance, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06004571 }
Mark Young0153e0b2016-11-03 14:27:13 -06004572 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004573 }
Ian Elliotteb450762015-02-05 15:19:15 -07004574 }
Jon Ashburn46888392015-01-29 15:45:51 -07004575
Mark Young3a587792016-08-19 15:25:08 -06004576 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004577}
4578
Mark Young0ad83132016-06-30 13:02:42 -06004579VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(
4580 VkInstance instance, const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06004581 struct loader_instance *ptr_instance = loader_instance(instance);
Karl Schultze2ef9e62017-01-13 14:01:35 -07004582 if (NULL == ptr_instance) {
4583 return;
4584 }
Mark Young0153e0b2016-11-03 14:27:13 -06004585 struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
4586 struct loader_icd_term *next_icd_term;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004587
4588 // Remove this instance from the list of instances:
4589 struct loader_instance *prev = NULL;
4590 struct loader_instance *next = loader.instances;
4591 while (next != NULL) {
4592 if (next == ptr_instance) {
4593 // Remove this instance from the list:
4594 if (prev)
4595 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07004596 else
4597 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004598 break;
4599 }
4600 prev = next;
4601 next = next->next;
4602 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004603
Mark Young0153e0b2016-11-03 14:27:13 -06004604 while (NULL != icd_terms) {
4605 if (icd_terms->instance) {
4606 icd_terms->DestroyInstance(icd_terms->instance, pAllocator);
Tony Barbourf20f87b2015-04-22 09:02:32 -06004607 }
Mark Young0153e0b2016-11-03 14:27:13 -06004608 next_icd_term = icd_terms->next;
4609 icd_terms->instance = VK_NULL_HANDLE;
4610 loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
Jon Ashburna6fd2612015-06-16 14:43:19 -06004611
Mark Young0153e0b2016-11-03 14:27:13 -06004612 icd_terms = next_icd_term;
Jon Ashburn46888392015-01-29 15:45:51 -07004613 }
Jon Ashburn491cd042016-05-16 14:01:18 -06004614
Jon Ashburn23d36b12016-02-02 17:47:28 -07004615 loader_delete_layer_properties(ptr_instance,
4616 &ptr_instance->instance_layer_list);
Mark Young0153e0b2016-11-03 14:27:13 -06004617 loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
Jon Ashburn23d36b12016-02-02 17:47:28 -07004618 loader_destroy_generic_list(
4619 ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07004620 if (ptr_instance->phys_devs_term) {
Mark Young0193d652016-12-28 16:10:10 -07004621 for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
Lenny Komow8a1f8a52016-12-20 15:35:11 -07004622 loader_instance_heap_free(ptr_instance,
4623 ptr_instance->phys_devs_term[i]);
4624 }
Mark Young0ad83132016-06-30 13:02:42 -06004625 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07004626 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004627 loader_free_dev_ext_table(ptr_instance);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004628}
4629
Mark Young0ad83132016-06-30 13:02:42 -06004630VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(
4631 VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
4632 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
4633 VkResult res = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06004634 struct loader_physical_device_term *phys_dev_term;
4635 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
4636 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004637
Jon Ashburncc407a22016-04-15 09:25:03 -06004638 struct loader_device *dev = (struct loader_device *)*pDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06004639 PFN_vkCreateDevice fpCreateDevice = icd_term->CreateDevice;
Mark Young0ad83132016-06-30 13:02:42 -06004640 struct loader_extension_list icd_exts;
4641
Mark Young65cb3662016-11-07 13:27:02 -07004642 dev->phys_dev_term = phys_dev_term;
4643
Mark Young0ad83132016-06-30 13:02:42 -06004644 icd_exts.list = NULL;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004645
Jon Ashburn1530c342016-02-26 13:14:27 -07004646 if (fpCreateDevice == NULL) {
Mark Young0153e0b2016-11-03 14:27:13 -06004647 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004648 "terminator_CreateDevice: No vkCreateDevice command exposed "
4649 "by ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06004650 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06004651 res = VK_ERROR_INITIALIZATION_FAILED;
4652 goto out;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004653 }
4654
Jon Ashburn1530c342016-02-26 13:14:27 -07004655 VkDeviceCreateInfo localCreateInfo;
4656 memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
Jon Ashburn1530c342016-02-26 13:14:27 -07004657
Mark Youngb6399312017-01-10 14:22:15 -07004658 // NOTE: Need to filter the extensions to only those supported by the ICD.
4659 // No ICD will advertise support for layers. An ICD library could
4660 // support a layer, but it would be independent of the actual ICD,
4661 // just in the same library.
Jon Ashburn1530c342016-02-26 13:14:27 -07004662 char **filtered_extension_names = NULL;
4663 filtered_extension_names =
4664 loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
Mark Youngb6399312017-01-10 14:22:15 -07004665 if (NULL == filtered_extension_names) {
4666 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4667 "terminator_CreateDevice: Failed to create extension name "
4668 "storage for %d extensions %d",
4669 pCreateInfo->enabledExtensionCount);
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004670 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004671 }
4672
Jon Ashburn1530c342016-02-26 13:14:27 -07004673 localCreateInfo.enabledLayerCount = 0;
4674 localCreateInfo.ppEnabledLayerNames = NULL;
4675
4676 localCreateInfo.enabledExtensionCount = 0;
4677 localCreateInfo.ppEnabledExtensionNames =
4678 (const char *const *)filtered_extension_names;
4679
Mark Youngb6399312017-01-10 14:22:15 -07004680 // Get the physical device (ICD) extensions
Mark Young0153e0b2016-11-03 14:27:13 -06004681 res = loader_init_generic_list(icd_term->this_instance,
4682 (struct loader_generic_list *)&icd_exts,
4683 sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06004684 if (VK_SUCCESS != res) {
Mark Young0ad83132016-06-30 13:02:42 -06004685 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07004686 }
4687
4688 res = loader_add_device_extensions(
Mark Young0153e0b2016-11-03 14:27:13 -06004689 icd_term->this_instance, icd_term->EnumerateDeviceExtensionProperties,
4690 phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
Jon Ashburn014438f2016-03-01 19:51:07 -07004691 if (res != VK_SUCCESS) {
Mark Young0ad83132016-06-30 13:02:42 -06004692 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07004693 }
4694
Jon Ashburn1530c342016-02-26 13:14:27 -07004695 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4696 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07004697 VkExtensionProperties *prop =
4698 get_extension_property(extension_name, &icd_exts);
Jon Ashburn1530c342016-02-26 13:14:27 -07004699 if (prop) {
4700 filtered_extension_names[localCreateInfo.enabledExtensionCount] =
4701 (char *)extension_name;
4702 localCreateInfo.enabledExtensionCount++;
Mark Young9a3ddd42016-10-21 16:25:47 -06004703 } else {
Mark Young0153e0b2016-11-03 14:27:13 -06004704 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT,
4705 0, "vkCreateDevice extension %s not available for "
4706 "devices associated with ICD %s",
4707 extension_name, icd_term->scanned_icd->lib_name);
Jon Ashburn1530c342016-02-26 13:14:27 -07004708 }
4709 }
4710
Mark Young0153e0b2016-11-03 14:27:13 -06004711 res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator,
Mark Young65cb3662016-11-07 13:27:02 -07004712 &dev->icd_device);
Jon Ashburn1530c342016-02-26 13:14:27 -07004713 if (res != VK_SUCCESS) {
Mark Young0153e0b2016-11-03 14:27:13 -06004714 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07004715 "terminator_CreateDevice: Failed in ICD %s vkCreateDevice"
4716 "call",
Mark Young0153e0b2016-11-03 14:27:13 -06004717 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06004718 goto out;
Jon Ashburn1530c342016-02-26 13:14:27 -07004719 }
4720
Mark Young65cb3662016-11-07 13:27:02 -07004721 *pDevice = dev->icd_device;
Mark Young0153e0b2016-11-03 14:27:13 -06004722 loader_add_logical_device(icd_term->this_instance, icd_term, dev);
Jon Ashburn1530c342016-02-26 13:14:27 -07004723
4724 /* Init dispatch pointer in new device object */
4725 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
4726
Mark Young0ad83132016-06-30 13:02:42 -06004727out:
4728 if (NULL != icd_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06004729 loader_destroy_generic_list(icd_term->this_instance,
Mark Young0ad83132016-06-30 13:02:42 -06004730 (struct loader_generic_list *)&icd_exts);
4731 }
4732
Jon Ashburn1530c342016-02-26 13:14:27 -07004733 return res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004734}
4735
Mark Young6267ae62017-01-12 12:27:19 -07004736VkResult setupLoaderTrampPhysDevs(VkInstance instance) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07004737 VkResult res = VK_SUCCESS;
Mark Young6267ae62017-01-12 12:27:19 -07004738 VkPhysicalDevice *local_phys_devs = NULL;
4739 struct loader_instance *inst;
4740 uint32_t total_count = 0;
4741 struct loader_physical_device_tramp **new_phys_devs = NULL;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07004742
Mark Young6267ae62017-01-12 12:27:19 -07004743 inst = loader_get_instance(instance);
4744 if (NULL == inst) {
4745 res = VK_ERROR_INITIALIZATION_FAILED;
4746 goto out;
4747 }
4748 total_count = inst->total_gpu_count;
4749
4750 // Create an array for the new physical devices, which will be stored
4751 // in the instance for the trampoline code.
4752 new_phys_devs =
4753 (struct loader_physical_device_tramp **)loader_instance_heap_alloc(
4754 inst,
4755 total_count * sizeof(struct loader_physical_device_tramp *),
4756 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4757 if (NULL == new_phys_devs) {
Lenny Komow5e4ad102017-01-12 15:47:53 -07004758 loader_log(
4759 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young2c84c0c2017-01-13 10:27:03 -07004760 "setupLoaderTrampPhysDevs: Failed to allocate new physical device"
4761 " array of size %d",
Lenny Komow5e4ad102017-01-12 15:47:53 -07004762 total_count);
Mark Youngd8382d72016-12-23 16:59:58 -07004763 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4764 goto out;
4765 }
Mark Young6267ae62017-01-12 12:27:19 -07004766 memset(new_phys_devs, 0,
4767 total_count * sizeof(struct loader_physical_device_tramp *));
Jon Ashburn014438f2016-03-01 19:51:07 -07004768
Mark Young6267ae62017-01-12 12:27:19 -07004769 // Create a temporary array (on the stack) to keep track of the
4770 // returned VkPhysicalDevice values.
4771 local_phys_devs =
4772 loader_stack_alloc(sizeof(VkPhysicalDevice) * total_count);
4773 if (NULL == local_phys_devs) {
4774 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4775 "setupLoaderTrampPhysDevs: Failed to allocate local "
4776 "physical device array of size %d",
4777 total_count);
4778 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4779 goto out;
4780 }
4781 memset(local_phys_devs, 0, sizeof(VkPhysicalDevice) * total_count);
4782
4783 res = inst->disp->EnumeratePhysicalDevices(instance, &total_count,
4784 local_phys_devs);
4785 if (VK_SUCCESS != res) {
4786 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4787 "setupLoaderTrampPhysDevs: Failed during dispatch call "
4788 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
4789 "loader.");
4790 goto out;
4791 }
4792
4793 // Copy or create everything to fill the new array of physical devices
4794 for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
4795
4796 // Check if this physical device is already in the old buffer
4797 for (uint32_t old_idx = 0;
4798 old_idx < inst->phys_dev_count_tramp;
4799 old_idx++) {
4800 if (local_phys_devs[new_idx] ==
4801 inst->phys_devs_tramp[old_idx]->phys_dev) {
4802 new_phys_devs[new_idx] = inst->phys_devs_tramp[old_idx];
4803 break;
4804 }
Mark Youngd8382d72016-12-23 16:59:58 -07004805 }
4806
Mark Young6267ae62017-01-12 12:27:19 -07004807 // If this physical device isn't in the old buffer, create it
4808 if (NULL == new_phys_devs[new_idx]) {
4809 new_phys_devs[new_idx] = (struct loader_physical_device_tramp *)
4810 loader_instance_heap_alloc(
4811 inst, sizeof(struct loader_physical_device_tramp),
4812 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4813 if (NULL == new_phys_devs[new_idx]) {
Mark Youngb6399312017-01-10 14:22:15 -07004814 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young6267ae62017-01-12 12:27:19 -07004815 "setupLoaderTrampPhysDevs: Failed to allocate "
4816 "physical device trampoline object %d",
4817 new_idx);
4818 total_count = new_idx;
Mark Youngd8382d72016-12-23 16:59:58 -07004819 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4820 goto out;
4821 }
4822
Mark Young6267ae62017-01-12 12:27:19 -07004823 // Initialize the new physicalDevice object
4824 loader_set_dispatch((void *)new_phys_devs[new_idx], inst->disp);
4825 new_phys_devs[new_idx]->this_instance = inst;
4826 new_phys_devs[new_idx]->phys_dev = local_phys_devs[new_idx];
Mark Young559d7502016-09-26 11:38:46 -06004827 }
Lenny Komowa5e01122016-12-22 15:29:43 -07004828 }
Mark Young559d7502016-09-26 11:38:46 -06004829
Lenny Komowa5e01122016-12-22 15:29:43 -07004830out:
Mark Youngd8382d72016-12-23 16:59:58 -07004831
Mark Young6267ae62017-01-12 12:27:19 -07004832 if (VK_SUCCESS != res) {
4833 if (NULL != new_phys_devs) {
4834 for (uint32_t i = 0; i < total_count; i++) {
4835 loader_instance_heap_free(inst, new_phys_devs[i]);
Lenny Komowa5e01122016-12-22 15:29:43 -07004836 }
4837 loader_instance_heap_free(inst, new_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07004838 }
4839 total_count = 0;
4840 } else {
4841 // Free everything that didn't carry over to the new array of
4842 // physical devices
4843 if (NULL != inst->phys_devs_tramp) {
4844 for (uint32_t i = 0; i < inst->phys_dev_count_tramp; i++) {
4845 bool found = false;
4846 for (uint32_t j = 0; j < total_count; j++) {
4847 if (inst->phys_devs_tramp[i] == new_phys_devs[j]) {
4848 found = true;
4849 break;
4850 }
4851 }
4852 if (!found) {
4853 loader_instance_heap_free(inst,
4854 inst->phys_devs_tramp[i]);
4855 }
4856 }
4857 loader_instance_heap_free(inst, inst->phys_devs_tramp);
4858 }
Mark Youngd8382d72016-12-23 16:59:58 -07004859
Mark Young6267ae62017-01-12 12:27:19 -07004860 // Swap in the new physical device list
4861 inst->phys_dev_count_tramp = total_count;
4862 inst->phys_devs_tramp = new_phys_devs;
4863 }
4864
4865 return res;
4866}
4867
4868VkResult setupLoaderTermPhysDevs(struct loader_instance *inst) {
4869 VkResult res = VK_SUCCESS;
4870 struct loader_icd_term *icd_term;
4871 struct loader_phys_dev_per_icd *icd_phys_dev_array = NULL;
4872 struct loader_physical_device_term **new_phys_devs = NULL;
4873 uint32_t i = 0;
4874
4875 inst->total_gpu_count = 0;
4876
4877 // Allocate something to store the physical device characteristics
4878 // that we read from each ICD.
4879 icd_phys_dev_array = (struct loader_phys_dev_per_icd *)loader_stack_alloc(
4880 sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
4881 if (NULL == icd_phys_dev_array) {
4882 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4883 "setupLoaderTermPhysDevs: Failed to allocate temporary "
Mark Young2c84c0c2017-01-13 10:27:03 -07004884 "ICD Physical device info array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07004885 inst->total_gpu_count);
4886 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4887 goto out;
4888 }
4889 memset(icd_phys_dev_array, 0,
4890 sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
4891 icd_term = inst->icd_terms;
4892
4893 // For each ICD, query the number of physical devices, and then get an
4894 // internal value for those physical devices.
4895 while (NULL != icd_term) {
4896 res = icd_term->EnumeratePhysicalDevices(
4897 icd_term->instance, &icd_phys_dev_array[i].count, NULL);
4898 if (VK_SUCCESS != res) {
4899 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4900 "setupLoaderTermPhysDevs: Call to "
4901 "ICD %d's \'vkEnumeratePhysicalDevices\' failed with"
4902 " error 0x%08x",
4903 i, res);
4904 goto out;
4905 }
4906
4907 icd_phys_dev_array[i].phys_devs =
4908 (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[i].count *
4909 sizeof(VkPhysicalDevice));
4910 if (NULL == icd_phys_dev_array[i].phys_devs) {
4911 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4912 "setupLoaderTermPhysDevs: Failed to allocate temporary "
Mark Young2c84c0c2017-01-13 10:27:03 -07004913 "ICD Physical device array for ICD %d of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07004914 i, inst->total_gpu_count);
4915 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4916 goto out;
4917 }
4918
4919 res = icd_term->EnumeratePhysicalDevices(
4920 icd_term->instance, &(icd_phys_dev_array[i].count),
4921 icd_phys_dev_array[i].phys_devs);
4922 if (VK_SUCCESS != res) {
4923 goto out;
4924 }
4925 inst->total_gpu_count += icd_phys_dev_array[i].count;
4926 icd_phys_dev_array[i].this_icd_term = icd_term;
4927
4928 icd_term = icd_term->next;
4929 i++;
4930 }
4931
4932 if (0 == inst->total_gpu_count) {
4933 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4934 "setupLoaderTermPhysDevs: Failed to detect any valid"
4935 " GPUs in the current config");
4936 res = VK_ERROR_INITIALIZATION_FAILED;
4937 goto out;
4938 }
4939
4940 new_phys_devs = loader_instance_heap_alloc(
4941 inst,
4942 sizeof(struct loader_physical_device_term *) * inst->total_gpu_count,
4943 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4944 if (NULL == new_phys_devs) {
4945 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4946 "setupLoaderTermPhysDevs: Failed to allocate new physical"
4947 " device array of size %d",
4948 inst->total_gpu_count);
4949 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4950 goto out;
4951 }
4952 memset(new_phys_devs, 0, sizeof(struct loader_physical_device_term *) *
4953 inst->total_gpu_count);
4954
4955 // Copy or create everything to fill the new array of physical devices
4956 uint32_t idx = 0;
4957 for (uint32_t icd_idx = 0; icd_idx < inst->total_icd_count; icd_idx++) {
4958 for (uint32_t pd_idx = 0; pd_idx < icd_phys_dev_array[icd_idx].count;
4959 pd_idx++) {
4960
4961 // Check if this physical device is already in the old buffer
4962 if (NULL != inst->phys_devs_term) {
4963 for (uint32_t old_idx = 0;
4964 old_idx < inst->phys_dev_count_term;
4965 old_idx++) {
4966 if (icd_phys_dev_array[icd_idx].phys_devs[pd_idx] ==
4967 inst->phys_devs_term[old_idx]->phys_dev) {
4968 new_phys_devs[idx] = inst->phys_devs_term[old_idx];
4969 break;
4970 }
4971 }
4972 }
4973 // If this physical device isn't in the old buffer, then we
4974 // need to create it.
4975 if (NULL == new_phys_devs[idx]) {
4976 new_phys_devs[idx] = loader_instance_heap_alloc(
4977 inst, sizeof(struct loader_physical_device_term),
4978 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4979 if (NULL == new_phys_devs[idx]) {
4980 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4981 "setupLoaderTermPhysDevs: Failed to allocate "
4982 "physical device terminator object %d",
4983 idx);
4984 inst->total_gpu_count = idx;
4985 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4986 goto out;
4987 }
4988
4989 loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
4990 new_phys_devs[idx]->this_icd_term =
4991 icd_phys_dev_array[icd_idx].this_icd_term;
4992 new_phys_devs[idx]->icd_index = (uint8_t)(icd_idx);
4993 new_phys_devs[idx]->phys_dev =
4994 icd_phys_dev_array[icd_idx].phys_devs[pd_idx];
4995 }
4996 idx++;
4997 }
4998 }
4999
5000out:
5001
5002 if (VK_SUCCESS != res) {
5003 if (NULL != inst->phys_devs_term) {
5004 // We've encountered an error, so we should free the
5005 // new buffers.
5006 for (uint32_t i = 0; i < inst->total_gpu_count; i++) {
5007 loader_instance_heap_free(inst, new_phys_devs[i]);
5008 }
5009 loader_instance_heap_free(inst, inst->phys_devs_term);
5010 inst->total_gpu_count = 0;
5011 }
5012 } else {
5013 // Free everything that didn't carry over to the new array of
5014 // physical devices. Everything else will have been copied over
5015 // to the new array.
5016 if (NULL != inst->phys_devs_term) {
5017 for (uint32_t cur_pd = 0; cur_pd < inst->phys_dev_count_term;
5018 cur_pd++) {
5019 bool found = false;
5020 for (uint32_t new_pd_idx = 0;
5021 new_pd_idx < inst->total_gpu_count;
5022 new_pd_idx++) {
5023 if (inst->phys_devs_term[cur_pd] ==
5024 new_phys_devs[new_pd_idx]) {
5025 found = true;
5026 break;
5027 }
5028 }
5029 if (!found) {
5030 loader_instance_heap_free(inst,
5031 inst->phys_devs_term[cur_pd]);
5032 }
5033 }
5034 loader_instance_heap_free(inst, inst->phys_devs_term);
5035 }
5036
5037 // Swap out old and new devices list
5038 inst->phys_dev_count_term = inst->total_gpu_count;
5039 inst->phys_devs_term = new_phys_devs;
5040 }
5041
5042 return res;
5043}
5044
5045VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(
5046 VkInstance instance, uint32_t *pPhysicalDeviceCount,
5047 VkPhysicalDevice *pPhysicalDevices) {
5048 struct loader_instance *inst = (struct loader_instance *)instance;
5049 VkResult res = VK_SUCCESS;
5050
5051 // Only do the setup if we're re-querying the number of devices, or
5052 // our count is currently 0.
5053 if (NULL == pPhysicalDevices || 0 == inst->total_gpu_count) {
5054 res = setupLoaderTermPhysDevs(inst);
5055 if (VK_SUCCESS != res) {
5056 goto out;
5057 }
5058 }
5059
5060 uint32_t copy_count = inst->total_gpu_count;
5061 if (NULL != pPhysicalDevices) {
5062 if (copy_count > *pPhysicalDeviceCount) {
5063 copy_count = *pPhysicalDeviceCount;
5064 res = VK_INCOMPLETE;
5065 }
5066
5067 for (uint32_t i = 0; i < copy_count; i++) {
5068 pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_term[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07005069 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005070 }
Mark Young559d7502016-09-26 11:38:46 -06005071
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07005072 *pPhysicalDeviceCount = copy_count;
5073
Mark Young6267ae62017-01-12 12:27:19 -07005074out:
5075
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005076 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005077}
5078
Jon Ashburn1530c342016-02-26 13:14:27 -07005079VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(
5080 VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005081 struct loader_physical_device_term *phys_dev_term =
5082 (struct loader_physical_device_term *)physicalDevice;
5083 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005084 if (NULL != icd_term->GetPhysicalDeviceProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005085 icd_term->GetPhysicalDeviceProperties(phys_dev_term->phys_dev,
5086 pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005087 }
Tony Barbour59a47322015-06-24 16:06:58 -06005088}
5089
Jon Ashburn1530c342016-02-26 13:14:27 -07005090VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07005091 VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
5092 VkQueueFamilyProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005093 struct loader_physical_device_term *phys_dev_term =
5094 (struct loader_physical_device_term *)physicalDevice;
5095 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005096 if (NULL != icd_term->GetPhysicalDeviceQueueFamilyProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005097 icd_term->GetPhysicalDeviceQueueFamilyProperties(
5098 phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005099 }
Tony Barbour59a47322015-06-24 16:06:58 -06005100}
5101
Jon Ashburn1530c342016-02-26 13:14:27 -07005102VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07005103 VkPhysicalDevice physicalDevice,
5104 VkPhysicalDeviceMemoryProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005105 struct loader_physical_device_term *phys_dev_term =
5106 (struct loader_physical_device_term *)physicalDevice;
5107 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005108 if (NULL != icd_term->GetPhysicalDeviceMemoryProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005109 icd_term->GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev,
5110 pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005111 }
Jon Ashburn3da71f22015-05-14 12:43:38 -06005112}
5113
Mark Young0153e0b2016-11-03 14:27:13 -06005114VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(
5115 VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures) {
5116 struct loader_physical_device_term *phys_dev_term =
5117 (struct loader_physical_device_term *)physicalDevice;
5118 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005119 if (NULL != icd_term->GetPhysicalDeviceFeatures) {
Mark Young0153e0b2016-11-03 14:27:13 -06005120 icd_term->GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
Mark Youngb6399312017-01-10 14:22:15 -07005121 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005122}
5123
Mark Young0153e0b2016-11-03 14:27:13 -06005124VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(
5125 VkPhysicalDevice physicalDevice, VkFormat format,
5126 VkFormatProperties *pFormatInfo) {
5127 struct loader_physical_device_term *phys_dev_term =
5128 (struct loader_physical_device_term *)physicalDevice;
5129 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005130 if (NULL != icd_term->GetPhysicalDeviceFormatProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005131 icd_term->GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev,
5132 format, pFormatInfo);
Mark Youngb6399312017-01-10 14:22:15 -07005133 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005134}
5135
Jon Ashburn1530c342016-02-26 13:14:27 -07005136VKAPI_ATTR VkResult VKAPI_CALL
5137terminator_GetPhysicalDeviceImageFormatProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07005138 VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
5139 VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
5140 VkImageFormatProperties *pImageFormatProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005141 struct loader_physical_device_term *phys_dev_term =
5142 (struct loader_physical_device_term *)physicalDevice;
5143 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005144 if (NULL == icd_term->GetPhysicalDeviceImageFormatProperties) {
5145 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5146 "Encountered the vkEnumerateDeviceLayerProperties "
5147 "terminator. This means a layer improperly continued.");
Chia-I Wu17241042015-10-31 00:31:16 +08005148 return VK_ERROR_INITIALIZATION_FAILED;
Mark Youngb6399312017-01-10 14:22:15 -07005149 }
Mark Young0153e0b2016-11-03 14:27:13 -06005150 return icd_term->GetPhysicalDeviceImageFormatProperties(
5151 phys_dev_term->phys_dev, format, type, tiling, usage, flags,
Jon Ashburn23d36b12016-02-02 17:47:28 -07005152 pImageFormatProperties);
Jon Ashburn754864f2015-07-23 18:49:07 -06005153}
5154
Jon Ashburn1530c342016-02-26 13:14:27 -07005155VKAPI_ATTR void VKAPI_CALL
5156terminator_GetPhysicalDeviceSparseImageFormatProperties(
Jon Ashburn23d36b12016-02-02 17:47:28 -07005157 VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
5158 VkSampleCountFlagBits samples, VkImageUsageFlags usage,
5159 VkImageTiling tiling, uint32_t *pNumProperties,
5160 VkSparseImageFormatProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005161 struct loader_physical_device_term *phys_dev_term =
5162 (struct loader_physical_device_term *)physicalDevice;
5163 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Youngb6399312017-01-10 14:22:15 -07005164 if (NULL != icd_term->GetPhysicalDeviceSparseImageFormatProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005165 icd_term->GetPhysicalDeviceSparseImageFormatProperties(
5166 phys_dev_term->phys_dev, format, type, samples, usage, tiling,
Jon Ashburn23d36b12016-02-02 17:47:28 -07005167 pNumProperties, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005168 }
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06005169}
5170
Jon Ashburn1530c342016-02-26 13:14:27 -07005171VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(
5172 VkPhysicalDevice physicalDevice, const char *pLayerName,
5173 uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005174 struct loader_physical_device_term *phys_dev_term;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07005175
Mark Young3a587792016-08-19 15:25:08 -06005176 struct loader_layer_list implicit_layer_list = {0};
5177 struct loader_extension_list all_exts = {0};
5178 struct loader_extension_list icd_exts = {0};
Jon Ashburn471f44c2016-01-13 12:51:43 -07005179
Jon Ashburndc5d9202016-02-29 13:00:51 -07005180 assert(pLayerName == NULL || strlen(pLayerName) == 0);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06005181
Jon Ashburndc5d9202016-02-29 13:00:51 -07005182 /* Any layer or trampoline wrapping should be removed at this point in time
5183 * can just cast to the expected type for VkPhysicalDevice. */
Mark Young0153e0b2016-11-03 14:27:13 -06005184 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005185
Jon Ashburndc5d9202016-02-29 13:00:51 -07005186 /* this case is during the call down the instance chain with pLayerName
5187 * == NULL*/
Mark Young0153e0b2016-11-03 14:27:13 -06005188 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005189 uint32_t icd_ext_count = *pPropertyCount;
5190 VkResult res;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005191
Jon Ashburndc5d9202016-02-29 13:00:51 -07005192 /* get device extensions */
Mark Young0153e0b2016-11-03 14:27:13 -06005193 res = icd_term->EnumerateDeviceExtensionProperties(
5194 phys_dev_term->phys_dev, NULL, &icd_ext_count, pProperties);
Mark Young3a587792016-08-19 15:25:08 -06005195 if (res != VK_SUCCESS) {
5196 goto out;
5197 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07005198
Mark Young0153e0b2016-11-03 14:27:13 -06005199 if (!loader_init_layer_list(icd_term->this_instance,
5200 &implicit_layer_list)) {
Mark Young3a587792016-08-19 15:25:08 -06005201 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5202 goto out;
5203 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005204
Jon Ashburndc5d9202016-02-29 13:00:51 -07005205 loader_add_layer_implicit(
Mark Young0153e0b2016-11-03 14:27:13 -06005206 icd_term->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
5207 &implicit_layer_list, &icd_term->this_instance->instance_layer_list);
Jon Ashburndc5d9202016-02-29 13:00:51 -07005208 /* we need to determine which implicit layers are active,
5209 * and then add their extensions. This can't be cached as
5210 * it depends on results of environment variables (which can change).
5211 */
5212 if (pProperties != NULL) {
5213 /* initialize dev_extension list within the physicalDevice object */
Mark Young0153e0b2016-11-03 14:27:13 -06005214 res = loader_init_device_extensions(icd_term->this_instance,
5215 phys_dev_term, icd_ext_count,
5216 pProperties, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06005217 if (res != VK_SUCCESS) {
5218 goto out;
5219 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005220
Jon Ashburndc5d9202016-02-29 13:00:51 -07005221 /* we need to determine which implicit layers are active,
5222 * and then add their extensions. This can't be cached as
5223 * it depends on results of environment variables (which can
5224 * change).
5225 */
Mark Young0153e0b2016-11-03 14:27:13 -06005226 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts,
Mark Young3a587792016-08-19 15:25:08 -06005227 icd_exts.count, icd_exts.list);
5228 if (res != VK_SUCCESS) {
5229 goto out;
5230 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005231
Jon Ashburndc5d9202016-02-29 13:00:51 -07005232 loader_add_layer_implicit(
Mark Young0153e0b2016-11-03 14:27:13 -06005233 icd_term->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
5234 &implicit_layer_list,
5235 &icd_term->this_instance->instance_layer_list);
Jon Ashburn471f44c2016-01-13 12:51:43 -07005236
Jon Ashburndc5d9202016-02-29 13:00:51 -07005237 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
5238 for (uint32_t j = 0;
Jon Ashburn014438f2016-03-01 19:51:07 -07005239 j < implicit_layer_list.list[i].device_extension_list.count;
5240 j++) {
Mark Young0153e0b2016-11-03 14:27:13 -06005241 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts,
5242 1,
Mark Young3a587792016-08-19 15:25:08 -06005243 &implicit_layer_list.list[i]
5244 .device_extension_list.list[j]
5245 .props);
5246 if (res != VK_SUCCESS) {
5247 goto out;
5248 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005249 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005250 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005251 uint32_t capacity = *pPropertyCount;
5252 VkExtensionProperties *props = pProperties;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005253
Jon Ashburndc5d9202016-02-29 13:00:51 -07005254 for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
5255 props[i] = all_exts.list[i];
5256 }
5257 /* wasn't enough space for the extensions, we did partial copy now
5258 * return VK_INCOMPLETE */
5259 if (capacity < all_exts.count) {
5260 res = VK_INCOMPLETE;
5261 } else {
5262 *pPropertyCount = all_exts.count;
5263 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005264 } else {
5265 /* just return the count; need to add in the count of implicit layer
5266 * extensions
5267 * don't worry about duplicates being added in the count */
5268 *pPropertyCount = icd_ext_count;
5269
5270 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
5271 *pPropertyCount +=
Jon Ashburn014438f2016-03-01 19:51:07 -07005272 implicit_layer_list.list[i].device_extension_list.count;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005273 }
5274 res = VK_SUCCESS;
Jon Ashburnb82c1852015-08-11 14:49:54 -06005275 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005276
Mark Young3a587792016-08-19 15:25:08 -06005277out:
5278
5279 if (NULL != implicit_layer_list.list) {
5280 loader_destroy_generic_list(
Mark Young0153e0b2016-11-03 14:27:13 -06005281 icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06005282 (struct loader_generic_list *)&implicit_layer_list);
5283 }
5284 if (NULL != all_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06005285 loader_destroy_generic_list(icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06005286 (struct loader_generic_list *)&all_exts);
5287 }
5288 if (NULL != icd_exts.list) {
Mark Young0153e0b2016-11-03 14:27:13 -06005289 loader_destroy_generic_list(icd_term->this_instance,
Mark Young3a587792016-08-19 15:25:08 -06005290 (struct loader_generic_list *)&icd_exts);
5291 }
5292
Jon Ashburndc5d9202016-02-29 13:00:51 -07005293 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06005294}
5295
Mark Young0153e0b2016-11-03 14:27:13 -06005296VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(
5297 VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
5298 VkLayerProperties *pProperties) {
Mark Youngb6399312017-01-10 14:22:15 -07005299 struct loader_physical_device_term *phys_dev_term =
5300 (struct loader_physical_device_term *)physicalDevice;
5301 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
5302 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5303 "Encountered the vkEnumerateDeviceLayerProperties "
5304 "terminator. This means a layer improperly continued.");
5305 // Should never get here this call isn't dispatched down the chain
Jon Ashburndc5d9202016-02-29 13:00:51 -07005306 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06005307}
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005308
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005309VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005310 VkStringErrorFlags result = VK_STRING_ERROR_NONE;
Karl Schultz2558bd32016-02-24 14:39:39 -07005311 int num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005312 int i, j;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005313
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07005314 for (i = 0; i <= max_length; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005315 if (utf8[i] == 0) {
5316 break;
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07005317 } else if (i == max_length) {
5318 result |= VK_STRING_ERROR_LENGTH;
5319 break;
Mark Lobodzinski36b4de22016-02-12 11:30:14 -07005320 } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005321 num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005322 } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005323 num_char_bytes = 1;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005324 } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005325 num_char_bytes = 2;
5326 } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
5327 num_char_bytes = 3;
5328 } else {
5329 result = VK_STRING_ERROR_BAD_DATA;
5330 }
5331
5332 // Validate the following num_char_bytes of data
5333 for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
5334 if (++i == max_length) {
5335 result |= VK_STRING_ERROR_LENGTH;
5336 break;
5337 }
5338 if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
5339 result |= VK_STRING_ERROR_BAD_DATA;
5340 }
5341 }
5342 }
5343 return result;
5344}