Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/openxr/src/loader/loader_core.cpp
9917 views
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 <[email protected]>, Dave Houlton <[email protected]>
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.
39
static std::mutex &GetGlobalLoaderMutex() {
40
static std::mutex loader_mutex;
41
return loader_mutex;
42
}
43
44
// Prototypes for the debug utils calls used internally.
45
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineCreateDebugUtilsMessengerEXT(
46
XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, XrDebugUtilsMessengerEXT *messenger);
47
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger);
48
49
// Terminal functions needed by xrCreateInstance.
50
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance, const char *, PFN_xrVoidFunction *);
51
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *, XrInstance *);
52
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *,
53
const struct XrApiLayerCreateInfo *, XrInstance *);
54
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance, const XrDebugUtilsObjectNameInfoEXT *);
55
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance,
56
const XrDebugUtilsMessengerCreateInfoEXT *,
57
XrDebugUtilsMessengerEXT *);
58
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT);
59
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
60
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
61
const XrDebugUtilsMessengerCallbackDataEXT *callbackData);
62
static 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.
67
template <size_t max_length>
68
inline 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.
79
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY {
80
LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline");
81
return InitializeLoaderInitData(loaderInitInfo);
82
}
83
XRLOADER_ABI_CATCH_FALLBACK
84
#endif
85
86
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
87
uint32_t *propertyCountOutput,
88
XrApiLayerProperties *properties) XRLOADER_ABI_TRY {
89
LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties", "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("xrEnumerateApiLayerProperties", propertyCapacityInput,
95
propertyCountOutput, properties);
96
if (XR_FAILED(result)) {
97
LoaderLogger::LogErrorMessage("xrEnumerateApiLayerProperties", "Failed ApiLayerInterface::GetApiLayerProperties");
98
}
99
100
return result;
101
}
102
XRLOADER_ABI_CATCH_FALLBACK
103
104
static XRAPI_ATTR XrResult XRAPI_CALL
105
LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput,
106
XrExtensionProperties *properties) XRLOADER_ABI_TRY {
107
bool just_layer_properties = false;
108
LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "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(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("xrEnumerateInstanceExtensionProperties", 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("xrEnumerateInstanceExtensionProperties");
134
if (XR_SUCCEEDED(result)) {
135
RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties);
136
} else {
137
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
138
"Failed to find default runtime with RuntimeInterface::LoadRuntime()");
139
}
140
}
141
}
142
143
if (XR_FAILED(result)) {
144
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", "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(existing_prop.extensionName, 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(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-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter",
177
"xrEnumerateInstanceExtensionProperties", "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-XrExtensionProperties-type-type",
191
"xrEnumerateInstanceExtensionProperties", "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-xrEnumerateInstanceExtensionProperties-properties-parameter",
199
"xrEnumerateInstanceExtensionProperties", "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("xrEnumerateInstanceExtensionProperties", "Completed loader trampoline");
210
return XR_SUCCESS;
211
}
212
XRLOADER_ABI_CATCH_FALLBACK
213
214
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCreateInfo *info,
215
XrInstance *instance) XRLOADER_ABI_TRY {
216
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader trampoline");
217
if (nullptr == info) {
218
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance", "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("xrCreateInstance", oss.str());
232
return XR_ERROR_API_VERSION_UNSUPPORTED;
233
}
234
235
if (nullptr == instance) {
236
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-instance-parameter", "xrCreateInstance", "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("xrCreateInstance", "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("xrCreateInstance");
260
if (XR_FAILED(result)) {
261
LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading runtime information");
262
} else {
263
// Load the appropriate layers
264
result = ApiLayerInterface::LoadApiLayers("xrCreateInstance", info->enabledApiLayerCount, info->enabledApiLayerNames,
265
api_layer_interfaces);
266
if (XR_FAILED(result)) {
267
LoaderLogger::LogErrorMessage("xrCreateInstance", "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(LoaderXrTermGetInstanceProcAddr, LoaderXrTermCreateInstance,
277
LoaderXrTermCreateApiLayerInstance, std::move(api_layer_interfaces), info,
278
&owned_loader_instance);
279
if (XR_SUCCEEDED(result)) {
280
loader_instance = owned_loader_instance.get();
281
result = ActiveLoaderInstance::Set(std::move(owned_loader_instance), "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("xrCreateInstance", "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain.");
292
dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);
293
XrDebugUtilsMessengerEXT messenger;
294
result = LoaderTrampolineCreateDebugUtilsMessengerEXT(loader_instance->GetInstanceHandle(), dbg_utils_create_info,
295
&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("xrCreateInstance");
310
LoaderLogger::LogErrorMessage("xrCreateInstance", "xrCreateInstance failed");
311
} else {
312
*instance = loader_instance->GetInstanceHandle();
313
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader trampoline");
314
}
315
316
return result;
317
}
318
XRLOADER_ABI_CATCH_FALLBACK
319
320
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
321
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "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("xrDestroyInstance", "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, "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("xrDestroyInstance", "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("xrDestroyInstance", "Completed loader trampoline");
355
356
// Finally, unload the runtime if necessary
357
RuntimeInterface::UnloadRuntime("xrDestroyInstance");
358
359
return XR_SUCCESS;
360
}
361
XRLOADER_ABI_CATCH_FALLBACK
362
363
// ---- Core 1.0 manual loader terminator functions
364
365
// Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid.
366
static XrResult ValidateApplicationInfo(const XrApplicationInfo &info) {
367
if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(info.applicationName)) {
368
LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-applicationName-parameter", "xrCreateInstance",
369
"application name missing NULL terminator.");
370
return XR_ERROR_NAME_INVALID;
371
}
372
if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(info.engineName)) {
373
LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-engineName-parameter", "xrCreateInstance",
374
"engine name missing NULL terminator.");
375
return XR_ERROR_NAME_INVALID;
376
}
377
if (strlen(info.applicationName) == 0) {
378
LoaderLogger::LogErrorMessage("xrCreateInstance",
379
"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
386
static XrResult ValidateInstanceCreateInfo(const XrInstanceCreateInfo *info) {
387
// Should have a valid 'type'
388
if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) {
389
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-type-type", "xrCreateInstance",
390
"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-XrInstanceCreateInfo-createFlags-zerobitmask", "xrCreateInstance",
396
"flags must be 0.");
397
return XR_ERROR_VALIDATION_FAILURE;
398
}
399
// ApplicationInfo struct must be valid
400
XrResult result = ValidateApplicationInfo(info->applicationInfo);
401
if (XR_FAILED(result)) {
402
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-applicationInfo-parameter", "xrCreateInstance",
403
"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-XrInstanceCreateInfo-enabledExtensionNames-parameter", "xrCreateInstance",
409
"enabledExtensionCount is non-0 but array is NULL");
410
return XR_ERROR_VALIDATION_FAILURE;
411
}
412
return XR_SUCCESS;
413
}
414
415
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *createInfo,
416
XrInstance *instance) XRLOADER_ABI_TRY {
417
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader terminator");
418
XrResult result = ValidateInstanceCreateInfo(createInfo);
419
if (XR_FAILED(result)) {
420
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance",
421
"something wrong with XrInstanceCreateInfo contents");
422
return result;
423
}
424
result = RuntimeInterface::GetRuntime().CreateInstance(createInfo, instance);
425
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader terminator");
426
return result;
427
}
428
XRLOADER_ABI_CATCH_FALLBACK
429
430
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info,
431
const struct XrApiLayerCreateInfo * /*apiLayerInfo*/,
432
XrInstance *instance) {
433
return LoaderXrTermCreateInstance(info, instance);
434
}
435
436
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
437
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader terminator");
438
LoaderLogger::GetInstance().RemoveLogRecordersForXrInstance(instance);
439
XrResult result = RuntimeInterface::GetRuntime().DestroyInstance(instance);
440
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader terminator");
441
return result;
442
}
443
XRLOADER_ABI_CATCH_FALLBACK
444
445
static 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(name, "xrGetInstanceProcAddr")) {
455
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermGetInstanceProcAddr);
456
} else if (0 == strcmp(name, "xrCreateInstance")) {
457
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateInstance);
458
} else if (0 == strcmp(name, "xrDestroyInstance")) {
459
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyInstance);
460
} else if (0 == strcmp(name, "xrSetDebugUtilsObjectNameEXT")) {
461
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSetDebugUtilsObjectNameEXT);
462
} else if (0 == strcmp(name, "xrCreateDebugUtilsMessengerEXT")) {
463
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateDebugUtilsMessengerEXT);
464
} else if (0 == strcmp(name, "xrDestroyDebugUtilsMessengerEXT")) {
465
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyDebugUtilsMessengerEXT);
466
} else if (0 == strcmp(name, "xrSubmitDebugUtilsMessageEXT")) {
467
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSubmitDebugUtilsMessageEXT);
468
} else if (0 == strcmp(name, "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
}
480
XRLOADER_ABI_CATCH_FALLBACK
481
482
// ---- Extension manual loader trampoline functions
483
484
static XRAPI_ATTR XrResult XRAPI_CALL
485
LoaderTrampolineCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
486
XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
487
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader trampoline");
488
489
if (instance == XR_NULL_HANDLE) {
490
LoaderLogger::LogErrorMessage("xrCreateDebugUtilsMessengerEXT", "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, "xrCreateDebugUtilsMessengerEXT");
496
if (XR_FAILED(result)) {
497
return result;
498
}
499
500
result = loader_instance->DispatchTable()->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
501
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader trampoline");
502
return result;
503
}
504
XRLOADER_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("xrDestroyDebugUtilsMessengerEXT", "Entering loader trampoline");
511
512
if (messenger == XR_NULL_HANDLE) {
513
LoaderLogger::LogErrorMessage("xrDestroyDebugUtilsMessengerEXT", "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, "xrDestroyDebugUtilsMessengerEXT");
519
if (XR_FAILED(result)) {
520
return result;
521
}
522
523
result = loader_instance->DispatchTable()->DestroyDebugUtilsMessengerEXT(messenger);
524
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader trampoline");
525
return result;
526
}
527
XRLOADER_ABI_CATCH_FALLBACK
528
529
static XRAPI_ATTR XrResult XRAPI_CALL
530
LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
531
if (session == XR_NULL_HANDLE) {
532
LoaderLogger::LogErrorMessage("xrSessionBeginDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");
533
return XR_ERROR_HANDLE_INVALID;
534
}
535
536
if (nullptr == labelInfo) {
537
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter",
538
"xrSessionBeginDebugUtilsLabelRegionEXT", "labelInfo must be non-NULL",
539
{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, "xrSessionBeginDebugUtilsLabelRegionEXT");
545
if (XR_FAILED(result)) {
546
return result;
547
}
548
LoaderLogger::GetInstance().BeginLabelRegion(session, 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
}
555
XRLOADER_ABI_CATCH_FALLBACK
556
557
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY {
558
if (session == XR_NULL_HANDLE) {
559
LoaderLogger::LogErrorMessage("xrSessionEndDebugUtilsLabelRegionEXT", "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, "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
}
576
XRLOADER_ABI_CATCH_FALLBACK
577
578
static XRAPI_ATTR XrResult XRAPI_CALL
579
LoaderTrampolineSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
580
if (session == XR_NULL_HANDLE) {
581
LoaderLogger::LogErrorMessage("xrSessionInsertDebugUtilsLabelEXT", "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, "xrSessionInsertDebugUtilsLabelEXT");
587
if (XR_FAILED(result)) {
588
return result;
589
}
590
591
if (nullptr == labelInfo) {
592
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter",
593
"xrSessionInsertDebugUtilsLabelEXT", "labelInfo must be non-NULL",
594
{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
595
return XR_ERROR_VALIDATION_FAILURE;
596
}
597
598
LoaderLogger::GetInstance().InsertLabel(session, 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
}
607
XRLOADER_ABI_CATCH_FALLBACK
608
609
// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.
610
static XRAPI_ATTR XrResult XRAPI_CALL
611
LoaderTrampolineSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
612
LoaderInstance *loader_instance;
613
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSetDebugUtilsObjectNameEXT");
614
if (XR_SUCCEEDED(result)) {
615
result = loader_instance->DispatchTable()->SetDebugUtilsObjectNameEXT(instance, nameInfo);
616
}
617
return result;
618
}
619
XRLOADER_ABI_CATCH_FALLBACK
620
621
// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.
622
static 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, "xrSubmitDebugUtilsMessageEXT");
627
if (XR_SUCCEEDED(result)) {
628
result =
629
loader_instance->DispatchTable()->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);
630
}
631
return result;
632
}
633
XRLOADER_ABI_CATCH_FALLBACK
634
635
// ---- Extension manual loader terminator functions
636
637
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance,
638
const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
639
XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
640
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader terminator");
641
if (nullptr == messenger) {
642
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter",
643
"xrCreateDebugUtilsMessengerEXT", "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, MakeDebugUtilsLoaderLogRecorder(createInfo, *messenger));
658
RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, *messenger);
659
}
660
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader terminator");
661
return result;
662
}
663
XRLOADER_ABI_CATCH_FALLBACK
664
665
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
666
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader terminator");
667
const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger);
668
XrResult result = XR_SUCCESS;
669
LoaderLogger::GetInstance().RemoveLogRecorder(MakeHandleGeneric(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(messenger)));
677
}
678
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader terminator");
679
return result;
680
}
681
XRLOADER_ABI_CATCH_FALLBACK
682
683
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
684
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
685
const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {
686
LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "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(messageSeverity, messageTypes, callbackData);
695
}
696
LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Completed loader terminator");
697
return result;
698
}
699
XRLOADER_ABI_CATCH_FALLBACK
700
701
XRAPI_ATTR XrResult XRAPI_CALL
702
LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
703
LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "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(nameInfo->objectHandle, nameInfo->objectType, nameInfo->objectName);
710
LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Completed loader terminator");
711
return result;
712
}
713
XRLOADER_ABI_CATCH_FALLBACK
714
715
XRAPI_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-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",
719
"Invalid Function pointer");
720
return XR_ERROR_VALIDATION_FAILURE;
721
}
722
723
if (nullptr == name) {
724
LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",
725
"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(name, "xrCreateInstance") != 0 && strcmp(name, "xrEnumerateApiLayerProperties") != 0 &&
736
strcmp(name, "xrEnumerateInstanceExtensionProperties") != 0 && strcmp(name, "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-xrGetInstanceProcAddr-instance-parameter", "xrGetInstanceProcAddr",
742
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, "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(name, "xrGetInstanceProcAddr") == 0) {
758
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrGetInstanceProcAddr);
759
return XR_SUCCESS;
760
} else if (strcmp(name, "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(name, "xrEnumerateApiLayerProperties") == 0) {
768
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateApiLayerProperties);
769
return XR_SUCCESS;
770
} else if (strcmp(name, "xrEnumerateInstanceExtensionProperties") == 0) {
771
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateInstanceExtensionProperties);
772
return XR_SUCCESS;
773
} else if (strcmp(name, "xrCreateInstance") == 0) {
774
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrCreateInstance);
775
return XR_SUCCESS;
776
} else if (strcmp(name, "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(name, "xrCreateDebugUtilsMessengerEXT") == 0) {
785
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineCreateDebugUtilsMessengerEXT);
786
} else if (strcmp(name, "xrDestroyDebugUtilsMessengerEXT") == 0) {
787
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineDestroyDebugUtilsMessengerEXT);
788
} else if (strcmp(name, "xrSessionBeginDebugUtilsLabelRegionEXT") == 0) {
789
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT);
790
} else if (strcmp(name, "xrSessionEndDebugUtilsLabelRegionEXT") == 0) {
791
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT);
792
} else if (strcmp(name, "xrSessionInsertDebugUtilsLabelEXT") == 0) {
793
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionInsertDebugUtilsLabelEXT);
794
} else if (strcmp(name, "xrSetDebugUtilsObjectNameEXT") == 0) {
795
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSetDebugUtilsObjectNameEXT);
796
} else if (strcmp(name, "xrSubmitDebugUtilsMessageEXT") == 0) {
797
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSubmitDebugUtilsMessageEXT);
798
}
799
800
if (*function != nullptr && !loader_instance->ExtensionIsEnabled("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
}
815
XRLOADER_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.
822
LOADER_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
828
LOADER_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
835
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) {
836
return LoaderXrCreateInstance(info, instance);
837
}
838
839
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) { return LoaderXrDestroyInstance(instance); }
840
841
LOADER_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
847
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) {
848
return LoaderXrInitializeLoaderKHR(loaderInitInfo);
849
}
850
#endif
851
852