Path: blob/master/thirdparty/openxr/src/loader/loader_instance.cpp
9917 views
// Copyright (c) 2017-2025 The Khronos Group Inc.1// Copyright (c) 2017-2019 Valve Corporation2// Copyright (c) 2017-2019 LunarG, Inc.3//4// SPDX-License-Identifier: Apache-2.0 OR MIT5//6// Initial Author: Mark Young <[email protected]>7//89#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)10#define _CRT_SECURE_NO_WARNINGS11#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)1213#include "loader_instance.hpp"1415#include "api_layer_interface.hpp"16#include "hex_and_handles.h"17#include "loader_logger.hpp"18#include "runtime_interface.hpp"19#include "xr_generated_dispatch_table_core.h"20#include "xr_generated_loader.hpp"2122#include <openxr/openxr.h>23#include <openxr/openxr_loader_negotiation.h>2425#include <cstring>26#include <memory>27#include <sstream>28#include <string>29#include <utility>30#include <vector>3132namespace {33std::unique_ptr<LoaderInstance>& GetSetCurrentLoaderInstance() {34static std::unique_ptr<LoaderInstance> current_loader_instance;35return current_loader_instance;36}37} // namespace3839namespace ActiveLoaderInstance {40XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name) {41if (GetSetCurrentLoaderInstance() != nullptr) {42LoaderLogger::LogErrorMessage(log_function_name, "Active XrInstance handle already exists");43return XR_ERROR_LIMIT_REACHED;44}4546GetSetCurrentLoaderInstance() = std::move(loader_instance);47return XR_SUCCESS;48}4950XrResult Get(LoaderInstance** loader_instance, const char* log_function_name) {51*loader_instance = GetSetCurrentLoaderInstance().get();52if (*loader_instance == nullptr) {53LoaderLogger::LogErrorMessage(log_function_name, "No active XrInstance handle.");54return XR_ERROR_HANDLE_INVALID;55}5657return XR_SUCCESS;58}5960bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; }6162void Remove() { GetSetCurrentLoaderInstance().reset(nullptr); }63} // namespace ActiveLoaderInstance6465// Extensions that are supported by the loader, but may not be supported66// the the runtime.67const std::array<XrExtensionProperties, 1>& LoaderInstance::LoaderSpecificExtensions() {68static const std::array<XrExtensionProperties, 1> extensions = {XrExtensionProperties{69XR_TYPE_EXTENSION_PROPERTIES, nullptr, XR_EXT_DEBUG_UTILS_EXTENSION_NAME, XR_EXT_debug_utils_SPEC_VERSION}};70return extensions;71}7273namespace {74class InstanceCreateInfoManager {75public:76explicit InstanceCreateInfoManager(const XrInstanceCreateInfo* info) : original_create_info(info), modified_create_info(*info) {77Reset();78}7980// Reset the "modified" state to match the original state.81void Reset() {82enabled_extensions_cstr.clear();83enabled_extensions_cstr.reserve(original_create_info->enabledExtensionCount);8485for (uint32_t i = 0; i < original_create_info->enabledExtensionCount; ++i) {86enabled_extensions_cstr.push_back(original_create_info->enabledExtensionNames[i]);87}88Update();89}9091// Remove extensions named in the parameter and return a pointer to the current state.92const XrInstanceCreateInfo* FilterOutExtensions(const std::vector<const char*>& extensions_to_skip) {93if (enabled_extensions_cstr.empty()) {94return Get();95}96if (extensions_to_skip.empty()) {97return Get();98}99for (auto& ext : extensions_to_skip) {100FilterOutExtension(ext);101}102return Update();103}104// Remove the extension named in the parameter and return a pointer to the current state.105const XrInstanceCreateInfo* FilterOutExtension(const char* extension_to_skip) {106if (enabled_extensions_cstr.empty()) {107return &modified_create_info;108}109auto b = enabled_extensions_cstr.begin();110auto e = enabled_extensions_cstr.end();111auto it = std::find_if(b, e, [&](const char* extension) { return strcmp(extension_to_skip, extension) == 0; });112if (it != e) {113// Just that one element goes away114enabled_extensions_cstr.erase(it);115}116return Update();117}118119// Get the current modified XrInstanceCreateInfo120const XrInstanceCreateInfo* Get() const { return &modified_create_info; }121122private:123const XrInstanceCreateInfo* Update() {124modified_create_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions_cstr.size());125modified_create_info.enabledExtensionNames = enabled_extensions_cstr.empty() ? nullptr : enabled_extensions_cstr.data();126return &modified_create_info;127}128const XrInstanceCreateInfo* original_create_info;129130XrInstanceCreateInfo modified_create_info;131std::vector<const char*> enabled_extensions_cstr;132};133} // namespace134135// Factory method136XrResult LoaderInstance::CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term,137PFN_xrCreateInstance create_instance_term,138PFN_xrCreateApiLayerInstance create_api_layer_instance_term,139std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces,140const XrInstanceCreateInfo* info, std::unique_ptr<LoaderInstance>* loader_instance) {141LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering LoaderInstance::CreateInstance");142143// Check the list of enabled extensions to make sure something supports them, and, if we do,144// add it to the list of enabled extensions145XrResult last_error = XR_SUCCESS;146for (uint32_t ext = 0; ext < info->enabledExtensionCount; ++ext) {147bool found = false;148// First check the runtime149if (RuntimeInterface::GetRuntime().SupportsExtension(info->enabledExtensionNames[ext])) {150found = true;151}152// Next check the loader153if (!found) {154for (auto& loader_extension : LoaderInstance::LoaderSpecificExtensions()) {155if (strcmp(loader_extension.extensionName, info->enabledExtensionNames[ext]) == 0) {156found = true;157break;158}159}160}161// Finally, check the enabled layers162if (!found) {163for (auto& layer_interface : api_layer_interfaces) {164if (layer_interface->SupportsExtension(info->enabledExtensionNames[ext])) {165found = true;166break;167}168}169}170if (!found) {171std::string msg = "LoaderInstance::CreateInstance, no support found for requested extension: ";172msg += info->enabledExtensionNames[ext];173LoaderLogger::LogErrorMessage("xrCreateInstance", msg);174last_error = XR_ERROR_EXTENSION_NOT_PRESENT;175break;176}177}178179// Topmost means "closest to the application"180PFN_xrGetInstanceProcAddr topmost_gipa = get_instance_proc_addr_term;181XrInstance instance{XR_NULL_HANDLE};182183if (XR_SUCCEEDED(last_error)) {184// Remove the loader-supported-extensions (debug utils), if it's in the list of enabled extensions but not supported by185// the runtime.186InstanceCreateInfoManager create_info_manager{info};187const XrInstanceCreateInfo* modified_create_info = info;188if (info->enabledExtensionCount > 0) {189std::vector<const char*> extensions_to_skip;190for (const auto& ext : LoaderInstance::LoaderSpecificExtensions()) {191if (!RuntimeInterface::GetRuntime().SupportsExtension(ext.extensionName)) {192extensions_to_skip.emplace_back(ext.extensionName);193}194}195modified_create_info = create_info_manager.FilterOutExtensions(extensions_to_skip);196}197198// Only start the xrCreateApiLayerInstance stack if we have layers.199if (!api_layer_interfaces.empty()) {200// Initialize an array of ApiLayerNextInfo structs201std::unique_ptr<XrApiLayerNextInfo[]> next_info_list(new XrApiLayerNextInfo[api_layer_interfaces.size()]);202size_t ni_index = api_layer_interfaces.size() - 1;203for (size_t i = 0; i <= ni_index; i++) {204next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO;205next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION;206next_info_list[i].structSize = sizeof(XrApiLayerNextInfo);207}208209// Go through all layers, and override the instance pointers with the layer version. However,210// go backwards through the layer list so we replace in reverse order so the layers can call their next function211// appropriately.212PFN_xrCreateApiLayerInstance topmost_cali_fp = create_api_layer_instance_term;213XrApiLayerNextInfo* topmost_nextinfo = nullptr;214for (auto layer_interface = api_layer_interfaces.rbegin(); layer_interface != api_layer_interfaces.rend();215++layer_interface) {216// Collect current layer's function pointers217PFN_xrGetInstanceProcAddr cur_gipa_fp = (*layer_interface)->GetInstanceProcAddrFuncPointer();218PFN_xrCreateApiLayerInstance cur_cali_fp = (*layer_interface)->GetCreateApiLayerInstanceFuncPointer();219220// Fill in layer info and link previous (lower) layer fxn pointers221strncpy(next_info_list[ni_index].layerName, (*layer_interface)->LayerName().c_str(),222XR_MAX_API_LAYER_NAME_SIZE - 1);223next_info_list[ni_index].layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';224next_info_list[ni_index].next = topmost_nextinfo;225next_info_list[ni_index].nextGetInstanceProcAddr = topmost_gipa;226next_info_list[ni_index].nextCreateApiLayerInstance = topmost_cali_fp;227228// Update saved pointers for next iteration229topmost_nextinfo = &next_info_list[ni_index];230topmost_gipa = cur_gipa_fp;231topmost_cali_fp = cur_cali_fp;232ni_index--;233}234235// Populate the ApiLayerCreateInfo struct and pass to topmost CreateApiLayerInstance()236XrApiLayerCreateInfo api_layer_ci = {};237api_layer_ci.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO;238api_layer_ci.structVersion = XR_API_LAYER_CREATE_INFO_STRUCT_VERSION;239api_layer_ci.structSize = sizeof(XrApiLayerCreateInfo);240api_layer_ci.loaderInstance = nullptr; // Not used.241api_layer_ci.settings_file_location[0] = '\0';242api_layer_ci.nextInfo = next_info_list.get();243//! @todo do we filter our create info extension list here?244//! Think that actually each layer might need to filter...245last_error = topmost_cali_fp(modified_create_info, &api_layer_ci, &instance);246247} else {248// The loader's terminator is the topmost CreateInstance if there are no layers.249last_error = create_instance_term(modified_create_info, &instance);250}251252if (XR_FAILED(last_error)) {253LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance chained CreateInstance call failed");254}255}256257if (XR_SUCCEEDED(last_error)) {258loader_instance->reset(new LoaderInstance(instance, info, topmost_gipa, std::move(api_layer_interfaces)));259260std::ostringstream oss;261oss << "LoaderInstance::CreateInstance succeeded with ";262oss << (*loader_instance)->LayerInterfaces().size();263oss << " layers enabled and runtime interface - created instance = ";264oss << HandleToHexString((*loader_instance)->GetInstanceHandle());265LoaderLogger::LogInfoMessage("xrCreateInstance", oss.str());266}267268return last_error;269}270271XrResult LoaderInstance::GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function) {272return _topmost_gipa(_runtime_instance, name, function);273}274275LoaderInstance::LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* create_info, PFN_xrGetInstanceProcAddr topmost_gipa,276std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces)277: _runtime_instance(instance),278_topmost_gipa(topmost_gipa),279_api_layer_interfaces(std::move(api_layer_interfaces)),280_dispatch_table(new XrGeneratedDispatchTableCore{}) {281for (uint32_t ext = 0; ext < create_info->enabledExtensionCount; ++ext) {282_enabled_extensions.push_back(create_info->enabledExtensionNames[ext]);283}284285GeneratedXrPopulateDispatchTableCore(_dispatch_table.get(), instance, topmost_gipa);286}287288LoaderInstance::~LoaderInstance() {289std::ostringstream oss;290oss << "Destroying LoaderInstance = ";291oss << PointerToHexString(this);292LoaderLogger::LogInfoMessage("xrDestroyInstance", oss.str());293}294295bool LoaderInstance::ExtensionIsEnabled(const std::string& extension) {296for (std::string& cur_enabled : _enabled_extensions) {297if (cur_enabled == extension) {298return true;299}300}301return false;302}303304305