Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/openxr/src/loader/loader_instance.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
#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 "loader_instance.hpp"
15
16
#include "api_layer_interface.hpp"
17
#include "hex_and_handles.h"
18
#include "loader_logger.hpp"
19
#include "runtime_interface.hpp"
20
#include "xr_generated_dispatch_table_core.h"
21
#include "xr_generated_loader.hpp"
22
23
#include <openxr/openxr.h>
24
#include <openxr/openxr_loader_negotiation.h>
25
26
#include <cstring>
27
#include <memory>
28
#include <sstream>
29
#include <string>
30
#include <utility>
31
#include <vector>
32
33
namespace {
34
std::unique_ptr<LoaderInstance>& GetSetCurrentLoaderInstance() {
35
static std::unique_ptr<LoaderInstance> current_loader_instance;
36
return current_loader_instance;
37
}
38
} // namespace
39
40
namespace ActiveLoaderInstance {
41
XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name) {
42
if (GetSetCurrentLoaderInstance() != nullptr) {
43
LoaderLogger::LogErrorMessage(log_function_name, "Active XrInstance handle already exists");
44
return XR_ERROR_LIMIT_REACHED;
45
}
46
47
GetSetCurrentLoaderInstance() = std::move(loader_instance);
48
return XR_SUCCESS;
49
}
50
51
XrResult Get(LoaderInstance** loader_instance, const char* log_function_name) {
52
*loader_instance = GetSetCurrentLoaderInstance().get();
53
if (*loader_instance == nullptr) {
54
LoaderLogger::LogErrorMessage(log_function_name, "No active XrInstance handle.");
55
return XR_ERROR_HANDLE_INVALID;
56
}
57
58
return XR_SUCCESS;
59
}
60
61
bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; }
62
63
void Remove() { GetSetCurrentLoaderInstance().reset(nullptr); }
64
} // namespace ActiveLoaderInstance
65
66
// Extensions that are supported by the loader, but may not be supported
67
// the the runtime.
68
const std::array<XrExtensionProperties, 1>& LoaderInstance::LoaderSpecificExtensions() {
69
static const std::array<XrExtensionProperties, 1> extensions = {XrExtensionProperties{
70
XR_TYPE_EXTENSION_PROPERTIES, nullptr, XR_EXT_DEBUG_UTILS_EXTENSION_NAME, XR_EXT_debug_utils_SPEC_VERSION}};
71
return extensions;
72
}
73
74
namespace {
75
class InstanceCreateInfoManager {
76
public:
77
explicit InstanceCreateInfoManager(const XrInstanceCreateInfo* info) : original_create_info(info), modified_create_info(*info) {
78
Reset();
79
}
80
81
// Reset the "modified" state to match the original state.
82
void Reset() {
83
enabled_extensions_cstr.clear();
84
enabled_extensions_cstr.reserve(original_create_info->enabledExtensionCount);
85
86
for (uint32_t i = 0; i < original_create_info->enabledExtensionCount; ++i) {
87
enabled_extensions_cstr.push_back(original_create_info->enabledExtensionNames[i]);
88
}
89
Update();
90
}
91
92
// Remove extensions named in the parameter and return a pointer to the current state.
93
const XrInstanceCreateInfo* FilterOutExtensions(const std::vector<const char*>& extensions_to_skip) {
94
if (enabled_extensions_cstr.empty()) {
95
return Get();
96
}
97
if (extensions_to_skip.empty()) {
98
return Get();
99
}
100
for (auto& ext : extensions_to_skip) {
101
FilterOutExtension(ext);
102
}
103
return Update();
104
}
105
// Remove the extension named in the parameter and return a pointer to the current state.
106
const XrInstanceCreateInfo* FilterOutExtension(const char* extension_to_skip) {
107
if (enabled_extensions_cstr.empty()) {
108
return &modified_create_info;
109
}
110
auto b = enabled_extensions_cstr.begin();
111
auto e = enabled_extensions_cstr.end();
112
auto it = std::find_if(b, e, [&](const char* extension) { return strcmp(extension_to_skip, extension) == 0; });
113
if (it != e) {
114
// Just that one element goes away
115
enabled_extensions_cstr.erase(it);
116
}
117
return Update();
118
}
119
120
// Get the current modified XrInstanceCreateInfo
121
const XrInstanceCreateInfo* Get() const { return &modified_create_info; }
122
123
private:
124
const XrInstanceCreateInfo* Update() {
125
modified_create_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions_cstr.size());
126
modified_create_info.enabledExtensionNames = enabled_extensions_cstr.empty() ? nullptr : enabled_extensions_cstr.data();
127
return &modified_create_info;
128
}
129
const XrInstanceCreateInfo* original_create_info;
130
131
XrInstanceCreateInfo modified_create_info;
132
std::vector<const char*> enabled_extensions_cstr;
133
};
134
} // namespace
135
136
// Factory method
137
XrResult LoaderInstance::CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term,
138
PFN_xrCreateInstance create_instance_term,
139
PFN_xrCreateApiLayerInstance create_api_layer_instance_term,
140
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces,
141
const XrInstanceCreateInfo* info, std::unique_ptr<LoaderInstance>* loader_instance) {
142
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering LoaderInstance::CreateInstance");
143
144
// Check the list of enabled extensions to make sure something supports them, and, if we do,
145
// add it to the list of enabled extensions
146
XrResult last_error = XR_SUCCESS;
147
for (uint32_t ext = 0; ext < info->enabledExtensionCount; ++ext) {
148
bool found = false;
149
// First check the runtime
150
if (RuntimeInterface::GetRuntime().SupportsExtension(info->enabledExtensionNames[ext])) {
151
found = true;
152
}
153
// Next check the loader
154
if (!found) {
155
for (auto& loader_extension : LoaderInstance::LoaderSpecificExtensions()) {
156
if (strcmp(loader_extension.extensionName, info->enabledExtensionNames[ext]) == 0) {
157
found = true;
158
break;
159
}
160
}
161
}
162
// Finally, check the enabled layers
163
if (!found) {
164
for (auto& layer_interface : api_layer_interfaces) {
165
if (layer_interface->SupportsExtension(info->enabledExtensionNames[ext])) {
166
found = true;
167
break;
168
}
169
}
170
}
171
if (!found) {
172
std::string msg = "LoaderInstance::CreateInstance, no support found for requested extension: ";
173
msg += info->enabledExtensionNames[ext];
174
LoaderLogger::LogErrorMessage("xrCreateInstance", msg);
175
last_error = XR_ERROR_EXTENSION_NOT_PRESENT;
176
break;
177
}
178
}
179
180
// Topmost means "closest to the application"
181
PFN_xrGetInstanceProcAddr topmost_gipa = get_instance_proc_addr_term;
182
XrInstance instance{XR_NULL_HANDLE};
183
184
if (XR_SUCCEEDED(last_error)) {
185
// Remove the loader-supported-extensions (debug utils), if it's in the list of enabled extensions but not supported by
186
// the runtime.
187
InstanceCreateInfoManager create_info_manager{info};
188
const XrInstanceCreateInfo* modified_create_info = info;
189
if (info->enabledExtensionCount > 0) {
190
std::vector<const char*> extensions_to_skip;
191
for (const auto& ext : LoaderInstance::LoaderSpecificExtensions()) {
192
if (!RuntimeInterface::GetRuntime().SupportsExtension(ext.extensionName)) {
193
extensions_to_skip.emplace_back(ext.extensionName);
194
}
195
}
196
modified_create_info = create_info_manager.FilterOutExtensions(extensions_to_skip);
197
}
198
199
// Only start the xrCreateApiLayerInstance stack if we have layers.
200
if (!api_layer_interfaces.empty()) {
201
// Initialize an array of ApiLayerNextInfo structs
202
std::unique_ptr<XrApiLayerNextInfo[]> next_info_list(new XrApiLayerNextInfo[api_layer_interfaces.size()]);
203
size_t ni_index = api_layer_interfaces.size() - 1;
204
for (size_t i = 0; i <= ni_index; i++) {
205
next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO;
206
next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION;
207
next_info_list[i].structSize = sizeof(XrApiLayerNextInfo);
208
}
209
210
// Go through all layers, and override the instance pointers with the layer version. However,
211
// go backwards through the layer list so we replace in reverse order so the layers can call their next function
212
// appropriately.
213
PFN_xrCreateApiLayerInstance topmost_cali_fp = create_api_layer_instance_term;
214
XrApiLayerNextInfo* topmost_nextinfo = nullptr;
215
for (auto layer_interface = api_layer_interfaces.rbegin(); layer_interface != api_layer_interfaces.rend();
216
++layer_interface) {
217
// Collect current layer's function pointers
218
PFN_xrGetInstanceProcAddr cur_gipa_fp = (*layer_interface)->GetInstanceProcAddrFuncPointer();
219
PFN_xrCreateApiLayerInstance cur_cali_fp = (*layer_interface)->GetCreateApiLayerInstanceFuncPointer();
220
221
// Fill in layer info and link previous (lower) layer fxn pointers
222
strncpy(next_info_list[ni_index].layerName, (*layer_interface)->LayerName().c_str(),
223
XR_MAX_API_LAYER_NAME_SIZE - 1);
224
next_info_list[ni_index].layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';
225
next_info_list[ni_index].next = topmost_nextinfo;
226
next_info_list[ni_index].nextGetInstanceProcAddr = topmost_gipa;
227
next_info_list[ni_index].nextCreateApiLayerInstance = topmost_cali_fp;
228
229
// Update saved pointers for next iteration
230
topmost_nextinfo = &next_info_list[ni_index];
231
topmost_gipa = cur_gipa_fp;
232
topmost_cali_fp = cur_cali_fp;
233
ni_index--;
234
}
235
236
// Populate the ApiLayerCreateInfo struct and pass to topmost CreateApiLayerInstance()
237
XrApiLayerCreateInfo api_layer_ci = {};
238
api_layer_ci.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO;
239
api_layer_ci.structVersion = XR_API_LAYER_CREATE_INFO_STRUCT_VERSION;
240
api_layer_ci.structSize = sizeof(XrApiLayerCreateInfo);
241
api_layer_ci.loaderInstance = nullptr; // Not used.
242
api_layer_ci.settings_file_location[0] = '\0';
243
api_layer_ci.nextInfo = next_info_list.get();
244
//! @todo do we filter our create info extension list here?
245
//! Think that actually each layer might need to filter...
246
last_error = topmost_cali_fp(modified_create_info, &api_layer_ci, &instance);
247
248
} else {
249
// The loader's terminator is the topmost CreateInstance if there are no layers.
250
last_error = create_instance_term(modified_create_info, &instance);
251
}
252
253
if (XR_FAILED(last_error)) {
254
LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance chained CreateInstance call failed");
255
}
256
}
257
258
if (XR_SUCCEEDED(last_error)) {
259
loader_instance->reset(new LoaderInstance(instance, info, topmost_gipa, std::move(api_layer_interfaces)));
260
261
std::ostringstream oss;
262
oss << "LoaderInstance::CreateInstance succeeded with ";
263
oss << (*loader_instance)->LayerInterfaces().size();
264
oss << " layers enabled and runtime interface - created instance = ";
265
oss << HandleToHexString((*loader_instance)->GetInstanceHandle());
266
LoaderLogger::LogInfoMessage("xrCreateInstance", oss.str());
267
}
268
269
return last_error;
270
}
271
272
XrResult LoaderInstance::GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function) {
273
return _topmost_gipa(_runtime_instance, name, function);
274
}
275
276
LoaderInstance::LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* create_info, PFN_xrGetInstanceProcAddr topmost_gipa,
277
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces)
278
: _runtime_instance(instance),
279
_topmost_gipa(topmost_gipa),
280
_api_layer_interfaces(std::move(api_layer_interfaces)),
281
_dispatch_table(new XrGeneratedDispatchTableCore{}) {
282
for (uint32_t ext = 0; ext < create_info->enabledExtensionCount; ++ext) {
283
_enabled_extensions.push_back(create_info->enabledExtensionNames[ext]);
284
}
285
286
GeneratedXrPopulateDispatchTableCore(_dispatch_table.get(), instance, topmost_gipa);
287
}
288
289
LoaderInstance::~LoaderInstance() {
290
std::ostringstream oss;
291
oss << "Destroying LoaderInstance = ";
292
oss << PointerToHexString(this);
293
LoaderLogger::LogInfoMessage("xrDestroyInstance", oss.str());
294
}
295
296
bool LoaderInstance::ExtensionIsEnabled(const std::string& extension) {
297
for (std::string& cur_enabled : _enabled_extensions) {
298
if (cur_enabled == extension) {
299
return true;
300
}
301
}
302
return false;
303
}
304
305