1// Copyright (c) 2017-2023, 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 <marky@lunarg.com>
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_interfaces.h"
19#include "loader_logger.hpp"
20#include "runtime_interface.hpp"
21#include "xr_generated_dispatch_table.h"
22#include "xr_generated_loader.hpp"
23
24#include <openxr/openxr.h>
25
26#include <cstring>
27#include <memory>
28#include <sstream>
29#include <string>
30#include <utility>
31#include <vector>
32
33namespace {
34std::unique_ptr<LoaderInstance>& GetSetCurrentLoaderInstance() {
35 static std::unique_ptr<LoaderInstance> current_loader_instance;
36 return current_loader_instance;
37}
38} // namespace
39
40namespace ActiveLoaderInstance {
41XrResult 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
51XrResult 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
61bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; }
62
63void Remove() { GetSetCurrentLoaderInstance().release(); }
64} // namespace ActiveLoaderInstance
65
66// Extensions that are supported by the loader, but may not be supported
67// the the runtime.
68const 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
74namespace {
75class 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
137XrResult 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
272XrResult LoaderInstance::GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function) {
273 return _topmost_gipa(_runtime_instance, name, function);
274}
275
276LoaderInstance::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 XrGeneratedDispatchTable{}) {
282 for (uint32_t ext = 0; ext < create_info->enabledExtensionCount; ++ext) {
283 _enabled_extensions.push_back(create_info->enabledExtensionNames[ext]);
284 }
285
286 GeneratedXrPopulateDispatchTable(_dispatch_table.get(), instance, topmost_gipa);
287}
288
289LoaderInstance::~LoaderInstance() {
290 std::ostringstream oss;
291 oss << "Destroying LoaderInstance = ";
292 oss << PointerToHexString(this);
293 LoaderLogger::LogInfoMessage("xrDestroyInstance", oss.str());
294}
295
296bool 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