1// Copyright (c) 2017-2025 The Khronos Group Inc.
2// Copyright (c) 2017-2019 Valve Corporation
3// Copyright (c) 2017-2019 LunarG, Inc.
4//
5// SPDX-License-Identifier: Apache-2.0 OR MIT
6//
7// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com>
8//
9
10#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
11#define _CRT_SECURE_NO_WARNINGS
12#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
13
14#include "api_layer_interface.hpp"
15#include "exception_handling.hpp"
16#include "hex_and_handles.h"
17#include "loader_init_data.hpp"
18#include "loader_instance.hpp"
19#include "loader_logger_recorders.hpp"
20#include "loader_logger.hpp"
21#include "loader_platform.hpp"
22#include "runtime_interface.hpp"
23#include "xr_generated_dispatch_table_core.h"
24#include "xr_generated_loader.hpp"
25
26#include <openxr/openxr.h>
27
28#include <cstring>
29#include <memory>
30#include <mutex>
31#include <sstream>
32#include <string>
33#include <utility>
34#include <vector>
35
36// Global loader lock to:
37// 1. Ensure ActiveLoaderInstance get and set operations are done atomically.
38// 2. Ensure RuntimeInterface isn't used to unload the runtime while the runtime is in use.
39static std::mutex &GetGlobalLoaderMutex() {
40 static std::mutex loader_mutex;
41 return loader_mutex;
42}
43
44// Prototypes for the debug utils calls used internally.
45static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineCreateDebugUtilsMessengerEXT(
46 XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, XrDebugUtilsMessengerEXT *messenger);
47static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger);
48
49// Terminal functions needed by xrCreateInstance.
50static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance, const char *, PFN_xrVoidFunction *);
51static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *, XrInstance *);
52static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *,
53 const struct XrApiLayerCreateInfo *, XrInstance *);
54static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance, const XrDebugUtilsObjectNameInfoEXT *);
55static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance,
56 const XrDebugUtilsMessengerCreateInfoEXT *,
57 XrDebugUtilsMessengerEXT *);
58static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT);
59static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
60 XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
61 const XrDebugUtilsMessengerCallbackDataEXT *callbackData);
62static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name,
63 PFN_xrVoidFunction *function);
64
65// Utility template function meant to validate if a fixed size string contains
66// a null-terminator.
67template <size_t max_length>
68inline bool IsMissingNullTerminator(const char (&str)[max_length]) {
69 for (size_t index = 0; index < max_length; ++index) {
70 if (str[index] == '\0') {
71 return false;
72 }
73 }
74 return true;
75}
76
77// ---- Core 1.0 manual loader trampoline functions
78#ifdef XR_KHR_LOADER_INIT_SUPPORT // platforms that support XR_KHR_loader_init.
79XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY {
80 LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline");
81 return InitializeLoaderInitData(loaderInitInfo);
82}
83XRLOADER_ABI_CATCH_FALLBACK
84#endif
85
86static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
87 uint32_t *propertyCountOutput,
88 XrApiLayerProperties *properties) XRLOADER_ABI_TRY {
89 LoaderLogger::LogVerboseMessage(command_name: "xrEnumerateApiLayerProperties", message: "Entering loader trampoline");
90
91 // Make sure only one thread is attempting to read the JSON files at a time.
92 std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
93
94 XrResult result = ApiLayerInterface::GetApiLayerProperties(openxr_command: "xrEnumerateApiLayerProperties", incoming_count: propertyCapacityInput,
95 outgoing_count: propertyCountOutput, api_layer_properties: properties);
96 if (XR_FAILED(result)) {
97 LoaderLogger::LogErrorMessage(command_name: "xrEnumerateApiLayerProperties", message: "Failed ApiLayerInterface::GetApiLayerProperties");
98 }
99
100 return result;
101}
102XRLOADER_ABI_CATCH_FALLBACK
103
104static XRAPI_ATTR XrResult XRAPI_CALL
105LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput,
106 XrExtensionProperties *properties) XRLOADER_ABI_TRY {
107 bool just_layer_properties = false;
108 LoaderLogger::LogVerboseMessage(command_name: "xrEnumerateInstanceExtensionProperties", message: "Entering loader trampoline");
109
110 // "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,
111 // and the function sets elementCountOutput." - 2.11
112 if (nullptr == propertyCountOutput) {
113 return XR_ERROR_VALIDATION_FAILURE;
114 }
115
116 if (nullptr != layerName && 0 != strlen(s: layerName)) {
117 // Application is only interested in layer's properties, not all of them.
118 just_layer_properties = true;
119 }
120
121 std::vector<XrExtensionProperties> extension_properties = {};
122 XrResult result;
123
124 {
125 // Make sure the runtime isn't unloaded while this call is in progress.
126 std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
127
128 // Get the layer extension properties
129 result = ApiLayerInterface::GetInstanceExtensionProperties(openxr_command: "xrEnumerateInstanceExtensionProperties", layer_name: layerName,
130 extension_properties);
131 if (XR_SUCCEEDED(result) && !just_layer_properties) {
132 // If not specific to a layer, get the runtime extension properties
133 result = RuntimeInterface::LoadRuntime(openxr_command: "xrEnumerateInstanceExtensionProperties");
134 if (XR_SUCCEEDED(result)) {
135 RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties);
136 } else {
137 LoaderLogger::LogErrorMessage(command_name: "xrEnumerateInstanceExtensionProperties",
138 message: "Failed to find default runtime with RuntimeInterface::LoadRuntime()");
139 }
140 }
141 }
142
143 if (XR_FAILED(result)) {
144 LoaderLogger::LogErrorMessage(command_name: "xrEnumerateInstanceExtensionProperties", message: "Failed querying extension properties");
145 return result;
146 }
147
148 // If this is not in reference to a specific layer, then add the loader-specific extension properties as well.
149 // These are extensions that the loader directly supports.
150 if (!just_layer_properties) {
151 for (const XrExtensionProperties &loader_prop : LoaderInstance::LoaderSpecificExtensions()) {
152 bool found_prop = false;
153 for (XrExtensionProperties &existing_prop : extension_properties) {
154 if (0 == strcmp(s1: existing_prop.extensionName, s2: loader_prop.extensionName)) {
155 found_prop = true;
156 // Use the loader version if it is newer
157 if (existing_prop.extensionVersion < loader_prop.extensionVersion) {
158 existing_prop.extensionVersion = loader_prop.extensionVersion;
159 }
160 break;
161 }
162 }
163 // Only add extensions not supported by the loader
164 if (!found_prop) {
165 extension_properties.push_back(x: loader_prop);
166 }
167 }
168 }
169
170 auto num_extension_properties = static_cast<uint32_t>(extension_properties.size());
171 if (propertyCapacityInput == 0) {
172 *propertyCountOutput = num_extension_properties;
173 } else if (nullptr != properties) {
174 if (propertyCapacityInput < num_extension_properties) {
175 *propertyCountOutput = num_extension_properties;
176 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter",
177 command_name: "xrEnumerateInstanceExtensionProperties", message: "insufficient space in array");
178 return XR_ERROR_SIZE_INSUFFICIENT;
179 }
180
181 uint32_t num_to_copy = num_extension_properties;
182 // Determine how many extension properties we can copy over
183 if (propertyCapacityInput < num_to_copy) {
184 num_to_copy = propertyCapacityInput;
185 }
186 bool properties_valid = true;
187 for (uint32_t prop = 0; prop < propertyCapacityInput && prop < extension_properties.size(); ++prop) {
188 if (XR_TYPE_EXTENSION_PROPERTIES != properties[prop].type) {
189 properties_valid = false;
190 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-XrExtensionProperties-type-type",
191 command_name: "xrEnumerateInstanceExtensionProperties", message: "unknown type in properties");
192 }
193 if (properties_valid) {
194 properties[prop] = extension_properties[prop];
195 }
196 }
197 if (!properties_valid) {
198 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrEnumerateInstanceExtensionProperties-properties-parameter",
199 command_name: "xrEnumerateInstanceExtensionProperties", message: "invalid properties");
200 return XR_ERROR_VALIDATION_FAILURE;
201 }
202 if (nullptr != propertyCountOutput) {
203 *propertyCountOutput = num_to_copy;
204 }
205 } else {
206 // incoming_count is not 0 BUT the properties is NULL
207 return XR_ERROR_VALIDATION_FAILURE;
208 }
209 LoaderLogger::LogVerboseMessage(command_name: "xrEnumerateInstanceExtensionProperties", message: "Completed loader trampoline");
210 return XR_SUCCESS;
211}
212XRLOADER_ABI_CATCH_FALLBACK
213
214static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCreateInfo *info,
215 XrInstance *instance) XRLOADER_ABI_TRY {
216 LoaderLogger::LogVerboseMessage(command_name: "xrCreateInstance", message: "Entering loader trampoline");
217 if (nullptr == info) {
218 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrCreateInstance-info-parameter", command_name: "xrCreateInstance", message: "must be non-NULL");
219 return XR_ERROR_VALIDATION_FAILURE;
220 }
221 // If application requested OpenXR API version is higher than the loader version, then we need to throw
222 // an error.
223 uint16_t app_major = XR_VERSION_MAJOR(info->applicationInfo.apiVersion); // NOLINT
224 uint16_t app_minor = XR_VERSION_MINOR(info->applicationInfo.apiVersion); // NOLINT
225 uint16_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); // NOLINT
226 uint16_t loader_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION); // NOLINT
227 if (app_major > loader_major || (app_major == loader_major && app_minor > loader_minor)) {
228 std::ostringstream oss;
229 oss << "xrCreateInstance called with invalid API version " << app_major << "." << app_minor
230 << ". Max supported version is " << loader_major << "." << loader_minor;
231 LoaderLogger::LogErrorMessage(command_name: "xrCreateInstance", message: oss.str());
232 return XR_ERROR_API_VERSION_UNSUPPORTED;
233 }
234
235 if (nullptr == instance) {
236 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrCreateInstance-instance-parameter", command_name: "xrCreateInstance", message: "must be non-NULL");
237 return XR_ERROR_VALIDATION_FAILURE;
238 }
239
240 // Make sure the ActiveLoaderInstance::IsAvailable check is done atomically with RuntimeInterface::LoadRuntime.
241 std::unique_lock<std::mutex> instance_lock(GetGlobalLoaderMutex());
242
243 // Check if there is already an XrInstance that is alive. If so, another instance cannot be created.
244 // The loader does not support multiple simultaneous instances because the loader is intended to be
245 // usable by apps using future OpenXR APIs (through xrGetInstanceProcAddr). Because the loader would
246 // not be aware of new handle types, it would not be able to look up the appropriate dispatch table
247 // in some cases.
248 if (ActiveLoaderInstance::IsAvailable()) { // If there is an XrInstance already alive.
249 LoaderLogger::LogErrorMessage(command_name: "xrCreateInstance", message: "Loader does not support simultaneous XrInstances");
250 return XR_ERROR_LIMIT_REACHED;
251 }
252
253 std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces;
254 XrResult result;
255
256 // Make sure only one thread is attempting to read the JSON files and use the instance.
257 {
258 // Load the available runtime
259 result = RuntimeInterface::LoadRuntime(openxr_command: "xrCreateInstance");
260 if (XR_FAILED(result)) {
261 LoaderLogger::LogErrorMessage(command_name: "xrCreateInstance", message: "Failed loading runtime information");
262 } else {
263 // Load the appropriate layers
264 result = ApiLayerInterface::LoadApiLayers(openxr_command: "xrCreateInstance", enabled_api_layer_count: info->enabledApiLayerCount, enabled_api_layer_names: info->enabledApiLayerNames,
265 api_layer_interfaces);
266 if (XR_FAILED(result)) {
267 LoaderLogger::LogErrorMessage(command_name: "xrCreateInstance", message: "Failed loading layer information");
268 }
269 }
270 }
271
272 // Create the loader instance (only send down first runtime interface)
273 LoaderInstance *loader_instance = nullptr;
274 if (XR_SUCCEEDED(result)) {
275 std::unique_ptr<LoaderInstance> owned_loader_instance;
276 result = LoaderInstance::CreateInstance(get_instance_proc_addr_term: LoaderXrTermGetInstanceProcAddr, create_instance_term: LoaderXrTermCreateInstance,
277 create_api_layer_instance_term: LoaderXrTermCreateApiLayerInstance, layer_interfaces: std::move(api_layer_interfaces), createInfo: info,
278 loader_instance: &owned_loader_instance);
279 if (XR_SUCCEEDED(result)) {
280 loader_instance = owned_loader_instance.get();
281 result = ActiveLoaderInstance::Set(loader_instance: std::move(owned_loader_instance), log_function_name: "xrCreateInstance");
282 }
283 }
284
285 if (XR_SUCCEEDED(result)) {
286 // Create a debug utils messenger if the create structure is in the "next" chain
287 const auto *next_header = reinterpret_cast<const XrBaseInStructure *>(info->next);
288 const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr;
289 while (next_header != nullptr) {
290 if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
291 LoaderLogger::LogInfoMessage(command_name: "xrCreateInstance", message: "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain.");
292 dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);
293 XrDebugUtilsMessengerEXT messenger;
294 result = LoaderTrampolineCreateDebugUtilsMessengerEXT(instance: loader_instance->GetInstanceHandle(), createInfo: dbg_utils_create_info,
295 messenger: &messenger);
296 if (XR_FAILED(result)) {
297 return XR_ERROR_VALIDATION_FAILURE;
298 }
299 loader_instance->SetDefaultDebugUtilsMessenger(messenger);
300 break;
301 }
302 next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next);
303 }
304 }
305
306 if (XR_FAILED(result)) {
307 // Ensure the global loader instance and runtime are destroyed if something went wrong.
308 ActiveLoaderInstance::Remove();
309 RuntimeInterface::UnloadRuntime(openxr_command: "xrCreateInstance");
310 LoaderLogger::LogErrorMessage(command_name: "xrCreateInstance", message: "xrCreateInstance failed");
311 } else {
312 *instance = loader_instance->GetInstanceHandle();
313 LoaderLogger::LogVerboseMessage(command_name: "xrCreateInstance", message: "Completed loader trampoline");
314 }
315
316 return result;
317}
318XRLOADER_ABI_CATCH_FALLBACK
319
320static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
321 LoaderLogger::LogVerboseMessage(command_name: "xrDestroyInstance", message: "Entering loader trampoline");
322 // Runtimes may detect XR_NULL_HANDLE provided as a required handle parameter and return XR_ERROR_HANDLE_INVALID. - 2.9
323 if (XR_NULL_HANDLE == instance) {
324 LoaderLogger::LogErrorMessage(command_name: "xrDestroyInstance", message: "Instance handle is XR_NULL_HANDLE.");
325 return XR_ERROR_HANDLE_INVALID;
326 }
327
328 // Make sure the runtime isn't unloaded while it is being used by xrEnumerateInstanceExtensionProperties.
329 std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
330
331 LoaderInstance *loader_instance;
332 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrDestroyInstance");
333 if (XR_FAILED(result)) {
334 return result;
335 }
336
337 const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();
338
339 // If we allocated a default debug utils messenger, free it
340 XrDebugUtilsMessengerEXT messenger = loader_instance->DefaultDebugUtilsMessenger();
341 if (messenger != XR_NULL_HANDLE) {
342 LoaderTrampolineDestroyDebugUtilsMessengerEXT(messenger);
343 }
344
345 // Now destroy the instance
346 if (XR_FAILED(dispatch_table->DestroyInstance(instance))) {
347 LoaderLogger::LogErrorMessage(command_name: "xrDestroyInstance", message: "Unknown error occurred calling down chain");
348 }
349
350 // Get rid of the loader instance. This will make it possible to create another instance in the future.
351 ActiveLoaderInstance::Remove();
352
353 // Lock the instance create/destroy mutex
354 LoaderLogger::LogVerboseMessage(command_name: "xrDestroyInstance", message: "Completed loader trampoline");
355
356 // Finally, unload the runtime if necessary
357 RuntimeInterface::UnloadRuntime(openxr_command: "xrDestroyInstance");
358
359 return XR_SUCCESS;
360}
361XRLOADER_ABI_CATCH_FALLBACK
362
363// ---- Core 1.0 manual loader terminator functions
364
365// Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid.
366static XrResult ValidateApplicationInfo(const XrApplicationInfo &info) {
367 if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(str: info.applicationName)) {
368 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-XrApplicationInfo-applicationName-parameter", command_name: "xrCreateInstance",
369 message: "application name missing NULL terminator.");
370 return XR_ERROR_NAME_INVALID;
371 }
372 if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(str: info.engineName)) {
373 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-XrApplicationInfo-engineName-parameter", command_name: "xrCreateInstance",
374 message: "engine name missing NULL terminator.");
375 return XR_ERROR_NAME_INVALID;
376 }
377 if (strlen(s: info.applicationName) == 0) {
378 LoaderLogger::LogErrorMessage(command_name: "xrCreateInstance",
379 message: "VUID-XrApplicationInfo-engineName-parameter: application name can not be empty.");
380 return XR_ERROR_NAME_INVALID;
381 }
382 return XR_SUCCESS;
383}
384
385// Validate that the XrInstanceCreateInfo is valid
386static XrResult ValidateInstanceCreateInfo(const XrInstanceCreateInfo *info) {
387 // Should have a valid 'type'
388 if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) {
389 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-XrInstanceCreateInfo-type-type", command_name: "xrCreateInstance",
390 message: "expected XR_TYPE_INSTANCE_CREATE_INFO.");
391 return XR_ERROR_VALIDATION_FAILURE;
392 }
393 // Flags must be 0
394 if (0 != info->createFlags) {
395 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-XrInstanceCreateInfo-createFlags-zerobitmask", command_name: "xrCreateInstance",
396 message: "flags must be 0.");
397 return XR_ERROR_VALIDATION_FAILURE;
398 }
399 // ApplicationInfo struct must be valid
400 XrResult result = ValidateApplicationInfo(info: info->applicationInfo);
401 if (XR_FAILED(result)) {
402 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-XrInstanceCreateInfo-applicationInfo-parameter", command_name: "xrCreateInstance",
403 message: "info->applicationInfo is not valid.");
404 return result;
405 }
406 // VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter already tested in LoadApiLayers()
407 if ((info->enabledExtensionCount != 0u) && nullptr == info->enabledExtensionNames) {
408 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-XrInstanceCreateInfo-enabledExtensionNames-parameter", command_name: "xrCreateInstance",
409 message: "enabledExtensionCount is non-0 but array is NULL");
410 return XR_ERROR_VALIDATION_FAILURE;
411 }
412 return XR_SUCCESS;
413}
414
415static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *createInfo,
416 XrInstance *instance) XRLOADER_ABI_TRY {
417 LoaderLogger::LogVerboseMessage(command_name: "xrCreateInstance", message: "Entering loader terminator");
418 XrResult result = ValidateInstanceCreateInfo(info: createInfo);
419 if (XR_FAILED(result)) {
420 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrCreateInstance-info-parameter", command_name: "xrCreateInstance",
421 message: "something wrong with XrInstanceCreateInfo contents");
422 return result;
423 }
424 result = RuntimeInterface::GetRuntime().CreateInstance(info: createInfo, instance);
425 LoaderLogger::LogVerboseMessage(command_name: "xrCreateInstance", message: "Completed loader terminator");
426 return result;
427}
428XRLOADER_ABI_CATCH_FALLBACK
429
430static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info,
431 const struct XrApiLayerCreateInfo * /*apiLayerInfo*/,
432 XrInstance *instance) {
433 return LoaderXrTermCreateInstance(createInfo: info, instance);
434}
435
436static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
437 LoaderLogger::LogVerboseMessage(command_name: "xrDestroyInstance", message: "Entering loader terminator");
438 LoaderLogger::GetInstance().RemoveLogRecordersForXrInstance(instance);
439 XrResult result = RuntimeInterface::GetRuntime().DestroyInstance(instance);
440 LoaderLogger::LogVerboseMessage(command_name: "xrDestroyInstance", message: "Completed loader terminator");
441 return result;
442}
443XRLOADER_ABI_CATCH_FALLBACK
444
445static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance instance, const char *name,
446 PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {
447 // A few instance commands need to go through a loader terminator.
448 // Otherwise, go directly to the runtime version of the command if it exists.
449 // But first set the function pointer to NULL so that the fall-through below actually works.
450 *function = nullptr;
451
452 // NOTE: ActiveLoaderInstance cannot be used in this function because it is called before an instance is made active.
453
454 if (0 == strcmp(s1: name, s2: "xrGetInstanceProcAddr")) {
455 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermGetInstanceProcAddr);
456 } else if (0 == strcmp(s1: name, s2: "xrCreateInstance")) {
457 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateInstance);
458 } else if (0 == strcmp(s1: name, s2: "xrDestroyInstance")) {
459 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyInstance);
460 } else if (0 == strcmp(s1: name, s2: "xrSetDebugUtilsObjectNameEXT")) {
461 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSetDebugUtilsObjectNameEXT);
462 } else if (0 == strcmp(s1: name, s2: "xrCreateDebugUtilsMessengerEXT")) {
463 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateDebugUtilsMessengerEXT);
464 } else if (0 == strcmp(s1: name, s2: "xrDestroyDebugUtilsMessengerEXT")) {
465 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyDebugUtilsMessengerEXT);
466 } else if (0 == strcmp(s1: name, s2: "xrSubmitDebugUtilsMessageEXT")) {
467 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSubmitDebugUtilsMessageEXT);
468 } else if (0 == strcmp(s1: name, s2: "xrCreateApiLayerInstance")) {
469 // Special layer version of xrCreateInstance terminator. If we get called this by a layer,
470 // we simply re-direct the information back into the standard xrCreateInstance terminator.
471 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateApiLayerInstance);
472 }
473
474 if (nullptr != *function) {
475 return XR_SUCCESS;
476 }
477
478 return RuntimeInterface::GetInstanceProcAddr(instance, name, function);
479}
480XRLOADER_ABI_CATCH_FALLBACK
481
482// ---- Extension manual loader trampoline functions
483
484static XRAPI_ATTR XrResult XRAPI_CALL
485LoaderTrampolineCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
486 XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
487 LoaderLogger::LogVerboseMessage(command_name: "xrCreateDebugUtilsMessengerEXT", message: "Entering loader trampoline");
488
489 if (instance == XR_NULL_HANDLE) {
490 LoaderLogger::LogErrorMessage(command_name: "xrCreateDebugUtilsMessengerEXT", message: "Instance handle is XR_NULL_HANDLE.");
491 return XR_ERROR_HANDLE_INVALID;
492 }
493
494 LoaderInstance *loader_instance;
495 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrCreateDebugUtilsMessengerEXT");
496 if (XR_FAILED(result)) {
497 return result;
498 }
499
500 result = loader_instance->DispatchTable()->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
501 LoaderLogger::LogVerboseMessage(command_name: "xrCreateDebugUtilsMessengerEXT", message: "Completed loader trampoline");
502 return result;
503}
504XRLOADER_ABI_CATCH_BAD_ALLOC_OOM XRLOADER_ABI_CATCH_FALLBACK
505
506 static XRAPI_ATTR XrResult XRAPI_CALL
507 LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
508 // TODO: get instance from messenger in loader
509 // Also, is the loader really doing all this every call?
510 LoaderLogger::LogVerboseMessage(command_name: "xrDestroyDebugUtilsMessengerEXT", message: "Entering loader trampoline");
511
512 if (messenger == XR_NULL_HANDLE) {
513 LoaderLogger::LogErrorMessage(command_name: "xrDestroyDebugUtilsMessengerEXT", message: "Messenger handle is XR_NULL_HANDLE.");
514 return XR_ERROR_HANDLE_INVALID;
515 }
516
517 LoaderInstance *loader_instance;
518 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrDestroyDebugUtilsMessengerEXT");
519 if (XR_FAILED(result)) {
520 return result;
521 }
522
523 result = loader_instance->DispatchTable()->DestroyDebugUtilsMessengerEXT(messenger);
524 LoaderLogger::LogVerboseMessage(command_name: "xrDestroyDebugUtilsMessengerEXT", message: "Completed loader trampoline");
525 return result;
526}
527XRLOADER_ABI_CATCH_FALLBACK
528
529static XRAPI_ATTR XrResult XRAPI_CALL
530LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
531 if (session == XR_NULL_HANDLE) {
532 LoaderLogger::LogErrorMessage(command_name: "xrSessionBeginDebugUtilsLabelRegionEXT", message: "Session handle is XR_NULL_HANDLE.");
533 return XR_ERROR_HANDLE_INVALID;
534 }
535
536 if (nullptr == labelInfo) {
537 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter",
538 command_name: "xrSessionBeginDebugUtilsLabelRegionEXT", message: "labelInfo must be non-NULL",
539 objects: {XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
540 return XR_ERROR_VALIDATION_FAILURE;
541 }
542
543 LoaderInstance *loader_instance;
544 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrSessionBeginDebugUtilsLabelRegionEXT");
545 if (XR_FAILED(result)) {
546 return result;
547 }
548 LoaderLogger::GetInstance().BeginLabelRegion(session, label_info: labelInfo);
549 const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();
550 if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) {
551 return dispatch_table->SessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);
552 }
553 return XR_SUCCESS;
554}
555XRLOADER_ABI_CATCH_FALLBACK
556
557static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY {
558 if (session == XR_NULL_HANDLE) {
559 LoaderLogger::LogErrorMessage(command_name: "xrSessionEndDebugUtilsLabelRegionEXT", message: "Session handle is XR_NULL_HANDLE.");
560 return XR_ERROR_HANDLE_INVALID;
561 }
562
563 LoaderInstance *loader_instance;
564 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrSessionEndDebugUtilsLabelRegionEXT");
565 if (XR_FAILED(result)) {
566 return result;
567 }
568
569 LoaderLogger::GetInstance().EndLabelRegion(session);
570 const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();
571 if (nullptr != dispatch_table->SessionEndDebugUtilsLabelRegionEXT) {
572 return dispatch_table->SessionEndDebugUtilsLabelRegionEXT(session);
573 }
574 return XR_SUCCESS;
575}
576XRLOADER_ABI_CATCH_FALLBACK
577
578static XRAPI_ATTR XrResult XRAPI_CALL
579LoaderTrampolineSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
580 if (session == XR_NULL_HANDLE) {
581 LoaderLogger::LogErrorMessage(command_name: "xrSessionInsertDebugUtilsLabelEXT", message: "Session handle is XR_NULL_HANDLE.");
582 return XR_ERROR_HANDLE_INVALID;
583 }
584
585 LoaderInstance *loader_instance;
586 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrSessionInsertDebugUtilsLabelEXT");
587 if (XR_FAILED(result)) {
588 return result;
589 }
590
591 if (nullptr == labelInfo) {
592 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter",
593 command_name: "xrSessionInsertDebugUtilsLabelEXT", message: "labelInfo must be non-NULL",
594 objects: {XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
595 return XR_ERROR_VALIDATION_FAILURE;
596 }
597
598 LoaderLogger::GetInstance().InsertLabel(session, label_info: labelInfo);
599
600 const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();
601 if (nullptr != dispatch_table->SessionInsertDebugUtilsLabelEXT) {
602 return dispatch_table->SessionInsertDebugUtilsLabelEXT(session, labelInfo);
603 }
604
605 return XR_SUCCESS;
606}
607XRLOADER_ABI_CATCH_FALLBACK
608
609// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.
610static XRAPI_ATTR XrResult XRAPI_CALL
611LoaderTrampolineSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
612 LoaderInstance *loader_instance;
613 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrSetDebugUtilsObjectNameEXT");
614 if (XR_SUCCEEDED(result)) {
615 result = loader_instance->DispatchTable()->SetDebugUtilsObjectNameEXT(instance, nameInfo);
616 }
617 return result;
618}
619XRLOADER_ABI_CATCH_FALLBACK
620
621// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.
622static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSubmitDebugUtilsMessageEXT(
623 XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
624 const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {
625 LoaderInstance *loader_instance;
626 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrSubmitDebugUtilsMessageEXT");
627 if (XR_SUCCEEDED(result)) {
628 result =
629 loader_instance->DispatchTable()->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);
630 }
631 return result;
632}
633XRLOADER_ABI_CATCH_FALLBACK
634
635// ---- Extension manual loader terminator functions
636
637XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance,
638 const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
639 XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
640 LoaderLogger::LogVerboseMessage(command_name: "xrCreateDebugUtilsMessengerEXT", message: "Entering loader terminator");
641 if (nullptr == messenger) {
642 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter",
643 command_name: "xrCreateDebugUtilsMessengerEXT", message: "invalid messenger pointer");
644 return XR_ERROR_VALIDATION_FAILURE;
645 }
646 const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
647 XrResult result = XR_SUCCESS;
648 // This extension is supported entirely by the loader which means the runtime may or may not support it.
649 if (nullptr != dispatch_table->CreateDebugUtilsMessengerEXT) {
650 result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
651 } else {
652 // Just allocate a character so we have a unique value
653 char *temp_mess_ptr = new char;
654 *messenger = reinterpret_cast<XrDebugUtilsMessengerEXT>(temp_mess_ptr);
655 }
656 if (XR_SUCCEEDED(result)) {
657 LoaderLogger::GetInstance().AddLogRecorderForXrInstance(instance, recorder: MakeDebugUtilsLoaderLogRecorder(create_info: createInfo, debug_messenger: *messenger));
658 RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, messenger: *messenger);
659 }
660 LoaderLogger::LogVerboseMessage(command_name: "xrCreateDebugUtilsMessengerEXT", message: "Completed loader terminator");
661 return result;
662}
663XRLOADER_ABI_CATCH_FALLBACK
664
665XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
666 LoaderLogger::LogVerboseMessage(command_name: "xrDestroyDebugUtilsMessengerEXT", message: "Entering loader terminator");
667 const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger);
668 XrResult result = XR_SUCCESS;
669 LoaderLogger::GetInstance().RemoveLogRecorder(unique_id: MakeHandleGeneric(handle: messenger));
670 RuntimeInterface::GetRuntime().ForgetDebugMessenger(messenger);
671 // This extension is supported entirely by the loader which means the runtime may or may not support it.
672 if (nullptr != dispatch_table->DestroyDebugUtilsMessengerEXT) {
673 result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger);
674 } else {
675 // Delete the character we would've created
676 delete (reinterpret_cast<char *>(MakeHandleGeneric(handle: messenger)));
677 }
678 LoaderLogger::LogVerboseMessage(command_name: "xrDestroyDebugUtilsMessengerEXT", message: "Completed loader terminator");
679 return result;
680}
681XRLOADER_ABI_CATCH_FALLBACK
682
683XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
684 XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
685 const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {
686 LoaderLogger::LogVerboseMessage(command_name: "xrSubmitDebugUtilsMessageEXT", message: "Entering loader terminator");
687 const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
688 XrResult result = XR_SUCCESS;
689 if (nullptr != dispatch_table->SubmitDebugUtilsMessageEXT) {
690 result = dispatch_table->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);
691 } else {
692 // Only log the message from the loader if the runtime doesn't support this extension. If we did,
693 // then the user would receive multiple instances of the same message.
694 LoaderLogger::GetInstance().LogDebugUtilsMessage(message_severity: messageSeverity, message_type: messageTypes, callback_data: callbackData);
695 }
696 LoaderLogger::LogVerboseMessage(command_name: "xrSubmitDebugUtilsMessageEXT", message: "Completed loader terminator");
697 return result;
698}
699XRLOADER_ABI_CATCH_FALLBACK
700
701XRAPI_ATTR XrResult XRAPI_CALL
702LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
703 LoaderLogger::LogVerboseMessage(command_name: "xrSetDebugUtilsObjectNameEXT", message: "Entering loader terminator");
704 const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
705 XrResult result = XR_SUCCESS;
706 if (nullptr != dispatch_table->SetDebugUtilsObjectNameEXT) {
707 result = dispatch_table->SetDebugUtilsObjectNameEXT(instance, nameInfo);
708 }
709 LoaderLogger::GetInstance().AddObjectName(object_handle: nameInfo->objectHandle, object_type: nameInfo->objectType, object_name: nameInfo->objectName);
710 LoaderLogger::LogVerboseMessage(command_name: "xrSetDebugUtilsObjectNameEXT", message: "Completed loader terminator");
711 return result;
712}
713XRLOADER_ABI_CATCH_FALLBACK
714
715XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name,
716 PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {
717 if (nullptr == function) {
718 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrGetInstanceProcAddr-function-parameter", command_name: "xrGetInstanceProcAddr",
719 message: "Invalid Function pointer");
720 return XR_ERROR_VALIDATION_FAILURE;
721 }
722
723 if (nullptr == name) {
724 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrGetInstanceProcAddr-function-parameter", command_name: "xrGetInstanceProcAddr",
725 message: "Invalid Name pointer");
726 return XR_ERROR_VALIDATION_FAILURE;
727 }
728
729 // Initialize the function to nullptr in case it does not get caught in a known case
730 *function = nullptr;
731
732 LoaderInstance *loader_instance = nullptr;
733 if (instance == XR_NULL_HANDLE) {
734 // Null instance is allowed for a few specific API entry points, otherwise return error
735 if (strcmp(s1: name, s2: "xrCreateInstance") != 0 && strcmp(s1: name, s2: "xrEnumerateApiLayerProperties") != 0 &&
736 strcmp(s1: name, s2: "xrEnumerateInstanceExtensionProperties") != 0 && strcmp(s1: name, s2: "xrInitializeLoaderKHR") != 0) {
737 // TODO why is xrGetInstanceProcAddr not listed in here?
738 std::string error_str = "XR_NULL_HANDLE for instance but query for ";
739 error_str += name;
740 error_str += " requires a valid instance";
741 LoaderLogger::LogValidationErrorMessage(vuid: "VUID-xrGetInstanceProcAddr-instance-parameter", command_name: "xrGetInstanceProcAddr",
742 message: error_str);
743 return XR_ERROR_HANDLE_INVALID;
744 }
745 } else {
746 // non null instance passed in, it should be our current instance
747 XrResult result = ActiveLoaderInstance::Get(loader_instance: &loader_instance, log_function_name: "xrGetInstanceProcAddr");
748 if (XR_FAILED(result)) {
749 return result;
750 }
751 if (loader_instance->GetInstanceHandle() != instance) {
752 return XR_ERROR_HANDLE_INVALID;
753 }
754 }
755
756 // These functions must always go through the loader's implementation (trampoline).
757 if (strcmp(s1: name, s2: "xrGetInstanceProcAddr") == 0) {
758 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrGetInstanceProcAddr);
759 return XR_SUCCESS;
760 } else if (strcmp(s1: name, s2: "xrInitializeLoaderKHR") == 0) {
761#ifdef XR_KHR_LOADER_INIT_SUPPORT
762 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrInitializeLoaderKHR);
763 return XR_SUCCESS;
764#else
765 return XR_ERROR_FUNCTION_UNSUPPORTED;
766#endif
767 } else if (strcmp(s1: name, s2: "xrEnumerateApiLayerProperties") == 0) {
768 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateApiLayerProperties);
769 return XR_SUCCESS;
770 } else if (strcmp(s1: name, s2: "xrEnumerateInstanceExtensionProperties") == 0) {
771 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateInstanceExtensionProperties);
772 return XR_SUCCESS;
773 } else if (strcmp(s1: name, s2: "xrCreateInstance") == 0) {
774 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrCreateInstance);
775 return XR_SUCCESS;
776 } else if (strcmp(s1: name, s2: "xrDestroyInstance") == 0) {
777 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrDestroyInstance);
778 return XR_SUCCESS;
779 }
780
781 // XR_EXT_debug_utils is built into the loader and handled partly through the xrGetInstanceProcAddress terminator,
782 // but the check to see if the extension is enabled must be done here where ActiveLoaderInstance is safe to use.
783 if (*function == nullptr) {
784 if (strcmp(s1: name, s2: "xrCreateDebugUtilsMessengerEXT") == 0) {
785 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineCreateDebugUtilsMessengerEXT);
786 } else if (strcmp(s1: name, s2: "xrDestroyDebugUtilsMessengerEXT") == 0) {
787 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineDestroyDebugUtilsMessengerEXT);
788 } else if (strcmp(s1: name, s2: "xrSessionBeginDebugUtilsLabelRegionEXT") == 0) {
789 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT);
790 } else if (strcmp(s1: name, s2: "xrSessionEndDebugUtilsLabelRegionEXT") == 0) {
791 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT);
792 } else if (strcmp(s1: name, s2: "xrSessionInsertDebugUtilsLabelEXT") == 0) {
793 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionInsertDebugUtilsLabelEXT);
794 } else if (strcmp(s1: name, s2: "xrSetDebugUtilsObjectNameEXT") == 0) {
795 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSetDebugUtilsObjectNameEXT);
796 } else if (strcmp(s1: name, s2: "xrSubmitDebugUtilsMessageEXT") == 0) {
797 *function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSubmitDebugUtilsMessageEXT);
798 }
799
800 if (*function != nullptr && !loader_instance->ExtensionIsEnabled(extension: "XR_EXT_debug_utils")) {
801 // The function matches one of the XR_EXT_debug_utils functions but the extension is not enabled.
802 *function = nullptr;
803 return XR_ERROR_FUNCTION_UNSUPPORTED;
804 }
805 }
806
807 if (*function != nullptr) {
808 // The loader has a trampoline or implementation of this function.
809 return XR_SUCCESS;
810 }
811
812 // If the function is not supported by the loader, call down to the next layer.
813 return loader_instance->GetInstanceProcAddr(name, function);
814}
815XRLOADER_ABI_CATCH_FALLBACK
816
817// Exported loader functions
818//
819// The application might override these by exporting the same symbols and so we can't use these
820// symbols anywhere in the loader code, and instead the internal non exported functions that these
821// stubs call should be used internally.
822LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
823 uint32_t *propertyCountOutput,
824 XrApiLayerProperties *properties) {
825 return LoaderXrEnumerateApiLayerProperties(propertyCapacityInput, propertyCountOutput, properties);
826}
827
828LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(const char *layerName,
829 uint32_t propertyCapacityInput,
830 uint32_t *propertyCountOutput,
831 XrExtensionProperties *properties) {
832 return LoaderXrEnumerateInstanceExtensionProperties(layerName, propertyCapacityInput, propertyCountOutput, properties);
833}
834
835LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) {
836 return LoaderXrCreateInstance(info, instance);
837}
838
839LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) { return LoaderXrDestroyInstance(instance); }
840
841LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(XrInstance instance, const char *name,
842 PFN_xrVoidFunction *function) {
843 return LoaderXrGetInstanceProcAddr(instance, name, function);
844}
845
846#ifdef XR_KHR_LOADER_INIT_SUPPORT
847LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) {
848 return LoaderXrInitializeLoaderKHR(loaderInitInfo);
849}
850#endif
851

source code of qtquick3d/src/3rdparty/openxr/src/loader/loader_core.cpp