summaryrefslogtreecommitdiff
path: root/thirdparty/openxr/src/loader/loader_instance.cpp
blob: b24c8de53ba3270ba1d6c9d69d7a5481cab6f9cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//

#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif  // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)

#include "loader_instance.hpp"

#include "api_layer_interface.hpp"
#include "hex_and_handles.h"
#include "loader_interfaces.h"
#include "loader_logger.hpp"
#include "runtime_interface.hpp"
#include "xr_generated_dispatch_table.h"
#include "xr_generated_loader.hpp"

#include <openxr/openxr.h>

#include <cstring>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

namespace {
std::unique_ptr<LoaderInstance>& GetSetCurrentLoaderInstance() {
    static std::unique_ptr<LoaderInstance> current_loader_instance;
    return current_loader_instance;
}
}  // namespace

namespace ActiveLoaderInstance {
XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name) {
    if (GetSetCurrentLoaderInstance() != nullptr) {
        LoaderLogger::LogErrorMessage(log_function_name, "Active XrInstance handle already exists");
        return XR_ERROR_LIMIT_REACHED;
    }

    GetSetCurrentLoaderInstance() = std::move(loader_instance);
    return XR_SUCCESS;
}

XrResult Get(LoaderInstance** loader_instance, const char* log_function_name) {
    *loader_instance = GetSetCurrentLoaderInstance().get();
    if (*loader_instance == nullptr) {
        LoaderLogger::LogErrorMessage(log_function_name, "No active XrInstance handle.");
        return XR_ERROR_HANDLE_INVALID;
    }

    return XR_SUCCESS;
}

bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; }

void Remove() { GetSetCurrentLoaderInstance().release(); }
}  // namespace ActiveLoaderInstance

// Extensions that are supported by the loader, but may not be supported
// the the runtime.
const std::array<XrExtensionProperties, 1>& LoaderInstance::LoaderSpecificExtensions() {
    static const std::array<XrExtensionProperties, 1> extensions = {XrExtensionProperties{
        XR_TYPE_EXTENSION_PROPERTIES, nullptr, XR_EXT_DEBUG_UTILS_EXTENSION_NAME, XR_EXT_debug_utils_SPEC_VERSION}};
    return extensions;
}

namespace {
class InstanceCreateInfoManager {
   public:
    explicit InstanceCreateInfoManager(const XrInstanceCreateInfo* info) : original_create_info(info), modified_create_info(*info) {
        Reset();
    }

    // Reset the "modified" state to match the original state.
    void Reset() {
        enabled_extensions_cstr.clear();
        enabled_extensions_cstr.reserve(original_create_info->enabledExtensionCount);

        for (uint32_t i = 0; i < original_create_info->enabledExtensionCount; ++i) {
            enabled_extensions_cstr.push_back(original_create_info->enabledExtensionNames[i]);
        }
        Update();
    }

    // Remove extensions named in the parameter and return a pointer to the current state.
    const XrInstanceCreateInfo* FilterOutExtensions(const std::vector<const char*>& extensions_to_skip) {
        if (enabled_extensions_cstr.empty()) {
            return Get();
        }
        if (extensions_to_skip.empty()) {
            return Get();
        }
        for (auto& ext : extensions_to_skip) {
            FilterOutExtension(ext);
        }
        return Update();
    }
    // Remove the extension named in the parameter and return a pointer to the current state.
    const XrInstanceCreateInfo* FilterOutExtension(const char* extension_to_skip) {
        if (enabled_extensions_cstr.empty()) {
            return &modified_create_info;
        }
        auto b = enabled_extensions_cstr.begin();
        auto e = enabled_extensions_cstr.end();
        auto it = std::find_if(b, e, [&](const char* extension) { return strcmp(extension_to_skip, extension) == 0; });
        if (it != e) {
            // Just that one element goes away
            enabled_extensions_cstr.erase(it);
        }
        return Update();
    }

    // Get the current modified XrInstanceCreateInfo
    const XrInstanceCreateInfo* Get() const { return &modified_create_info; }

   private:
    const XrInstanceCreateInfo* Update() {
        modified_create_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions_cstr.size());
        modified_create_info.enabledExtensionNames = enabled_extensions_cstr.empty() ? nullptr : enabled_extensions_cstr.data();
        return &modified_create_info;
    }
    const XrInstanceCreateInfo* original_create_info;

    XrInstanceCreateInfo modified_create_info;
    std::vector<const char*> enabled_extensions_cstr;
};
}  // namespace

// Factory method
XrResult LoaderInstance::CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term,
                                        PFN_xrCreateInstance create_instance_term,
                                        PFN_xrCreateApiLayerInstance create_api_layer_instance_term,
                                        std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces,
                                        const XrInstanceCreateInfo* info, std::unique_ptr<LoaderInstance>* loader_instance) {
    LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering LoaderInstance::CreateInstance");

    // Check the list of enabled extensions to make sure something supports them, and, if we do,
    // add it to the list of enabled extensions
    XrResult last_error = XR_SUCCESS;
    for (uint32_t ext = 0; ext < info->enabledExtensionCount; ++ext) {
        bool found = false;
        // First check the runtime
        if (RuntimeInterface::GetRuntime().SupportsExtension(info->enabledExtensionNames[ext])) {
            found = true;
        }
        // Next check the loader
        if (!found) {
            for (auto& loader_extension : LoaderInstance::LoaderSpecificExtensions()) {
                if (strcmp(loader_extension.extensionName, info->enabledExtensionNames[ext]) == 0) {
                    found = true;
                    break;
                }
            }
        }
        // Finally, check the enabled layers
        if (!found) {
            for (auto& layer_interface : api_layer_interfaces) {
                if (layer_interface->SupportsExtension(info->enabledExtensionNames[ext])) {
                    found = true;
                    break;
                }
            }
        }
        if (!found) {
            std::string msg = "LoaderInstance::CreateInstance, no support found for requested extension: ";
            msg += info->enabledExtensionNames[ext];
            LoaderLogger::LogErrorMessage("xrCreateInstance", msg);
            last_error = XR_ERROR_EXTENSION_NOT_PRESENT;
            break;
        }
    }

    // Topmost means "closest to the application"
    PFN_xrGetInstanceProcAddr topmost_gipa = get_instance_proc_addr_term;
    XrInstance instance{XR_NULL_HANDLE};

    if (XR_SUCCEEDED(last_error)) {
        // Remove the loader-supported-extensions (debug utils), if it's in the list of enabled extensions but not supported by
        // the runtime.
        InstanceCreateInfoManager create_info_manager{info};
        const XrInstanceCreateInfo* modified_create_info = info;
        if (info->enabledExtensionCount > 0) {
            std::vector<const char*> extensions_to_skip;
            for (const auto& ext : LoaderInstance::LoaderSpecificExtensions()) {
                if (!RuntimeInterface::GetRuntime().SupportsExtension(ext.extensionName)) {
                    extensions_to_skip.emplace_back(ext.extensionName);
                }
            }
            modified_create_info = create_info_manager.FilterOutExtensions(extensions_to_skip);
        }

        // Only start the xrCreateApiLayerInstance stack if we have layers.
        if (!api_layer_interfaces.empty()) {
            // Initialize an array of ApiLayerNextInfo structs
            std::unique_ptr<XrApiLayerNextInfo[]> next_info_list(new XrApiLayerNextInfo[api_layer_interfaces.size()]);
            auto ni_index = static_cast<uint32_t>(api_layer_interfaces.size() - 1);
            for (uint32_t i = 0; i <= ni_index; i++) {
                next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO;
                next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION;
                next_info_list[i].structSize = sizeof(XrApiLayerNextInfo);
            }

            // Go through all layers, and override the instance pointers with the layer version.  However,
            // go backwards through the layer list so we replace in reverse order so the layers can call their next function
            // appropriately.
            PFN_xrCreateApiLayerInstance topmost_cali_fp = create_api_layer_instance_term;
            XrApiLayerNextInfo* topmost_nextinfo = nullptr;
            for (auto layer_interface = api_layer_interfaces.rbegin(); layer_interface != api_layer_interfaces.rend();
                 ++layer_interface) {
                // Collect current layer's function pointers
                PFN_xrGetInstanceProcAddr cur_gipa_fp = (*layer_interface)->GetInstanceProcAddrFuncPointer();
                PFN_xrCreateApiLayerInstance cur_cali_fp = (*layer_interface)->GetCreateApiLayerInstanceFuncPointer();

                // Fill in layer info and link previous (lower) layer fxn pointers
                strncpy(next_info_list[ni_index].layerName, (*layer_interface)->LayerName().c_str(),
                        XR_MAX_API_LAYER_NAME_SIZE - 1);
                next_info_list[ni_index].layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';
                next_info_list[ni_index].next = topmost_nextinfo;
                next_info_list[ni_index].nextGetInstanceProcAddr = topmost_gipa;
                next_info_list[ni_index].nextCreateApiLayerInstance = topmost_cali_fp;

                // Update saved pointers for next iteration
                topmost_nextinfo = &next_info_list[ni_index];
                topmost_gipa = cur_gipa_fp;
                topmost_cali_fp = cur_cali_fp;
                ni_index--;
            }

            // Populate the ApiLayerCreateInfo struct and pass to topmost CreateApiLayerInstance()
            XrApiLayerCreateInfo api_layer_ci = {};
            api_layer_ci.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO;
            api_layer_ci.structVersion = XR_API_LAYER_CREATE_INFO_STRUCT_VERSION;
            api_layer_ci.structSize = sizeof(XrApiLayerCreateInfo);
            api_layer_ci.loaderInstance = nullptr;  // Not used.
            api_layer_ci.settings_file_location[0] = '\0';
            api_layer_ci.nextInfo = next_info_list.get();
            //! @todo do we filter our create info extension list here?
            //! Think that actually each layer might need to filter...
            last_error = topmost_cali_fp(modified_create_info, &api_layer_ci, &instance);

        } else {
            // The loader's terminator is the topmost CreateInstance if there are no layers.
            last_error = create_instance_term(modified_create_info, &instance);
        }

        if (XR_FAILED(last_error)) {
            LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance chained CreateInstance call failed");
        }
    }

    if (XR_SUCCEEDED(last_error)) {
        loader_instance->reset(new LoaderInstance(instance, info, topmost_gipa, std::move(api_layer_interfaces)));

        std::ostringstream oss;
        oss << "LoaderInstance::CreateInstance succeeded with ";
        oss << (*loader_instance)->LayerInterfaces().size();
        oss << " layers enabled and runtime interface - created instance = ";
        oss << HandleToHexString((*loader_instance)->GetInstanceHandle());
        LoaderLogger::LogInfoMessage("xrCreateInstance", oss.str());
    }

    return last_error;
}

XrResult LoaderInstance::GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function) {
    return _topmost_gipa(_runtime_instance, name, function);
}

LoaderInstance::LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* create_info, PFN_xrGetInstanceProcAddr topmost_gipa,
                               std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces)
    : _runtime_instance(instance),
      _topmost_gipa(topmost_gipa),
      _api_layer_interfaces(std::move(api_layer_interfaces)),
      _dispatch_table(new XrGeneratedDispatchTable{}) {
    for (uint32_t ext = 0; ext < create_info->enabledExtensionCount; ++ext) {
        _enabled_extensions.push_back(create_info->enabledExtensionNames[ext]);
    }

    GeneratedXrPopulateDispatchTable(_dispatch_table.get(), instance, topmost_gipa);
}

LoaderInstance::~LoaderInstance() {
    std::ostringstream oss;
    oss << "Destroying LoaderInstance = ";
    oss << PointerToHexString(this);
    LoaderLogger::LogInfoMessage("xrDestroyInstance", oss.str());
}

bool LoaderInstance::ExtensionIsEnabled(const std::string& extension) {
    for (std::string& cur_enabled : _enabled_extensions) {
        if (cur_enabled == extension) {
            return true;
        }
    }
    return false;
}