Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/openxr/src/loader/api_layer_interface.cpp
20837 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 Author: Mark Young <[email protected]>
8
//
9
10
#include "api_layer_interface.hpp"
11
12
#include "loader_init_data.hpp"
13
#include "loader_logger.hpp"
14
#include "loader_properties.hpp"
15
#include "loader_platform.hpp"
16
#include "manifest_file.hpp"
17
#include "platform_utils.hpp"
18
19
#include <openxr/openxr.h>
20
#include <openxr/openxr_loader_negotiation.h>
21
22
#include <algorithm>
23
#include <cstring>
24
#include <iterator>
25
#include <memory>
26
#include <sstream>
27
#include <string>
28
#include <utility>
29
#include <vector>
30
31
#define OPENXR_ENABLE_LAYERS_ENV_VAR "XR_ENABLE_API_LAYERS"
32
33
// Add any layers defined in the loader layer environment variable.
34
static void AddEnvironmentApiLayers(std::vector<std::string>& enabled_layers) {
35
std::string layers = LoaderProperty::Get(OPENXR_ENABLE_LAYERS_ENV_VAR);
36
37
std::size_t last_found = 0;
38
std::size_t found = layers.find_first_of(PATH_SEPARATOR);
39
std::string cur_search;
40
41
// Handle any path listings in the string (separated by the appropriate path separator)
42
while (found != std::string::npos) {
43
cur_search = layers.substr(last_found, found - last_found);
44
enabled_layers.push_back(cur_search);
45
last_found = found + 1;
46
found = layers.find_first_of(PATH_SEPARATOR, last_found);
47
}
48
49
// If there's something remaining in the string, copy it over
50
if (last_found < layers.size()) {
51
cur_search = layers.substr(last_found);
52
enabled_layers.push_back(cur_search);
53
}
54
}
55
56
XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count,
57
uint32_t* outgoing_count, XrApiLayerProperties* api_layer_properties) {
58
std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;
59
uint32_t manifest_count = 0;
60
// Validate props struct before proceeding
61
if (0 < incoming_count && nullptr != api_layer_properties) {
62
for (uint32_t i = 0; i < incoming_count; i++) {
63
if (XR_TYPE_API_LAYER_PROPERTIES != api_layer_properties[i].type) {
64
LoaderLogger::LogErrorMessage(openxr_command,
65
"VUID-XrApiLayerProperties-type-type: unknown type in api_layer_properties");
66
return XR_ERROR_VALIDATION_FAILURE;
67
}
68
}
69
}
70
71
// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,
72
// and the function sets elementCountOutput." - 2.11
73
if (nullptr == outgoing_count) {
74
return XR_ERROR_VALIDATION_FAILURE;
75
}
76
77
// Find any implicit layers which we may need to report information for.
78
XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
79
if (XR_SUCCEEDED(result)) {
80
// Find any explicit layers which we may need to report information for.
81
result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);
82
}
83
if (XR_FAILED(result)) {
84
LoaderLogger::LogErrorMessage(openxr_command,
85
"ApiLayerInterface::GetApiLayerProperties - failed searching for API layer manifest files");
86
return result;
87
}
88
89
// check for potential overflow before static_cast<uint32_t>
90
if (manifest_files.size() >= UINT32_MAX) {
91
LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::GetApiLayerProperties - too many API layers found");
92
return XR_ERROR_RUNTIME_FAILURE;
93
}
94
95
manifest_count = static_cast<uint32_t>(manifest_files.size());
96
if (nullptr == outgoing_count) {
97
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
98
"VUID-xrEnumerateApiLayerProperties-propertyCountOutput-parameter: null propertyCountOutput");
99
return XR_ERROR_VALIDATION_FAILURE;
100
}
101
102
*outgoing_count = manifest_count;
103
if (0 == incoming_count) {
104
// capacity check only
105
return XR_SUCCESS;
106
}
107
if (nullptr == api_layer_properties) {
108
// incoming_count is not 0 BUT the api_layer_properties is NULL
109
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
110
"VUID-xrEnumerateApiLayerProperties-properties-parameter: non-zero capacity but null array");
111
return XR_ERROR_VALIDATION_FAILURE;
112
}
113
if (incoming_count < manifest_count) {
114
LoaderLogger::LogErrorMessage(
115
"xrEnumerateInstanceExtensionProperties",
116
"VUID-xrEnumerateApiLayerProperties-propertyCapacityInput-parameter: insufficient space in array");
117
return XR_ERROR_SIZE_INSUFFICIENT;
118
}
119
120
for (uint32_t prop = 0; prop < incoming_count && prop < manifest_count; ++prop) {
121
manifest_files[prop]->PopulateApiLayerProperties(api_layer_properties[prop]);
122
}
123
return XR_SUCCESS;
124
}
125
126
XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,
127
std::vector<XrExtensionProperties>& extension_properties) {
128
std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;
129
130
// If a layer name is supplied, only use the information out of that one layer
131
if (nullptr != layer_name && 0 != strlen(layer_name)) {
132
XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
133
if (XR_SUCCEEDED(result)) {
134
// Find any explicit layers which we may need to report information for.
135
result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);
136
if (XR_FAILED(result)) {
137
LoaderLogger::LogErrorMessage(
138
openxr_command,
139
"ApiLayerInterface::GetInstanceExtensionProperties - failed searching for API layer manifest files");
140
return result;
141
}
142
143
bool found = false;
144
size_t num_files = manifest_files.size();
145
for (size_t man_file = 0; man_file < num_files; ++man_file) {
146
// If a layer with the provided name exists, get it's instance extension information.
147
if (manifest_files[man_file]->LayerName() == layer_name) {
148
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
149
found = true;
150
break;
151
}
152
}
153
154
// If nothing found, report 0
155
if (!found) {
156
return XR_ERROR_API_LAYER_NOT_PRESENT;
157
}
158
}
159
// Otherwise, we want to add only implicit API layers and explicit API layers enabled using the environment variables
160
} else {
161
XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
162
if (XR_SUCCEEDED(result)) {
163
// Find any environmentally enabled explicit layers. If they're present, treat them like implicit layers
164
// since we know that they're going to be enabled.
165
std::vector<std::string> env_enabled_layers;
166
AddEnvironmentApiLayers(env_enabled_layers);
167
if (!env_enabled_layers.empty()) {
168
std::vector<std::unique_ptr<ApiLayerManifestFile>> exp_layer_man_files = {};
169
result =
170
ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files);
171
if (XR_SUCCEEDED(result)) {
172
for (auto& exp_layer_man_file : exp_layer_man_files) {
173
for (std::string& enabled_layer : env_enabled_layers) {
174
// If this is an enabled layer, transfer it over to the manifest list.
175
if (enabled_layer == exp_layer_man_file->LayerName()) {
176
manifest_files.push_back(std::move(exp_layer_man_file));
177
break;
178
}
179
}
180
}
181
}
182
}
183
}
184
185
// Grab the layer instance extensions information
186
size_t num_files = manifest_files.size();
187
for (size_t man_file = 0; man_file < num_files; ++man_file) {
188
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
189
}
190
}
191
return XR_SUCCESS;
192
}
193
194
XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,
195
const char* const* enabled_api_layer_names,
196
std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces) {
197
XrResult last_error = XR_SUCCESS;
198
std::unordered_set<std::string> layers_already_found;
199
200
bool any_loaded = false;
201
std::vector<std::unique_ptr<ApiLayerManifestFile>> enabled_layer_manifest_files_in_init_order = {};
202
203
// Find any implicit layers.
204
XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER,
205
enabled_layer_manifest_files_in_init_order);
206
207
for (const auto& enabled_layer_manifest_file : enabled_layer_manifest_files_in_init_order) {
208
layers_already_found.insert(enabled_layer_manifest_file->LayerName());
209
}
210
211
// Find any explicit layers.
212
std::vector<std::unique_ptr<ApiLayerManifestFile>> explicit_layer_manifest_files = {};
213
214
if (XR_SUCCEEDED(result)) {
215
result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER,
216
explicit_layer_manifest_files);
217
}
218
219
bool found_all_layers = true;
220
221
if (XR_SUCCEEDED(result)) {
222
// Put all explicit and then xrCreateInstance enabled layers into a string vector
223
224
std::vector<std::string> enabled_explicit_api_layer_names = {};
225
226
AddEnvironmentApiLayers(enabled_explicit_api_layer_names);
227
228
if (enabled_api_layer_count > 0) {
229
if (nullptr == enabled_api_layer_names) {
230
LoaderLogger::LogErrorMessage(
231
"xrCreateInstance",
232
"VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter: enabledApiLayerCount is non-0 but array is NULL");
233
LoaderLogger::LogErrorMessage(
234
"xrCreateInstance", "VUID-xrCreateInstance-info-parameter: something wrong with XrInstanceCreateInfo contents");
235
return XR_ERROR_VALIDATION_FAILURE;
236
}
237
238
std::copy(enabled_api_layer_names, enabled_api_layer_names + enabled_api_layer_count,
239
std::back_inserter(enabled_explicit_api_layer_names));
240
}
241
242
// add explicit layers to list of layers to enable
243
for (const auto& layer_name : enabled_explicit_api_layer_names) {
244
bool found_this_layer = false;
245
246
if (layers_already_found.count(layer_name) > 0) {
247
found_this_layer = true;
248
} else {
249
for (auto it = explicit_layer_manifest_files.begin(); it != explicit_layer_manifest_files.end();) {
250
bool erased_layer_manifest_file = false;
251
252
if (layer_name == (*it)->LayerName()) {
253
found_this_layer = true;
254
layers_already_found.insert(layer_name);
255
enabled_layer_manifest_files_in_init_order.push_back(std::move(*it));
256
it = explicit_layer_manifest_files.erase(it);
257
erased_layer_manifest_file = true;
258
}
259
260
if (!erased_layer_manifest_file) {
261
it++;
262
}
263
}
264
}
265
266
// If even one of the layers wasn't found, we want to return an error
267
if (!found_this_layer) {
268
found_all_layers = false;
269
std::string error_message = "ApiLayerInterface::LoadApiLayers - failed to find layer ";
270
error_message += layer_name;
271
LoaderLogger::LogErrorMessage(openxr_command, error_message);
272
}
273
}
274
}
275
276
for (std::unique_ptr<ApiLayerManifestFile>& manifest_file : enabled_layer_manifest_files_in_init_order) {
277
LoaderPlatformLibraryHandle layer_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());
278
if (nullptr == layer_library) {
279
if (!any_loaded) {
280
last_error = XR_ERROR_FILE_ACCESS_ERROR;
281
}
282
std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());
283
std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";
284
warning_message += manifest_file->LayerName();
285
warning_message += ", failed to load with message \"";
286
warning_message += library_message;
287
warning_message += "\"";
288
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
289
continue;
290
}
291
#if defined(XR_HAS_REQUIRED_PLATFORM_LOADER_INIT_STRUCT) // Cannot proceed without mandatory xrInitializeLoaderKHR call.
292
if (!LoaderInitData::instance().initialized()) {
293
LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::LoadApiLayers skipping manifest file " +
294
manifest_file->Filename() +
295
" because xrInitializeLoaderKHR was not yet called.");
296
297
LoaderPlatformLibraryClose(layer_library);
298
return XR_ERROR_VALIDATION_FAILURE;
299
}
300
#endif
301
302
bool forwardedInitLoader = false;
303
if (LoaderInitData::instance().getPlatformParam() != nullptr) {
304
// If we have xrInitializeLoaderKHR exposed as an export, forward call to it.
305
const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR");
306
auto initLoader =
307
reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(layer_library, function_name));
308
if (initLoader != nullptr) {
309
// we found the entry point one way or another.
310
LoaderLogger::LogInfoMessage(openxr_command,
311
"ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer "
312
"before calling xrNegotiateLoaderApiLayerInterface.");
313
XrResult res = initLoader(LoaderInitData::instance().getPlatformParam());
314
if (!XR_SUCCEEDED(res)) {
315
LoaderLogger::LogErrorMessage(
316
openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed.");
317
318
LoaderPlatformLibraryClose(layer_library);
319
return res;
320
}
321
forwardedInitLoader = true;
322
}
323
}
324
325
// Get and settle on an layer interface version (using any provided name if required).
326
std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface");
327
auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderApiLayerInterface>(
328
LoaderPlatformLibraryGetProcAddr(layer_library, function_name));
329
330
if (nullptr == negotiate) {
331
std::ostringstream oss;
332
oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()
333
<< " because negotiation function " << function_name << " was not found";
334
LoaderLogger::LogErrorMessage(openxr_command, oss.str());
335
LoaderPlatformLibraryClose(layer_library);
336
last_error = XR_ERROR_API_LAYER_NOT_PRESENT;
337
continue;
338
}
339
340
// Loader info for negotiation
341
XrNegotiateLoaderInfo loader_info = {};
342
loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;
343
loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;
344
loader_info.structSize = sizeof(XrNegotiateLoaderInfo);
345
loader_info.minInterfaceVersion = 1;
346
loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;
347
loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);
348
loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.
349
350
// Set up the layer return structure
351
XrNegotiateApiLayerRequest api_layer_info = {};
352
api_layer_info.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST;
353
api_layer_info.structVersion = XR_API_LAYER_INFO_STRUCT_VERSION;
354
api_layer_info.structSize = sizeof(XrNegotiateApiLayerRequest);
355
356
XrResult res = negotiate(&loader_info, manifest_file->LayerName().c_str(), &api_layer_info);
357
// If we supposedly succeeded, but got a nullptr for getInstanceProcAddr
358
// then something still went wrong, so return with an error.
359
if (XR_SUCCEEDED(res) && nullptr == api_layer_info.getInstanceProcAddr) {
360
std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";
361
warning_message += manifest_file->LayerName();
362
warning_message += ", negotiation did not return a valid getInstanceProcAddr";
363
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
364
res = XR_ERROR_FILE_CONTENTS_INVALID;
365
}
366
367
if (XR_SUCCEEDED(res) && !forwardedInitLoader && LoaderInitData::instance().getPlatformParam() != nullptr) {
368
// Forward initialize loader call, where possible and if we did not do so before.
369
PFN_xrVoidFunction initializeVoid = nullptr;
370
PFN_xrInitializeLoaderKHR initialize = nullptr;
371
372
// Now we may try asking xrGetInstanceProcAddr on the API layer
373
if (XR_SUCCEEDED(api_layer_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) {
374
if (initializeVoid == nullptr) {
375
LoaderLogger::LogErrorMessage(openxr_command,
376
"ApiLayerInterface::LoadApiLayers got success from xrGetInstanceProcAddr "
377
"for xrInitializeLoaderKHR, but output a null pointer.");
378
res = XR_ERROR_RUNTIME_FAILURE;
379
} else {
380
initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid);
381
}
382
}
383
if (initialize != nullptr) {
384
// we found the entry point one way or another.
385
LoaderLogger::LogInfoMessage(openxr_command,
386
"ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer "
387
"after calling xrNegotiateLoaderApiLayerInterface.");
388
res = initialize(LoaderInitData::instance().getPlatformParam());
389
if (!XR_SUCCEEDED(res)) {
390
LoaderLogger::LogErrorMessage(
391
openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed.");
392
}
393
}
394
}
395
396
if (XR_FAILED(res)) {
397
if (!any_loaded) {
398
last_error = res;
399
}
400
std::ostringstream oss;
401
oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()
402
<< " due to failed negotiation with error " << res;
403
LoaderLogger::LogWarningMessage(openxr_command, oss.str());
404
LoaderPlatformLibraryClose(layer_library);
405
continue;
406
}
407
408
{
409
std::ostringstream oss;
410
oss << "ApiLayerInterface::LoadApiLayers succeeded loading layer " << manifest_file->LayerName()
411
<< " using interface version " << api_layer_info.layerInterfaceVersion << " and OpenXR API version "
412
<< XR_VERSION_MAJOR(api_layer_info.layerApiVersion) << "." << XR_VERSION_MINOR(api_layer_info.layerApiVersion);
413
LoaderLogger::LogInfoMessage(openxr_command, oss.str());
414
}
415
416
// Grab the list of extensions this layer supports for easy filtering after the
417
// xrCreateInstance call
418
std::vector<std::string> supported_extensions;
419
std::vector<XrExtensionProperties> extension_properties;
420
manifest_file->GetInstanceExtensionProperties(extension_properties);
421
supported_extensions.reserve(extension_properties.size());
422
for (XrExtensionProperties& ext_prop : extension_properties) {
423
supported_extensions.emplace_back(ext_prop.extensionName);
424
}
425
426
// Add this API layer to the vector
427
api_layer_interfaces.emplace_back(new ApiLayerInterface(manifest_file->LayerName(), layer_library, supported_extensions,
428
api_layer_info.getInstanceProcAddr,
429
api_layer_info.createApiLayerInstance));
430
431
// If we load one, clear all errors.
432
any_loaded = true;
433
last_error = XR_SUCCESS;
434
}
435
436
// Set error here to preserve prior error behavior
437
if (!found_all_layers) {
438
last_error = XR_ERROR_API_LAYER_NOT_PRESENT;
439
}
440
441
// If we failed catastrophically for some reason, clean up everything.
442
if (XR_FAILED(last_error)) {
443
api_layer_interfaces.clear();
444
}
445
446
return last_error;
447
}
448
449
ApiLayerInterface::ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,
450
std::vector<std::string>& supported_extensions,
451
PFN_xrGetInstanceProcAddr get_instance_proc_addr,
452
PFN_xrCreateApiLayerInstance create_api_layer_instance)
453
: _layer_name(layer_name),
454
_layer_library(layer_library),
455
_get_instance_proc_addr(get_instance_proc_addr),
456
_create_api_layer_instance(create_api_layer_instance),
457
_supported_extensions(supported_extensions) {}
458
459
ApiLayerInterface::~ApiLayerInterface() {
460
std::string info_message = "ApiLayerInterface being destroyed for layer ";
461
info_message += _layer_name;
462
LoaderLogger::LogInfoMessage("", info_message);
463
LoaderPlatformLibraryClose(_layer_library);
464
}
465
466
bool ApiLayerInterface::SupportsExtension(const std::string& extension_name) const {
467
bool found_prop = false;
468
for (const std::string& supported_extension : _supported_extensions) {
469
if (supported_extension == extension_name) {
470
found_prop = true;
471
break;
472
}
473
}
474
return found_prop;
475
}
476
477