Path: blob/master/thirdparty/openxr/src/loader/api_layer_interface.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#include "api_layer_interface.hpp"1011#include "loader_init_data.hpp"12#include "loader_logger.hpp"13#include "loader_platform.hpp"14#include "manifest_file.hpp"15#include "platform_utils.hpp"1617#include <openxr/openxr.h>18#include <openxr/openxr_loader_negotiation.h>1920#include <cstring>21#include <memory>22#include <sstream>23#include <string>24#include <utility>25#include <vector>2627#define OPENXR_ENABLE_LAYERS_ENV_VAR "XR_ENABLE_API_LAYERS"2829// Add any layers defined in the loader layer environment variable.30static void AddEnvironmentApiLayers(std::vector<std::string>& enabled_layers) {31std::string layers = PlatformUtilsGetEnv(OPENXR_ENABLE_LAYERS_ENV_VAR);3233std::size_t last_found = 0;34std::size_t found = layers.find_first_of(PATH_SEPARATOR);35std::string cur_search;3637// Handle any path listings in the string (separated by the appropriate path separator)38while (found != std::string::npos) {39cur_search = layers.substr(last_found, found - last_found);40enabled_layers.push_back(cur_search);41last_found = found + 1;42found = layers.find_first_of(PATH_SEPARATOR, last_found);43}4445// If there's something remaining in the string, copy it over46if (last_found < layers.size()) {47cur_search = layers.substr(last_found);48enabled_layers.push_back(cur_search);49}50}5152XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count,53uint32_t* outgoing_count, XrApiLayerProperties* api_layer_properties) {54std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;55uint32_t manifest_count = 0;56// Validate props struct before proceeding57if (0 < incoming_count && nullptr != api_layer_properties) {58for (uint32_t i = 0; i < incoming_count; i++) {59if (XR_TYPE_API_LAYER_PROPERTIES != api_layer_properties[i].type) {60LoaderLogger::LogErrorMessage(openxr_command,61"VUID-XrApiLayerProperties-type-type: unknown type in api_layer_properties");62return XR_ERROR_VALIDATION_FAILURE;63}64}65}6667// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,68// and the function sets elementCountOutput." - 2.1169if (nullptr == outgoing_count) {70return XR_ERROR_VALIDATION_FAILURE;71}7273// Find any implicit layers which we may need to report information for.74XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);75if (XR_SUCCEEDED(result)) {76// Find any explicit layers which we may need to report information for.77result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);78}79if (XR_FAILED(result)) {80LoaderLogger::LogErrorMessage(openxr_command,81"ApiLayerInterface::GetApiLayerProperties - failed searching for API layer manifest files");82return result;83}8485// check for potential overflow before static_cast<uint32_t>86if (manifest_files.size() >= UINT32_MAX) {87LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::GetApiLayerProperties - too many API layers found");88return XR_ERROR_RUNTIME_FAILURE;89}9091manifest_count = static_cast<uint32_t>(manifest_files.size());92if (nullptr == outgoing_count) {93LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",94"VUID-xrEnumerateApiLayerProperties-propertyCountOutput-parameter: null propertyCountOutput");95return XR_ERROR_VALIDATION_FAILURE;96}9798*outgoing_count = manifest_count;99if (0 == incoming_count) {100// capacity check only101return XR_SUCCESS;102}103if (nullptr == api_layer_properties) {104// incoming_count is not 0 BUT the api_layer_properties is NULL105LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",106"VUID-xrEnumerateApiLayerProperties-properties-parameter: non-zero capacity but null array");107return XR_ERROR_VALIDATION_FAILURE;108}109if (incoming_count < manifest_count) {110LoaderLogger::LogErrorMessage(111"xrEnumerateInstanceExtensionProperties",112"VUID-xrEnumerateApiLayerProperties-propertyCapacityInput-parameter: insufficient space in array");113return XR_ERROR_SIZE_INSUFFICIENT;114}115116for (uint32_t prop = 0; prop < incoming_count && prop < manifest_count; ++prop) {117manifest_files[prop]->PopulateApiLayerProperties(api_layer_properties[prop]);118}119return XR_SUCCESS;120}121122XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,123std::vector<XrExtensionProperties>& extension_properties) {124std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;125126// If a layer name is supplied, only use the information out of that one layer127if (nullptr != layer_name && 0 != strlen(layer_name)) {128XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);129if (XR_SUCCEEDED(result)) {130// Find any explicit layers which we may need to report information for.131result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);132if (XR_FAILED(result)) {133LoaderLogger::LogErrorMessage(134openxr_command,135"ApiLayerInterface::GetInstanceExtensionProperties - failed searching for API layer manifest files");136return result;137}138139bool found = false;140size_t num_files = manifest_files.size();141for (size_t man_file = 0; man_file < num_files; ++man_file) {142// If a layer with the provided name exists, get it's instance extension information.143if (manifest_files[man_file]->LayerName() == layer_name) {144manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);145found = true;146break;147}148}149150// If nothing found, report 0151if (!found) {152return XR_ERROR_API_LAYER_NOT_PRESENT;153}154}155// Otherwise, we want to add only implicit API layers and explicit API layers enabled using the environment variables156} else {157XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);158if (XR_SUCCEEDED(result)) {159// Find any environmentally enabled explicit layers. If they're present, treat them like implicit layers160// since we know that they're going to be enabled.161std::vector<std::string> env_enabled_layers;162AddEnvironmentApiLayers(env_enabled_layers);163if (!env_enabled_layers.empty()) {164std::vector<std::unique_ptr<ApiLayerManifestFile>> exp_layer_man_files = {};165result =166ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files);167if (XR_SUCCEEDED(result)) {168for (auto& exp_layer_man_file : exp_layer_man_files) {169for (std::string& enabled_layer : env_enabled_layers) {170// If this is an enabled layer, transfer it over to the manifest list.171if (enabled_layer == exp_layer_man_file->LayerName()) {172manifest_files.push_back(std::move(exp_layer_man_file));173break;174}175}176}177}178}179}180181// Grab the layer instance extensions information182size_t num_files = manifest_files.size();183for (size_t man_file = 0; man_file < num_files; ++man_file) {184manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);185}186}187return XR_SUCCESS;188}189190XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,191const char* const* enabled_api_layer_names,192std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces) {193XrResult last_error = XR_SUCCESS;194std::unordered_set<std::string> layers_already_found;195196bool any_loaded = false;197std::vector<std::unique_ptr<ApiLayerManifestFile>> enabled_layer_manifest_files_in_init_order = {};198199// Find any implicit layers.200XrResult result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_IMPLICIT_API_LAYER,201enabled_layer_manifest_files_in_init_order);202203for (const auto& enabled_layer_manifest_file : enabled_layer_manifest_files_in_init_order) {204layers_already_found.insert(enabled_layer_manifest_file->LayerName());205}206207// Find any explicit layers.208std::vector<std::unique_ptr<ApiLayerManifestFile>> explicit_layer_manifest_files = {};209210if (XR_SUCCEEDED(result)) {211result = ApiLayerManifestFile::FindManifestFiles(openxr_command, MANIFEST_TYPE_EXPLICIT_API_LAYER,212explicit_layer_manifest_files);213}214215bool found_all_layers = true;216217if (XR_SUCCEEDED(result)) {218// Put all explicit and then xrCreateInstance enabled layers into a string vector219220std::vector<std::string> enabled_explicit_api_layer_names = {};221222AddEnvironmentApiLayers(enabled_explicit_api_layer_names);223224if (enabled_api_layer_count > 0) {225if (nullptr == enabled_api_layer_names) {226LoaderLogger::LogErrorMessage(227"xrCreateInstance",228"VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter: enabledApiLayerCount is non-0 but array is NULL");229LoaderLogger::LogErrorMessage(230"xrCreateInstance", "VUID-xrCreateInstance-info-parameter: something wrong with XrInstanceCreateInfo contents");231return XR_ERROR_VALIDATION_FAILURE;232}233234std::copy(enabled_api_layer_names, enabled_api_layer_names + enabled_api_layer_count,235std::back_inserter(enabled_explicit_api_layer_names));236}237238// add explicit layers to list of layers to enable239for (const auto& layer_name : enabled_explicit_api_layer_names) {240bool found_this_layer = false;241242if (layers_already_found.count(layer_name) > 0) {243found_this_layer = true;244} else {245for (auto it = explicit_layer_manifest_files.begin(); it != explicit_layer_manifest_files.end();) {246bool erased_layer_manifest_file = false;247248if (layer_name == (*it)->LayerName()) {249found_this_layer = true;250layers_already_found.insert(layer_name);251enabled_layer_manifest_files_in_init_order.push_back(std::move(*it));252it = explicit_layer_manifest_files.erase(it);253erased_layer_manifest_file = true;254}255256if (!erased_layer_manifest_file) {257it++;258}259}260}261262// If even one of the layers wasn't found, we want to return an error263if (!found_this_layer) {264found_all_layers = false;265std::string error_message = "ApiLayerInterface::LoadApiLayers - failed to find layer ";266error_message += layer_name;267LoaderLogger::LogErrorMessage(openxr_command, error_message);268}269}270}271272for (std::unique_ptr<ApiLayerManifestFile>& manifest_file : enabled_layer_manifest_files_in_init_order) {273LoaderPlatformLibraryHandle layer_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());274if (nullptr == layer_library) {275if (!any_loaded) {276last_error = XR_ERROR_FILE_ACCESS_ERROR;277}278std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());279std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";280warning_message += manifest_file->LayerName();281warning_message += ", failed to load with message \"";282warning_message += library_message;283warning_message += "\"";284LoaderLogger::LogWarningMessage(openxr_command, warning_message);285continue;286}287#ifdef XR_KHR_LOADER_INIT_SUPPORT288if (!LoaderInitData::instance().initialized()) {289LoaderLogger::LogErrorMessage(openxr_command, "ApiLayerInterface::LoadApiLayers skipping manifest file " +290manifest_file->Filename() +291" because xrInitializeLoaderKHR was not yet called.");292293LoaderPlatformLibraryClose(layer_library);294return XR_ERROR_VALIDATION_FAILURE;295}296bool forwardedInitLoader = false;297{298// If we have xrInitializeLoaderKHR exposed as an export, forward call to it.299const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR");300auto initLoader =301reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(layer_library, function_name));302if (initLoader != nullptr) {303// we found the entry point one way or another.304LoaderLogger::LogInfoMessage(openxr_command,305"ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer "306"before calling xrNegotiateLoaderApiLayerInterface.");307XrResult res = initLoader(LoaderInitData::instance().getParam());308if (!XR_SUCCEEDED(res)) {309LoaderLogger::LogErrorMessage(310openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed.");311312LoaderPlatformLibraryClose(layer_library);313return res;314}315forwardedInitLoader = true;316}317}318#endif319320// Get and settle on an layer interface version (using any provided name if required).321std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface");322auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderApiLayerInterface>(323LoaderPlatformLibraryGetProcAddr(layer_library, function_name));324325if (nullptr == negotiate) {326std::ostringstream oss;327oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()328<< " because negotiation function " << function_name << " was not found";329LoaderLogger::LogErrorMessage(openxr_command, oss.str());330LoaderPlatformLibraryClose(layer_library);331last_error = XR_ERROR_API_LAYER_NOT_PRESENT;332continue;333}334335// Loader info for negotiation336XrNegotiateLoaderInfo loader_info = {};337loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;338loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;339loader_info.structSize = sizeof(XrNegotiateLoaderInfo);340loader_info.minInterfaceVersion = 1;341loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;342loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);343loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.344345// Set up the layer return structure346XrNegotiateApiLayerRequest api_layer_info = {};347api_layer_info.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST;348api_layer_info.structVersion = XR_API_LAYER_INFO_STRUCT_VERSION;349api_layer_info.structSize = sizeof(XrNegotiateApiLayerRequest);350351XrResult res = negotiate(&loader_info, manifest_file->LayerName().c_str(), &api_layer_info);352// If we supposedly succeeded, but got a nullptr for getInstanceProcAddr353// then something still went wrong, so return with an error.354if (XR_SUCCEEDED(res) && nullptr == api_layer_info.getInstanceProcAddr) {355std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";356warning_message += manifest_file->LayerName();357warning_message += ", negotiation did not return a valid getInstanceProcAddr";358LoaderLogger::LogWarningMessage(openxr_command, warning_message);359res = XR_ERROR_FILE_CONTENTS_INVALID;360}361362#ifdef XR_KHR_LOADER_INIT_SUPPORT363if (XR_SUCCEEDED(res) && !forwardedInitLoader) {364// Forward initialize loader call, where possible and if we did not do so before.365PFN_xrVoidFunction initializeVoid = nullptr;366PFN_xrInitializeLoaderKHR initialize = nullptr;367368// Now we may try asking xrGetInstanceProcAddr on the API layer369if (XR_SUCCEEDED(api_layer_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) {370if (initializeVoid == nullptr) {371LoaderLogger::LogErrorMessage(openxr_command,372"ApiLayerInterface::LoadApiLayers got success from xrGetInstanceProcAddr "373"for xrInitializeLoaderKHR, but output a null pointer.");374res = XR_ERROR_RUNTIME_FAILURE;375} else {376initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid);377}378}379if (initialize != nullptr) {380// we found the entry point one way or another.381LoaderLogger::LogInfoMessage(openxr_command,382"ApiLayerInterface::LoadApiLayers forwarding xrInitializeLoaderKHR call to API layer "383"after calling xrNegotiateLoaderApiLayerInterface.");384res = initialize(LoaderInitData::instance().getParam());385if (!XR_SUCCEEDED(res)) {386LoaderLogger::LogErrorMessage(387openxr_command, "ApiLayerInterface::LoadApiLayers forwarded call to xrInitializeLoaderKHR failed.");388}389}390}391#endif392393if (XR_FAILED(res)) {394if (!any_loaded) {395last_error = res;396}397std::ostringstream oss;398oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()399<< " due to failed negotiation with error " << res;400LoaderLogger::LogWarningMessage(openxr_command, oss.str());401LoaderPlatformLibraryClose(layer_library);402continue;403}404405{406std::ostringstream oss;407oss << "ApiLayerInterface::LoadApiLayers succeeded loading layer " << manifest_file->LayerName()408<< " using interface version " << api_layer_info.layerInterfaceVersion << " and OpenXR API version "409<< XR_VERSION_MAJOR(api_layer_info.layerApiVersion) << "." << XR_VERSION_MINOR(api_layer_info.layerApiVersion);410LoaderLogger::LogInfoMessage(openxr_command, oss.str());411}412413// Grab the list of extensions this layer supports for easy filtering after the414// xrCreateInstance call415std::vector<std::string> supported_extensions;416std::vector<XrExtensionProperties> extension_properties;417manifest_file->GetInstanceExtensionProperties(extension_properties);418supported_extensions.reserve(extension_properties.size());419for (XrExtensionProperties& ext_prop : extension_properties) {420supported_extensions.emplace_back(ext_prop.extensionName);421}422423// Add this API layer to the vector424api_layer_interfaces.emplace_back(new ApiLayerInterface(manifest_file->LayerName(), layer_library, supported_extensions,425api_layer_info.getInstanceProcAddr,426api_layer_info.createApiLayerInstance));427428// If we load one, clear all errors.429any_loaded = true;430last_error = XR_SUCCESS;431}432433// Set error here to preserve prior error behavior434if (!found_all_layers) {435last_error = XR_ERROR_API_LAYER_NOT_PRESENT;436}437438// If we failed catastrophically for some reason, clean up everything.439if (XR_FAILED(last_error)) {440api_layer_interfaces.clear();441}442443return last_error;444}445446ApiLayerInterface::ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,447std::vector<std::string>& supported_extensions,448PFN_xrGetInstanceProcAddr get_instance_proc_addr,449PFN_xrCreateApiLayerInstance create_api_layer_instance)450: _layer_name(layer_name),451_layer_library(layer_library),452_get_instance_proc_addr(get_instance_proc_addr),453_create_api_layer_instance(create_api_layer_instance),454_supported_extensions(supported_extensions) {}455456ApiLayerInterface::~ApiLayerInterface() {457std::string info_message = "ApiLayerInterface being destroyed for layer ";458info_message += _layer_name;459LoaderLogger::LogInfoMessage("", info_message);460LoaderPlatformLibraryClose(_layer_library);461}462463bool ApiLayerInterface::SupportsExtension(const std::string& extension_name) const {464bool found_prop = false;465for (const std::string& supported_extension : _supported_extensions) {466if (supported_extension == extension_name) {467found_prop = true;468break;469}470}471return found_prop;472}473474475