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