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