Path: blob/master/thirdparty/openxr/src/loader/loader_core.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 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 functions77#ifdef XR_KHR_LOADER_INIT_SUPPORT // platforms that support XR_KHR_loader_init.78XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY {79LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline");80return InitializeLoaderInitData(loaderInitInfo);81}82XRLOADER_ABI_CATCH_FALLBACK83#endif8485static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,86uint32_t *propertyCountOutput,87XrApiLayerProperties *properties) XRLOADER_ABI_TRY {88LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties", "Entering loader trampoline");8990// Make sure only one thread is attempting to read the JSON files at a time.91std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());9293XrResult result = ApiLayerInterface::GetApiLayerProperties("xrEnumerateApiLayerProperties", propertyCapacityInput,94propertyCountOutput, properties);95if (XR_FAILED(result)) {96LoaderLogger::LogErrorMessage("xrEnumerateApiLayerProperties", "Failed ApiLayerInterface::GetApiLayerProperties");97}9899return result;100}101XRLOADER_ABI_CATCH_FALLBACK102103static XRAPI_ATTR XrResult XRAPI_CALL104LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput,105XrExtensionProperties *properties) XRLOADER_ABI_TRY {106bool just_layer_properties = false;107LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Entering loader trampoline");108109// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,110// and the function sets elementCountOutput." - 2.11111if (nullptr == propertyCountOutput) {112return XR_ERROR_VALIDATION_FAILURE;113}114115if (nullptr != layerName && 0 != strlen(layerName)) {116// Application is only interested in layer's properties, not all of them.117just_layer_properties = true;118}119120std::vector<XrExtensionProperties> extension_properties = {};121XrResult result;122123{124// Make sure the runtime isn't unloaded while this call is in progress.125std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());126127// Get the layer extension properties128result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties", layerName,129extension_properties);130if (XR_SUCCEEDED(result) && !just_layer_properties) {131// If not specific to a layer, get the runtime extension properties132result = RuntimeInterface::LoadRuntime("xrEnumerateInstanceExtensionProperties");133if (XR_SUCCEEDED(result)) {134RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties);135} else {136LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",137"Failed to find default runtime with RuntimeInterface::LoadRuntime()");138}139}140}141142if (XR_FAILED(result)) {143LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", "Failed querying extension properties");144return result;145}146147// If this is not in reference to a specific layer, then add the loader-specific extension properties as well.148// These are extensions that the loader directly supports.149if (!just_layer_properties) {150for (const XrExtensionProperties &loader_prop : LoaderInstance::LoaderSpecificExtensions()) {151bool found_prop = false;152for (XrExtensionProperties &existing_prop : extension_properties) {153if (0 == strcmp(existing_prop.extensionName, loader_prop.extensionName)) {154found_prop = true;155// Use the loader version if it is newer156if (existing_prop.extensionVersion < loader_prop.extensionVersion) {157existing_prop.extensionVersion = loader_prop.extensionVersion;158}159break;160}161}162// Only add extensions not supported by the loader163if (!found_prop) {164extension_properties.push_back(loader_prop);165}166}167}168169auto num_extension_properties = static_cast<uint32_t>(extension_properties.size());170if (propertyCapacityInput == 0) {171*propertyCountOutput = num_extension_properties;172} else if (nullptr != properties) {173if (propertyCapacityInput < num_extension_properties) {174*propertyCountOutput = num_extension_properties;175LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter",176"xrEnumerateInstanceExtensionProperties", "insufficient space in array");177return XR_ERROR_SIZE_INSUFFICIENT;178}179180uint32_t num_to_copy = num_extension_properties;181// Determine how many extension properties we can copy over182if (propertyCapacityInput < num_to_copy) {183num_to_copy = propertyCapacityInput;184}185bool properties_valid = true;186for (uint32_t prop = 0; prop < propertyCapacityInput && prop < extension_properties.size(); ++prop) {187if (XR_TYPE_EXTENSION_PROPERTIES != properties[prop].type) {188properties_valid = false;189LoaderLogger::LogValidationErrorMessage("VUID-XrExtensionProperties-type-type",190"xrEnumerateInstanceExtensionProperties", "unknown type in properties");191}192if (properties_valid) {193properties[prop] = extension_properties[prop];194}195}196if (!properties_valid) {197LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-properties-parameter",198"xrEnumerateInstanceExtensionProperties", "invalid properties");199return XR_ERROR_VALIDATION_FAILURE;200}201if (nullptr != propertyCountOutput) {202*propertyCountOutput = num_to_copy;203}204} else {205// incoming_count is not 0 BUT the properties is NULL206return XR_ERROR_VALIDATION_FAILURE;207}208LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Completed loader trampoline");209return XR_SUCCESS;210}211XRLOADER_ABI_CATCH_FALLBACK212213static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCreateInfo *info,214XrInstance *instance) XRLOADER_ABI_TRY {215LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader trampoline");216if (nullptr == info) {217LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance", "must be non-NULL");218return XR_ERROR_VALIDATION_FAILURE;219}220// If application requested OpenXR API version is higher than the loader version, then we need to throw221// an error.222uint16_t app_major = XR_VERSION_MAJOR(info->applicationInfo.apiVersion); // NOLINT223uint16_t app_minor = XR_VERSION_MINOR(info->applicationInfo.apiVersion); // NOLINT224uint16_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); // NOLINT225uint16_t loader_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION); // NOLINT226if (app_major > loader_major || (app_major == loader_major && app_minor > loader_minor)) {227std::ostringstream oss;228oss << "xrCreateInstance called with invalid API version " << app_major << "." << app_minor229<< ". Max supported version is " << loader_major << "." << loader_minor;230LoaderLogger::LogErrorMessage("xrCreateInstance", oss.str());231return XR_ERROR_API_VERSION_UNSUPPORTED;232}233234if (nullptr == instance) {235LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-instance-parameter", "xrCreateInstance", "must be non-NULL");236return XR_ERROR_VALIDATION_FAILURE;237}238239// Make sure the ActiveLoaderInstance::IsAvailable check is done atomically with RuntimeInterface::LoadRuntime.240std::unique_lock<std::mutex> instance_lock(GetGlobalLoaderMutex());241242// Check if there is already an XrInstance that is alive. If so, another instance cannot be created.243// The loader does not support multiple simultaneous instances because the loader is intended to be244// usable by apps using future OpenXR APIs (through xrGetInstanceProcAddr). Because the loader would245// not be aware of new handle types, it would not be able to look up the appropriate dispatch table246// in some cases.247if (ActiveLoaderInstance::IsAvailable()) { // If there is an XrInstance already alive.248LoaderLogger::LogErrorMessage("xrCreateInstance", "Loader does not support simultaneous XrInstances");249return XR_ERROR_LIMIT_REACHED;250}251252std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces;253XrResult result;254255// Make sure only one thread is attempting to read the JSON files and use the instance.256{257// Load the available runtime258result = RuntimeInterface::LoadRuntime("xrCreateInstance");259if (XR_FAILED(result)) {260LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading runtime information");261} else {262// Load the appropriate layers263result = ApiLayerInterface::LoadApiLayers("xrCreateInstance", info->enabledApiLayerCount, info->enabledApiLayerNames,264api_layer_interfaces);265if (XR_FAILED(result)) {266LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading layer information");267}268}269}270271// Create the loader instance (only send down first runtime interface)272LoaderInstance *loader_instance = nullptr;273if (XR_SUCCEEDED(result)) {274std::unique_ptr<LoaderInstance> owned_loader_instance;275result = LoaderInstance::CreateInstance(LoaderXrTermGetInstanceProcAddr, LoaderXrTermCreateInstance,276LoaderXrTermCreateApiLayerInstance, std::move(api_layer_interfaces), info,277&owned_loader_instance);278if (XR_SUCCEEDED(result)) {279loader_instance = owned_loader_instance.get();280result = ActiveLoaderInstance::Set(std::move(owned_loader_instance), "xrCreateInstance");281}282}283284if (XR_SUCCEEDED(result)) {285// Create a debug utils messenger if the create structure is in the "next" chain286const auto *next_header = reinterpret_cast<const XrBaseInStructure *>(info->next);287const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr;288while (next_header != nullptr) {289if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {290LoaderLogger::LogInfoMessage("xrCreateInstance", "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain.");291dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);292XrDebugUtilsMessengerEXT messenger;293result = LoaderTrampolineCreateDebugUtilsMessengerEXT(loader_instance->GetInstanceHandle(), dbg_utils_create_info,294&messenger);295if (XR_FAILED(result)) {296return XR_ERROR_VALIDATION_FAILURE;297}298loader_instance->SetDefaultDebugUtilsMessenger(messenger);299break;300}301next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next);302}303}304305if (XR_FAILED(result)) {306// Ensure the global loader instance and runtime are destroyed if something went wrong.307ActiveLoaderInstance::Remove();308RuntimeInterface::UnloadRuntime("xrCreateInstance");309LoaderLogger::LogErrorMessage("xrCreateInstance", "xrCreateInstance failed");310} else {311*instance = loader_instance->GetInstanceHandle();312LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader trampoline");313}314315return result;316}317XRLOADER_ABI_CATCH_FALLBACK318319static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {320LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader trampoline");321// Runtimes may detect XR_NULL_HANDLE provided as a required handle parameter and return XR_ERROR_HANDLE_INVALID. - 2.9322if (XR_NULL_HANDLE == instance) {323LoaderLogger::LogErrorMessage("xrDestroyInstance", "Instance handle is XR_NULL_HANDLE.");324return XR_ERROR_HANDLE_INVALID;325}326327// Make sure the runtime isn't unloaded while it is being used by xrEnumerateInstanceExtensionProperties.328std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());329330LoaderInstance *loader_instance;331XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyInstance");332if (XR_FAILED(result)) {333return result;334}335336const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();337338// If we allocated a default debug utils messenger, free it339XrDebugUtilsMessengerEXT messenger = loader_instance->DefaultDebugUtilsMessenger();340if (messenger != XR_NULL_HANDLE) {341LoaderTrampolineDestroyDebugUtilsMessengerEXT(messenger);342}343344// Now destroy the instance345if (XR_FAILED(dispatch_table->DestroyInstance(instance))) {346LoaderLogger::LogErrorMessage("xrDestroyInstance", "Unknown error occurred calling down chain");347}348349// Get rid of the loader instance. This will make it possible to create another instance in the future.350ActiveLoaderInstance::Remove();351352// Lock the instance create/destroy mutex353LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader trampoline");354355// Finally, unload the runtime if necessary356RuntimeInterface::UnloadRuntime("xrDestroyInstance");357358return XR_SUCCESS;359}360XRLOADER_ABI_CATCH_FALLBACK361362// ---- Core 1.0 manual loader terminator functions363364// Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid.365static XrResult ValidateApplicationInfo(const XrApplicationInfo &info) {366if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(info.applicationName)) {367LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-applicationName-parameter", "xrCreateInstance",368"application name missing NULL terminator.");369return XR_ERROR_NAME_INVALID;370}371if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(info.engineName)) {372LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-engineName-parameter", "xrCreateInstance",373"engine name missing NULL terminator.");374return XR_ERROR_NAME_INVALID;375}376if (strlen(info.applicationName) == 0) {377LoaderLogger::LogErrorMessage("xrCreateInstance",378"VUID-XrApplicationInfo-engineName-parameter: application name can not be empty.");379return XR_ERROR_NAME_INVALID;380}381return XR_SUCCESS;382}383384// Validate that the XrInstanceCreateInfo is valid385static XrResult ValidateInstanceCreateInfo(const XrInstanceCreateInfo *info) {386// Should have a valid 'type'387if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) {388LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-type-type", "xrCreateInstance",389"expected XR_TYPE_INSTANCE_CREATE_INFO.");390return XR_ERROR_VALIDATION_FAILURE;391}392// Flags must be 0393if (0 != info->createFlags) {394LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-createFlags-zerobitmask", "xrCreateInstance",395"flags must be 0.");396return XR_ERROR_VALIDATION_FAILURE;397}398// ApplicationInfo struct must be valid399XrResult result = ValidateApplicationInfo(info->applicationInfo);400if (XR_FAILED(result)) {401LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-applicationInfo-parameter", "xrCreateInstance",402"info->applicationInfo is not valid.");403return result;404}405// VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter already tested in LoadApiLayers()406if ((info->enabledExtensionCount != 0u) && nullptr == info->enabledExtensionNames) {407LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-enabledExtensionNames-parameter", "xrCreateInstance",408"enabledExtensionCount is non-0 but array is NULL");409return XR_ERROR_VALIDATION_FAILURE;410}411return XR_SUCCESS;412}413414static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *createInfo,415XrInstance *instance) XRLOADER_ABI_TRY {416LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader terminator");417XrResult result = ValidateInstanceCreateInfo(createInfo);418if (XR_FAILED(result)) {419LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance",420"something wrong with XrInstanceCreateInfo contents");421return result;422}423result = RuntimeInterface::GetRuntime().CreateInstance(createInfo, instance);424LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader terminator");425return result;426}427XRLOADER_ABI_CATCH_FALLBACK428429static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info,430const struct XrApiLayerCreateInfo * /*apiLayerInfo*/,431XrInstance *instance) {432return LoaderXrTermCreateInstance(info, instance);433}434435static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {436LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader terminator");437LoaderLogger::GetInstance().RemoveLogRecordersForXrInstance(instance);438XrResult result = RuntimeInterface::GetRuntime().DestroyInstance(instance);439LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader terminator");440return result;441}442XRLOADER_ABI_CATCH_FALLBACK443444static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance instance, const char *name,445PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {446// A few instance commands need to go through a loader terminator.447// Otherwise, go directly to the runtime version of the command if it exists.448// But first set the function pointer to NULL so that the fall-through below actually works.449*function = nullptr;450451// NOTE: ActiveLoaderInstance cannot be used in this function because it is called before an instance is made active.452453if (0 == strcmp(name, "xrGetInstanceProcAddr")) {454*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermGetInstanceProcAddr);455} else if (0 == strcmp(name, "xrCreateInstance")) {456*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateInstance);457} else if (0 == strcmp(name, "xrDestroyInstance")) {458*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyInstance);459} else if (0 == strcmp(name, "xrSetDebugUtilsObjectNameEXT")) {460*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSetDebugUtilsObjectNameEXT);461} else if (0 == strcmp(name, "xrCreateDebugUtilsMessengerEXT")) {462*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateDebugUtilsMessengerEXT);463} else if (0 == strcmp(name, "xrDestroyDebugUtilsMessengerEXT")) {464*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyDebugUtilsMessengerEXT);465} else if (0 == strcmp(name, "xrSubmitDebugUtilsMessageEXT")) {466*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSubmitDebugUtilsMessageEXT);467} else if (0 == strcmp(name, "xrCreateApiLayerInstance")) {468// Special layer version of xrCreateInstance terminator. If we get called this by a layer,469// we simply re-direct the information back into the standard xrCreateInstance terminator.470*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateApiLayerInstance);471}472473if (nullptr != *function) {474return XR_SUCCESS;475}476477return RuntimeInterface::GetInstanceProcAddr(instance, name, function);478}479XRLOADER_ABI_CATCH_FALLBACK480481// ---- Extension manual loader trampoline functions482483static XRAPI_ATTR XrResult XRAPI_CALL484LoaderTrampolineCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo,485XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {486LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader trampoline");487488if (instance == XR_NULL_HANDLE) {489LoaderLogger::LogErrorMessage("xrCreateDebugUtilsMessengerEXT", "Instance handle is XR_NULL_HANDLE.");490return XR_ERROR_HANDLE_INVALID;491}492493LoaderInstance *loader_instance;494XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateDebugUtilsMessengerEXT");495if (XR_FAILED(result)) {496return result;497}498499result = loader_instance->DispatchTable()->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);500LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader trampoline");501return result;502}503XRLOADER_ABI_CATCH_BAD_ALLOC_OOM XRLOADER_ABI_CATCH_FALLBACK504505static XRAPI_ATTR XrResult XRAPI_CALL506LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {507// TODO: get instance from messenger in loader508// Also, is the loader really doing all this every call?509LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader trampoline");510511if (messenger == XR_NULL_HANDLE) {512LoaderLogger::LogErrorMessage("xrDestroyDebugUtilsMessengerEXT", "Messenger handle is XR_NULL_HANDLE.");513return XR_ERROR_HANDLE_INVALID;514}515516LoaderInstance *loader_instance;517XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyDebugUtilsMessengerEXT");518if (XR_FAILED(result)) {519return result;520}521522result = loader_instance->DispatchTable()->DestroyDebugUtilsMessengerEXT(messenger);523LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader trampoline");524return result;525}526XRLOADER_ABI_CATCH_FALLBACK527528static XRAPI_ATTR XrResult XRAPI_CALL529LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {530if (session == XR_NULL_HANDLE) {531LoaderLogger::LogErrorMessage("xrSessionBeginDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");532return XR_ERROR_HANDLE_INVALID;533}534535if (nullptr == labelInfo) {536LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter",537"xrSessionBeginDebugUtilsLabelRegionEXT", "labelInfo must be non-NULL",538{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});539return XR_ERROR_VALIDATION_FAILURE;540}541542LoaderInstance *loader_instance;543XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionBeginDebugUtilsLabelRegionEXT");544if (XR_FAILED(result)) {545return result;546}547LoaderLogger::GetInstance().BeginLabelRegion(session, labelInfo);548const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();549if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) {550return dispatch_table->SessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);551}552return XR_SUCCESS;553}554XRLOADER_ABI_CATCH_FALLBACK555556static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY {557if (session == XR_NULL_HANDLE) {558LoaderLogger::LogErrorMessage("xrSessionEndDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");559return XR_ERROR_HANDLE_INVALID;560}561562LoaderInstance *loader_instance;563XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionEndDebugUtilsLabelRegionEXT");564if (XR_FAILED(result)) {565return result;566}567568LoaderLogger::GetInstance().EndLabelRegion(session);569const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();570if (nullptr != dispatch_table->SessionEndDebugUtilsLabelRegionEXT) {571return dispatch_table->SessionEndDebugUtilsLabelRegionEXT(session);572}573return XR_SUCCESS;574}575XRLOADER_ABI_CATCH_FALLBACK576577static XRAPI_ATTR XrResult XRAPI_CALL578LoaderTrampolineSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {579if (session == XR_NULL_HANDLE) {580LoaderLogger::LogErrorMessage("xrSessionInsertDebugUtilsLabelEXT", "Session handle is XR_NULL_HANDLE.");581return XR_ERROR_HANDLE_INVALID;582}583584LoaderInstance *loader_instance;585XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionInsertDebugUtilsLabelEXT");586if (XR_FAILED(result)) {587return result;588}589590if (nullptr == labelInfo) {591LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter",592"xrSessionInsertDebugUtilsLabelEXT", "labelInfo must be non-NULL",593{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});594return XR_ERROR_VALIDATION_FAILURE;595}596597LoaderLogger::GetInstance().InsertLabel(session, labelInfo);598599const std::unique_ptr<XrGeneratedDispatchTableCore> &dispatch_table = loader_instance->DispatchTable();600if (nullptr != dispatch_table->SessionInsertDebugUtilsLabelEXT) {601return dispatch_table->SessionInsertDebugUtilsLabelEXT(session, labelInfo);602}603604return XR_SUCCESS;605}606XRLOADER_ABI_CATCH_FALLBACK607608// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.609static XRAPI_ATTR XrResult XRAPI_CALL610LoaderTrampolineSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {611LoaderInstance *loader_instance;612XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSetDebugUtilsObjectNameEXT");613if (XR_SUCCEEDED(result)) {614result = loader_instance->DispatchTable()->SetDebugUtilsObjectNameEXT(instance, nameInfo);615}616return result;617}618XRLOADER_ABI_CATCH_FALLBACK619620// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.621static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSubmitDebugUtilsMessageEXT(622XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,623const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {624LoaderInstance *loader_instance;625XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSubmitDebugUtilsMessageEXT");626if (XR_SUCCEEDED(result)) {627result =628loader_instance->DispatchTable()->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);629}630return result;631}632XRLOADER_ABI_CATCH_FALLBACK633634// ---- Extension manual loader terminator functions635636XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance,637const XrDebugUtilsMessengerCreateInfoEXT *createInfo,638XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {639LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader terminator");640if (nullptr == messenger) {641LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter",642"xrCreateDebugUtilsMessengerEXT", "invalid messenger pointer");643return XR_ERROR_VALIDATION_FAILURE;644}645const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);646XrResult result = XR_SUCCESS;647// This extension is supported entirely by the loader which means the runtime may or may not support it.648if (nullptr != dispatch_table->CreateDebugUtilsMessengerEXT) {649result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);650} else {651// Just allocate a character so we have a unique value652char *temp_mess_ptr = new char;653*messenger = reinterpret_cast<XrDebugUtilsMessengerEXT>(temp_mess_ptr);654}655if (XR_SUCCEEDED(result)) {656LoaderLogger::GetInstance().AddLogRecorderForXrInstance(instance, MakeDebugUtilsLoaderLogRecorder(createInfo, *messenger));657RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, *messenger);658}659LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader terminator");660return result;661}662XRLOADER_ABI_CATCH_FALLBACK663664XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {665LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader terminator");666const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger);667XrResult result = XR_SUCCESS;668LoaderLogger::GetInstance().RemoveLogRecorder(MakeHandleGeneric(messenger));669RuntimeInterface::GetRuntime().ForgetDebugMessenger(messenger);670// This extension is supported entirely by the loader which means the runtime may or may not support it.671if (nullptr != dispatch_table->DestroyDebugUtilsMessengerEXT) {672result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger);673} else {674// Delete the character we would've created675delete (reinterpret_cast<char *>(MakeHandleGeneric(messenger)));676}677LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader terminator");678return result;679}680XRLOADER_ABI_CATCH_FALLBACK681682XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(683XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,684const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {685LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Entering loader terminator");686const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);687XrResult result = XR_SUCCESS;688if (nullptr != dispatch_table->SubmitDebugUtilsMessageEXT) {689result = dispatch_table->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);690} else {691// Only log the message from the loader if the runtime doesn't support this extension. If we did,692// then the user would receive multiple instances of the same message.693LoaderLogger::GetInstance().LogDebugUtilsMessage(messageSeverity, messageTypes, callbackData);694}695LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Completed loader terminator");696return result;697}698XRLOADER_ABI_CATCH_FALLBACK699700XRAPI_ATTR XrResult XRAPI_CALL701LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {702LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Entering loader terminator");703const XrGeneratedDispatchTableCore *dispatch_table = RuntimeInterface::GetDispatchTable(instance);704XrResult result = XR_SUCCESS;705if (nullptr != dispatch_table->SetDebugUtilsObjectNameEXT) {706result = dispatch_table->SetDebugUtilsObjectNameEXT(instance, nameInfo);707}708LoaderLogger::GetInstance().AddObjectName(nameInfo->objectHandle, nameInfo->objectType, nameInfo->objectName);709LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Completed loader terminator");710return result;711}712XRLOADER_ABI_CATCH_FALLBACK713714XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name,715PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {716if (nullptr == function) {717LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",718"Invalid Function pointer");719return XR_ERROR_VALIDATION_FAILURE;720}721722if (nullptr == name) {723LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",724"Invalid Name pointer");725return XR_ERROR_VALIDATION_FAILURE;726}727728// Initialize the function to nullptr in case it does not get caught in a known case729*function = nullptr;730731LoaderInstance *loader_instance = nullptr;732if (instance == XR_NULL_HANDLE) {733// Null instance is allowed for a few specific API entry points, otherwise return error734if (strcmp(name, "xrCreateInstance") != 0 && strcmp(name, "xrEnumerateApiLayerProperties") != 0 &&735strcmp(name, "xrEnumerateInstanceExtensionProperties") != 0 && strcmp(name, "xrInitializeLoaderKHR") != 0) {736// TODO why is xrGetInstanceProcAddr not listed in here?737std::string error_str = "XR_NULL_HANDLE for instance but query for ";738error_str += name;739error_str += " requires a valid instance";740LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-instance-parameter", "xrGetInstanceProcAddr",741error_str);742return XR_ERROR_HANDLE_INVALID;743}744} else {745// non null instance passed in, it should be our current instance746XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProcAddr");747if (XR_FAILED(result)) {748return result;749}750if (loader_instance->GetInstanceHandle() != instance) {751return XR_ERROR_HANDLE_INVALID;752}753}754755// These functions must always go through the loader's implementation (trampoline).756if (strcmp(name, "xrGetInstanceProcAddr") == 0) {757*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrGetInstanceProcAddr);758return XR_SUCCESS;759} else if (strcmp(name, "xrInitializeLoaderKHR") == 0) {760#ifdef XR_KHR_LOADER_INIT_SUPPORT761*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrInitializeLoaderKHR);762return XR_SUCCESS;763#else764return XR_ERROR_FUNCTION_UNSUPPORTED;765#endif766} else if (strcmp(name, "xrEnumerateApiLayerProperties") == 0) {767*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateApiLayerProperties);768return XR_SUCCESS;769} else if (strcmp(name, "xrEnumerateInstanceExtensionProperties") == 0) {770*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateInstanceExtensionProperties);771return XR_SUCCESS;772} else if (strcmp(name, "xrCreateInstance") == 0) {773*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrCreateInstance);774return XR_SUCCESS;775} else if (strcmp(name, "xrDestroyInstance") == 0) {776*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrDestroyInstance);777return XR_SUCCESS;778}779780// XR_EXT_debug_utils is built into the loader and handled partly through the xrGetInstanceProcAddress terminator,781// but the check to see if the extension is enabled must be done here where ActiveLoaderInstance is safe to use.782if (*function == nullptr) {783if (strcmp(name, "xrCreateDebugUtilsMessengerEXT") == 0) {784*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineCreateDebugUtilsMessengerEXT);785} else if (strcmp(name, "xrDestroyDebugUtilsMessengerEXT") == 0) {786*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineDestroyDebugUtilsMessengerEXT);787} else if (strcmp(name, "xrSessionBeginDebugUtilsLabelRegionEXT") == 0) {788*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT);789} else if (strcmp(name, "xrSessionEndDebugUtilsLabelRegionEXT") == 0) {790*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT);791} else if (strcmp(name, "xrSessionInsertDebugUtilsLabelEXT") == 0) {792*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionInsertDebugUtilsLabelEXT);793} else if (strcmp(name, "xrSetDebugUtilsObjectNameEXT") == 0) {794*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSetDebugUtilsObjectNameEXT);795} else if (strcmp(name, "xrSubmitDebugUtilsMessageEXT") == 0) {796*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSubmitDebugUtilsMessageEXT);797}798799if (*function != nullptr && !loader_instance->ExtensionIsEnabled("XR_EXT_debug_utils")) {800// The function matches one of the XR_EXT_debug_utils functions but the extension is not enabled.801*function = nullptr;802return XR_ERROR_FUNCTION_UNSUPPORTED;803}804}805806if (*function != nullptr) {807// The loader has a trampoline or implementation of this function.808return XR_SUCCESS;809}810811// If the function is not supported by the loader, call down to the next layer.812return loader_instance->GetInstanceProcAddr(name, function);813}814XRLOADER_ABI_CATCH_FALLBACK815816// Exported loader functions817//818// The application might override these by exporting the same symbols and so we can't use these819// symbols anywhere in the loader code, and instead the internal non exported functions that these820// stubs call should be used internally.821LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,822uint32_t *propertyCountOutput,823XrApiLayerProperties *properties) {824return LoaderXrEnumerateApiLayerProperties(propertyCapacityInput, propertyCountOutput, properties);825}826827LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(const char *layerName,828uint32_t propertyCapacityInput,829uint32_t *propertyCountOutput,830XrExtensionProperties *properties) {831return LoaderXrEnumerateInstanceExtensionProperties(layerName, propertyCapacityInput, propertyCountOutput, properties);832}833834LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) {835return LoaderXrCreateInstance(info, instance);836}837838LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) { return LoaderXrDestroyInstance(instance); }839840LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(XrInstance instance, const char *name,841PFN_xrVoidFunction *function) {842return LoaderXrGetInstanceProcAddr(instance, name, function);843}844845#ifdef XR_KHR_LOADER_INIT_SUPPORT846LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) {847return LoaderXrInitializeLoaderKHR(loaderInitInfo);848}849#endif850851852