Welcome to mirror list, hosted at ThFree Co, Russian Federation.

loader_instance.cpp « loader « src - github.com/KhronosGroup/OpenXR-SDK.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c5799e76bb2f6ff8c9224ffcb0f8a51b0f2623ff (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
// Copyright (c) 2017-2019 The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Mark Young <marky@lunarg.com>
//

#ifdef XR_OS_WINDOWS
#define _CRT_SECURE_NO_WARNINGS
#endif

#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"

//! @todo can we remove this? Everything but Windows is using it only for includes that aren't needed in this file.
#ifdef _WIN32
#include "xr_dependencies.h"
#endif
#include <openxr/openxr.h>

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

// Extensions that are supported by the loader, but may not be supported
// the the runtime.
static const XrExtensionProperties g_debug_utils_props = {XR_TYPE_EXTENSION_PROPERTIES, nullptr, XR_EXT_DEBUG_UTILS_EXTENSION_NAME,
                                                          XR_EXT_debug_utils_SPEC_VERSION};
const std::vector<XrExtensionProperties> LoaderInstance::_loader_supported_extensions = {g_debug_utils_props};

// Factory method
XrResult LoaderInstance::CreateInstance(std::vector<std::unique_ptr<ApiLayerInterface>>&& api_layer_interfaces,
                                        const XrInstanceCreateInfo* info, XrInstance* instance) {
    XrResult last_error = XR_SUCCESS;
    try {
        LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering LoaderInstance::CreateInstance");

        // Topmost means "closest to the application"
        PFN_xrCreateInstance topmost_ci_fp = LoaderXrTermCreateInstance;
        PFN_xrCreateApiLayerInstance topmost_cali_fp = LoaderXrTermCreateApiLayerInstance;

        // Create the loader instance
        std::unique_ptr<LoaderInstance> loader_instance(new LoaderInstance(std::move(api_layer_interfaces)));
        *instance = reinterpret_cast<XrInstance>(loader_instance.get());

        // Only start the xrCreateApiLayerInstance stack if we have layers.
        std::vector<std::unique_ptr<ApiLayerInterface>>& layer_interfaces = loader_instance->LayerInterfaces();
        if (!layer_interfaces.empty()) {
            // Initialize an array of ApiLayerNextInfo structs
            auto* next_info_list = new XrApiLayerNextInfo[layer_interfaces.size()];
            auto ni_index = static_cast<uint32_t>(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.
            XrApiLayerNextInfo* prev_nextinfo = nullptr;
            PFN_xrGetInstanceProcAddr prev_gipa_fp = LoaderXrTermGetInstanceProcAddr;
            PFN_xrCreateApiLayerInstance prev_cali_fp = LoaderXrTermCreateApiLayerInstance;
            for (auto layer_interface = layer_interfaces.rbegin(); layer_interface != 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();
                // Update topmosts
                cur_gipa_fp(XR_NULL_HANDLE, "xrCreateInstance", reinterpret_cast<PFN_xrVoidFunction*>(&topmost_ci_fp));
                topmost_cali_fp = cur_cali_fp;

                // 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 = prev_nextinfo;
                next_info_list[ni_index].nextGetInstanceProcAddr = prev_gipa_fp;
                next_info_list[ni_index].nextCreateApiLayerInstance = prev_cali_fp;

                // Update saved pointers for next iteration
                prev_nextinfo = &next_info_list[ni_index];
                prev_gipa_fp = cur_gipa_fp;
                prev_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 = reinterpret_cast<void*>(loader_instance.get());
            api_layer_ci.settings_file_location[0] = '\0';
            api_layer_ci.nextInfo = next_info_list;
            last_error = topmost_cali_fp(info, &api_layer_ci, instance);

            delete[] next_info_list;
        } else {
            last_error = topmost_ci_fp(info, instance);
        }

        if (XR_SUCCEEDED(last_error)) {
            // Check the list of enabled extensions to make sure something supports them, and, if we do,
            // add it to the list of enabled extensions
            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::_loader_supported_extensions) {
                        if (strcmp(loader_extension.extensionName, info->enabledExtensionNames[ext]) == 0) {
                            found = true;
                            break;
                        }
                    }
                }
                // Finally, check the enabled layers
                if (!found) {
                    for (auto& layer_interface : 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;
                }
                loader_instance->AddEnabledExtension(info->enabledExtensionNames[ext]);
            }
        } else {
            LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance chained CreateInstance call failed");
        }

        if (XR_SUCCEEDED(last_error)) {
            // Create the top-level dispatch table for the instance.  This will contain the function pointers to the
            // first instantiation of every command, whether that is in a layer, or a runtime.
            last_error = loader_instance->CreateDispatchTable(*instance);
            if (XR_FAILED(last_error)) {
                LoaderLogger::LogErrorMessage("xrCreateInstance",
                                              "LoaderInstance::CreateInstance failed creating top-level dispatch table");
            } else {
                last_error = g_instance_map.Insert(*instance, *loader_instance);
                if (XR_FAILED(last_error)) {
                    LoaderLogger::LogErrorMessage(
                        "xrCreateInstance",
                        "LoaderInstance::CreateInstance failed inserting new instance into map: may be null or not unique");
                }
            }
        }

        if (XR_SUCCEEDED(last_error)) {
            std::ostringstream oss;
            oss << "LoaderInstance::CreateInstance succeeded with ";
            oss << loader_instance->LayerInterfaces().size();
            oss << " layers enabled and runtime interface - created instance = ";
            oss << HandleToHexString(*instance);
            LoaderLogger::LogInfoMessage("xrCreateInstance", oss.str());
            // Make the unique_ptr no longer delete this.
            // Don't need to save the return value because we already set *instance
            (void)loader_instance.release();
        }
    } catch (std::bad_alloc&) {
        LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance - failed to allocate memory");
        last_error = XR_ERROR_OUT_OF_MEMORY;
    } catch (...) {
        LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance - unknown error occurred");
        last_error = XR_ERROR_INITIALIZATION_FAILED;
    }

    // Always clear the input lists.  Either we use them or we don't.
    api_layer_interfaces.clear();

    return last_error;
}

LoaderInstance::LoaderInstance(std::vector<std::unique_ptr<ApiLayerInterface>>&& api_layer_interfaces) try
    : _unique_id(0xDECAFBAD),
      _api_version(XR_CURRENT_API_VERSION),
      _api_layer_interfaces(std::move(api_layer_interfaces)),
      _dispatch_valid(false),
      _messenger(XR_NULL_HANDLE) {
} catch (...) {
    LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::LoaderInstance - Unknown error occurred");
    throw;
}

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

XrResult LoaderInstance::CreateDispatchTable(XrInstance instance) {
    XrResult res = XR_SUCCESS;
    try {
        // Create the top-level dispatch table.  First, we want to start with a dispatch table generated
        // using the commands from the runtime, with the exception of commands that we need a terminator
        // for.  The loaderGenInitInstanceDispatchTable utility function handles that automatically for us.
        std::unique_ptr<XrGeneratedDispatchTable> new_instance_dispatch_table(new XrGeneratedDispatchTable());
        LoaderGenInitInstanceDispatchTable(_runtime_instance, new_instance_dispatch_table);

        // 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.
        if (!_api_layer_interfaces.empty()) {
            (*_api_layer_interfaces.begin())->GenUpdateInstanceDispatchTable(instance, new_instance_dispatch_table);
        }

        // Set the top-level instance dispatch table to the top-most commands now that we've figured them out.
        _dispatch_table = std::move(new_instance_dispatch_table);
        _dispatch_valid = true;
    } catch (std::bad_alloc&) {
        LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateDispatchTable - failed to allocate memory");
        res = XR_ERROR_OUT_OF_MEMORY;
    } catch (...) {
        LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateDispatchTable - unknown error occurred");
        res = XR_ERROR_INITIALIZATION_FAILED;
    }
    return res;
}

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