Path: blob/master/thirdparty/openxr/src/loader/loader_core.cpp
20898 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 Authors: Mark Young <[email protected]>, Dave Houlton <[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 "api_layer_interface.hpp"14#include "exception_handling.hpp"15#include "hex_and_handles.h"16#include "loader_init_data.hpp"17#include "loader_instance.hpp"18#include "loader_logger_recorders.hpp"19#include "loader_logger.hpp"20#include "loader_platform.hpp"21#include "runtime_interface.hpp"22#include "xr_generated_dispatch_table_core.h"23#include "xr_generated_loader.hpp"2425#include <openxr/openxr.h>2627#include <cstring>28#include <memory>29#include <mutex>30#include <sstream>31#include <string>32#include <utility>33#include <vector>3435// Global loader lock to:36// 1. Ensure ActiveLoaderInstance get and set operations are done atomically.37// 2. Ensure RuntimeInterface isn't used to unload the runtime while the runtime is in use.38static std::mutex &GetGlobalLoaderMutex() {39static std::mutex loader_mutex;40return loader_mutex;41}4243// Prototypes for the debug utils calls used internally.44static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineCreateDebugUtilsMessengerEXT(45XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, XrDebugUtilsMessengerEXT *messenger);46static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger);4748// Terminal functions needed by xrCreateInstance.49static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance, const char *, PFN_xrVoidFunction *);50static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *, XrInstance *);51static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *,52const struct XrApiLayerCreateInfo *, XrInstance *);53static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance, const XrDebugUtilsObjectNameInfoEXT *);54static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance,55const XrDebugUtilsMessengerCreateInfoEXT *,56XrDebugUtilsMessengerEXT *);57static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT);58static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(59XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,60const XrDebugUtilsMessengerCallbackDataEXT *callbackData);61static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name,62PFN_xrVoidFunction *function);6364// Utility template function meant to validate if a fixed size string contains65// a null-terminator.66template <size_t max_length>67inline bool IsMissingNullTerminator(const char (&str)[max_length]) {68for (size_t index = 0; index < max_length; ++index) {69if (str[index] == '\0') {70return false;71}72}73return true;74}7576// ---- Core 1.0 manual loader trampoline functions77static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *);7879static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo)80XRLOADER_ABI_TRY {81LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline");82return InitializeLoaderInitData(loaderInitInfo);83}84XRLOADER_ABI_CATCH_FALLBACK8586static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,87uint32_t *propertyCountOutput,88XrApiLayerProperties *properties) XRLOADER_ABI_TRY {89LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties", "Entering loader trampoline");9091// Make sure only one thread is attempting to read the JSON files at a time.92std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());9394XrResult result = ApiLayerInterface::GetApiLayerProperties("xrEnumerateApiLayerProperties", propertyCapacityInput,95propertyCountOutput, properties);96if (XR_FAILED(result)) {97LoaderLogger::LogErrorMessage("xrEnumerateApiLayerProperties", "Failed ApiLayerInterface::GetApiLayerProperties");98}99100return result;101}102XRLOADER_ABI_CATCH_FALLBACK103104static XRAPI_ATTR XrResult XRAPI_CALL105LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput,106XrExtensionProperties *properties) XRLOADER_ABI_TRY {107bool just_layer_properties = false;108LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Entering loader trampoline");109110// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,111// and the function sets elementCountOutput." - 2.11112if (nullptr == propertyCountOutput) {113return XR_ERROR_VALIDATION_FAILURE;114}115116if (nullptr != layerName && 0 != strlen(layerName)) {117// Application is only interested in layer's properties, not all of them.118just_layer_properties = true;119}120121std::vector<XrExtensionProperties> extension_properties = {};122XrResult result;123124{125// Make sure the runtime isn't unloaded while this call is in progress.126std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());127128// Get the layer extension properties129result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties", layerName,130extension_properties);131if (XR_SUCCEEDED(result) && !just_layer_properties) {132// If not specific to a layer, get the runtime extension properties133result = RuntimeInterface::LoadRuntime("xrEnumerateInstanceExtensionProperties");134if (XR_SUCCEEDED(result)) {135RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties);136} else {137LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",138"Failed to find default runtime with RuntimeInterface::LoadRuntime()");139}140}141}142143if (XR_FAILED(result)) {144LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", "Failed querying extension properties");145return result;146}147148// If this is not in reference to a specific layer, then add the loader-specific extension properties as well.149// These are extensions that the loader directly supports.150if (!just_layer_properties) {151for (const XrExtensionProperties &loader_prop : LoaderInstance::LoaderSpecificExtensions()) {152bool found_prop = false;153for (XrExtensionProperties &existing_prop : extension_properties) {154if (0 == strcmp(existing_prop.extensionName, loader_prop.extensionName)) {155found_prop = true;156// Use the loader version if it is newer157if (existing_prop.extensionVersion < loader_prop.extensionVersion) {158existing_prop.extensionVersion = loader_prop.extensionVersion;159}160break;161}162}163// Only add extensions not supported by the loader164if (!found_prop) {165extension_properties.push_back(loader_prop);166}167}168}169170auto num_extension_properties = static_cast<uint32_t>(extension_properties.size());171if (propertyCapacityInput == 0) {172*propertyCountOutput = num_extension_properties;173} else if (nullptr != properties) {174if (propertyCapacityInput < num_extension_properties) {175*propertyCountOutput = num_extension_properties;176LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter",177"xrEnumerateInstanceExtensionProperties", "insufficient space in array");178return XR_ERROR_SIZE_INSUFFICIENT;179}180181uint32_t num_to_copy = num_extension_properties;182// Determine how many extension properties we can copy over183if (propertyCapacityInput < num_to_copy) {184num_to_copy = propertyCapacityInput;185}186bool properties_valid = true;187for (uint32_t prop = 0; prop < propertyCapacityInput && prop < extension_properties.size(); ++prop) {188if (XR_TYPE_EXTENSION_PROPERTIES != properties[prop].type) {189properties_valid = false;190LoaderLogger::LogValidationErrorMessage("VUID-XrExtensionProperties-type-type",191"xrEnumerateInstanceExtensionProperties", "unknown type in properties");192}193if (properties_valid) {194properties[prop] = extension_properties[prop];195}196}197if (!properties_valid) {198LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-properties-parameter",199"xrEnumerateInstanceExtensionProperties", "invalid properties");200return XR_ERROR_VALIDATION_FAILURE;201}202if (nullptr != propertyCountOutput) {203*propertyCountOutput = num_to_copy;204}205} else {206// incoming_count is not 0 BUT the properties is NULL207return XR_ERROR_VALIDATION_FAILURE;208}209LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Completed loader trampoline");210return XR_SUCCESS;211}212XRLOADER_ABI_CATCH_FALLBACK213214static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCreateInfo *info,215XrInstance *instance) XRLOADER_ABI_TRY {216LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader trampoline");217if (nullptr == info) {218LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance", "must be non-NULL");219return XR_ERROR_VALIDATION_FAILURE;220}221// If application requested OpenXR API version is higher than the loader version, then we need to throw222// an error.223uint16_t app_major = XR_VERSION_MAJOR(info->applicationInfo.apiVersion); // NOLINT224uint16_t app_minor = XR_VERSION_MINOR(info->applicationInfo.apiVersion); // NOLINT225uint16_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); // NOLINT226uint16_t loader_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION); // NOLINT227if (app_major > loader_major || (app_major == loader_major && app_minor > loader_minor)) {228std::ostringstream oss;229oss << "xrCreateInstance called with invalid API version " << app_major << "." << app_minor230<< ". Max supported version is " << loader_major << "." << loader_minor;231LoaderLogger::LogErrorMessage("xrCreateInstance", oss.str());232return XR_ERROR_API_VERSION_UNSUPPORTED;233}234235if (nullptr == instance) {236LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-instance-parameter", "xrCreateInstance", "must be non-NULL");237return XR_ERROR_VALIDATION_FAILURE;238}239240// Make sure the ActiveLoaderInstance::IsAvailable check is done atomically with RuntimeInterface::LoadRuntime.241std::unique_lock<std::mutex> instance_lock(GetGlobalLoaderMutex());242243// Check if there is already an XrInstance that is alive. If so, another instance cannot be created.244// The loader does not support multiple simultaneous instances because the loader is intended to be245// usable by apps using future OpenXR APIs (through xrGetInstanceProcAddr). Because the loader would246// not be aware of new handle types, it would not be able to look up the appropriate dispatch table247// in some cases.248if (ActiveLoaderInstance::IsAvailable()) { // If there is an XrInstance already alive.249LoaderLogger::LogErrorMessage("xrCreateInstance", "Loader does not support simultaneous XrInstances");250return XR_ERROR_LIMIT_REACHED;251}252253std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces;254XrResult result;255256// Make sure only one thread is attempting to read the JSON files and use the instance.257{258// Load the available runtime259result = RuntimeInterface::LoadRuntime("xrCreateInstance");260if (XR_FAILED(result)) {261LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading runtime information");262} else {263// Load the appropriate layers264result = ApiLayerInterface::LoadApiLayers("xrCreateInstance", info->enabledApiLayerCount, info->enabledApiLayerNames,265api_layer_interfaces);266if (XR_FAILED(result)) {267LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading layer information");268}269}270}271272// Create the loader instance (only send down first runtime interface)273LoaderInstance *loader_instance = nullptr;274if (XR_SUCCEEDED(result)) {275std::unique_ptr<LoaderInstance> owned_loader_instance;276result = LoaderInstance::CreateInstance(LoaderXrTermGetInstanceProcAddr, LoaderXrTermCreateInstance,277LoaderXrTermCreateApiLayerInstance, std::move(api_layer_interfaces), info,278&owned_loader_instance);279if (XR_SUCCEEDED(result)) {280loader_instance = owned_loader_instance.get();281result = ActiveLoaderInstance::Set(std::move(owned_loader_instance), "xrCreateInstance");282}283}284285if (XR_SUCCEEDED(result)) {286// Create a debug utils messenger if the create structure is in the "next" chain287const auto *next_header = reinterpret_cast<const XrBaseInStructure *>(info->next);288const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr;289while (next_header != nullptr) {290if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {291LoaderLogger::LogInfoMessage("xrCreateInstance", "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain.");292dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);293XrDebugUtilsMessengerEXT messenger;294result = LoaderTrampolineCreateDebugUtilsMessengerEXT(loader_instance->GetInstanceHandle(), dbg_utils_create_info,295&messenger);296if (XR_FAILED(result)) {297return XR_ERROR_VALIDATION_FAILURE;298}299loader_instance->SetDefaultDebugUtilsMessenger(messenger);300break;301}302next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next);303}304}305306if (XR_FAILED(result)) {307// Ensure the global loader instance and runtime are destroyed if something went wrong.308ActiveLoaderInstance::Remove();309RuntimeInterface::UnloadRuntime("xrCreateInstance");310LoaderLogger::LogErrorMessage("xrCreateInstance", "xrCreateInstance failed");311} else {312*instance = loader_instance->GetInstanceHandle();313LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader trampoline");314}315316return result;317}318XRLOADER_ABI_CATCH_FALLBACK319320static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {321LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader trampoline");322// Runtimes may detect XR_NULL_HANDLE provided as a required handle parameter and return XR_ERROR_HANDLE_INVALID. - 2.9323if (XR_NULL_HANDLE == instance) {324LoaderLogger::LogErrorMessage("xrDestroyInstance", "Instance handle is XR_NULL_HANDLE.");325return XR_ERROR_HANDLE_INVALID;326}327328// Make sure the runtime isn't unloaded while it is being used by xrEnumerateInstanceExtensionProperties.329std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());330331LoaderInstance *loader_instance;332XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyInstance");333if (XR_FAILED(result)) {334return result;335}336337const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();338339// If we allocated a default debug utils messenger, free it340XrDebugUtilsMessengerEXT messenger = loader_instance->DefaultDebugUtilsMessenger();341if (messenger != XR_NULL_HANDLE) {342LoaderTrampolineDestroyDebugUtilsMessengerEXT(messenger);343}344345// Now destroy the instance346if (XR_FAILED(dispatch_table->DestroyInstance(instance))) {347LoaderLogger::LogErrorMessage("xrDestroyInstance", "Unknown error occurred calling down chain");348}349350// Get rid of the loader instance. This will make it possible to create another instance in the future.351ActiveLoaderInstance::Remove();352353// Lock the instance create/destroy mutex354LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader trampoline");355356// Finally, unload the runtime if necessary357RuntimeInterface::UnloadRuntime("xrDestroyInstance");358359return XR_SUCCESS;360}361XRLOADER_ABI_CATCH_FALLBACK362363// ---- Core 1.0 manual loader terminator functions364365// Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid.366static XrResult ValidateApplicationInfo(const XrApplicationInfo &info) {367if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(info.applicationName)) {368LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-applicationName-parameter", "xrCreateInstance",369"application name missing NULL terminator.");370return XR_ERROR_NAME_INVALID;371}372if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(info.engineName)) {373LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-engineName-parameter", "xrCreateInstance",374"engine name missing NULL terminator.");375return XR_ERROR_NAME_INVALID;376}377if (strlen(info.applicationName) == 0) {378LoaderLogger::LogErrorMessage("xrCreateInstance",379"VUID-XrApplicationInfo-engineName-parameter: application name can not be empty.");380return XR_ERROR_NAME_INVALID;381}382return XR_SUCCESS;383}384385// Validate that the XrInstanceCreateInfo is valid386static XrResult ValidateInstanceCreateInfo(const XrInstanceCreateInfo *info) {387// Should have a valid 'type'388if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) {389LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-type-type", "xrCreateInstance",390"expected XR_TYPE_INSTANCE_CREATE_INFO.");391return XR_ERROR_VALIDATION_FAILURE;392}393// Flags must be 0394if (0 != info->createFlags) {395LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-createFlags-zerobitmask", "xrCreateInstance",396"flags must be 0.");397return XR_ERROR_VALIDATION_FAILURE;398}399// ApplicationInfo struct must be valid400XrResult result = ValidateApplicationInfo(info->applicationInfo);401if (XR_FAILED(result)) {402LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-applicationInfo-parameter", "xrCreateInstance",403"info->applicationInfo is not valid.");404return result;405}406// VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter already tested in LoadApiLayers()407if ((info->enabledExtensionCount != 0u) && nullptr == info->enabledExtensionNames) {408LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-enabledExtensionNames-parameter", "xrCreateInstance",409"enabledExtensionCount is non-0 but array is NULL");410return XR_ERROR_VALIDATION_FAILURE;411}412return XR_SUCCESS;413}414415static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *createInfo,416XrInstance *instance) XRLOADER_ABI_TRY {417LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader terminator");418XrResult result = ValidateInstanceCreateInfo(createInfo);419if (XR_FAILED(result)) {420LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance",421"something wrong with XrInstanceCreateInfo contents");422return result;423}424result = RuntimeInterface::GetRuntime().CreateInstance(createInfo, instance);425LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader terminator");426return result;427}428XRLOADER_ABI_CATCH_FALLBACK429430static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info,431const struct XrApiLayerCreateInfo * /*apiLayerInfo*/,432XrInstance *instance) {433return LoaderXrTermCreateInstance(info, instance);434}435436static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {437LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader terminator");438LoaderLogger::GetInstance().RemoveLogRecordersForXrInstance(instance);439XrResult result = RuntimeInterface::GetRuntime().DestroyInstance(instance);440LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader terminator");441return result;442}443XRLOADER_ABI_CATCH_FALLBACK444445static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance instance, const char *name,446PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {447// A few instance commands need to go through a loader terminator.448// Otherwise, go directly to the runtime version of the command if it exists.449// But first set the function pointer to NULL so that the fall-through below actually works.450*function = nullptr;451452// NOTE: ActiveLoaderInstance cannot be used in this function because it is called before an instance is made active.453454if (0 == strcmp(name, "xrGetInstanceProcAddr")) {455*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermGetInstanceProcAddr);456} else if (0 == strcmp(name, "xrCreateInstance")) {457*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateInstance);458} else if (0 == strcmp(name, "xrDestroyInstance")) {459*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyInstance);460} else if (0 == strcmp(name, "xrSetDebugUtilsObjectNameEXT")) {461*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSetDebugUtilsObjectNameEXT);462} else if (0 == strcmp(name, "xrCreateDebugUtilsMessengerEXT")) {463*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateDebugUtilsMessengerEXT);464} else if (0 == strcmp(name, "xrDestroyDebugUtilsMessengerEXT")) {465*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyDebugUtilsMessengerEXT);466} else if (0 == strcmp(name, "xrSubmitDebugUtilsMessageEXT")) {467*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSubmitDebugUtilsMessageEXT);468} else if (0 == strcmp(name, "xrCreateApiLayerInstance")) {469// Special layer version of xrCreateInstance terminator. If we get called this by a layer,470// we simply re-direct the information back into the standard xrCreateInstance terminator.471*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateApiLayerInstance);472}473474if (nullptr != *function) {475return XR_SUCCESS;476}477478return RuntimeInterface::GetInstanceProcAddr(instance, name, function);479}480XRLOADER_ABI_CATCH_FALLBACK481482// ---- Extension manual loader trampoline functions483484static XRAPI_ATTR XrResult XRAPI_CALL485LoaderTrampolineCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo,486XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {487LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader trampoline");488489if (instance == XR_NULL_HANDLE) {490LoaderLogger::LogErrorMessage("xrCreateDebugUtilsMessengerEXT", "Instance handle is XR_NULL_HANDLE.");491return XR_ERROR_HANDLE_INVALID;492}493494LoaderInstance *loader_instance;495XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateDebugUtilsMessengerEXT");496if (XR_FAILED(result)) {497return result;498}499500result = loader_instance->DispatchTable()->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);501LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader trampoline");502return result;503}504XRLOADER_ABI_CATCH_BAD_ALLOC_OOM XRLOADER_ABI_CATCH_FALLBACK505506static XRAPI_ATTR XrResult XRAPI_CALL507LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {508// TODO: get instance from messenger in loader509// Also, is the loader really doing all this every call?510LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader trampoline");511512if (messenger == XR_NULL_HANDLE) {513LoaderLogger::LogErrorMessage("xrDestroyDebugUtilsMessengerEXT", "Messenger handle is XR_NULL_HANDLE.");514return XR_ERROR_HANDLE_INVALID;515}516517LoaderInstance *loader_instance;518XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyDebugUtilsMessengerEXT");519if (XR_FAILED(result)) {520return result;521}522523result = loader_instance->DispatchTable()->DestroyDebugUtilsMessengerEXT(messenger);524LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader trampoline");525return result;526}527XRLOADER_ABI_CATCH_FALLBACK528529static XRAPI_ATTR XrResult XRAPI_CALL530LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {531if (session == XR_NULL_HANDLE) {532LoaderLogger::LogErrorMessage("xrSessionBeginDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");533return XR_ERROR_HANDLE_INVALID;534}535536if (nullptr == labelInfo) {537LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter",538"xrSessionBeginDebugUtilsLabelRegionEXT", "labelInfo must be non-NULL",539{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});540return XR_ERROR_VALIDATION_FAILURE;541}542543LoaderInstance *loader_instance;544XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionBeginDebugUtilsLabelRegionEXT");545if (XR_FAILED(result)) {546return result;547}548LoaderLogger::GetInstance().BeginLabelRegion(session, labelInfo);549const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();550if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) {551return dispatch_table->SessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);552}553return XR_SUCCESS;554}555XRLOADER_ABI_CATCH_FALLBACK556557static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY {558if (session == XR_NULL_HANDLE) {559LoaderLogger::LogErrorMessage("xrSessionEndDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");560return XR_ERROR_HANDLE_INVALID;561}562563LoaderInstance *loader_instance;564XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionEndDebugUtilsLabelRegionEXT");565if (XR_FAILED(result)) {566return result;567}568569LoaderLogger::GetInstance().EndLabelRegion(session);570const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();571if (nullptr != dispatch_table->SessionEndDebugUtilsLabelRegionEXT) {572return dispatch_table->SessionEndDebugUtilsLabelRegionEXT(session);573}574return XR_SUCCESS;575}576XRLOADER_ABI_CATCH_FALLBACK577578static XRAPI_ATTR XrResult XRAPI_CALL579LoaderTrampolineSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {580if (session == XR_NULL_HANDLE) {581LoaderLogger::LogErrorMessage("xrSessionInsertDebugUtilsLabelEXT", "Session handle is XR_NULL_HANDLE.");582return XR_ERROR_HANDLE_INVALID;583}584585LoaderInstance *loader_instance;586XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionInsertDebugUtilsLabelEXT");587if (XR_FAILED(result)) {588return result;589}590591if (nullptr == labelInfo) {592LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter",593"xrSessionInsertDebugUtilsLabelEXT", "labelInfo must be non-NULL",594{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});595return XR_ERROR_VALIDATION_FAILURE;596}597598LoaderLogger::GetInstance().InsertLabel(session, labelInfo);599600const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();601if (nullptr != dispatch_table->SessionInsertDebugUtilsLabelEXT) {602return dispatch_table->SessionInsertDebugUtilsLabelEXT(session, labelInfo);603}604605return XR_SUCCESS;606}607XRLOADER_ABI_CATCH_FALLBACK608609// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.610static XRAPI_ATTR XrResult XRAPI_CALL611LoaderTrampolineSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {612LoaderInstance *loader_instance;613XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSetDebugUtilsObjectNameEXT");614if (XR_SUCCEEDED(result)) {615result = loader_instance->DispatchTable()->SetDebugUtilsObjectNameEXT(instance, nameInfo);616}617return result;618}619XRLOADER_ABI_CATCH_FALLBACK620621// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.622static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSubmitDebugUtilsMessageEXT(623XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,624const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {625LoaderInstance *loader_instance;626XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSubmitDebugUtilsMessageEXT");627if (XR_SUCCEEDED(result)) {628result =629loader_instance->DispatchTable()->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);630}631return result;632}633XRLOADER_ABI_CATCH_FALLBACK634635// ---- Extension manual loader terminator functions636637XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance,638const XrDebugUtilsMessengerCreateInfoEXT *createInfo,639XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {640LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader terminator");641if (nullptr == messenger) {642LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter",643"xrCreateDebugUtilsMessengerEXT", "invalid messenger pointer");644return XR_ERROR_VALIDATION_FAILURE;645}646const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);647XrResult result = XR_SUCCESS;648// This extension is supported entirely by the loader which means the runtime may or may not support it.649if (nullptr != dispatch_table->CreateDebugUtilsMessengerEXT) {650result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);651} else {652// Just allocate a character so we have a unique value653char *temp_mess_ptr = new char;654*messenger = reinterpret_cast<XrDebugUtilsMessengerEXT>(temp_mess_ptr);655}656if (XR_SUCCEEDED(result)) {657LoaderLogger::GetInstance().AddLogRecorderForXrInstance(instance, MakeDebugUtilsLoaderLogRecorder(createInfo, *messenger));658RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, *messenger);659}660LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader terminator");661return result;662}663XRLOADER_ABI_CATCH_FALLBACK664665XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {666LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader terminator");667const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger);668XrResult result = XR_SUCCESS;669LoaderLogger::GetInstance().RemoveLogRecorder(MakeHandleGeneric(messenger));670RuntimeInterface::GetRuntime().ForgetDebugMessenger(messenger);671// This extension is supported entirely by the loader which means the runtime may or may not support it.672if (nullptr != dispatch_table->DestroyDebugUtilsMessengerEXT) {673result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger);674} else {675// Delete the character we would've created676delete (reinterpret_cast<char *>(MakeHandleGeneric(messenger)));677}678LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader terminator");679return result;680}681XRLOADER_ABI_CATCH_FALLBACK682683XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(684XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,685const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {686LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Entering loader terminator");687const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);688XrResult result = XR_SUCCESS;689if (nullptr != dispatch_table->SubmitDebugUtilsMessageEXT) {690result = dispatch_table->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);691} else {692// Only log the message from the loader if the runtime doesn't support this extension. If we did,693// then the user would receive multiple instances of the same message.694LoaderLogger::GetInstance().LogDebugUtilsMessage(messageSeverity, messageTypes, callbackData);695}696LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Completed loader terminator");697return result;698}699XRLOADER_ABI_CATCH_FALLBACK700701XRAPI_ATTR XrResult XRAPI_CALL702LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {703LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Entering loader terminator");704const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);705XrResult result = XR_SUCCESS;706if (nullptr != dispatch_table->SetDebugUtilsObjectNameEXT) {707result = dispatch_table->SetDebugUtilsObjectNameEXT(instance, nameInfo);708}709LoaderLogger::GetInstance().AddObjectName(nameInfo->objectHandle, nameInfo->objectType, nameInfo->objectName);710LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Completed loader terminator");711return result;712}713XRLOADER_ABI_CATCH_FALLBACK714715XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name,716PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {717if (nullptr == function) {718LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",719"Invalid Function pointer");720return XR_ERROR_VALIDATION_FAILURE;721}722723if (nullptr == name) {724LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",725"Invalid Name pointer");726return XR_ERROR_VALIDATION_FAILURE;727}728729// Initialize the function to nullptr in case it does not get caught in a known case730*function = nullptr;731732LoaderInstance *loader_instance = nullptr;733if (instance == XR_NULL_HANDLE) {734// Null instance is allowed for a few specific API entry points, otherwise return error735if (strcmp(name, "xrCreateInstance") != 0 && strcmp(name, "xrEnumerateApiLayerProperties") != 0 &&736strcmp(name, "xrEnumerateInstanceExtensionProperties") != 0 && strcmp(name, "xrInitializeLoaderKHR") != 0) {737// TODO why is xrGetInstanceProcAddr not listed in here?738std::string error_str = "XR_NULL_HANDLE for instance but query for ";739error_str += name;740error_str += " requires a valid instance";741LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-instance-parameter", "xrGetInstanceProcAddr",742error_str);743return XR_ERROR_HANDLE_INVALID;744}745} else {746// non null instance passed in, it should be our current instance747XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProcAddr");748if (XR_FAILED(result)) {749return result;750}751if (loader_instance->GetInstanceHandle() != instance) {752return XR_ERROR_HANDLE_INVALID;753}754}755756// These functions must always go through the loader's implementation (trampoline).757if (strcmp(name, "xrGetInstanceProcAddr") == 0) {758*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrGetInstanceProcAddr);759return XR_SUCCESS;760} else if (strcmp(name, "xrInitializeLoaderKHR") == 0) {761*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrInitializeLoaderKHR);762return XR_SUCCESS;763} else if (strcmp(name, "xrEnumerateApiLayerProperties") == 0) {764*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateApiLayerProperties);765return XR_SUCCESS;766} else if (strcmp(name, "xrEnumerateInstanceExtensionProperties") == 0) {767*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateInstanceExtensionProperties);768return XR_SUCCESS;769} else if (strcmp(name, "xrCreateInstance") == 0) {770*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrCreateInstance);771return XR_SUCCESS;772} else if (strcmp(name, "xrDestroyInstance") == 0) {773*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrDestroyInstance);774return XR_SUCCESS;775}776777// XR_EXT_debug_utils is built into the loader and handled partly through the xrGetInstanceProcAddress terminator,778// but the check to see if the extension is enabled must be done here where ActiveLoaderInstance is safe to use.779if (*function == nullptr) {780if (strcmp(name, "xrCreateDebugUtilsMessengerEXT") == 0) {781*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineCreateDebugUtilsMessengerEXT);782} else if (strcmp(name, "xrDestroyDebugUtilsMessengerEXT") == 0) {783*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineDestroyDebugUtilsMessengerEXT);784} else if (strcmp(name, "xrSessionBeginDebugUtilsLabelRegionEXT") == 0) {785*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT);786} else if (strcmp(name, "xrSessionEndDebugUtilsLabelRegionEXT") == 0) {787*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT);788} else if (strcmp(name, "xrSessionInsertDebugUtilsLabelEXT") == 0) {789*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionInsertDebugUtilsLabelEXT);790} else if (strcmp(name, "xrSetDebugUtilsObjectNameEXT") == 0) {791*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSetDebugUtilsObjectNameEXT);792} else if (strcmp(name, "xrSubmitDebugUtilsMessageEXT") == 0) {793*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSubmitDebugUtilsMessageEXT);794}795796if (*function != nullptr && !loader_instance->ExtensionIsEnabled("XR_EXT_debug_utils")) {797// The function matches one of the XR_EXT_debug_utils functions but the extension is not enabled.798*function = nullptr;799return XR_ERROR_FUNCTION_UNSUPPORTED;800}801}802803if (*function != nullptr) {804// The loader has a trampoline or implementation of this function.805return XR_SUCCESS;806}807808// If the function is not supported by the loader, call down to the next layer.809return loader_instance->GetInstanceProcAddr(name, function);810}811XRLOADER_ABI_CATCH_FALLBACK812813// Exported loader functions814//815// The application might override these by exporting the same symbols and so we can't use these816// symbols anywhere in the loader code, and instead the internal non exported functions that these817// stubs call should be used internally.818LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,819uint32_t *propertyCountOutput,820XrApiLayerProperties *properties) {821return LoaderXrEnumerateApiLayerProperties(propertyCapacityInput, propertyCountOutput, properties);822}823824LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(const char *layerName,825uint32_t propertyCapacityInput,826uint32_t *propertyCountOutput,827XrExtensionProperties *properties) {828return LoaderXrEnumerateInstanceExtensionProperties(layerName, propertyCapacityInput, propertyCountOutput, properties);829}830831LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) {832return LoaderXrCreateInstance(info, instance);833}834835LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) { return LoaderXrDestroyInstance(instance); }836837LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(XrInstance instance, const char *name,838PFN_xrVoidFunction *function) {839return LoaderXrGetInstanceProcAddr(instance, name, function);840}841842843