1/* 2 * Copyright © 2021 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "vk_instance.h" 25 26#include "vk_alloc.h" 27#include "vk_common_entrypoints.h" 28#include "vk_dispatch_trampolines.h" 29#include "vk_log.h" 30#include "vk_util.h" 31#include "vk_debug_utils.h" 32 33#include "compiler/glsl_types.h" 34 35#define VERSION_IS_1_0(version) \ 36 (VK_API_VERSION_MAJOR(version) == 1 && VK_API_VERSION_MINOR(version) == 0) 37 38VkResult 39vk_instance_init(struct vk_instance *instance, 40 const struct vk_instance_extension_table *supported_extensions, 41 const struct vk_instance_dispatch_table *dispatch_table, 42 const VkInstanceCreateInfo *pCreateInfo, 43 const VkAllocationCallbacks *alloc) 44{ 45 memset(instance, 0, sizeof(*instance)); 46 vk_object_base_init(NULL, &instance->base, VK_OBJECT_TYPE_INSTANCE); 47 instance->alloc = *alloc; 48 49 /* VK_EXT_debug_utils */ 50 /* These messengers will only be used during vkCreateInstance or 51 * vkDestroyInstance calls. We do this first so that it's safe to use 52 * vk_errorf and friends. 53 */ 54 list_inithead(&instance->debug_utils.instance_callbacks); 55 vk_foreach_struct_const(ext, pCreateInfo->pNext) { 56 if (ext->sType == 57 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) { 58 const VkDebugUtilsMessengerCreateInfoEXT *debugMessengerCreateInfo = 59 (const VkDebugUtilsMessengerCreateInfoEXT *)ext; 60 struct vk_debug_utils_messenger *messenger = 61 vk_alloc2(alloc, alloc, sizeof(struct vk_debug_utils_messenger), 8, 62 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 63 64 if (!messenger) 65 return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY); 66 67 vk_object_base_init(NULL, &messenger->base, 68 VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT); 69 70 messenger->alloc = *alloc; 71 messenger->severity = debugMessengerCreateInfo->messageSeverity; 72 messenger->type = debugMessengerCreateInfo->messageType; 73 messenger->callback = debugMessengerCreateInfo->pfnUserCallback; 74 messenger->data = debugMessengerCreateInfo->pUserData; 75 76 list_addtail(&messenger->link, 77 &instance->debug_utils.instance_callbacks); 78 } 79 } 80 81 uint32_t instance_version = VK_API_VERSION_1_0; 82 if (dispatch_table->EnumerateInstanceVersion) 83 dispatch_table->EnumerateInstanceVersion(&instance_version); 84 85 instance->app_info = (struct vk_app_info) { .api_version = 0 }; 86 if (pCreateInfo->pApplicationInfo) { 87 const VkApplicationInfo *app = pCreateInfo->pApplicationInfo; 88 89 instance->app_info.app_name = 90 vk_strdup(&instance->alloc, app->pApplicationName, 91 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 92 instance->app_info.app_version = app->applicationVersion; 93 94 instance->app_info.engine_name = 95 vk_strdup(&instance->alloc, app->pEngineName, 96 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 97 instance->app_info.engine_version = app->engineVersion; 98 99 instance->app_info.api_version = app->apiVersion; 100 } 101 102 /* From the Vulkan 1.2.199 spec: 103 * 104 * "Note: 105 * 106 * Providing a NULL VkInstanceCreateInfo::pApplicationInfo or providing 107 * an apiVersion of 0 is equivalent to providing an apiVersion of 108 * VK_MAKE_API_VERSION(0,1,0,0)." 109 */ 110 if (instance->app_info.api_version == 0) 111 instance->app_info.api_version = VK_API_VERSION_1_0; 112 113 /* From the Vulkan 1.2.199 spec: 114 * 115 * VUID-VkApplicationInfo-apiVersion-04010 116 * 117 * "If apiVersion is not 0, then it must be greater than or equal to 118 * VK_API_VERSION_1_0" 119 */ 120 assert(instance->app_info.api_version >= VK_API_VERSION_1_0); 121 122 /* From the Vulkan 1.2.199 spec: 123 * 124 * "Vulkan 1.0 implementations were required to return 125 * VK_ERROR_INCOMPATIBLE_DRIVER if apiVersion was larger than 1.0. 126 * Implementations that support Vulkan 1.1 or later must not return 127 * VK_ERROR_INCOMPATIBLE_DRIVER for any value of apiVersion." 128 */ 129 if (VERSION_IS_1_0(instance_version) && 130 !VERSION_IS_1_0(instance->app_info.api_version)) 131 return VK_ERROR_INCOMPATIBLE_DRIVER; 132 133 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) { 134 int idx; 135 for (idx = 0; idx < VK_INSTANCE_EXTENSION_COUNT; idx++) { 136 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], 137 vk_instance_extensions[idx].extensionName) == 0) 138 break; 139 } 140 141 if (idx >= VK_INSTANCE_EXTENSION_COUNT) 142 return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, 143 "%s not supported", 144 pCreateInfo->ppEnabledExtensionNames[i]); 145 146 if (!supported_extensions->extensions[idx]) 147 return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, 148 "%s not supported", 149 pCreateInfo->ppEnabledExtensionNames[i]); 150 151#ifdef ANDROID 152 if (!vk_android_allowed_instance_extensions.extensions[idx]) 153 return vk_errorf(instance, VK_ERROR_EXTENSION_NOT_PRESENT, 154 "%s not supported", 155 pCreateInfo->ppEnabledExtensionNames[i]); 156#endif 157 158 instance->enabled_extensions.extensions[idx] = true; 159 } 160 161 instance->dispatch_table = *dispatch_table; 162 163 /* Add common entrypoints without overwriting driver-provided ones. */ 164 vk_instance_dispatch_table_from_entrypoints( 165 &instance->dispatch_table, &vk_common_instance_entrypoints, false); 166 167 if (mtx_init(&instance->debug_report.callbacks_mutex, mtx_plain) != 0) 168 return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED); 169 170 list_inithead(&instance->debug_report.callbacks); 171 172 if (mtx_init(&instance->debug_utils.callbacks_mutex, mtx_plain) != 0) { 173 mtx_destroy(&instance->debug_report.callbacks_mutex); 174 return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED); 175 } 176 177 list_inithead(&instance->debug_utils.callbacks); 178 179 glsl_type_singleton_init_or_ref(); 180 181 return VK_SUCCESS; 182} 183 184void 185vk_instance_finish(struct vk_instance *instance) 186{ 187 glsl_type_singleton_decref(); 188 if (unlikely(!list_is_empty(&instance->debug_utils.callbacks))) { 189 list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, 190 &instance->debug_utils.callbacks, link) { 191 list_del(&messenger->link); 192 vk_object_base_finish(&messenger->base); 193 vk_free2(&instance->alloc, &messenger->alloc, messenger); 194 } 195 } 196 if (unlikely(!list_is_empty(&instance->debug_utils.instance_callbacks))) { 197 list_for_each_entry_safe(struct vk_debug_utils_messenger, messenger, 198 &instance->debug_utils.instance_callbacks, 199 link) { 200 list_del(&messenger->link); 201 vk_object_base_finish(&messenger->base); 202 vk_free2(&instance->alloc, &messenger->alloc, messenger); 203 } 204 } 205 mtx_destroy(&instance->debug_report.callbacks_mutex); 206 mtx_destroy(&instance->debug_utils.callbacks_mutex); 207 vk_free(&instance->alloc, (char *)instance->app_info.app_name); 208 vk_free(&instance->alloc, (char *)instance->app_info.engine_name); 209 vk_object_base_finish(&instance->base); 210} 211 212VkResult 213vk_enumerate_instance_extension_properties( 214 const struct vk_instance_extension_table *supported_extensions, 215 uint32_t *pPropertyCount, 216 VkExtensionProperties *pProperties) 217{ 218 VK_OUTARRAY_MAKE_TYPED(VkExtensionProperties, out, pProperties, pPropertyCount); 219 220 for (int i = 0; i < VK_INSTANCE_EXTENSION_COUNT; i++) { 221 if (!supported_extensions->extensions[i]) 222 continue; 223 224#ifdef ANDROID 225 if (!vk_android_allowed_instance_extensions.extensions[i]) 226 continue; 227#endif 228 229 vk_outarray_append_typed(VkExtensionProperties, &out, prop) { 230 *prop = vk_instance_extensions[i]; 231 } 232 } 233 234 return vk_outarray_status(&out); 235} 236 237PFN_vkVoidFunction 238vk_instance_get_proc_addr(const struct vk_instance *instance, 239 const struct vk_instance_entrypoint_table *entrypoints, 240 const char *name) 241{ 242 PFN_vkVoidFunction func; 243 244 /* The Vulkan 1.0 spec for vkGetInstanceProcAddr has a table of exactly 245 * when we have to return valid function pointers, NULL, or it's left 246 * undefined. See the table for exact details. 247 */ 248 if (name == NULL) 249 return NULL; 250 251#define LOOKUP_VK_ENTRYPOINT(entrypoint) \ 252 if (strcmp(name, "vk" #entrypoint) == 0) \ 253 return (PFN_vkVoidFunction)entrypoints->entrypoint 254 255 LOOKUP_VK_ENTRYPOINT(EnumerateInstanceExtensionProperties); 256 LOOKUP_VK_ENTRYPOINT(EnumerateInstanceLayerProperties); 257 LOOKUP_VK_ENTRYPOINT(EnumerateInstanceVersion); 258 LOOKUP_VK_ENTRYPOINT(CreateInstance); 259 260 /* GetInstanceProcAddr() can also be called with a NULL instance. 261 * See https://gitlab.khronos.org/vulkan/vulkan/issues/2057 262 */ 263 LOOKUP_VK_ENTRYPOINT(GetInstanceProcAddr); 264 265#undef LOOKUP_VK_ENTRYPOINT 266 267 if (instance == NULL) 268 return NULL; 269 270 func = vk_instance_dispatch_table_get_if_supported(&instance->dispatch_table, 271 name, 272 instance->app_info.api_version, 273 &instance->enabled_extensions); 274 if (func != NULL) 275 return func; 276 277 func = vk_physical_device_dispatch_table_get_if_supported(&vk_physical_device_trampolines, 278 name, 279 instance->app_info.api_version, 280 &instance->enabled_extensions); 281 if (func != NULL) 282 return func; 283 284 func = vk_device_dispatch_table_get_if_supported(&vk_device_trampolines, 285 name, 286 instance->app_info.api_version, 287 &instance->enabled_extensions, 288 NULL); 289 if (func != NULL) 290 return func; 291 292 return NULL; 293} 294 295PFN_vkVoidFunction 296vk_instance_get_proc_addr_unchecked(const struct vk_instance *instance, 297 const char *name) 298{ 299 PFN_vkVoidFunction func; 300 301 if (instance == NULL || name == NULL) 302 return NULL; 303 304 func = vk_instance_dispatch_table_get(&instance->dispatch_table, name); 305 if (func != NULL) 306 return func; 307 308 func = vk_physical_device_dispatch_table_get( 309 &vk_physical_device_trampolines, name); 310 if (func != NULL) 311 return func; 312 313 func = vk_device_dispatch_table_get(&vk_device_trampolines, name); 314 if (func != NULL) 315 return func; 316 317 return NULL; 318} 319 320PFN_vkVoidFunction 321vk_instance_get_physical_device_proc_addr(const struct vk_instance *instance, 322 const char *name) 323{ 324 if (instance == NULL || name == NULL) 325 return NULL; 326 327 return vk_physical_device_dispatch_table_get_if_supported(&vk_physical_device_trampolines, 328 name, 329 instance->app_info.api_version, 330 &instance->enabled_extensions); 331} 332