Path: blob/master/thirdparty/openxr/src/loader/api_layer_interface.cpp
20837 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#include "api_layer_interface.hpp"1011#include "loader_init_data.hpp"12#include "loader_logger.hpp"13#include "loader_properties.hpp"14#include "loader_platform.hpp"15#include "manifest_file.hpp"16#include "platform_utils.hpp"1718#include <openxr/openxr.h>19#include <openxr/openxr_loader_negotiation.h>2021#include <algorithm>22#include <cstring>23#include <iterator>24#include <memory>25#include <sstream>26#include <string>27#include <utility>28#include <vector>2930#define OPENXR_ENABLE_LAYERS_ENV_VAR "XR_ENABLE_API_LAYERS"3132// Add any layers defined in the loader layer environment variable.33static void AddEnvironmentApiLayers(std::vector<std::string>& enabled_layers) {34std::string layers = LoaderProperty::Get(OPENXR_ENABLE_LAYERS_ENV_VAR);3536std::size_t last_found = 0;37std::size_t found = layers.find_first_of(PATH_SEPARATOR);38std::string cur_search;3940// Handle any path listings in the string (separated by the appropriate path separator)41while (found != std::string::npos) {42cur_search = layers.substr(last_found, found - last_found);43enabled_layers.push_back(cur_search);44last_found = found + 1;45found = layers.find_first_of(PATH_SEPARATOR, last_found);46}4748// If there's something remaining in the string, copy it over49if (last_found < layers.size()) {50cur_search = layers.substr(last_found);51enabled_layers.push_back(cur_search);52}53}5455XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count,56uint32_t* outgoing_count, XrApiLayerProperties* api_layer_properties) {57std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;58uint32_t manifest_count = 0;59// Validate props struct before proceeding60if (0 < incoming_count && nullptr != api_layer_properties) {61for (uint32_t i = 0; i < incoming_count; i++) {62if (XR_TYPE_API_LAYER_PROPERTIES != api_layer_properties[i].type) {63LoaderLogger::LogErrorMessage(openxr_command,64"VUID-XrApiLayerProperties-type-type: unknown type in api_layer_properties");65return XR_ERROR_VALIDATION_FAILURE;66}67}68}6970// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,71// and the function sets elementCountOutput." - 2.1172if (nullptr == outgoing_count) {73return XR_ERROR_VALIDATION_FAILURE;74}7576// Find any implicit layers which we may need to report information for.77XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);78if (XR_SUCCEEDED(result)) {79// Find any explicit layers which we may need to report information for.80result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);81}82if (XR_FAILED(result)) {83LoaderLogger::LogErrorMessage(openxr_command,84"ApiLayerInterface::GetApiLayerProperties - failed searching for API layer manifest files");85return result;86}8788// check for potential overflow before static_cast<uint32_t>89if (manifest_files.size() >= UINT32_MAX) {90LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::GetApiLayerProperties - too many API layers found");91return XR_ERROR_RUNTIME_FAILURE;92}9394manifest_count = static_cast<uint32_t>(manifest_files.size());95if (nullptr == outgoing_count) {96LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",97"VUID-xrEnumerateApiLayerProperties-propertyCountOutput-parameter: null propertyCountOutput");98return XR_ERROR_VALIDATION_FAILURE;99}100101*outgoing_count = manifest_count;102if (0 == incoming_count) {103// capacity check only104return XR_SUCCESS;105}106if (nullptr == api_layer_properties) {107// incoming_count is not 0 BUT the api_layer_properties is NULL108LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",109"VUID-xrEnumerateApiLayerProperties-properties-parameter: non-zero capacity but null array");110return XR_ERROR_VALIDATION_FAILURE;111}112if (incoming_count < manifest_count) {113LoaderLogger::LogErrorMessage(114"xrEnumerateInstanceExtensionProperties",115"VUID-xrEnumerateApiLayerProperties-propertyCapacityInput-parameter: insufficient space in array");116return XR_ERROR_SIZE_INSUFFICIENT;117}118119for (uint32_t prop = 0; prop < incoming_count && prop < manifest_count; ++prop) {120manifest_files[prop]->PopulateApiLayerProperties(api_layer_properties[prop]);121}122return XR_SUCCESS;123}124125XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,126std::vector<XrExtensionProperties>& extension_properties) {127std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;128129// If a layer name is supplied, only use the information out of that one layer130if (nullptr != layer_name && 0 != strlen(layer_name)) {131XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);132if (XR_SUCCEEDED(result)) {133// Find any explicit layers which we may need to report information for.134result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);135if (XR_FAILED(result)) {136LoaderLogger::LogErrorMessage(137openxr_command,138"ApiLayerInterface::GetInstanceExtensionProperties - failed searching for API layer manifest files");139return result;140}141142bool found = false;143size_t num_files = manifest_files.size();144for (size_t man_file = 0; man_file < num_files; ++man_file) {145// If a layer with the provided name exists, get it's instance extension information.146if (manifest_files[man_file]->LayerName() == layer_name) {147manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);148found = true;149break;150}151}152153// If nothing found, report 0154if (!found) {155return XR_ERROR_API_LAYER_NOT_PRESENT;156}157}158// Otherwise, we want to add only implicit API layers and explicit API layers enabled using the environment variables159} else {160XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);161if (XR_SUCCEEDED(result)) {162// Find any environmentally enabled explicit layers. If they're present, treat them like implicit layers163// since we know that they're going to be enabled.164std::vector<std::string> env_enabled_layers;165AddEnvironmentApiLayers(env_enabled_layers);166if (!env_enabled_layers.empty()) {167std::vector<std::unique_ptr<ApiLayerManifestFile>> exp_layer_man_files = {};168result =169ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files);170if (XR_SUCCEEDED(result)) {171for (auto& exp_layer_man_file : exp_layer_man_files) {172for (std::string& enabled_layer : env_enabled_layers) {173// If this is an enabled layer, transfer it over to the manifest list.174if (enabled_layer == exp_layer_man_file->LayerName()) {175manifest_files.push_back(std::move(exp_layer_man_file));176break;177}178}179}180}181}182}183184// Grab the layer instance extensions information185size_t num_files = manifest_files.size();186for (size_t man_file = 0; man_file < num_files; ++man_file) {187manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);188}189}190return XR_SUCCESS;191}192193XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,194const char* const* enabled_api_layer_names,195std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces) {196XrResult last_error = XR_SUCCESS;197std::unordered_set<std::string> layers_already_found;198199bool any_loaded = false;200std::vector<std::unique_ptr<ApiLayerManifestFile>> enabled_layer_manifest_files_in_init_order = {};201202// Find any implicit layers.203XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER,204enabled_layer_manifest_files_in_init_order);205206for (const auto& enabled_layer_manifest_file : enabled_layer_manifest_files_in_init_order) {207layers_already_found.insert(enabled_layer_manifest_file->LayerName());208}209210// Find any explicit layers.211std::vector<std::unique_ptr<ApiLayerManifestFile>> explicit_layer_manifest_files = {};212213if (XR_SUCCEEDED(result)) {214result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER,215explicit_layer_manifest_files);216}217218bool found_all_layers = true;219220if (XR_SUCCEEDED(result)) {221// Put all explicit and then xrCreateInstance enabled layers into a string vector222223std::vector<std::string> enabled_explicit_api_layer_names = {};224225AddEnvironmentApiLayers(enabled_explicit_api_layer_names);226227if (enabled_api_layer_count > 0) {228if (nullptr == enabled_api_layer_names) {229LoaderLogger::LogErrorMessage(230"xrCreateInstance",231"VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter: enabledApiLayerCount is non-0 but array is NULL");232LoaderLogger::LogErrorMessage(233"xrCreateInstance", "VUID-xrCreateInstance-info-parameter: something wrong with XrInstanceCreateInfo contents");234return XR_ERROR_VALIDATION_FAILURE;235}236237std::copy(enabled_api_layer_names, enabled_api_layer_names + enabled_api_layer_count,238std::back_inserter(enabled_explicit_api_layer_names));239}240241// add explicit layers to list of layers to enable242for (const auto& layer_name : enabled_explicit_api_layer_names) {243bool found_this_layer = false;244245if (layers_already_found.count(layer_name) > 0) {246found_this_layer = true;247} else {248for (auto it = explicit_layer_manifest_files.begin(); it != explicit_layer_manifest_files.end();) {249bool erased_layer_manifest_file = false;250251if (layer_name == (*it)->LayerName()) {252found_this_layer = true;253layers_already_found.insert(layer_name);254enabled_layer_manifest_files_in_init_order.push_back(std::move(*it));255it = explicit_layer_manifest_files.erase(it);256erased_layer_manifest_file = true;257}258259if (!erased_layer_manifest_file) {260it++;261}262}263}264265// If even one of the layers wasn't found, we want to return an error266if (!found_this_layer) {267found_all_layers = false;268std::string error_message = "ApiLayerInterface::LoadApiLayers - failed to find layer ";269error_message += layer_name;270LoaderLogger::LogErrorMessage(openxr_command, error_message);271}272}273}274275for (std::unique_ptr<ApiLayerManifestFile>& manifest_file : enabled_layer_manifest_files_in_init_order) {276LoaderPlatformLibraryHandle layer_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());277if (nullptr == layer_library) {278if (!any_loaded) {279last_error = XR_ERROR_FILE_ACCESS_ERROR;280}281std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());282std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";283warning_message += manifest_file->LayerName();284warning_message += ", failed to load with message \"";285warning_message += library_message;286warning_message += "\"";287LoaderLogger::LogWarningMessage(openxr_command, warning_message);288continue;289}290#if defined(XR_HAS_REQUIRED_PLATFORM_LOADER_INIT_STRUCT) // Cannot proceed without mandatory xrInitializeLoaderKHR call.291if (!LoaderInitData::instance().initialized()) {292LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::LoadApiLayers skipping manifest file " +293manifest_file->Filename() +294" because xrInitializeLoaderKHR was not yet called.");295296LoaderPlatformLibraryClose(layer_library);297return XR_ERROR_VALIDATION_FAILURE;298}299#endif300301bool forwardedInitLoader = false;302if (LoaderInitData::instance().getPlatformParam() != nullptr) {303// If we have xrInitializeLoaderKHR exposed as an export, forward call to it.304const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR");305auto initLoader =306reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(layer_library, function_name));307if (initLoader != nullptr) {308// we found the entry point one way or another.309LoaderLogger::LogInfoMessage(openxr_command,310"ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer "311"before calling xrNegotiateLoaderApiLayerInterface.");312XrResult res = initLoader(LoaderInitData::instance().getPlatformParam());313if (!XR_SUCCEEDED(res)) {314LoaderLogger::LogErrorMessage(315openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed.");316317LoaderPlatformLibraryClose(layer_library);318return res;319}320forwardedInitLoader = true;321}322}323324// Get and settle on an layer interface version (using any provided name if required).325std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface");326auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderApiLayerInterface>(327LoaderPlatformLibraryGetProcAddr(layer_library, function_name));328329if (nullptr == negotiate) {330std::ostringstream oss;331oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()332<< " because negotiation function " << function_name << " was not found";333LoaderLogger::LogErrorMessage(openxr_command, oss.str());334LoaderPlatformLibraryClose(layer_library);335last_error = XR_ERROR_API_LAYER_NOT_PRESENT;336continue;337}338339// Loader info for negotiation340XrNegotiateLoaderInfo loader_info = {};341loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;342loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;343loader_info.structSize = sizeof(XrNegotiateLoaderInfo);344loader_info.minInterfaceVersion = 1;345loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;346loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);347loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.348349// Set up the layer return structure350XrNegotiateApiLayerRequest api_layer_info = {};351api_layer_info.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST;352api_layer_info.structVersion = XR_API_LAYER_INFO_STRUCT_VERSION;353api_layer_info.structSize = sizeof(XrNegotiateApiLayerRequest);354355XrResult res = negotiate(&loader_info, manifest_file->LayerName().c_str(), &api_layer_info);356// If we supposedly succeeded, but got a nullptr for getInstanceProcAddr357// then something still went wrong, so return with an error.358if (XR_SUCCEEDED(res) && nullptr == api_layer_info.getInstanceProcAddr) {359std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";360warning_message += manifest_file->LayerName();361warning_message += ", negotiation did not return a valid getInstanceProcAddr";362LoaderLogger::LogWarningMessage(openxr_command, warning_message);363res = XR_ERROR_FILE_CONTENTS_INVALID;364}365366if (XR_SUCCEEDED(res) && !forwardedInitLoader && LoaderInitData::instance().getPlatformParam() != nullptr) {367// Forward initialize loader call, where possible and if we did not do so before.368PFN_xrVoidFunction initializeVoid = nullptr;369PFN_xrInitializeLoaderKHR initialize = nullptr;370371// Now we may try asking xrGetInstanceProcAddr on the API layer372if (XR_SUCCEEDED(api_layer_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) {373if (initializeVoid == nullptr) {374LoaderLogger::LogErrorMessage(openxr_command,375"ApiLayerInterface::LoadApiLayers got success from xrGetInstanceProcAddr "376"for xrInitializeLoaderKHR, but output a null pointer.");377res = XR_ERROR_RUNTIME_FAILURE;378} else {379initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid);380}381}382if (initialize != nullptr) {383// we found the entry point one way or another.384LoaderLogger::LogInfoMessage(openxr_command,385"ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer "386"after calling xrNegotiateLoaderApiLayerInterface.");387res = initialize(LoaderInitData::instance().getPlatformParam());388if (!XR_SUCCEEDED(res)) {389LoaderLogger::LogErrorMessage(390openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed.");391}392}393}394395if (XR_FAILED(res)) {396if (!any_loaded) {397last_error = res;398}399std::ostringstream oss;400oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()401<< " due to failed negotiation with error " << res;402LoaderLogger::LogWarningMessage(openxr_command, oss.str());403LoaderPlatformLibraryClose(layer_library);404continue;405}406407{408std::ostringstream oss;409oss << "ApiLayerInterface::LoadApiLayers succeeded loading layer " << manifest_file->LayerName()410<< " using interface version " << api_layer_info.layerInterfaceVersion << " and OpenXR API version "411<< XR_VERSION_MAJOR(api_layer_info.layerApiVersion) << "." << XR_VERSION_MINOR(api_layer_info.layerApiVersion);412LoaderLogger::LogInfoMessage(openxr_command, oss.str());413}414415// Grab the list of extensions this layer supports for easy filtering after the416// xrCreateInstance call417std::vector<std::string> supported_extensions;418std::vector<XrExtensionProperties> extension_properties;419manifest_file->GetInstanceExtensionProperties(extension_properties);420supported_extensions.reserve(extension_properties.size());421for (XrExtensionProperties& ext_prop : extension_properties) {422supported_extensions.emplace_back(ext_prop.extensionName);423}424425// Add this API layer to the vector426api_layer_interfaces.emplace_back(new ApiLayerInterface(manifest_file->LayerName(), layer_library, supported_extensions,427api_layer_info.getInstanceProcAddr,428api_layer_info.createApiLayerInstance));429430// If we load one, clear all errors.431any_loaded = true;432last_error = XR_SUCCESS;433}434435// Set error here to preserve prior error behavior436if (!found_all_layers) {437last_error = XR_ERROR_API_LAYER_NOT_PRESENT;438}439440// If we failed catastrophically for some reason, clean up everything.441if (XR_FAILED(last_error)) {442api_layer_interfaces.clear();443}444445return last_error;446}447448ApiLayerInterface::ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,449std::vector<std::string>& supported_extensions,450PFN_xrGetInstanceProcAddr get_instance_proc_addr,451PFN_xrCreateApiLayerInstance create_api_layer_instance)452: _layer_name(layer_name),453_layer_library(layer_library),454_get_instance_proc_addr(get_instance_proc_addr),455_create_api_layer_instance(create_api_layer_instance),456_supported_extensions(supported_extensions) {}457458ApiLayerInterface::~ApiLayerInterface() {459std::string info_message = "ApiLayerInterface being destroyed for layer ";460info_message += _layer_name;461LoaderLogger::LogInfoMessage("", info_message);462LoaderPlatformLibraryClose(_layer_library);463}464465bool ApiLayerInterface::SupportsExtension(const std::string& extension_name) const {466bool found_prop = false;467for (const std::string& supported_extension : _supported_extensions) {468if (supported_extension == extension_name) {469found_prop = true;470break;471}472}473return found_prop;474}475476477