You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-12-03 16:55:53 +00:00
Add OpenXR 1.0.22 to thirdparty libraries
Will be compiled and used in the next commit. Co-authored-by: Rémi Verschelde <rverschelde@gmail.com>
This commit is contained in:
committed by
Rémi Verschelde
parent
fcf8c2006d
commit
65bae5a341
5
thirdparty/openxr/src/loader/.gitignore
vendored
Normal file
5
thirdparty/openxr/src/loader/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Copyright (c) 2020 The Khronos Group Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
!openxr_loader_for_android.pom
|
||||
319
thirdparty/openxr/src/loader/android_utilities.cpp
vendored
Normal file
319
thirdparty/openxr/src/loader/android_utilities.cpp
vendored
Normal file
@@ -0,0 +1,319 @@
|
||||
// Copyright (c) 2020-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2020-2021, Collabora, Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
|
||||
#include "android_utilities.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <wrap/android.net.h>
|
||||
#include <wrap/android.content.h>
|
||||
#include <wrap/android.database.h>
|
||||
#include <json/value.h>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <android/log.h>
|
||||
|
||||
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "openxr_loader", __VA_ARGS__)
|
||||
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, "openxr_loader", __VA_ARGS__)
|
||||
#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "openxr_loader", __VA_ARGS__)
|
||||
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, "openxr_loader", __VA_ARGS__)
|
||||
|
||||
namespace openxr_android {
|
||||
using wrap::android::content::ContentUris;
|
||||
using wrap::android::content::Context;
|
||||
using wrap::android::database::Cursor;
|
||||
using wrap::android::net::Uri;
|
||||
using wrap::android::net::Uri_Builder;
|
||||
|
||||
// Code in here corresponds roughly to the Java "BrokerContract" class and subclasses.
|
||||
namespace {
|
||||
constexpr auto AUTHORITY = "org.khronos.openxr.runtime_broker";
|
||||
constexpr auto SYSTEM_AUTHORITY = "org.khronos.openxr.system_runtime_broker";
|
||||
constexpr auto BASE_PATH = "openxr";
|
||||
constexpr auto ABI_PATH = "abi";
|
||||
constexpr auto RUNTIMES_PATH = "runtimes";
|
||||
|
||||
constexpr const char *getBrokerAuthority(bool systemBroker) { return systemBroker ? SYSTEM_AUTHORITY : AUTHORITY; }
|
||||
|
||||
struct BaseColumns {
|
||||
/**
|
||||
* The unique ID for a row.
|
||||
*/
|
||||
[[maybe_unused]] static constexpr auto ID = "_id";
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains details for the /openxr/[major_ver]/abi/[abi]/runtimes/active URI.
|
||||
* <p>
|
||||
* This URI represents a "table" containing at most one item, the currently active runtime. The
|
||||
* policy of which runtime is chosen to be active (if more than one is installed) is left to the
|
||||
* content provider.
|
||||
* <p>
|
||||
* No sort order is required to be honored by the content provider.
|
||||
*/
|
||||
namespace active_runtime {
|
||||
/**
|
||||
* Final path component to this URI.
|
||||
*/
|
||||
static constexpr auto TABLE_PATH = "active";
|
||||
|
||||
/**
|
||||
* Create a content URI for querying the data on the active runtime for a
|
||||
* given major version of OpenXR.
|
||||
*
|
||||
* @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
|
||||
* @param majorVer The major version of OpenXR.
|
||||
* @param abi The Android ABI name in use.
|
||||
* @return A content URI for a single item: the active runtime.
|
||||
*/
|
||||
static Uri makeContentUri(bool systemBroker, int majorVersion, const char *abi) {
|
||||
auto builder = Uri_Builder::construct();
|
||||
builder.scheme("content")
|
||||
.authority(getBrokerAuthority(systemBroker))
|
||||
.appendPath(BASE_PATH)
|
||||
.appendPath(std::to_string(majorVersion))
|
||||
.appendPath(ABI_PATH)
|
||||
.appendPath(abi)
|
||||
.appendPath(RUNTIMES_PATH)
|
||||
.appendPath(TABLE_PATH);
|
||||
ContentUris::appendId(builder, 0);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
struct Columns : BaseColumns {
|
||||
/**
|
||||
* Constant for the PACKAGE_NAME column name
|
||||
*/
|
||||
static constexpr auto PACKAGE_NAME = "package_name";
|
||||
|
||||
/**
|
||||
* Constant for the NATIVE_LIB_DIR column name
|
||||
*/
|
||||
static constexpr auto NATIVE_LIB_DIR = "native_lib_dir";
|
||||
|
||||
/**
|
||||
* Constant for the SO_FILENAME column name
|
||||
*/
|
||||
static constexpr auto SO_FILENAME = "so_filename";
|
||||
|
||||
/**
|
||||
* Constant for the HAS_FUNCTIONS column name.
|
||||
* <p>
|
||||
* If this column contains true, you should check the /functions/ URI for that runtime.
|
||||
*/
|
||||
static constexpr auto HAS_FUNCTIONS = "has_functions";
|
||||
};
|
||||
} // namespace active_runtime
|
||||
|
||||
/**
|
||||
* Contains details for the /openxr/[major_ver]/abi/[abi]/runtimes/[package]/functions URI.
|
||||
* <p>
|
||||
* This URI is for package-specific function name remapping. Since this is an optional field in
|
||||
* the corresponding JSON manifests for OpenXR, it is optional here as well. If the active
|
||||
* runtime contains "true" in its "has_functions" column, then this table must exist and be
|
||||
* queryable.
|
||||
* <p>
|
||||
* No sort order is required to be honored by the content provider.
|
||||
*/
|
||||
namespace functions {
|
||||
/**
|
||||
* Final path component to this URI.
|
||||
*/
|
||||
static constexpr auto TABLE_PATH = "functions";
|
||||
|
||||
/**
|
||||
* Create a content URI for querying all rows of the function remapping data for a given
|
||||
* runtime package and major version of OpenXR.
|
||||
*
|
||||
* @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
|
||||
* @param majorVer The major version of OpenXR.
|
||||
* @param packageName The package name of the runtime.
|
||||
* @param abi The Android ABI name in use.
|
||||
* @return A content URI for the entire table: the function remapping for that runtime.
|
||||
*/
|
||||
static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &packageName, const char *abi) {
|
||||
auto builder = Uri_Builder::construct();
|
||||
builder.scheme("content")
|
||||
.authority(getBrokerAuthority(systemBroker))
|
||||
.appendPath(BASE_PATH)
|
||||
.appendPath(std::to_string(majorVersion))
|
||||
.appendPath(ABI_PATH)
|
||||
.appendPath(abi)
|
||||
.appendPath(RUNTIMES_PATH)
|
||||
.appendPath(packageName)
|
||||
.appendPath(TABLE_PATH);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
struct Columns : BaseColumns {
|
||||
/**
|
||||
* Constant for the FUNCTION_NAME column name
|
||||
*/
|
||||
static constexpr auto FUNCTION_NAME = "function_name";
|
||||
|
||||
/**
|
||||
* Constant for the SYMBOL_NAME column name
|
||||
*/
|
||||
static constexpr auto SYMBOL_NAME = "symbol_name";
|
||||
};
|
||||
} // namespace functions
|
||||
|
||||
} // namespace
|
||||
|
||||
static inline jni::Array<std::string> makeArray(std::initializer_list<const char *> &&list) {
|
||||
auto ret = jni::Array<std::string>{(long)list.size()};
|
||||
long i = 0;
|
||||
for (auto &&elt : list) {
|
||||
ret.setElement(i, elt);
|
||||
++i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static constexpr auto TAG = "OpenXR-Loader";
|
||||
|
||||
#if defined(__arm__)
|
||||
static constexpr auto ABI = "armeabi-v7l";
|
||||
#elif defined(__aarch64__)
|
||||
static constexpr auto ABI = "arm64-v8a";
|
||||
#elif defined(__i386__)
|
||||
static constexpr auto ABI = "x86";
|
||||
#elif defined(__x86_64__)
|
||||
static constexpr auto ABI = "x86_64";
|
||||
#else
|
||||
#error "Unknown ABI!"
|
||||
#endif
|
||||
|
||||
/// Helper class to generate the jsoncpp object corresponding to a synthetic runtime manifest.
|
||||
class JsonManifestBuilder {
|
||||
public:
|
||||
JsonManifestBuilder(const std::string &libraryPathParent, const std::string &libraryPath);
|
||||
JsonManifestBuilder &function(const std::string &functionName, const std::string &symbolName);
|
||||
|
||||
Json::Value build() const { return root_node; }
|
||||
|
||||
private:
|
||||
Json::Value root_node;
|
||||
};
|
||||
|
||||
inline JsonManifestBuilder::JsonManifestBuilder(const std::string &libraryPathParent, const std::string &libraryPath)
|
||||
: root_node(Json::objectValue) {
|
||||
root_node["file_format_version"] = "1.0.0";
|
||||
root_node["instance_extensions"] = Json::Value(Json::arrayValue);
|
||||
root_node["functions"] = Json::Value(Json::objectValue);
|
||||
root_node[libraryPathParent] = Json::objectValue;
|
||||
root_node[libraryPathParent]["library_path"] = libraryPath;
|
||||
}
|
||||
|
||||
inline JsonManifestBuilder &JsonManifestBuilder::function(const std::string &functionName, const std::string &symbolName) {
|
||||
root_node["functions"][functionName] = symbolName;
|
||||
return *this;
|
||||
}
|
||||
|
||||
static constexpr const char *getBrokerTypeName(bool systemBroker) { return systemBroker ? "system" : "installable"; }
|
||||
|
||||
static int populateFunctions(wrap::android::content::Context const &context, bool systemBroker, const std::string &packageName,
|
||||
JsonManifestBuilder &builder) {
|
||||
jni::Array<std::string> projection = makeArray({functions::Columns::FUNCTION_NAME, functions::Columns::SYMBOL_NAME});
|
||||
|
||||
auto uri = functions::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI);
|
||||
ALOGI("populateFunctions: Querying URI: %s", uri.toString().c_str());
|
||||
|
||||
Cursor cursor = context.getContentResolver().query(uri, projection);
|
||||
|
||||
if (cursor.isNull()) {
|
||||
ALOGE("Null cursor when querying content resolver for functions.");
|
||||
return -1;
|
||||
}
|
||||
if (cursor.getCount() < 1) {
|
||||
ALOGE("Non-null but empty cursor when querying content resolver for functions.");
|
||||
cursor.close();
|
||||
return -1;
|
||||
}
|
||||
auto functionIndex = cursor.getColumnIndex(functions::Columns::FUNCTION_NAME);
|
||||
auto symbolIndex = cursor.getColumnIndex(functions::Columns::SYMBOL_NAME);
|
||||
while (cursor.moveToNext()) {
|
||||
builder.function(cursor.getString(functionIndex), cursor.getString(symbolIndex));
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Get cursor for active runtime, parameterized by whether or not we use the system broker
|
||||
static bool getActiveRuntimeCursor(wrap::android::content::Context const &context, jni::Array<std::string> const &projection,
|
||||
bool systemBroker, Cursor &cursor) {
|
||||
auto uri = active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI);
|
||||
ALOGI("getActiveRuntimeCursor: Querying URI: %s", uri.toString().c_str());
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, projection);
|
||||
} catch (const std::exception &e) {
|
||||
ALOGW("Exception when querying %s content resolver: %s", getBrokerTypeName(systemBroker), e.what());
|
||||
cursor = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cursor.isNull()) {
|
||||
ALOGW("Null cursor when querying %s content resolver.", getBrokerTypeName(systemBroker));
|
||||
cursor = {};
|
||||
return false;
|
||||
}
|
||||
if (cursor.getCount() < 1) {
|
||||
ALOGW("Non-null but empty cursor when querying %s content resolver.", getBrokerTypeName(systemBroker));
|
||||
cursor.close();
|
||||
cursor = {};
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest) {
|
||||
jni::Array<std::string> projection = makeArray({active_runtime::Columns::PACKAGE_NAME, active_runtime::Columns::NATIVE_LIB_DIR,
|
||||
active_runtime::Columns::SO_FILENAME, active_runtime::Columns::HAS_FUNCTIONS});
|
||||
|
||||
// First, try getting the installable broker's provider
|
||||
bool systemBroker = false;
|
||||
Cursor cursor;
|
||||
if (!getActiveRuntimeCursor(context, projection, systemBroker, cursor)) {
|
||||
// OK, try the system broker as a fallback.
|
||||
systemBroker = true;
|
||||
getActiveRuntimeCursor(context, projection, systemBroker, cursor);
|
||||
}
|
||||
|
||||
if (cursor.isNull()) {
|
||||
// Couldn't find either broker
|
||||
ALOGE("Could access neither the installable nor system runtime broker.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cursor.moveToFirst();
|
||||
|
||||
auto filename = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::SO_FILENAME));
|
||||
auto libDir = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::NATIVE_LIB_DIR));
|
||||
auto packageName = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::PACKAGE_NAME));
|
||||
|
||||
auto hasFunctions = cursor.getInt(cursor.getColumnIndex(active_runtime::Columns::HAS_FUNCTIONS)) == 1;
|
||||
__android_log_print(ANDROID_LOG_INFO, TAG, "Got runtime: package: %s, so filename: %s, native lib dir: %s, has functions: %s",
|
||||
packageName.c_str(), libDir.c_str(), filename.c_str(), (hasFunctions ? "yes" : "no"));
|
||||
|
||||
auto lib_path = libDir + "/" + filename;
|
||||
cursor.close();
|
||||
|
||||
JsonManifestBuilder builder{"runtime", lib_path};
|
||||
if (hasFunctions) {
|
||||
int result = populateFunctions(context, systemBroker, packageName, builder);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
virtualManifest = builder.build();
|
||||
return 0;
|
||||
}
|
||||
} // namespace openxr_android
|
||||
|
||||
#endif // __ANDROID__
|
||||
32
thirdparty/openxr/src/loader/android_utilities.h
vendored
Normal file
32
thirdparty/openxr/src/loader/android_utilities.h
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2020-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2020-2021, Collabora, Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
|
||||
#pragma once
|
||||
#ifdef __ANDROID__
|
||||
|
||||
#include "wrap/android.content.h"
|
||||
|
||||
#include <string>
|
||||
namespace Json {
|
||||
class Value;
|
||||
} // namespace Json
|
||||
|
||||
namespace openxr_android {
|
||||
using wrap::android::content::Context;
|
||||
|
||||
/*!
|
||||
* Find the single active OpenXR runtime on the system, and return a constructed JSON object representing it.
|
||||
*
|
||||
* @param context An Android context, preferably an Activity Context.
|
||||
* @param[out] virtualManifest The Json::Value to fill with the virtual manifest.
|
||||
*
|
||||
* @return 0 on success, something else on failure.
|
||||
*/
|
||||
int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest);
|
||||
} // namespace openxr_android
|
||||
|
||||
#endif // __ANDROID__
|
||||
399
thirdparty/openxr/src/loader/api_layer_interface.cpp
vendored
Normal file
399
thirdparty/openxr/src/loader/api_layer_interface.cpp
vendored
Normal file
@@ -0,0 +1,399 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#include "api_layer_interface.hpp"
|
||||
|
||||
#include "loader_interfaces.h"
|
||||
#include "loader_logger.hpp"
|
||||
#include "loader_platform.hpp"
|
||||
#include "manifest_file.hpp"
|
||||
#include "platform_utils.hpp"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#define OPENXR_ENABLE_LAYERS_ENV_VAR "XR_ENABLE_API_LAYERS"
|
||||
|
||||
// Add any layers defined in the loader layer environment variable.
|
||||
static void AddEnvironmentApiLayers(std::vector<std::string>& enabled_layers) {
|
||||
std::string layers = PlatformUtilsGetEnv(OPENXR_ENABLE_LAYERS_ENV_VAR);
|
||||
|
||||
std::size_t last_found = 0;
|
||||
std::size_t found = layers.find_first_of(PATH_SEPARATOR);
|
||||
std::string cur_search;
|
||||
|
||||
// Handle any path listings in the string (separated by the appropriate path separator)
|
||||
while (found != std::string::npos) {
|
||||
cur_search = layers.substr(last_found, found - last_found);
|
||||
enabled_layers.push_back(cur_search);
|
||||
last_found = found + 1;
|
||||
found = layers.find_first_of(PATH_SEPARATOR, last_found);
|
||||
}
|
||||
|
||||
// If there's something remaining in the string, copy it over
|
||||
if (last_found < layers.size()) {
|
||||
cur_search = layers.substr(last_found);
|
||||
enabled_layers.push_back(cur_search);
|
||||
}
|
||||
}
|
||||
|
||||
XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count,
|
||||
uint32_t* outgoing_count, XrApiLayerProperties* api_layer_properties) {
|
||||
std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;
|
||||
uint32_t manifest_count = 0;
|
||||
|
||||
// Validate props struct before proceeding
|
||||
if (0 < incoming_count && nullptr != api_layer_properties) {
|
||||
for (uint32_t i = 0; i < incoming_count; i++) {
|
||||
if (XR_TYPE_API_LAYER_PROPERTIES != api_layer_properties[i].type) {
|
||||
LoaderLogger::LogErrorMessage(openxr_command,
|
||||
"VUID-XrApiLayerProperties-type-type: unknown type in api_layer_properties");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,
|
||||
// and the function sets elementCountOutput." - 2.11
|
||||
if (nullptr == outgoing_count) {
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
// Find any implicit layers which we may need to report information for.
|
||||
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
// Find any explicit layers which we may need to report information for.
|
||||
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);
|
||||
}
|
||||
if (XR_FAILED(result)) {
|
||||
LoaderLogger::LogErrorMessage(openxr_command,
|
||||
"ApiLayerInterface::GetApiLayerProperties - failed searching for API layer manifest files");
|
||||
return result;
|
||||
}
|
||||
|
||||
manifest_count = static_cast<uint32_t>(manifest_files.size());
|
||||
if (nullptr == outgoing_count) {
|
||||
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
|
||||
"VUID-xrEnumerateApiLayerProperties-propertyCountOutput-parameter: null propertyCountOutput");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
*outgoing_count = manifest_count;
|
||||
if (0 == incoming_count) {
|
||||
// capacity check only
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
if (nullptr == api_layer_properties) {
|
||||
// incoming_count is not 0 BUT the api_layer_properties is NULL
|
||||
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
|
||||
"VUID-xrEnumerateApiLayerProperties-properties-parameter: non-zero capacity but null array");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
if (incoming_count < manifest_count) {
|
||||
LoaderLogger::LogErrorMessage(
|
||||
"xrEnumerateInstanceExtensionProperties",
|
||||
"VUID-xrEnumerateApiLayerProperties-propertyCapacityInput-parameter: insufficient space in array");
|
||||
return XR_ERROR_SIZE_INSUFFICIENT;
|
||||
}
|
||||
|
||||
for (uint32_t prop = 0; prop < incoming_count && prop < manifest_count; ++prop) {
|
||||
manifest_files[prop]->PopulateApiLayerProperties(api_layer_properties[prop]);
|
||||
}
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,
|
||||
std::vector<XrExtensionProperties>& extension_properties) {
|
||||
std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;
|
||||
|
||||
// If a layer name is supplied, only use the information out of that one layer
|
||||
if (nullptr != layer_name && 0 != strlen(layer_name)) {
|
||||
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
// Find any explicit layers which we may need to report information for.
|
||||
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);
|
||||
if (XR_FAILED(result)) {
|
||||
LoaderLogger::LogErrorMessage(
|
||||
openxr_command,
|
||||
"ApiLayerInterface::GetInstanceExtensionProperties - failed searching for API layer manifest files");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
auto num_files = static_cast<uint32_t>(manifest_files.size());
|
||||
for (uint32_t man_file = 0; man_file < num_files; ++man_file) {
|
||||
// If a layer with the provided name exists, get it's instance extension information.
|
||||
if (manifest_files[man_file]->LayerName() == layer_name) {
|
||||
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing found, report 0
|
||||
if (!found) {
|
||||
return XR_ERROR_API_LAYER_NOT_PRESENT;
|
||||
}
|
||||
}
|
||||
// Otherwise, we want to add only implicit API layers and explicit API layers enabled using the environment variables
|
||||
} else {
|
||||
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
// Find any environmentally enabled explicit layers. If they're present, treat them like implicit layers
|
||||
// since we know that they're going to be enabled.
|
||||
std::vector<std::string> env_enabled_layers;
|
||||
AddEnvironmentApiLayers(env_enabled_layers);
|
||||
if (!env_enabled_layers.empty()) {
|
||||
std::vector<std::unique_ptr<ApiLayerManifestFile>> exp_layer_man_files = {};
|
||||
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files);
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
for (auto& exp_layer_man_file : exp_layer_man_files) {
|
||||
for (std::string& enabled_layer : env_enabled_layers) {
|
||||
// If this is an enabled layer, transfer it over to the manifest list.
|
||||
if (enabled_layer == exp_layer_man_file->LayerName()) {
|
||||
manifest_files.push_back(std::move(exp_layer_man_file));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grab the layer instance extensions information
|
||||
auto num_files = static_cast<uint32_t>(manifest_files.size());
|
||||
for (uint32_t man_file = 0; man_file < num_files; ++man_file) {
|
||||
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
|
||||
}
|
||||
}
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,
|
||||
const char* const* enabled_api_layer_names,
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces) {
|
||||
XrResult last_error = XR_SUCCESS;
|
||||
std::unordered_set<std::string> layers_already_found;
|
||||
|
||||
bool any_loaded = false;
|
||||
std::vector<std::unique_ptr<ApiLayerManifestFile>> enabled_layer_manifest_files_in_init_order = {};
|
||||
|
||||
// Find any implicit layers.
|
||||
XrResult result =
|
||||
ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, enabled_layer_manifest_files_in_init_order);
|
||||
|
||||
for (const auto& enabled_layer_manifest_file : enabled_layer_manifest_files_in_init_order) {
|
||||
layers_already_found.insert(enabled_layer_manifest_file->LayerName());
|
||||
}
|
||||
|
||||
// Find any explicit layers.
|
||||
std::vector<std::unique_ptr<ApiLayerManifestFile>> explicit_layer_manifest_files = {};
|
||||
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, explicit_layer_manifest_files);
|
||||
}
|
||||
|
||||
bool found_all_layers = true;
|
||||
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
// Put all explicit and then xrCreateInstance enabled layers into a string vector
|
||||
|
||||
std::vector<std::string> enabled_explicit_api_layer_names = {};
|
||||
|
||||
AddEnvironmentApiLayers(enabled_explicit_api_layer_names);
|
||||
|
||||
if (enabled_api_layer_count > 0) {
|
||||
if (nullptr == enabled_api_layer_names) {
|
||||
LoaderLogger::LogErrorMessage(
|
||||
"xrCreateInstance",
|
||||
"VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter: enabledApiLayerCount is non-0 but array is NULL");
|
||||
LoaderLogger::LogErrorMessage(
|
||||
"xrCreateInstance", "VUID-xrCreateInstance-info-parameter: something wrong with XrInstanceCreateInfo contents");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
std::copy(enabled_api_layer_names, enabled_api_layer_names + enabled_api_layer_count,
|
||||
std::back_inserter(enabled_explicit_api_layer_names));
|
||||
}
|
||||
|
||||
// add explicit layers to list of layers to enable
|
||||
for (const auto& layer_name : enabled_explicit_api_layer_names) {
|
||||
bool found_this_layer = false;
|
||||
|
||||
for (auto it = explicit_layer_manifest_files.begin(); it != explicit_layer_manifest_files.end();) {
|
||||
bool erased_layer_manifest_file = false;
|
||||
|
||||
if (layers_already_found.count(layer_name) > 0) {
|
||||
found_this_layer = true;
|
||||
} else if (layer_name == (*it)->LayerName()) {
|
||||
found_this_layer = true;
|
||||
layers_already_found.insert(layer_name);
|
||||
enabled_layer_manifest_files_in_init_order.push_back(std::move(*it));
|
||||
it = explicit_layer_manifest_files.erase(it);
|
||||
erased_layer_manifest_file = true;
|
||||
}
|
||||
|
||||
if (!erased_layer_manifest_file) {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
// If even one of the layers wasn't found, we want to return an error
|
||||
if (!found_this_layer) {
|
||||
found_all_layers = false;
|
||||
std::string error_message = "ApiLayerInterface::LoadApiLayers - failed to find layer ";
|
||||
error_message += layer_name;
|
||||
LoaderLogger::LogErrorMessage(openxr_command, error_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::unique_ptr<ApiLayerManifestFile>& manifest_file : enabled_layer_manifest_files_in_init_order) {
|
||||
LoaderPlatformLibraryHandle layer_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());
|
||||
if (nullptr == layer_library) {
|
||||
if (!any_loaded) {
|
||||
last_error = XR_ERROR_FILE_ACCESS_ERROR;
|
||||
}
|
||||
std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());
|
||||
std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";
|
||||
warning_message += manifest_file->LayerName();
|
||||
warning_message += ", failed to load with message \"";
|
||||
warning_message += library_message;
|
||||
warning_message += "\"";
|
||||
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get and settle on an layer interface version (using any provided name if required).
|
||||
std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface");
|
||||
auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderApiLayerInterface>(
|
||||
LoaderPlatformLibraryGetProcAddr(layer_library, function_name));
|
||||
|
||||
if (nullptr == negotiate) {
|
||||
std::ostringstream oss;
|
||||
oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()
|
||||
<< " because negotiation function " << function_name << " was not found";
|
||||
LoaderLogger::LogErrorMessage(openxr_command, oss.str());
|
||||
LoaderPlatformLibraryClose(layer_library);
|
||||
last_error = XR_ERROR_API_LAYER_NOT_PRESENT;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Loader info for negotiation
|
||||
XrNegotiateLoaderInfo loader_info = {};
|
||||
loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;
|
||||
loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;
|
||||
loader_info.structSize = sizeof(XrNegotiateLoaderInfo);
|
||||
loader_info.minInterfaceVersion = 1;
|
||||
loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;
|
||||
loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);
|
||||
loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.
|
||||
|
||||
// Set up the layer return structure
|
||||
XrNegotiateApiLayerRequest api_layer_info = {};
|
||||
api_layer_info.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST;
|
||||
api_layer_info.structVersion = XR_API_LAYER_INFO_STRUCT_VERSION;
|
||||
api_layer_info.structSize = sizeof(XrNegotiateApiLayerRequest);
|
||||
|
||||
XrResult res = negotiate(&loader_info, manifest_file->LayerName().c_str(), &api_layer_info);
|
||||
// If we supposedly succeeded, but got a nullptr for getInstanceProcAddr
|
||||
// then something still went wrong, so return with an error.
|
||||
if (XR_SUCCEEDED(res) && nullptr == api_layer_info.getInstanceProcAddr) {
|
||||
std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";
|
||||
warning_message += manifest_file->LayerName();
|
||||
warning_message += ", negotiation did not return a valid getInstanceProcAddr";
|
||||
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
|
||||
res = XR_ERROR_FILE_CONTENTS_INVALID;
|
||||
}
|
||||
if (XR_FAILED(res)) {
|
||||
if (!any_loaded) {
|
||||
last_error = res;
|
||||
}
|
||||
std::ostringstream oss;
|
||||
oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()
|
||||
<< " due to failed negotiation with error " << res;
|
||||
LoaderLogger::LogWarningMessage(openxr_command, oss.str());
|
||||
LoaderPlatformLibraryClose(layer_library);
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "ApiLayerInterface::LoadApiLayers succeeded loading layer " << manifest_file->LayerName()
|
||||
<< " using interface version " << api_layer_info.layerInterfaceVersion << " and OpenXR API version "
|
||||
<< XR_VERSION_MAJOR(api_layer_info.layerApiVersion) << "." << XR_VERSION_MINOR(api_layer_info.layerApiVersion);
|
||||
LoaderLogger::LogInfoMessage(openxr_command, oss.str());
|
||||
}
|
||||
|
||||
// Grab the list of extensions this layer supports for easy filtering after the
|
||||
// xrCreateInstance call
|
||||
std::vector<std::string> supported_extensions;
|
||||
std::vector<XrExtensionProperties> extension_properties;
|
||||
manifest_file->GetInstanceExtensionProperties(extension_properties);
|
||||
supported_extensions.reserve(extension_properties.size());
|
||||
for (XrExtensionProperties& ext_prop : extension_properties) {
|
||||
supported_extensions.emplace_back(ext_prop.extensionName);
|
||||
}
|
||||
|
||||
// Add this API layer to the vector
|
||||
api_layer_interfaces.emplace_back(new ApiLayerInterface(manifest_file->LayerName(), layer_library, supported_extensions,
|
||||
api_layer_info.getInstanceProcAddr,
|
||||
api_layer_info.createApiLayerInstance));
|
||||
|
||||
// If we load one, clear all errors.
|
||||
any_loaded = true;
|
||||
last_error = XR_SUCCESS;
|
||||
}
|
||||
|
||||
// Set error here to preserve prior error behavior
|
||||
if (!found_all_layers) {
|
||||
last_error = XR_ERROR_API_LAYER_NOT_PRESENT;
|
||||
}
|
||||
|
||||
// If we failed catastrophically for some reason, clean up everything.
|
||||
if (XR_FAILED(last_error)) {
|
||||
api_layer_interfaces.clear();
|
||||
}
|
||||
|
||||
return last_error;
|
||||
}
|
||||
|
||||
ApiLayerInterface::ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,
|
||||
std::vector<std::string>& supported_extensions,
|
||||
PFN_xrGetInstanceProcAddr get_instance_proc_addr,
|
||||
PFN_xrCreateApiLayerInstance create_api_layer_instance)
|
||||
: _layer_name(layer_name),
|
||||
_layer_library(layer_library),
|
||||
_get_instance_proc_addr(get_instance_proc_addr),
|
||||
_create_api_layer_instance(create_api_layer_instance),
|
||||
_supported_extensions(supported_extensions) {}
|
||||
|
||||
ApiLayerInterface::~ApiLayerInterface() {
|
||||
std::string info_message = "ApiLayerInterface being destroyed for layer ";
|
||||
info_message += _layer_name;
|
||||
LoaderLogger::LogInfoMessage("", info_message);
|
||||
LoaderPlatformLibraryClose(_layer_library);
|
||||
}
|
||||
|
||||
bool ApiLayerInterface::SupportsExtension(const std::string& extension_name) const {
|
||||
bool found_prop = false;
|
||||
for (const std::string& supported_extension : _supported_extensions) {
|
||||
if (supported_extension == extension_name) {
|
||||
found_prop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found_prop;
|
||||
}
|
||||
54
thirdparty/openxr/src/loader/api_layer_interface.hpp
vendored
Normal file
54
thirdparty/openxr/src/loader/api_layer_interface.hpp
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include "loader_platform.hpp"
|
||||
#include "loader_interfaces.h"
|
||||
|
||||
struct XrGeneratedDispatchTable;
|
||||
|
||||
class ApiLayerInterface {
|
||||
public:
|
||||
// Factory method
|
||||
static XrResult LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,
|
||||
const char* const* enabled_api_layer_names,
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces);
|
||||
// Static queries
|
||||
static XrResult GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count, uint32_t* outgoing_count,
|
||||
XrApiLayerProperties* api_layer_properties);
|
||||
static XrResult GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,
|
||||
std::vector<XrExtensionProperties>& extension_properties);
|
||||
|
||||
ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,
|
||||
std::vector<std::string>& supported_extensions, PFN_xrGetInstanceProcAddr get_instance_proc_addr,
|
||||
PFN_xrCreateApiLayerInstance create_api_layer_instance);
|
||||
virtual ~ApiLayerInterface();
|
||||
|
||||
PFN_xrGetInstanceProcAddr GetInstanceProcAddrFuncPointer() { return _get_instance_proc_addr; }
|
||||
PFN_xrCreateApiLayerInstance GetCreateApiLayerInstanceFuncPointer() { return _create_api_layer_instance; }
|
||||
|
||||
std::string LayerName() { return _layer_name; }
|
||||
|
||||
// Generated methods
|
||||
bool SupportsExtension(const std::string& extension_name) const;
|
||||
|
||||
private:
|
||||
std::string _layer_name;
|
||||
LoaderPlatformLibraryHandle _layer_library;
|
||||
PFN_xrGetInstanceProcAddr _get_instance_proc_addr;
|
||||
PFN_xrCreateApiLayerInstance _create_api_layer_instance;
|
||||
std::vector<std::string> _supported_extensions;
|
||||
};
|
||||
40
thirdparty/openxr/src/loader/exception_handling.hpp
vendored
Normal file
40
thirdparty/openxr/src/loader/exception_handling.hpp
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2019-2022, The Khronos Group Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
//
|
||||
// Provides protection for C ABI functions if standard library functions may throw.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef OPENXR_HAVE_COMMON_CONFIG
|
||||
#include "common_config.h"
|
||||
#endif // OPENXR_HAVE_COMMON_CONFIG
|
||||
|
||||
#ifdef XRLOADER_DISABLE_EXCEPTION_HANDLING
|
||||
|
||||
#define XRLOADER_ABI_TRY
|
||||
#define XRLOADER_ABI_CATCH_BAD_ALLOC_OOM
|
||||
#define XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
#else
|
||||
|
||||
#include <stdexcept>
|
||||
#define XRLOADER_ABI_TRY try
|
||||
#define XRLOADER_ABI_CATCH_BAD_ALLOC_OOM \
|
||||
catch (const std::bad_alloc&) { \
|
||||
LoaderLogger::LogErrorMessage("", "failed allocating memory"); \
|
||||
return XR_ERROR_OUT_OF_MEMORY; \
|
||||
}
|
||||
#define XRLOADER_ABI_CATCH_FALLBACK \
|
||||
catch (const std::exception& e) { \
|
||||
LoaderLogger::LogErrorMessage("", "Unknown failure: " + std::string(e.what())); \
|
||||
return XR_ERROR_RUNTIME_FAILURE; \
|
||||
} \
|
||||
catch (...) { \
|
||||
LoaderLogger::LogErrorMessage("", "Unknown failure"); \
|
||||
return XR_ERROR_RUNTIME_FAILURE; \
|
||||
}
|
||||
|
||||
#endif
|
||||
847
thirdparty/openxr/src/loader/loader_core.cpp
vendored
Normal file
847
thirdparty/openxr/src/loader/loader_core.cpp
vendored
Normal file
@@ -0,0 +1,847 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com>
|
||||
//
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
#include "api_layer_interface.hpp"
|
||||
#include "exception_handling.hpp"
|
||||
#include "hex_and_handles.h"
|
||||
#include "loader_instance.hpp"
|
||||
#include "loader_logger_recorders.hpp"
|
||||
#include "loader_logger.hpp"
|
||||
#include "loader_platform.hpp"
|
||||
#include "runtime_interface.hpp"
|
||||
#include "xr_generated_dispatch_table.h"
|
||||
#include "xr_generated_loader.hpp"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// Global loader lock to:
|
||||
// 1. Ensure ActiveLoaderInstance get and set operations are done atomically.
|
||||
// 2. Ensure RuntimeInterface isn't used to unload the runtime while the runtime is in use.
|
||||
std::mutex &GetGlobalLoaderMutex() {
|
||||
static std::mutex loader_mutex;
|
||||
return loader_mutex;
|
||||
}
|
||||
|
||||
// Prototypes for the debug utils calls used internally.
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineCreateDebugUtilsMessengerEXT(
|
||||
XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, XrDebugUtilsMessengerEXT *messenger);
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger);
|
||||
|
||||
// Terminal functions needed by xrCreateInstance.
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance, const char *, PFN_xrVoidFunction *);
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *, XrInstance *);
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *,
|
||||
const struct XrApiLayerCreateInfo *, XrInstance *);
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance, const XrDebugUtilsObjectNameInfoEXT *);
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance,
|
||||
const XrDebugUtilsMessengerCreateInfoEXT *,
|
||||
XrDebugUtilsMessengerEXT *);
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT);
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
|
||||
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT *callbackData);
|
||||
|
||||
// Utility template function meant to validate if a fixed size string contains
|
||||
// a null-terminator.
|
||||
template <size_t max_length>
|
||||
inline bool IsMissingNullTerminator(const char (&str)[max_length]) {
|
||||
for (size_t index = 0; index < max_length; ++index) {
|
||||
if (str[index] == '\0') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---- Core 1.0 manual loader trampoline functions
|
||||
#ifdef XR_KHR_LOADER_INIT_SUPPORT // platforms that support XR_KHR_loader_init.
|
||||
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline");
|
||||
return InitializeLoader(loaderInitInfo);
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
#endif
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
|
||||
uint32_t *propertyCountOutput,
|
||||
XrApiLayerProperties *properties) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties", "Entering loader trampoline");
|
||||
|
||||
// Make sure only one thread is attempting to read the JSON files at a time.
|
||||
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
|
||||
|
||||
XrResult result = ApiLayerInterface::GetApiLayerProperties("xrEnumerateApiLayerProperties", propertyCapacityInput,
|
||||
propertyCountOutput, properties);
|
||||
if (XR_FAILED(result)) {
|
||||
LoaderLogger::LogErrorMessage("xrEnumerateApiLayerProperties", "Failed ApiLayerInterface::GetApiLayerProperties");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL
|
||||
LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput,
|
||||
XrExtensionProperties *properties) XRLOADER_ABI_TRY {
|
||||
bool just_layer_properties = false;
|
||||
LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Entering loader trampoline");
|
||||
|
||||
// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,
|
||||
// and the function sets elementCountOutput." - 2.11
|
||||
if (nullptr == propertyCountOutput) {
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (nullptr != layerName && 0 != strlen(layerName)) {
|
||||
// Application is only interested in layer's properties, not all of them.
|
||||
just_layer_properties = true;
|
||||
}
|
||||
|
||||
std::vector<XrExtensionProperties> extension_properties = {};
|
||||
XrResult result;
|
||||
|
||||
{
|
||||
// Make sure the runtime isn't unloaded while this call is in progress.
|
||||
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
|
||||
|
||||
// Get the layer extension properties
|
||||
result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties", layerName,
|
||||
extension_properties);
|
||||
if (XR_SUCCEEDED(result) && !just_layer_properties) {
|
||||
// If not specific to a layer, get the runtime extension properties
|
||||
result = RuntimeInterface::LoadRuntime("xrEnumerateInstanceExtensionProperties");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties);
|
||||
} else {
|
||||
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
|
||||
"Failed to find default runtime with RuntimeInterface::LoadRuntime()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (XR_FAILED(result)) {
|
||||
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", "Failed querying extension properties");
|
||||
return result;
|
||||
}
|
||||
|
||||
// If this is not in reference to a specific layer, then add the loader-specific extension properties as well.
|
||||
// These are extensions that the loader directly supports.
|
||||
if (!just_layer_properties) {
|
||||
for (const XrExtensionProperties &loader_prop : LoaderInstance::LoaderSpecificExtensions()) {
|
||||
bool found_prop = false;
|
||||
for (XrExtensionProperties &existing_prop : extension_properties) {
|
||||
if (0 == strcmp(existing_prop.extensionName, loader_prop.extensionName)) {
|
||||
found_prop = true;
|
||||
// Use the loader version if it is newer
|
||||
if (existing_prop.extensionVersion < loader_prop.extensionVersion) {
|
||||
existing_prop.extensionVersion = loader_prop.extensionVersion;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Only add extensions not supported by the loader
|
||||
if (!found_prop) {
|
||||
extension_properties.push_back(loader_prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto num_extension_properties = static_cast<uint32_t>(extension_properties.size());
|
||||
if (propertyCapacityInput == 0) {
|
||||
*propertyCountOutput = num_extension_properties;
|
||||
} else if (nullptr != properties) {
|
||||
if (propertyCapacityInput < num_extension_properties) {
|
||||
*propertyCountOutput = num_extension_properties;
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter",
|
||||
"xrEnumerateInstanceExtensionProperties", "insufficient space in array");
|
||||
return XR_ERROR_SIZE_INSUFFICIENT;
|
||||
}
|
||||
|
||||
uint32_t num_to_copy = num_extension_properties;
|
||||
// Determine how many extension properties we can copy over
|
||||
if (propertyCapacityInput < num_to_copy) {
|
||||
num_to_copy = propertyCapacityInput;
|
||||
}
|
||||
bool properties_valid = true;
|
||||
for (uint32_t prop = 0; prop < propertyCapacityInput && prop < extension_properties.size(); ++prop) {
|
||||
if (XR_TYPE_EXTENSION_PROPERTIES != properties[prop].type) {
|
||||
properties_valid = false;
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-XrExtensionProperties-type-type",
|
||||
"xrEnumerateInstanceExtensionProperties", "unknown type in properties");
|
||||
}
|
||||
if (properties_valid) {
|
||||
properties[prop] = extension_properties[prop];
|
||||
}
|
||||
}
|
||||
if (!properties_valid) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-properties-parameter",
|
||||
"xrEnumerateInstanceExtensionProperties", "invalid properties");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
if (nullptr != propertyCountOutput) {
|
||||
*propertyCountOutput = num_to_copy;
|
||||
}
|
||||
} else {
|
||||
// incoming_count is not 0 BUT the properties is NULL
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Completed loader trampoline");
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCreateInfo *info,
|
||||
XrInstance *instance) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader trampoline");
|
||||
if (nullptr == info) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance", "must be non-NULL");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
// If application requested OpenXR API version is higher than the loader version, then we need to throw
|
||||
// an error.
|
||||
uint16_t app_major = XR_VERSION_MAJOR(info->applicationInfo.apiVersion); // NOLINT
|
||||
uint16_t app_minor = XR_VERSION_MINOR(info->applicationInfo.apiVersion); // NOLINT
|
||||
uint16_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); // NOLINT
|
||||
uint16_t loader_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION); // NOLINT
|
||||
if (app_major > loader_major || (app_major == loader_major && app_minor > loader_minor)) {
|
||||
std::ostringstream oss;
|
||||
oss << "xrCreateInstance called with invalid API version " << app_major << "." << app_minor
|
||||
<< ". Max supported version is " << loader_major << "." << loader_minor;
|
||||
LoaderLogger::LogErrorMessage("xrCreateInstance", oss.str());
|
||||
return XR_ERROR_API_VERSION_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (nullptr == instance) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-instance-parameter", "xrCreateInstance", "must be non-NULL");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
// Make sure the ActiveLoaderInstance::IsAvailable check is done atomically with RuntimeInterface::LoadRuntime.
|
||||
std::unique_lock<std::mutex> instance_lock(GetGlobalLoaderMutex());
|
||||
|
||||
// Check if there is already an XrInstance that is alive. If so, another instance cannot be created.
|
||||
// The loader does not support multiple simultaneous instances because the loader is intended to be
|
||||
// usable by apps using future OpenXR APIs (through xrGetInstanceProcAddr). Because the loader would
|
||||
// not be aware of new handle types, it would not be able to look up the appropriate dispatch table
|
||||
// in some cases.
|
||||
if (ActiveLoaderInstance::IsAvailable()) { // If there is an XrInstance already alive.
|
||||
LoaderLogger::LogErrorMessage("xrCreateInstance", "Loader does not support simultaneous XrInstances");
|
||||
return XR_ERROR_LIMIT_REACHED;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces;
|
||||
XrResult result;
|
||||
|
||||
// Make sure only one thread is attempting to read the JSON files and use the instance.
|
||||
{
|
||||
// Load the available runtime
|
||||
result = RuntimeInterface::LoadRuntime("xrCreateInstance");
|
||||
if (XR_FAILED(result)) {
|
||||
LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading runtime information");
|
||||
} else {
|
||||
// Load the appropriate layers
|
||||
result = ApiLayerInterface::LoadApiLayers("xrCreateInstance", info->enabledApiLayerCount, info->enabledApiLayerNames,
|
||||
api_layer_interfaces);
|
||||
if (XR_FAILED(result)) {
|
||||
LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading layer information");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the loader instance (only send down first runtime interface)
|
||||
LoaderInstance *loader_instance = nullptr;
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
std::unique_ptr<LoaderInstance> owned_loader_instance;
|
||||
result = LoaderInstance::CreateInstance(LoaderXrTermGetInstanceProcAddr, LoaderXrTermCreateInstance,
|
||||
LoaderXrTermCreateApiLayerInstance, std::move(api_layer_interfaces), info,
|
||||
&owned_loader_instance);
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
loader_instance = owned_loader_instance.get();
|
||||
result = ActiveLoaderInstance::Set(std::move(owned_loader_instance), "xrCreateInstance");
|
||||
}
|
||||
}
|
||||
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
// Create a debug utils messenger if the create structure is in the "next" chain
|
||||
const auto *next_header = reinterpret_cast<const XrBaseInStructure *>(info->next);
|
||||
const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr;
|
||||
while (next_header != nullptr) {
|
||||
if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
|
||||
LoaderLogger::LogInfoMessage("xrCreateInstance", "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain.");
|
||||
dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);
|
||||
XrDebugUtilsMessengerEXT messenger;
|
||||
result = LoaderTrampolineCreateDebugUtilsMessengerEXT(loader_instance->GetInstanceHandle(), dbg_utils_create_info,
|
||||
&messenger);
|
||||
if (XR_FAILED(result)) {
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
loader_instance->SetDefaultDebugUtilsMessenger(messenger);
|
||||
break;
|
||||
}
|
||||
next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next);
|
||||
}
|
||||
}
|
||||
|
||||
if (XR_FAILED(result)) {
|
||||
// Ensure the global loader instance and runtime are destroyed if something went wrong.
|
||||
ActiveLoaderInstance::Remove();
|
||||
RuntimeInterface::UnloadRuntime("xrCreateInstance");
|
||||
LoaderLogger::LogErrorMessage("xrCreateInstance", "xrCreateInstance failed");
|
||||
} else {
|
||||
*instance = loader_instance->GetInstanceHandle();
|
||||
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader trampoline");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader trampoline");
|
||||
// Runtimes may detect XR_NULL_HANDLE provided as a required handle parameter and return XR_ERROR_HANDLE_INVALID. - 2.9
|
||||
if (XR_NULL_HANDLE == instance) {
|
||||
LoaderLogger::LogErrorMessage("xrDestroyInstance", "Instance handle is XR_NULL_HANDLE.");
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
// Make sure the runtime isn't unloaded while it is being used by xrEnumerateInstanceExtensionProperties.
|
||||
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
|
||||
|
||||
LoaderInstance *loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyInstance");
|
||||
if (XR_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
|
||||
|
||||
// If we allocated a default debug utils messenger, free it
|
||||
XrDebugUtilsMessengerEXT messenger = loader_instance->DefaultDebugUtilsMessenger();
|
||||
if (messenger != XR_NULL_HANDLE) {
|
||||
LoaderTrampolineDestroyDebugUtilsMessengerEXT(messenger);
|
||||
}
|
||||
|
||||
// Now destroy the instance
|
||||
if (XR_FAILED(dispatch_table->DestroyInstance(instance))) {
|
||||
LoaderLogger::LogErrorMessage("xrDestroyInstance", "Unknown error occurred calling down chain");
|
||||
}
|
||||
|
||||
// Get rid of the loader instance. This will make it possible to create another instance in the future.
|
||||
ActiveLoaderInstance::Remove();
|
||||
|
||||
// Lock the instance create/destroy mutex
|
||||
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader trampoline");
|
||||
|
||||
// Finally, unload the runtime if necessary
|
||||
RuntimeInterface::UnloadRuntime("xrDestroyInstance");
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
// ---- Core 1.0 manual loader terminator functions
|
||||
|
||||
// Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid.
|
||||
static XrResult ValidateApplicationInfo(const XrApplicationInfo &info) {
|
||||
if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(info.applicationName)) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-applicationName-parameter", "xrCreateInstance",
|
||||
"application name missing NULL terminator.");
|
||||
return XR_ERROR_NAME_INVALID;
|
||||
}
|
||||
if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(info.engineName)) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-engineName-parameter", "xrCreateInstance",
|
||||
"engine name missing NULL terminator.");
|
||||
return XR_ERROR_NAME_INVALID;
|
||||
}
|
||||
if (strlen(info.applicationName) == 0) {
|
||||
LoaderLogger::LogErrorMessage("xrCreateInstance",
|
||||
"VUID-XrApplicationInfo-engineName-parameter: application name can not be empty.");
|
||||
return XR_ERROR_NAME_INVALID;
|
||||
}
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
// Validate that the XrInstanceCreateInfo is valid
|
||||
static XrResult ValidateInstanceCreateInfo(const XrInstanceCreateInfo *info) {
|
||||
// Should have a valid 'type'
|
||||
if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-type-type", "xrCreateInstance",
|
||||
"expected XR_TYPE_INSTANCE_CREATE_INFO.");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
// Flags must be 0
|
||||
if (0 != info->createFlags) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-createFlags-zerobitmask", "xrCreateInstance",
|
||||
"flags must be 0.");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
// ApplicationInfo struct must be valid
|
||||
XrResult result = ValidateApplicationInfo(info->applicationInfo);
|
||||
if (XR_FAILED(result)) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-applicationInfo-parameter", "xrCreateInstance",
|
||||
"info->applicationInfo is not valid.");
|
||||
return result;
|
||||
}
|
||||
// VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter already tested in LoadApiLayers()
|
||||
if ((info->enabledExtensionCount != 0u) && nullptr == info->enabledExtensionNames) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-enabledExtensionNames-parameter", "xrCreateInstance",
|
||||
"enabledExtensionCount is non-0 but array is NULL");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *createInfo,
|
||||
XrInstance *instance) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader terminator");
|
||||
XrResult result = ValidateInstanceCreateInfo(createInfo);
|
||||
if (XR_FAILED(result)) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance",
|
||||
"something wrong with XrInstanceCreateInfo contents");
|
||||
return result;
|
||||
}
|
||||
result = RuntimeInterface::GetRuntime().CreateInstance(createInfo, instance);
|
||||
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader terminator");
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info,
|
||||
const struct XrApiLayerCreateInfo * /*apiLayerInfo*/,
|
||||
XrInstance *instance) {
|
||||
return LoaderXrTermCreateInstance(info, instance);
|
||||
}
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader terminator");
|
||||
LoaderLogger::GetInstance().RemoveLogRecordersForXrInstance(instance);
|
||||
XrResult result = RuntimeInterface::GetRuntime().DestroyInstance(instance);
|
||||
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader terminator");
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance instance, const char *name,
|
||||
PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {
|
||||
// A few instance commands need to go through a loader terminator.
|
||||
// Otherwise, go directly to the runtime version of the command if it exists.
|
||||
// But first set the function pointer to NULL so that the fall-through below actually works.
|
||||
*function = nullptr;
|
||||
|
||||
// NOTE: ActiveLoaderInstance cannot be used in this function because it is called before an instance is made active.
|
||||
|
||||
if (0 == strcmp(name, "xrGetInstanceProcAddr")) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermGetInstanceProcAddr);
|
||||
} else if (0 == strcmp(name, "xrCreateInstance")) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateInstance);
|
||||
} else if (0 == strcmp(name, "xrDestroyInstance")) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyInstance);
|
||||
} else if (0 == strcmp(name, "xrSetDebugUtilsObjectNameEXT")) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSetDebugUtilsObjectNameEXT);
|
||||
} else if (0 == strcmp(name, "xrCreateDebugUtilsMessengerEXT")) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateDebugUtilsMessengerEXT);
|
||||
} else if (0 == strcmp(name, "xrDestroyDebugUtilsMessengerEXT")) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyDebugUtilsMessengerEXT);
|
||||
} else if (0 == strcmp(name, "xrSubmitDebugUtilsMessageEXT")) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSubmitDebugUtilsMessageEXT);
|
||||
} else if (0 == strcmp(name, "xrCreateApiLayerInstance")) {
|
||||
// Special layer version of xrCreateInstance terminator. If we get called this by a layer,
|
||||
// we simply re-direct the information back into the standard xrCreateInstance terminator.
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateApiLayerInstance);
|
||||
}
|
||||
|
||||
if (nullptr != *function) {
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
return RuntimeInterface::GetInstanceProcAddr(instance, name, function);
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
// ---- Extension manual loader trampoline functions
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL
|
||||
LoaderTrampolineCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
|
||||
XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader trampoline");
|
||||
|
||||
if (instance == XR_NULL_HANDLE) {
|
||||
LoaderLogger::LogErrorMessage("xrCreateDebugUtilsMessengerEXT", "Instance handle is XR_NULL_HANDLE.");
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
LoaderInstance *loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateDebugUtilsMessengerEXT");
|
||||
if (XR_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = loader_instance->DispatchTable()->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
|
||||
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader trampoline");
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_BAD_ALLOC_OOM XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL
|
||||
LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
|
||||
// TODO: get instance from messenger in loader
|
||||
// Also, is the loader really doing all this every call?
|
||||
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader trampoline");
|
||||
|
||||
if (messenger == XR_NULL_HANDLE) {
|
||||
LoaderLogger::LogErrorMessage("xrDestroyDebugUtilsMessengerEXT", "Messenger handle is XR_NULL_HANDLE.");
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
LoaderInstance *loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyDebugUtilsMessengerEXT");
|
||||
if (XR_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = loader_instance->DispatchTable()->DestroyDebugUtilsMessengerEXT(messenger);
|
||||
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader trampoline");
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL
|
||||
LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
|
||||
if (session == XR_NULL_HANDLE) {
|
||||
LoaderLogger::LogErrorMessage("xrSessionBeginDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
if (nullptr == labelInfo) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter",
|
||||
"xrSessionBeginDebugUtilsLabelRegionEXT", "labelInfo must be non-NULL",
|
||||
{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
LoaderInstance *loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionBeginDebugUtilsLabelRegionEXT");
|
||||
if (XR_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
LoaderLogger::GetInstance().BeginLabelRegion(session, labelInfo);
|
||||
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
|
||||
if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) {
|
||||
return dispatch_table->SessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);
|
||||
}
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY {
|
||||
if (session == XR_NULL_HANDLE) {
|
||||
LoaderLogger::LogErrorMessage("xrSessionEndDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
LoaderInstance *loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionEndDebugUtilsLabelRegionEXT");
|
||||
if (XR_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
LoaderLogger::GetInstance().EndLabelRegion(session);
|
||||
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
|
||||
if (nullptr != dispatch_table->SessionEndDebugUtilsLabelRegionEXT) {
|
||||
return dispatch_table->SessionEndDebugUtilsLabelRegionEXT(session);
|
||||
}
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL
|
||||
LoaderTrampolineSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
|
||||
if (session == XR_NULL_HANDLE) {
|
||||
LoaderLogger::LogErrorMessage("xrSessionInsertDebugUtilsLabelEXT", "Session handle is XR_NULL_HANDLE.");
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
LoaderInstance *loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionInsertDebugUtilsLabelEXT");
|
||||
if (XR_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (nullptr == labelInfo) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter",
|
||||
"xrSessionInsertDebugUtilsLabelEXT", "labelInfo must be non-NULL",
|
||||
{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
LoaderLogger::GetInstance().InsertLabel(session, labelInfo);
|
||||
|
||||
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
|
||||
if (nullptr != dispatch_table->SessionInsertDebugUtilsLabelEXT) {
|
||||
return dispatch_table->SessionInsertDebugUtilsLabelEXT(session, labelInfo);
|
||||
}
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL
|
||||
LoaderTrampolineSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance *loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSetDebugUtilsObjectNameEXT");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->SetDebugUtilsObjectNameEXT(instance, nameInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.
|
||||
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSubmitDebugUtilsMessageEXT(
|
||||
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {
|
||||
LoaderInstance *loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSubmitDebugUtilsMessageEXT");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result =
|
||||
loader_instance->DispatchTable()->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
// ---- Extension manual loader terminator functions
|
||||
|
||||
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance,
|
||||
const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
|
||||
XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader terminator");
|
||||
if (nullptr == messenger) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter",
|
||||
"xrCreateDebugUtilsMessengerEXT", "invalid messenger pointer");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
|
||||
XrResult result = XR_SUCCESS;
|
||||
// This extension is supported entirely by the loader which means the runtime may or may not support it.
|
||||
if (nullptr != dispatch_table->CreateDebugUtilsMessengerEXT) {
|
||||
result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
|
||||
} else {
|
||||
// Just allocate a character so we have a unique value
|
||||
char *temp_mess_ptr = new char;
|
||||
*messenger = reinterpret_cast<XrDebugUtilsMessengerEXT>(temp_mess_ptr);
|
||||
}
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
LoaderLogger::GetInstance().AddLogRecorderForXrInstance(instance, MakeDebugUtilsLoaderLogRecorder(createInfo, *messenger));
|
||||
RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, *messenger);
|
||||
}
|
||||
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader terminator");
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader terminator");
|
||||
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger);
|
||||
XrResult result = XR_SUCCESS;
|
||||
LoaderLogger::GetInstance().RemoveLogRecorder(MakeHandleGeneric(messenger));
|
||||
RuntimeInterface::GetRuntime().ForgetDebugMessenger(messenger);
|
||||
// This extension is supported entirely by the loader which means the runtime may or may not support it.
|
||||
if (nullptr != dispatch_table->DestroyDebugUtilsMessengerEXT) {
|
||||
result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger);
|
||||
} else {
|
||||
// Delete the character we would've created
|
||||
delete (reinterpret_cast<char *>(MakeHandleGeneric(messenger)));
|
||||
}
|
||||
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader terminator");
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
|
||||
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Entering loader terminator");
|
||||
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
|
||||
XrResult result = XR_SUCCESS;
|
||||
if (nullptr != dispatch_table->SubmitDebugUtilsMessageEXT) {
|
||||
result = dispatch_table->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);
|
||||
} else {
|
||||
// Only log the message from the loader if the runtime doesn't support this extension. If we did,
|
||||
// then the user would receive multiple instances of the same message.
|
||||
LoaderLogger::GetInstance().LogDebugUtilsMessage(messageSeverity, messageTypes, callbackData);
|
||||
}
|
||||
LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Completed loader terminator");
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
XRAPI_ATTR XrResult XRAPI_CALL
|
||||
LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
|
||||
LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Entering loader terminator");
|
||||
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
|
||||
XrResult result = XR_SUCCESS;
|
||||
if (nullptr != dispatch_table->SetDebugUtilsObjectNameEXT) {
|
||||
result = dispatch_table->SetDebugUtilsObjectNameEXT(instance, nameInfo);
|
||||
}
|
||||
LoaderLogger::GetInstance().AddObjectName(nameInfo->objectHandle, nameInfo->objectType, nameInfo->objectName);
|
||||
LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Completed loader terminator");
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name,
|
||||
PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {
|
||||
// Initialize the function to nullptr in case it does not get caught in a known case
|
||||
*function = nullptr;
|
||||
|
||||
if (nullptr == function) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",
|
||||
"Invalid Function pointer");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
if (nullptr == name) {
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",
|
||||
"Invalid Name pointer");
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
|
||||
LoaderInstance *loader_instance = nullptr;
|
||||
if (instance == XR_NULL_HANDLE) {
|
||||
// Null instance is allowed for a few specific API entry points, otherwise return error
|
||||
if (strcmp(name, "xrCreateInstance") != 0 && strcmp(name, "xrEnumerateApiLayerProperties") != 0 &&
|
||||
strcmp(name, "xrEnumerateInstanceExtensionProperties") != 0 && strcmp(name, "xrInitializeLoaderKHR") != 0) {
|
||||
// TODO why is xrGetInstanceProcAddr not listed in here?
|
||||
std::string error_str = "XR_NULL_HANDLE for instance but query for ";
|
||||
error_str += name;
|
||||
error_str += " requires a valid instance";
|
||||
LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-instance-parameter", "xrGetInstanceProcAddr",
|
||||
error_str);
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
} else {
|
||||
// non null instance passed in, it should be our current instance
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProcAddr");
|
||||
if (XR_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
if (loader_instance->GetInstanceHandle() != instance) {
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
// These functions must always go through the loader's implementation (trampoline).
|
||||
if (strcmp(name, "xrGetInstanceProcAddr") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrGetInstanceProcAddr);
|
||||
return XR_SUCCESS;
|
||||
} else if (strcmp(name, "xrInitializeLoaderKHR") == 0) {
|
||||
#ifdef XR_KHR_LOADER_INIT_SUPPORT
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrInitializeLoaderKHR);
|
||||
return XR_SUCCESS;
|
||||
#else
|
||||
return XR_ERROR_FUNCTION_UNSUPPORTED;
|
||||
#endif
|
||||
} else if (strcmp(name, "xrEnumerateApiLayerProperties") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateApiLayerProperties);
|
||||
return XR_SUCCESS;
|
||||
} else if (strcmp(name, "xrEnumerateInstanceExtensionProperties") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateInstanceExtensionProperties);
|
||||
return XR_SUCCESS;
|
||||
} else if (strcmp(name, "xrCreateInstance") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrCreateInstance);
|
||||
return XR_SUCCESS;
|
||||
} else if (strcmp(name, "xrDestroyInstance") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrDestroyInstance);
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
// XR_EXT_debug_utils is built into the loader and handled partly through the xrGetInstanceProcAddress terminator,
|
||||
// but the check to see if the extension is enabled must be done here where ActiveLoaderInstance is safe to use.
|
||||
if (*function == nullptr) {
|
||||
if (strcmp(name, "xrCreateDebugUtilsMessengerEXT") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineCreateDebugUtilsMessengerEXT);
|
||||
} else if (strcmp(name, "xrDestroyDebugUtilsMessengerEXT") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineDestroyDebugUtilsMessengerEXT);
|
||||
} else if (strcmp(name, "xrSessionBeginDebugUtilsLabelRegionEXT") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT);
|
||||
} else if (strcmp(name, "xrSessionEndDebugUtilsLabelRegionEXT") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT);
|
||||
} else if (strcmp(name, "xrSessionInsertDebugUtilsLabelEXT") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionInsertDebugUtilsLabelEXT);
|
||||
} else if (strcmp(name, "xrSetDebugUtilsObjectNameEXT") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSetDebugUtilsObjectNameEXT);
|
||||
} else if (strcmp(name, "xrSubmitDebugUtilsMessageEXT") == 0) {
|
||||
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSubmitDebugUtilsMessageEXT);
|
||||
}
|
||||
|
||||
if (*function != nullptr && !loader_instance->ExtensionIsEnabled("XR_EXT_debug_utils")) {
|
||||
// The function matches one of the XR_EXT_debug_utils functions but the extension is not enabled.
|
||||
*function = nullptr;
|
||||
return XR_ERROR_FUNCTION_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (*function != nullptr) {
|
||||
// The loader has a trampoline or implementation of this function.
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
// If the function is not supported by the loader, call down to the next layer.
|
||||
return loader_instance->GetInstanceProcAddr(name, function);
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
// Exported loader functions
|
||||
//
|
||||
// The application might override these by exporting the same symbols and so we can't use these
|
||||
// symbols anywhere in the loader code, and instead the internal non exported functions that these
|
||||
// stubs call should be used internally.
|
||||
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
|
||||
uint32_t *propertyCountOutput,
|
||||
XrApiLayerProperties *properties) {
|
||||
return LoaderXrEnumerateApiLayerProperties(propertyCapacityInput, propertyCountOutput, properties);
|
||||
}
|
||||
|
||||
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(const char *layerName,
|
||||
uint32_t propertyCapacityInput,
|
||||
uint32_t *propertyCountOutput,
|
||||
XrExtensionProperties *properties) {
|
||||
return LoaderXrEnumerateInstanceExtensionProperties(layerName, propertyCapacityInput, propertyCountOutput, properties);
|
||||
}
|
||||
|
||||
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) {
|
||||
return LoaderXrCreateInstance(info, instance);
|
||||
}
|
||||
|
||||
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) { return LoaderXrDestroyInstance(instance); }
|
||||
|
||||
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(XrInstance instance, const char *name,
|
||||
PFN_xrVoidFunction *function) {
|
||||
return LoaderXrGetInstanceProcAddr(instance, name, function);
|
||||
}
|
||||
|
||||
#ifdef XR_KHR_LOADER_INIT_SUPPORT
|
||||
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) {
|
||||
return LoaderXrInitializeLoaderKHR(loaderInitInfo);
|
||||
}
|
||||
#endif
|
||||
303
thirdparty/openxr/src/loader/loader_instance.cpp
vendored
Normal file
303
thirdparty/openxr/src/loader/loader_instance.cpp
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
#include "loader_instance.hpp"
|
||||
|
||||
#include "api_layer_interface.hpp"
|
||||
#include "hex_and_handles.h"
|
||||
#include "loader_interfaces.h"
|
||||
#include "loader_logger.hpp"
|
||||
#include "runtime_interface.hpp"
|
||||
#include "xr_generated_dispatch_table.h"
|
||||
#include "xr_generated_loader.hpp"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
std::unique_ptr<LoaderInstance>& GetSetCurrentLoaderInstance() {
|
||||
static std::unique_ptr<LoaderInstance> current_loader_instance;
|
||||
return current_loader_instance;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace ActiveLoaderInstance {
|
||||
XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name) {
|
||||
if (GetSetCurrentLoaderInstance() != nullptr) {
|
||||
LoaderLogger::LogErrorMessage(log_function_name, "Active XrInstance handle already exists");
|
||||
return XR_ERROR_LIMIT_REACHED;
|
||||
}
|
||||
|
||||
GetSetCurrentLoaderInstance() = std::move(loader_instance);
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
XrResult Get(LoaderInstance** loader_instance, const char* log_function_name) {
|
||||
*loader_instance = GetSetCurrentLoaderInstance().get();
|
||||
if (*loader_instance == nullptr) {
|
||||
LoaderLogger::LogErrorMessage(log_function_name, "No active XrInstance handle.");
|
||||
return XR_ERROR_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; }
|
||||
|
||||
void Remove() { GetSetCurrentLoaderInstance().release(); }
|
||||
} // namespace ActiveLoaderInstance
|
||||
|
||||
// Extensions that are supported by the loader, but may not be supported
|
||||
// the the runtime.
|
||||
const std::array<XrExtensionProperties, 1>& LoaderInstance::LoaderSpecificExtensions() {
|
||||
static const std::array<XrExtensionProperties, 1> extensions = {XrExtensionProperties{
|
||||
XR_TYPE_EXTENSION_PROPERTIES, nullptr, XR_EXT_DEBUG_UTILS_EXTENSION_NAME, XR_EXT_debug_utils_SPEC_VERSION}};
|
||||
return extensions;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class InstanceCreateInfoManager {
|
||||
public:
|
||||
explicit InstanceCreateInfoManager(const XrInstanceCreateInfo* info) : original_create_info(info), modified_create_info(*info) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
// Reset the "modified" state to match the original state.
|
||||
void Reset() {
|
||||
enabled_extensions_cstr.clear();
|
||||
enabled_extensions_cstr.reserve(original_create_info->enabledExtensionCount);
|
||||
|
||||
for (uint32_t i = 0; i < original_create_info->enabledExtensionCount; ++i) {
|
||||
enabled_extensions_cstr.push_back(original_create_info->enabledExtensionNames[i]);
|
||||
}
|
||||
Update();
|
||||
}
|
||||
|
||||
// Remove extensions named in the parameter and return a pointer to the current state.
|
||||
const XrInstanceCreateInfo* FilterOutExtensions(const std::vector<const char*>& extensions_to_skip) {
|
||||
if (enabled_extensions_cstr.empty()) {
|
||||
return Get();
|
||||
}
|
||||
if (extensions_to_skip.empty()) {
|
||||
return Get();
|
||||
}
|
||||
for (auto& ext : extensions_to_skip) {
|
||||
FilterOutExtension(ext);
|
||||
}
|
||||
return Update();
|
||||
}
|
||||
// Remove the extension named in the parameter and return a pointer to the current state.
|
||||
const XrInstanceCreateInfo* FilterOutExtension(const char* extension_to_skip) {
|
||||
if (enabled_extensions_cstr.empty()) {
|
||||
return &modified_create_info;
|
||||
}
|
||||
auto b = enabled_extensions_cstr.begin();
|
||||
auto e = enabled_extensions_cstr.end();
|
||||
auto it = std::find_if(b, e, [&](const char* extension) { return strcmp(extension_to_skip, extension) == 0; });
|
||||
if (it != e) {
|
||||
// Just that one element goes away
|
||||
enabled_extensions_cstr.erase(it);
|
||||
}
|
||||
return Update();
|
||||
}
|
||||
|
||||
// Get the current modified XrInstanceCreateInfo
|
||||
const XrInstanceCreateInfo* Get() const { return &modified_create_info; }
|
||||
|
||||
private:
|
||||
const XrInstanceCreateInfo* Update() {
|
||||
modified_create_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions_cstr.size());
|
||||
modified_create_info.enabledExtensionNames = enabled_extensions_cstr.empty() ? nullptr : enabled_extensions_cstr.data();
|
||||
return &modified_create_info;
|
||||
}
|
||||
const XrInstanceCreateInfo* original_create_info;
|
||||
|
||||
XrInstanceCreateInfo modified_create_info;
|
||||
std::vector<const char*> enabled_extensions_cstr;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Factory method
|
||||
XrResult LoaderInstance::CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term,
|
||||
PFN_xrCreateInstance create_instance_term,
|
||||
PFN_xrCreateApiLayerInstance create_api_layer_instance_term,
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces,
|
||||
const XrInstanceCreateInfo* info, std::unique_ptr<LoaderInstance>* loader_instance) {
|
||||
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering LoaderInstance::CreateInstance");
|
||||
|
||||
// Check the list of enabled extensions to make sure something supports them, and, if we do,
|
||||
// add it to the list of enabled extensions
|
||||
XrResult last_error = XR_SUCCESS;
|
||||
for (uint32_t ext = 0; ext < info->enabledExtensionCount; ++ext) {
|
||||
bool found = false;
|
||||
// First check the runtime
|
||||
if (RuntimeInterface::GetRuntime().SupportsExtension(info->enabledExtensionNames[ext])) {
|
||||
found = true;
|
||||
}
|
||||
// Next check the loader
|
||||
if (!found) {
|
||||
for (auto& loader_extension : LoaderInstance::LoaderSpecificExtensions()) {
|
||||
if (strcmp(loader_extension.extensionName, info->enabledExtensionNames[ext]) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally, check the enabled layers
|
||||
if (!found) {
|
||||
for (auto& layer_interface : api_layer_interfaces) {
|
||||
if (layer_interface->SupportsExtension(info->enabledExtensionNames[ext])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
std::string msg = "LoaderInstance::CreateInstance, no support found for requested extension: ";
|
||||
msg += info->enabledExtensionNames[ext];
|
||||
LoaderLogger::LogErrorMessage("xrCreateInstance", msg);
|
||||
last_error = XR_ERROR_EXTENSION_NOT_PRESENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Topmost means "closest to the application"
|
||||
PFN_xrGetInstanceProcAddr topmost_gipa = get_instance_proc_addr_term;
|
||||
XrInstance instance{XR_NULL_HANDLE};
|
||||
|
||||
if (XR_SUCCEEDED(last_error)) {
|
||||
// Remove the loader-supported-extensions (debug utils), if it's in the list of enabled extensions but not supported by
|
||||
// the runtime.
|
||||
InstanceCreateInfoManager create_info_manager{info};
|
||||
const XrInstanceCreateInfo* modified_create_info = info;
|
||||
if (info->enabledExtensionCount > 0) {
|
||||
std::vector<const char*> extensions_to_skip;
|
||||
for (const auto& ext : LoaderInstance::LoaderSpecificExtensions()) {
|
||||
if (!RuntimeInterface::GetRuntime().SupportsExtension(ext.extensionName)) {
|
||||
extensions_to_skip.emplace_back(ext.extensionName);
|
||||
}
|
||||
}
|
||||
modified_create_info = create_info_manager.FilterOutExtensions(extensions_to_skip);
|
||||
}
|
||||
|
||||
// Only start the xrCreateApiLayerInstance stack if we have layers.
|
||||
if (!api_layer_interfaces.empty()) {
|
||||
// Initialize an array of ApiLayerNextInfo structs
|
||||
std::unique_ptr<XrApiLayerNextInfo[]> next_info_list(new XrApiLayerNextInfo[api_layer_interfaces.size()]);
|
||||
auto ni_index = static_cast<uint32_t>(api_layer_interfaces.size() - 1);
|
||||
for (uint32_t i = 0; i <= ni_index; i++) {
|
||||
next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO;
|
||||
next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION;
|
||||
next_info_list[i].structSize = sizeof(XrApiLayerNextInfo);
|
||||
}
|
||||
|
||||
// Go through all layers, and override the instance pointers with the layer version. However,
|
||||
// go backwards through the layer list so we replace in reverse order so the layers can call their next function
|
||||
// appropriately.
|
||||
PFN_xrCreateApiLayerInstance topmost_cali_fp = create_api_layer_instance_term;
|
||||
XrApiLayerNextInfo* topmost_nextinfo = nullptr;
|
||||
for (auto layer_interface = api_layer_interfaces.rbegin(); layer_interface != api_layer_interfaces.rend();
|
||||
++layer_interface) {
|
||||
// Collect current layer's function pointers
|
||||
PFN_xrGetInstanceProcAddr cur_gipa_fp = (*layer_interface)->GetInstanceProcAddrFuncPointer();
|
||||
PFN_xrCreateApiLayerInstance cur_cali_fp = (*layer_interface)->GetCreateApiLayerInstanceFuncPointer();
|
||||
|
||||
// Fill in layer info and link previous (lower) layer fxn pointers
|
||||
strncpy(next_info_list[ni_index].layerName, (*layer_interface)->LayerName().c_str(),
|
||||
XR_MAX_API_LAYER_NAME_SIZE - 1);
|
||||
next_info_list[ni_index].layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';
|
||||
next_info_list[ni_index].next = topmost_nextinfo;
|
||||
next_info_list[ni_index].nextGetInstanceProcAddr = topmost_gipa;
|
||||
next_info_list[ni_index].nextCreateApiLayerInstance = topmost_cali_fp;
|
||||
|
||||
// Update saved pointers for next iteration
|
||||
topmost_nextinfo = &next_info_list[ni_index];
|
||||
topmost_gipa = cur_gipa_fp;
|
||||
topmost_cali_fp = cur_cali_fp;
|
||||
ni_index--;
|
||||
}
|
||||
|
||||
// Populate the ApiLayerCreateInfo struct and pass to topmost CreateApiLayerInstance()
|
||||
XrApiLayerCreateInfo api_layer_ci = {};
|
||||
api_layer_ci.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO;
|
||||
api_layer_ci.structVersion = XR_API_LAYER_CREATE_INFO_STRUCT_VERSION;
|
||||
api_layer_ci.structSize = sizeof(XrApiLayerCreateInfo);
|
||||
api_layer_ci.loaderInstance = nullptr; // Not used.
|
||||
api_layer_ci.settings_file_location[0] = '\0';
|
||||
api_layer_ci.nextInfo = next_info_list.get();
|
||||
//! @todo do we filter our create info extension list here?
|
||||
//! Think that actually each layer might need to filter...
|
||||
last_error = topmost_cali_fp(modified_create_info, &api_layer_ci, &instance);
|
||||
|
||||
} else {
|
||||
// The loader's terminator is the topmost CreateInstance if there are no layers.
|
||||
last_error = create_instance_term(modified_create_info, &instance);
|
||||
}
|
||||
|
||||
if (XR_FAILED(last_error)) {
|
||||
LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance chained CreateInstance call failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (XR_SUCCEEDED(last_error)) {
|
||||
loader_instance->reset(new LoaderInstance(instance, info, topmost_gipa, std::move(api_layer_interfaces)));
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "LoaderInstance::CreateInstance succeeded with ";
|
||||
oss << (*loader_instance)->LayerInterfaces().size();
|
||||
oss << " layers enabled and runtime interface - created instance = ";
|
||||
oss << HandleToHexString((*loader_instance)->GetInstanceHandle());
|
||||
LoaderLogger::LogInfoMessage("xrCreateInstance", oss.str());
|
||||
}
|
||||
|
||||
return last_error;
|
||||
}
|
||||
|
||||
XrResult LoaderInstance::GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function) {
|
||||
return _topmost_gipa(_runtime_instance, name, function);
|
||||
}
|
||||
|
||||
LoaderInstance::LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* create_info, PFN_xrGetInstanceProcAddr topmost_gipa,
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces)
|
||||
: _runtime_instance(instance),
|
||||
_topmost_gipa(topmost_gipa),
|
||||
_api_layer_interfaces(std::move(api_layer_interfaces)),
|
||||
_dispatch_table(new XrGeneratedDispatchTable{}) {
|
||||
for (uint32_t ext = 0; ext < create_info->enabledExtensionCount; ++ext) {
|
||||
_enabled_extensions.push_back(create_info->enabledExtensionNames[ext]);
|
||||
}
|
||||
|
||||
GeneratedXrPopulateDispatchTable(_dispatch_table.get(), instance, topmost_gipa);
|
||||
}
|
||||
|
||||
LoaderInstance::~LoaderInstance() {
|
||||
std::ostringstream oss;
|
||||
oss << "Destroying LoaderInstance = ";
|
||||
oss << PointerToHexString(this);
|
||||
LoaderLogger::LogInfoMessage("xrDestroyInstance", oss.str());
|
||||
}
|
||||
|
||||
bool LoaderInstance::ExtensionIsEnabled(const std::string& extension) {
|
||||
for (std::string& cur_enabled : _enabled_extensions) {
|
||||
if (cur_enabled == extension) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
77
thirdparty/openxr/src/loader/loader_instance.hpp
vendored
Normal file
77
thirdparty/openxr/src/loader/loader_instance.hpp
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "extra_algorithms.h"
|
||||
#include "loader_interfaces.h"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class ApiLayerInterface;
|
||||
struct XrGeneratedDispatchTable;
|
||||
class LoaderInstance;
|
||||
|
||||
// Manage the single loader instance that is available.
|
||||
namespace ActiveLoaderInstance {
|
||||
// Set the active loader instance. This will fail if there is already an active loader instance.
|
||||
XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name);
|
||||
|
||||
// Returns true if there is an active loader instance.
|
||||
bool IsAvailable();
|
||||
|
||||
// Get the active LoaderInstance.
|
||||
XrResult Get(LoaderInstance** loader_instance, const char* log_function_name);
|
||||
|
||||
// Destroy the currently active LoaderInstance if there is one. This will make the loader able to create a new XrInstance if needed.
|
||||
void Remove();
|
||||
}; // namespace ActiveLoaderInstance
|
||||
|
||||
// Manages information needed by the loader for an XrInstance, such as what extensions are available and the dispatch table.
|
||||
class LoaderInstance {
|
||||
public:
|
||||
// Factory method
|
||||
static XrResult CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term, PFN_xrCreateInstance create_instance_term,
|
||||
PFN_xrCreateApiLayerInstance create_api_layer_instance_term,
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>> layer_interfaces,
|
||||
const XrInstanceCreateInfo* createInfo, std::unique_ptr<LoaderInstance>* loader_instance);
|
||||
static const std::array<XrExtensionProperties, 1>& LoaderSpecificExtensions();
|
||||
|
||||
virtual ~LoaderInstance();
|
||||
|
||||
XrInstance GetInstanceHandle() { return _runtime_instance; }
|
||||
const std::unique_ptr<XrGeneratedDispatchTable>& DispatchTable() { return _dispatch_table; }
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>>& LayerInterfaces() { return _api_layer_interfaces; }
|
||||
bool ExtensionIsEnabled(const std::string& extension);
|
||||
XrDebugUtilsMessengerEXT DefaultDebugUtilsMessenger() { return _messenger; }
|
||||
void SetDefaultDebugUtilsMessenger(XrDebugUtilsMessengerEXT messenger) { _messenger = messenger; }
|
||||
XrResult GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);
|
||||
|
||||
private:
|
||||
LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* createInfo, PFN_xrGetInstanceProcAddr topmost_gipa,
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces);
|
||||
|
||||
private:
|
||||
XrInstance _runtime_instance{XR_NULL_HANDLE};
|
||||
PFN_xrGetInstanceProcAddr _topmost_gipa{nullptr};
|
||||
std::vector<std::string> _enabled_extensions;
|
||||
std::vector<std::unique_ptr<ApiLayerInterface>> _api_layer_interfaces;
|
||||
|
||||
std::unique_ptr<XrGeneratedDispatchTable> _dispatch_table;
|
||||
// Internal debug messenger created during xrCreateInstance
|
||||
XrDebugUtilsMessengerEXT _messenger{XR_NULL_HANDLE};
|
||||
};
|
||||
239
thirdparty/openxr/src/loader/loader_logger.cpp
vendored
Normal file
239
thirdparty/openxr/src/loader/loader_logger.cpp
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#include "loader_logger.hpp"
|
||||
|
||||
#include "extra_algorithms.h"
|
||||
#include "hex_and_handles.h"
|
||||
#include "loader_logger_recorders.hpp"
|
||||
#include "platform_utils.hpp"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
bool LoaderLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT /*message_severity*/,
|
||||
XrDebugUtilsMessageTypeFlagsEXT /*message_type*/,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT* /*callback_data*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Utility functions for converting to/from XR_EXT_debug_utils values
|
||||
|
||||
XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities(
|
||||
XrDebugUtilsMessageSeverityFlagsEXT utils_severities) {
|
||||
XrLoaderLogMessageSeverityFlags log_severities = 0UL;
|
||||
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0u) {
|
||||
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT;
|
||||
}
|
||||
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0u) {
|
||||
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT;
|
||||
}
|
||||
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0u) {
|
||||
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT;
|
||||
}
|
||||
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0u) {
|
||||
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT;
|
||||
}
|
||||
return log_severities;
|
||||
}
|
||||
|
||||
XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities(
|
||||
XrLoaderLogMessageSeverityFlags log_severities) {
|
||||
XrDebugUtilsMessageSeverityFlagsEXT utils_severities = 0UL;
|
||||
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT) != 0u) {
|
||||
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
|
||||
}
|
||||
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT) != 0u) {
|
||||
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
|
||||
}
|
||||
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT) != 0u) {
|
||||
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
|
||||
}
|
||||
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT) != 0u) {
|
||||
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
}
|
||||
return utils_severities;
|
||||
}
|
||||
|
||||
XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types) {
|
||||
XrLoaderLogMessageTypeFlagBits log_types = 0UL;
|
||||
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) != 0u) {
|
||||
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT;
|
||||
}
|
||||
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) != 0u) {
|
||||
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT;
|
||||
}
|
||||
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0u) {
|
||||
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT;
|
||||
}
|
||||
return log_types;
|
||||
}
|
||||
|
||||
XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types) {
|
||||
XrDebugUtilsMessageTypeFlagsEXT utils_types = 0UL;
|
||||
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT) != 0u) {
|
||||
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
|
||||
}
|
||||
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT) != 0u) {
|
||||
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
|
||||
}
|
||||
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT) != 0u) {
|
||||
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
}
|
||||
return utils_types;
|
||||
}
|
||||
|
||||
LoaderLogger::LoaderLogger() {
|
||||
std::string debug_string = PlatformUtilsGetEnv("XR_LOADER_DEBUG");
|
||||
|
||||
// Add an error logger by default so that we at least get errors out to std::cerr.
|
||||
// Normally we enable stderr output. But if the XR_LOADER_DEBUG environment variable is
|
||||
// present as "none" then we don't.
|
||||
if (debug_string != "none") {
|
||||
AddLogRecorder(MakeStdErrLoaderLogRecorder(nullptr));
|
||||
#ifdef __ANDROID__
|
||||
// Add a logcat logger by default.
|
||||
AddLogRecorder(MakeLogcatLoaderLogRecorder());
|
||||
#endif // __ANDROID__
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Add an debugger logger by default so that we at least get errors out to the debugger.
|
||||
AddLogRecorder(MakeDebuggerLoaderLogRecorder(nullptr));
|
||||
#endif
|
||||
|
||||
// If the environment variable to enable loader debugging is set, then enable the
|
||||
// appropriate logging out to std::cout.
|
||||
if (!debug_string.empty()) {
|
||||
XrLoaderLogMessageSeverityFlags debug_flags = {};
|
||||
if (debug_string == "error") {
|
||||
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT;
|
||||
} else if (debug_string == "warn") {
|
||||
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT;
|
||||
} else if (debug_string == "info") {
|
||||
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT |
|
||||
XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT;
|
||||
} else if (debug_string == "all" || debug_string == "verbose") {
|
||||
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT |
|
||||
XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT;
|
||||
}
|
||||
AddLogRecorder(MakeStdOutLoaderLogRecorder(nullptr, debug_flags));
|
||||
}
|
||||
}
|
||||
|
||||
void LoaderLogger::AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder) {
|
||||
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
|
||||
_recorders.push_back(std::move(recorder));
|
||||
}
|
||||
|
||||
void LoaderLogger::AddLogRecorderForXrInstance(XrInstance instance, std::unique_ptr<LoaderLogRecorder>&& recorder) {
|
||||
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
|
||||
_recordersByInstance[instance].insert(recorder->UniqueId());
|
||||
_recorders.emplace_back(std::move(recorder));
|
||||
}
|
||||
|
||||
void LoaderLogger::RemoveLogRecorder(uint64_t unique_id) {
|
||||
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
|
||||
vector_remove_if_and_erase(
|
||||
_recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) { return recorder->UniqueId() == unique_id; });
|
||||
for (auto& recorders : _recordersByInstance) {
|
||||
auto& messengersForInstance = recorders.second;
|
||||
if (messengersForInstance.count(unique_id) > 0) {
|
||||
messengersForInstance.erase(unique_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoaderLogger::RemoveLogRecordersForXrInstance(XrInstance instance) {
|
||||
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
|
||||
if (_recordersByInstance.find(instance) != _recordersByInstance.end()) {
|
||||
auto recorders = _recordersByInstance[instance];
|
||||
vector_remove_if_and_erase(_recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) {
|
||||
return recorders.find(recorder->UniqueId()) != recorders.end();
|
||||
});
|
||||
_recordersByInstance.erase(instance);
|
||||
}
|
||||
}
|
||||
|
||||
bool LoaderLogger::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
|
||||
const std::string& message_id, const std::string& command_name, const std::string& message,
|
||||
const std::vector<XrSdkLogObjectInfo>& objects) {
|
||||
XrLoaderLogMessengerCallbackData callback_data = {};
|
||||
callback_data.message_id = message_id.c_str();
|
||||
callback_data.command_name = command_name.c_str();
|
||||
callback_data.message = message.c_str();
|
||||
|
||||
auto names_and_labels = data_.PopulateNamesAndLabels(objects);
|
||||
callback_data.objects = names_and_labels.sdk_objects.empty() ? nullptr : names_and_labels.sdk_objects.data();
|
||||
callback_data.object_count = static_cast<uint8_t>(names_and_labels.objects.size());
|
||||
|
||||
callback_data.session_labels = names_and_labels.labels.empty() ? nullptr : names_and_labels.labels.data();
|
||||
callback_data.session_labels_count = static_cast<uint8_t>(names_and_labels.labels.size());
|
||||
|
||||
std::shared_lock<std::shared_timed_mutex> lock(_mutex);
|
||||
bool exit_app = false;
|
||||
for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) {
|
||||
if ((recorder->MessageSeverities() & message_severity) == message_severity &&
|
||||
(recorder->MessageTypes() & message_type) == message_type) {
|
||||
exit_app |= recorder->LogMessage(message_severity, message_type, &callback_data);
|
||||
}
|
||||
}
|
||||
return exit_app;
|
||||
}
|
||||
|
||||
// Extension-specific logging functions
|
||||
bool LoaderLogger::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
|
||||
XrDebugUtilsMessageTypeFlagsEXT message_type,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) {
|
||||
bool exit_app = false;
|
||||
XrLoaderLogMessageSeverityFlags log_message_severity = DebugUtilsSeveritiesToLoaderLogMessageSeverities(message_severity);
|
||||
XrLoaderLogMessageTypeFlags log_message_type = DebugUtilsMessageTypesToLoaderLogMessageTypes(message_type);
|
||||
|
||||
AugmentedCallbackData augmented_data;
|
||||
data_.WrapCallbackData(&augmented_data, callback_data);
|
||||
|
||||
// Loop through the recorders
|
||||
std::shared_lock<std::shared_timed_mutex> lock(_mutex);
|
||||
for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) {
|
||||
// Only send the message if it's a debug utils recorder and of the type the recorder cares about.
|
||||
if (recorder->Type() != XR_LOADER_LOG_DEBUG_UTILS ||
|
||||
(recorder->MessageSeverities() & log_message_severity) != log_message_severity ||
|
||||
(recorder->MessageTypes() & log_message_type) != log_message_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
exit_app |= recorder->LogDebugUtilsMessage(message_severity, message_type, augmented_data.exported_data);
|
||||
}
|
||||
return exit_app;
|
||||
}
|
||||
|
||||
void LoaderLogger::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) {
|
||||
data_.AddObjectName(object_handle, object_type, object_name);
|
||||
}
|
||||
|
||||
void LoaderLogger::BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info) {
|
||||
data_.BeginLabelRegion(session, *label_info);
|
||||
}
|
||||
|
||||
void LoaderLogger::EndLabelRegion(XrSession session) { data_.EndLabelRegion(session); }
|
||||
|
||||
void LoaderLogger::InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info) {
|
||||
data_.InsertLabel(session, *label_info);
|
||||
}
|
||||
|
||||
void LoaderLogger::DeleteSessionLabels(XrSession session) { data_.DeleteSessionLabels(session); }
|
||||
194
thirdparty/openxr/src/loader/loader_logger.hpp
vendored
Normal file
194
thirdparty/openxr/src/loader/loader_logger.hpp
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <shared_mutex>
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include "hex_and_handles.h"
|
||||
#include "object_info.h"
|
||||
|
||||
// Use internal versions of flags similar to XR_EXT_debug_utils so that
|
||||
// we're not tightly coupled to that extension. This way, if the extension
|
||||
// changes or gets replaced, we can be flexible in the loader.
|
||||
#define XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT 0x00000001
|
||||
#define XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT 0x00000010
|
||||
#define XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT 0x00000100
|
||||
#define XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT 0x00001000
|
||||
#define XR_LOADER_LOG_MESSAGE_SEVERITY_DEFAULT_BITS 0x00000000
|
||||
typedef XrFlags64 XrLoaderLogMessageSeverityFlagBits;
|
||||
typedef XrFlags64 XrLoaderLogMessageSeverityFlags;
|
||||
|
||||
#define XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT 0x00000001
|
||||
#define XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT 0x00000002
|
||||
#define XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT 0x00000004
|
||||
#define XR_LOADER_LOG_MESSAGE_TYPE_DEFAULT_BITS 0xffffffff
|
||||
typedef XrFlags64 XrLoaderLogMessageTypeFlagBits;
|
||||
typedef XrFlags64 XrLoaderLogMessageTypeFlags;
|
||||
|
||||
struct XrLoaderLogMessengerCallbackData {
|
||||
const char* message_id;
|
||||
const char* command_name;
|
||||
const char* message;
|
||||
uint8_t object_count;
|
||||
XrSdkLogObjectInfo* objects;
|
||||
uint8_t session_labels_count;
|
||||
XrDebugUtilsLabelEXT* session_labels;
|
||||
};
|
||||
|
||||
enum XrLoaderLogType {
|
||||
XR_LOADER_LOG_UNKNOWN = 0,
|
||||
XR_LOADER_LOG_STDERR,
|
||||
XR_LOADER_LOG_STDOUT,
|
||||
XR_LOADER_LOG_DEBUG_UTILS,
|
||||
XR_LOADER_LOG_DEBUGGER,
|
||||
XR_LOADER_LOG_LOGCAT,
|
||||
};
|
||||
|
||||
class LoaderLogRecorder {
|
||||
public:
|
||||
LoaderLogRecorder(XrLoaderLogType type, void* user_data, XrLoaderLogMessageSeverityFlags message_severities,
|
||||
XrLoaderLogMessageTypeFlags message_types) {
|
||||
_active = false;
|
||||
_user_data = user_data;
|
||||
_type = type;
|
||||
_unique_id = 0;
|
||||
_message_severities = message_severities;
|
||||
_message_types = message_types;
|
||||
}
|
||||
virtual ~LoaderLogRecorder() = default;
|
||||
|
||||
XrLoaderLogType Type() { return _type; }
|
||||
|
||||
uint64_t UniqueId() { return _unique_id; }
|
||||
|
||||
XrLoaderLogMessageSeverityFlags MessageSeverities() { return _message_severities; }
|
||||
|
||||
XrLoaderLogMessageTypeFlags MessageTypes() { return _message_types; }
|
||||
|
||||
virtual void Start() { _active = true; }
|
||||
|
||||
bool IsPaused() { return _active; }
|
||||
|
||||
virtual void Pause() { _active = false; }
|
||||
|
||||
virtual void Resume() { _active = true; }
|
||||
|
||||
virtual void Stop() { _active = false; }
|
||||
|
||||
virtual bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) = 0;
|
||||
|
||||
// Extension-specific logging functions - defaults to do nothing.
|
||||
virtual bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
|
||||
XrDebugUtilsMessageTypeFlagsEXT message_type,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT* callback_data);
|
||||
|
||||
protected:
|
||||
bool _active;
|
||||
XrLoaderLogType _type;
|
||||
uint64_t _unique_id;
|
||||
void* _user_data;
|
||||
XrLoaderLogMessageSeverityFlags _message_severities;
|
||||
XrLoaderLogMessageTypeFlags _message_types;
|
||||
};
|
||||
|
||||
class LoaderLogger {
|
||||
public:
|
||||
static LoaderLogger& GetInstance() {
|
||||
static LoaderLogger instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder);
|
||||
void RemoveLogRecorder(uint64_t unique_id);
|
||||
|
||||
void AddLogRecorderForXrInstance(XrInstance instance, std::unique_ptr<LoaderLogRecorder>&& recorder);
|
||||
void RemoveLogRecordersForXrInstance(XrInstance instance);
|
||||
|
||||
//! Called from LoaderXrTermSetDebugUtilsObjectNameEXT - an empty name means remove
|
||||
void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
|
||||
void BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info);
|
||||
void EndLabelRegion(XrSession session);
|
||||
void InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info);
|
||||
void DeleteSessionLabels(XrSession session);
|
||||
|
||||
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
|
||||
const std::string& message_id, const std::string& command_name, const std::string& message,
|
||||
const std::vector<XrSdkLogObjectInfo>& objects = {});
|
||||
static bool LogErrorMessage(const std::string& command_name, const std::string& message,
|
||||
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
|
||||
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
|
||||
"OpenXR-Loader", command_name, message, objects);
|
||||
}
|
||||
static bool LogWarningMessage(const std::string& command_name, const std::string& message,
|
||||
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
|
||||
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
|
||||
"OpenXR-Loader", command_name, message, objects);
|
||||
}
|
||||
static bool LogInfoMessage(const std::string& command_name, const std::string& message,
|
||||
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
|
||||
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
|
||||
"OpenXR-Loader", command_name, message, objects);
|
||||
}
|
||||
static bool LogVerboseMessage(const std::string& command_name, const std::string& message,
|
||||
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
|
||||
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
|
||||
"OpenXR-Loader", command_name, message, objects);
|
||||
}
|
||||
static bool LogValidationErrorMessage(const std::string& vuid, const std::string& command_name, const std::string& message,
|
||||
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
|
||||
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT,
|
||||
vuid, command_name, message, objects);
|
||||
}
|
||||
static bool LogValidationWarningMessage(const std::string& vuid, const std::string& command_name, const std::string& message,
|
||||
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
|
||||
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT,
|
||||
vuid, command_name, message, objects);
|
||||
}
|
||||
|
||||
// Extension-specific logging functions
|
||||
bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT* callback_data);
|
||||
|
||||
// Non-copyable
|
||||
LoaderLogger(const LoaderLogger&) = delete;
|
||||
LoaderLogger& operator=(const LoaderLogger&) = delete;
|
||||
|
||||
private:
|
||||
LoaderLogger();
|
||||
|
||||
std::shared_timed_mutex _mutex;
|
||||
|
||||
// List of *all* available recorder objects (including created specifically for an Instance)
|
||||
std::vector<std::unique_ptr<LoaderLogRecorder>> _recorders;
|
||||
|
||||
// List of recorder objects only created specifically for an XrInstance
|
||||
std::unordered_map<XrInstance, std::unordered_set<uint64_t>> _recordersByInstance;
|
||||
|
||||
DebugUtilsData data_;
|
||||
};
|
||||
|
||||
// Utility functions for converting to/from XR_EXT_debug_utils values
|
||||
XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities(
|
||||
XrDebugUtilsMessageSeverityFlagsEXT utils_severities);
|
||||
XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities(
|
||||
XrLoaderLogMessageSeverityFlags log_severities);
|
||||
XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types);
|
||||
XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types);
|
||||
291
thirdparty/openxr/src/loader/loader_logger_recorders.cpp
vendored
Normal file
291
thirdparty/openxr/src/loader/loader_logger_recorders.cpp
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#include "loader_logger_recorders.hpp"
|
||||
|
||||
#include "hex_and_handles.h"
|
||||
#include "loader_logger.hpp"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "android/log.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Anonymous namespace to keep these types private
|
||||
namespace {
|
||||
void OutputMessageToStream(std::ostream& os, XrLoaderLogMessageSeverityFlagBits message_severity,
|
||||
XrLoaderLogMessageTypeFlags message_type, const XrLoaderLogMessengerCallbackData* callback_data) {
|
||||
if (XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT > message_severity) {
|
||||
os << "Verbose [";
|
||||
} else if (XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT > message_severity) {
|
||||
os << "Info [";
|
||||
} else if (XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT > message_severity) {
|
||||
os << "Warning [";
|
||||
} else {
|
||||
os << "Error [";
|
||||
}
|
||||
switch (message_type) {
|
||||
case XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT:
|
||||
os << "GENERAL";
|
||||
break;
|
||||
case XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT:
|
||||
os << "SPEC";
|
||||
break;
|
||||
case XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT:
|
||||
os << "PERF";
|
||||
break;
|
||||
default:
|
||||
os << "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
os << " | " << callback_data->command_name << " | " << callback_data->message_id << "] : " << callback_data->message
|
||||
<< std::endl;
|
||||
|
||||
for (uint32_t obj = 0; obj < callback_data->object_count; ++obj) {
|
||||
os << " Object[" << obj << "] = " << callback_data->objects[obj].ToString();
|
||||
os << std::endl;
|
||||
}
|
||||
for (uint32_t label = 0; label < callback_data->session_labels_count; ++label) {
|
||||
os << " SessionLabel[" << std::to_string(label) << "] = " << callback_data->session_labels[label].labelName;
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// With std::cerr: Standard Error logger, always on for now
|
||||
// With std::cout: Standard Output logger used with XR_LOADER_DEBUG
|
||||
class OstreamLoaderLogRecorder : public LoaderLogRecorder {
|
||||
public:
|
||||
OstreamLoaderLogRecorder(std::ostream& os, void* user_data, XrLoaderLogMessageSeverityFlags flags);
|
||||
|
||||
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) override;
|
||||
|
||||
private:
|
||||
std::ostream& os_;
|
||||
};
|
||||
|
||||
// Debug Utils logger used with XR_EXT_debug_utils
|
||||
class DebugUtilsLogRecorder : public LoaderLogRecorder {
|
||||
public:
|
||||
DebugUtilsLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info, XrDebugUtilsMessengerEXT debug_messenger);
|
||||
|
||||
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) override;
|
||||
|
||||
// Extension-specific logging functions
|
||||
bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) override;
|
||||
|
||||
private:
|
||||
PFN_xrDebugUtilsMessengerCallbackEXT _user_callback;
|
||||
};
|
||||
#ifdef __ANDROID__
|
||||
|
||||
class LogcatLoaderLogRecorder : public LoaderLogRecorder {
|
||||
public:
|
||||
LogcatLoaderLogRecorder();
|
||||
|
||||
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// Output to debugger
|
||||
class DebuggerLoaderLogRecorder : public LoaderLogRecorder {
|
||||
public:
|
||||
DebuggerLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags);
|
||||
|
||||
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Unified stdout/stderr logger
|
||||
OstreamLoaderLogRecorder::OstreamLoaderLogRecorder(std::ostream& os, void* user_data, XrLoaderLogMessageSeverityFlags flags)
|
||||
: LoaderLogRecorder(XR_LOADER_LOG_STDOUT, user_data, flags, 0xFFFFFFFFUL), os_(os) {
|
||||
// Automatically start
|
||||
Start();
|
||||
}
|
||||
|
||||
bool OstreamLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
|
||||
XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) {
|
||||
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
|
||||
OutputMessageToStream(os_, message_severity, message_type, callback_data);
|
||||
}
|
||||
|
||||
// Return of "true" means that we should exit the application after the logged message. We
|
||||
// don't want to do that for our internal logging. Only let a user return true.
|
||||
return false;
|
||||
}
|
||||
|
||||
// A logger associated with the XR_EXT_debug_utils extension
|
||||
|
||||
DebugUtilsLogRecorder::DebugUtilsLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
|
||||
XrDebugUtilsMessengerEXT debug_messenger)
|
||||
: LoaderLogRecorder(XR_LOADER_LOG_DEBUG_UTILS, static_cast<void*>(create_info->userData),
|
||||
DebugUtilsSeveritiesToLoaderLogMessageSeverities(create_info->messageSeverities),
|
||||
DebugUtilsMessageTypesToLoaderLogMessageTypes(create_info->messageTypes)),
|
||||
_user_callback(create_info->userCallback) {
|
||||
// Use the debug messenger value to uniquely identify this logger with that messenger
|
||||
_unique_id = MakeHandleGeneric(debug_messenger);
|
||||
Start();
|
||||
}
|
||||
|
||||
// Extension-specific logging functions
|
||||
bool DebugUtilsLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
|
||||
XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) {
|
||||
bool should_exit = false;
|
||||
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
|
||||
XrDebugUtilsMessageSeverityFlagsEXT utils_severity = DebugUtilsSeveritiesToLoaderLogMessageSeverities(message_severity);
|
||||
XrDebugUtilsMessageTypeFlagsEXT utils_type = LoaderLogMessageTypesToDebugUtilsMessageTypes(message_type);
|
||||
|
||||
// Convert the loader log message into the debug utils log message information
|
||||
XrDebugUtilsMessengerCallbackDataEXT utils_callback_data = {};
|
||||
utils_callback_data.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
|
||||
utils_callback_data.messageId = callback_data->message_id;
|
||||
utils_callback_data.functionName = callback_data->command_name;
|
||||
utils_callback_data.message = callback_data->message;
|
||||
std::vector<XrDebugUtilsObjectNameInfoEXT> utils_objects;
|
||||
utils_objects.resize(callback_data->object_count);
|
||||
for (uint8_t object = 0; object < callback_data->object_count; ++object) {
|
||||
utils_objects[object].type = XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
utils_objects[object].next = nullptr;
|
||||
utils_objects[object].objectHandle = callback_data->objects[object].handle;
|
||||
utils_objects[object].objectType = callback_data->objects[object].type;
|
||||
utils_objects[object].objectName = callback_data->objects[object].name.c_str();
|
||||
}
|
||||
utils_callback_data.objectCount = callback_data->object_count;
|
||||
utils_callback_data.objects = utils_objects.data();
|
||||
utils_callback_data.sessionLabelCount = callback_data->session_labels_count;
|
||||
utils_callback_data.sessionLabels = callback_data->session_labels;
|
||||
|
||||
// Call the user callback with the appropriate info
|
||||
// Return of "true" means that we should exit the application after the logged message.
|
||||
should_exit = (_user_callback(utils_severity, utils_type, &utils_callback_data, _user_data) == XR_TRUE);
|
||||
}
|
||||
|
||||
return should_exit;
|
||||
}
|
||||
|
||||
bool DebugUtilsLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
|
||||
XrDebugUtilsMessageTypeFlagsEXT message_type,
|
||||
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) {
|
||||
// Call the user callback with the appropriate info
|
||||
// Return of "true" means that we should exit the application after the logged message.
|
||||
return (_user_callback(message_severity, message_type, callback_data, _user_data) == XR_TRUE);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
static inline android_LogPriority LoaderToAndroidLogPriority(XrLoaderLogMessageSeverityFlags message_severity) {
|
||||
if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT)) {
|
||||
return ANDROID_LOG_ERROR;
|
||||
}
|
||||
if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT)) {
|
||||
return ANDROID_LOG_WARN;
|
||||
}
|
||||
if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT)) {
|
||||
return ANDROID_LOG_INFO;
|
||||
}
|
||||
return ANDROID_LOG_VERBOSE;
|
||||
}
|
||||
|
||||
LogcatLoaderLogRecorder::LogcatLoaderLogRecorder()
|
||||
: LoaderLogRecorder(XR_LOADER_LOG_LOGCAT, nullptr,
|
||||
XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT |
|
||||
XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT,
|
||||
0xFFFFFFFFUL) {
|
||||
// Automatically start
|
||||
Start();
|
||||
}
|
||||
|
||||
bool LogcatLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
|
||||
XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) {
|
||||
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
|
||||
std::stringstream ss;
|
||||
OutputMessageToStream(ss, message_severity, message_type, callback_data);
|
||||
__android_log_write(LoaderToAndroidLogPriority(message_severity), "OpenXR-Loader", ss.str().c_str());
|
||||
}
|
||||
|
||||
// Return of "true" means that we should exit the application after the logged message. We
|
||||
// don't want to do that for our internal logging. Only let a user return true.
|
||||
return false;
|
||||
}
|
||||
#endif // __ANDROID__
|
||||
|
||||
#ifdef _WIN32
|
||||
// Unified stdout/stderr logger
|
||||
DebuggerLoaderLogRecorder::DebuggerLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags)
|
||||
: LoaderLogRecorder(XR_LOADER_LOG_DEBUGGER, user_data, flags, 0xFFFFFFFFUL) {
|
||||
// Automatically start
|
||||
Start();
|
||||
}
|
||||
|
||||
bool DebuggerLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
|
||||
XrLoaderLogMessageTypeFlags message_type,
|
||||
const XrLoaderLogMessengerCallbackData* callback_data) {
|
||||
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
|
||||
std::stringstream ss;
|
||||
OutputMessageToStream(ss, message_severity, message_type, callback_data);
|
||||
|
||||
OutputDebugStringA(ss.str().c_str());
|
||||
}
|
||||
|
||||
// Return of "true" means that we should exit the application after the logged message. We
|
||||
// don't want to do that for our internal logging. Only let a user return true.
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<LoaderLogRecorder> MakeStdOutLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags) {
|
||||
std::unique_ptr<LoaderLogRecorder> recorder(new OstreamLoaderLogRecorder(std::cout, user_data, flags));
|
||||
return recorder;
|
||||
}
|
||||
|
||||
std::unique_ptr<LoaderLogRecorder> MakeStdErrLoaderLogRecorder(void* user_data) {
|
||||
std::unique_ptr<LoaderLogRecorder> recorder(
|
||||
new OstreamLoaderLogRecorder(std::cerr, user_data, XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT));
|
||||
return recorder;
|
||||
}
|
||||
|
||||
std::unique_ptr<LoaderLogRecorder> MakeDebugUtilsLoaderLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
|
||||
XrDebugUtilsMessengerEXT debug_messenger) {
|
||||
std::unique_ptr<LoaderLogRecorder> recorder(new DebugUtilsLogRecorder(create_info, debug_messenger));
|
||||
return recorder;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
std::unique_ptr<LoaderLogRecorder> MakeLogcatLoaderLogRecorder() {
|
||||
std::unique_ptr<LoaderLogRecorder> recorder(new LogcatLoaderLogRecorder());
|
||||
return recorder;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
std::unique_ptr<LoaderLogRecorder> MakeDebuggerLoaderLogRecorder(void* user_data) {
|
||||
std::unique_ptr<LoaderLogRecorder> recorder(new DebuggerLoaderLogRecorder(user_data, XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT));
|
||||
return recorder;
|
||||
}
|
||||
#endif
|
||||
40
thirdparty/openxr/src/loader/loader_logger_recorders.hpp
vendored
Normal file
40
thirdparty/openxr/src/loader/loader_logger_recorders.hpp
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "loader_logger.hpp"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
//! Standard Error logger, on by default. Disabled with environment variable XR_LOADER_DEBUG = "none".
|
||||
std::unique_ptr<LoaderLogRecorder> MakeStdErrLoaderLogRecorder(void* user_data);
|
||||
|
||||
//! Standard Output logger used with XR_LOADER_DEBUG environment variable.
|
||||
std::unique_ptr<LoaderLogRecorder> MakeStdOutLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
//! Android liblog ("logcat") logger
|
||||
std::unique_ptr<LoaderLogRecorder> MakeLogcatLoaderLogRecorder();
|
||||
#endif
|
||||
|
||||
// Debug Utils logger used with XR_EXT_debug_utils
|
||||
std::unique_ptr<LoaderLogRecorder> MakeDebugUtilsLoaderLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
|
||||
XrDebugUtilsMessengerEXT debug_messenger);
|
||||
|
||||
#ifdef _WIN32
|
||||
//! Win32 debugger output
|
||||
std::unique_ptr<LoaderLogRecorder> MakeDebuggerLoaderLogRecorder(void* user_data);
|
||||
#endif
|
||||
|
||||
// TODO: Add other Derived classes:
|
||||
// - FileLoaderLogRecorder - During/after xrCreateInstance
|
||||
// - PipeLoaderLogRecorder? - During/after xrCreateInstance
|
||||
204
thirdparty/openxr/src/loader/loader_platform.hpp
vendored
Normal file
204
thirdparty/openxr/src/loader/loader_platform.hpp
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com>
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "xr_dependencies.h"
|
||||
#include "platform_utils.hpp"
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define LOADER_EXPORT __attribute__((visibility("default")))
|
||||
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
|
||||
#define LOADER_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define LOADER_EXPORT
|
||||
#endif
|
||||
|
||||
// Environment variables
|
||||
#if defined(XR_OS_LINUX) || defined(XR_OS_APPLE) || defined(XR_OS_ANDROID)
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
#define PATH_SEPARATOR ':'
|
||||
#define DIRECTORY_SYMBOL '/'
|
||||
|
||||
// Dynamic Loading of libraries:
|
||||
typedef void *LoaderPlatformLibraryHandle;
|
||||
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
|
||||
// When loading the library, we use RTLD_LAZY so that not all symbols have to be
|
||||
// resolved at this time (which improves performance). Note that if not all symbols
|
||||
// can be resolved, this could cause crashes later.
|
||||
// For experimenting/debugging: Define the LD_BIND_NOW environment variable to force all
|
||||
// symbols to be resolved here.
|
||||
return dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||
}
|
||||
|
||||
static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) {
|
||||
(void)path;
|
||||
return dlerror();
|
||||
}
|
||||
|
||||
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { dlclose(library); }
|
||||
|
||||
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
|
||||
assert(library);
|
||||
assert(!name.empty());
|
||||
return dlsym(library, name.c_str());
|
||||
}
|
||||
|
||||
static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) {
|
||||
(void)name;
|
||||
return dlerror();
|
||||
}
|
||||
|
||||
#elif defined(XR_OS_WINDOWS)
|
||||
|
||||
#define PATH_SEPARATOR ';'
|
||||
#define DIRECTORY_SYMBOL '\\'
|
||||
|
||||
// Workaround for MS VS 2010/2013 missing snprintf and vsnprintf
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#include <stdint.h>
|
||||
|
||||
static inline int32_t xr_vsnprintf(char *result_buffer, size_t buffer_size, const char *print_format, va_list varying_list) {
|
||||
int32_t copy_count = -1;
|
||||
if (buffer_size != 0) {
|
||||
copy_count = _vsnprintf_s(result_buffer, buffer_size, _TRUNCATE, print_format, varying_list);
|
||||
}
|
||||
if (copy_count == -1) {
|
||||
copy_count = _vscprintf(print_format, varying_list);
|
||||
}
|
||||
return copy_count;
|
||||
}
|
||||
|
||||
static inline int32_t xr_snprintf(char *result_buffer, size_t buffer_size, const char *print_format, ...) {
|
||||
va_list varying_list;
|
||||
va_start(varying_list, print_format);
|
||||
int32_t copy_count = xr_vsnprintf(result_buffer, buffer_size, print_format, varying_list);
|
||||
va_end(varying_list);
|
||||
return copy_count;
|
||||
}
|
||||
|
||||
#define snprintf xr_snprintf
|
||||
#define vsnprintf xr_vsnprintf
|
||||
|
||||
#endif
|
||||
|
||||
static inline std::string DescribeError(uint32_t code, bool prefixErrorCode = true) {
|
||||
std::string str;
|
||||
|
||||
if (prefixErrorCode) {
|
||||
char prefixBuffer[64];
|
||||
snprintf(prefixBuffer, sizeof(prefixBuffer), "0x%llx (%lld): ", (uint64_t)code, (int64_t)code);
|
||||
str = prefixBuffer;
|
||||
}
|
||||
|
||||
// Could use FORMAT_MESSAGE_FROM_HMODULE to specify an error source.
|
||||
WCHAR errorBufferW[1024]{};
|
||||
const DWORD errorBufferWCapacity = sizeof(errorBufferW) / sizeof(errorBufferW[0]);
|
||||
const DWORD length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, (DWORD)code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), errorBufferW, errorBufferWCapacity, nullptr);
|
||||
|
||||
if (length) { // If errorBufferW contains what we are looking for...
|
||||
str += wide_to_utf8(errorBufferW);
|
||||
} else {
|
||||
str = "(unknown)";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// Dynamic Loading:
|
||||
typedef HMODULE LoaderPlatformLibraryHandle;
|
||||
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
|
||||
const std::wstring pathW = utf8_to_wide(path);
|
||||
|
||||
// Try loading the library the original way first.
|
||||
LoaderPlatformLibraryHandle handle = LoadLibraryW(pathW.c_str());
|
||||
|
||||
if (handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) {
|
||||
const DWORD dwAttrib = GetFileAttributesW(pathW.c_str());
|
||||
const bool fileExists = (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
if (fileExists) {
|
||||
// If that failed, then try loading it with broader search folders.
|
||||
handle = LoadLibraryExW(pathW.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
}
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static inline std::string LoaderPlatformLibraryOpenError(const std::string &path) {
|
||||
std::stringstream ss;
|
||||
const DWORD dwLastError = GetLastError();
|
||||
const std::string strError = DescribeError(dwLastError);
|
||||
ss << "Failed to open dynamic library " << path << " with error " << dwLastError << ": " << strError;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { FreeLibrary(library); }
|
||||
|
||||
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
|
||||
assert(library);
|
||||
assert(name.size() > 0);
|
||||
return reinterpret_cast<void *>(GetProcAddress(library, name.c_str()));
|
||||
}
|
||||
|
||||
static inline std::string LoaderPlatformLibraryGetProcAddrAddrError(const std::string &name) {
|
||||
std::stringstream ss;
|
||||
ss << "Failed to find function " << name << " in dynamic library";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
#else // Not Linux or Windows
|
||||
|
||||
#define PATH_SEPARATOR ':'
|
||||
#define DIRECTORY_SYMBOL '/'
|
||||
|
||||
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
|
||||
// Stub func
|
||||
#error("Unknown platform, undefined dynamic library routines resulting");
|
||||
(void)path;
|
||||
}
|
||||
|
||||
static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) {
|
||||
// Stub func
|
||||
(void)path;
|
||||
}
|
||||
|
||||
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) {
|
||||
// Stub func
|
||||
(void)library;
|
||||
}
|
||||
|
||||
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
|
||||
// Stub func
|
||||
void(library);
|
||||
void(name);
|
||||
}
|
||||
|
||||
static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) {
|
||||
// Stub func
|
||||
(void)name;
|
||||
}
|
||||
|
||||
#endif
|
||||
845
thirdparty/openxr/src/loader/manifest_file.cpp
vendored
Normal file
845
thirdparty/openxr/src/loader/manifest_file.cpp
vendored
Normal file
@@ -0,0 +1,845 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com>
|
||||
//
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
#include "manifest_file.hpp"
|
||||
|
||||
#ifdef OPENXR_HAVE_COMMON_CONFIG
|
||||
#include "common_config.h"
|
||||
#endif // OPENXR_HAVE_COMMON_CONFIG
|
||||
|
||||
#include "filesystem_utils.hpp"
|
||||
#include "loader_platform.hpp"
|
||||
#include "platform_utils.hpp"
|
||||
#include "loader_logger.hpp"
|
||||
|
||||
#include <json/json.h>
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifndef FALLBACK_CONFIG_DIRS
|
||||
#define FALLBACK_CONFIG_DIRS "/etc/xdg"
|
||||
#endif // !FALLBACK_CONFIG_DIRS
|
||||
|
||||
#ifndef FALLBACK_DATA_DIRS
|
||||
#define FALLBACK_DATA_DIRS "/usr/local/share:/usr/share"
|
||||
#endif // !FALLBACK_DATA_DIRS
|
||||
|
||||
#ifndef SYSCONFDIR
|
||||
#define SYSCONFDIR "/etc"
|
||||
#endif // !SYSCONFDIR
|
||||
|
||||
#ifdef XRLOADER_DISABLE_EXCEPTION_HANDLING
|
||||
#if JSON_USE_EXCEPTIONS
|
||||
#error \
|
||||
"Loader is configured to not catch exceptions, but jsoncpp was built with exception-throwing enabled, which could violate the C ABI. One of those two things needs to change."
|
||||
#endif // JSON_USE_EXCEPTIONS
|
||||
#endif // !XRLOADER_DISABLE_EXCEPTION_HANDLING
|
||||
|
||||
#include "runtime_interface.hpp"
|
||||
|
||||
// Utility functions for finding files in the appropriate paths
|
||||
|
||||
static inline bool StringEndsWith(const std::string &value, const std::string &ending) {
|
||||
if (ending.size() > value.size()) {
|
||||
return false;
|
||||
}
|
||||
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
|
||||
}
|
||||
|
||||
// If the file found is a manifest file name, add it to the out_files manifest list.
|
||||
static void AddIfJson(const std::string &full_file, std::vector<std::string> &manifest_files) {
|
||||
if (full_file.empty() || !StringEndsWith(full_file, ".json")) {
|
||||
return;
|
||||
}
|
||||
manifest_files.push_back(full_file);
|
||||
}
|
||||
|
||||
// Check the current path for any manifest files. If the provided search_path is a directory, look for
|
||||
// all included JSON files in that directory. Otherwise, just check the provided search_path which should
|
||||
// be a single filename.
|
||||
static void CheckAllFilesInThePath(const std::string &search_path, bool is_directory_list,
|
||||
std::vector<std::string> &manifest_files) {
|
||||
if (FileSysUtilsPathExists(search_path)) {
|
||||
std::string absolute_path;
|
||||
if (!is_directory_list) {
|
||||
// If the file exists, try to add it
|
||||
if (FileSysUtilsIsRegularFile(search_path)) {
|
||||
FileSysUtilsGetAbsolutePath(search_path, absolute_path);
|
||||
AddIfJson(absolute_path, manifest_files);
|
||||
}
|
||||
} else {
|
||||
std::vector<std::string> files;
|
||||
if (FileSysUtilsFindFilesInPath(search_path, files)) {
|
||||
for (std::string &cur_file : files) {
|
||||
std::string relative_path;
|
||||
FileSysUtilsCombinePaths(search_path, cur_file, relative_path);
|
||||
if (!FileSysUtilsGetAbsolutePath(relative_path, absolute_path)) {
|
||||
continue;
|
||||
}
|
||||
AddIfJson(absolute_path, manifest_files);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add all manifest files in the provided paths to the manifest_files list. If search_path
|
||||
// is made up of directory listings (versus direct manifest file names) search each path for
|
||||
// any manifest files.
|
||||
static void AddFilesInPath(const std::string &search_path, bool is_directory_list, std::vector<std::string> &manifest_files) {
|
||||
std::size_t last_found = 0;
|
||||
std::size_t found = search_path.find_first_of(PATH_SEPARATOR);
|
||||
std::string cur_search;
|
||||
|
||||
// Handle any path listings in the string (separated by the appropriate path separator)
|
||||
while (found != std::string::npos) {
|
||||
// substr takes a start index and length.
|
||||
std::size_t length = found - last_found;
|
||||
cur_search = search_path.substr(last_found, length);
|
||||
|
||||
CheckAllFilesInThePath(cur_search, is_directory_list, manifest_files);
|
||||
|
||||
// This works around issue if multiple path separator follow each other directly.
|
||||
last_found = found;
|
||||
while (found == last_found) {
|
||||
last_found = found + 1;
|
||||
found = search_path.find_first_of(PATH_SEPARATOR, last_found);
|
||||
}
|
||||
}
|
||||
|
||||
// If there's something remaining in the string, copy it over
|
||||
if (last_found < search_path.size()) {
|
||||
cur_search = search_path.substr(last_found);
|
||||
CheckAllFilesInThePath(cur_search, is_directory_list, manifest_files);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy all paths listed in the cur_path string into output_path and append the appropriate relative_path onto the end of each.
|
||||
static void CopyIncludedPaths(bool is_directory_list, const std::string &cur_path, const std::string &relative_path,
|
||||
std::string &output_path) {
|
||||
if (!cur_path.empty()) {
|
||||
std::size_t last_found = 0;
|
||||
std::size_t found = cur_path.find_first_of(PATH_SEPARATOR);
|
||||
|
||||
// Handle any path listings in the string (separated by the appropriate path separator)
|
||||
while (found != std::string::npos) {
|
||||
std::size_t length = found - last_found;
|
||||
output_path += cur_path.substr(last_found, length);
|
||||
if (is_directory_list && (cur_path[found - 1] != '\\' && cur_path[found - 1] != '/')) {
|
||||
output_path += DIRECTORY_SYMBOL;
|
||||
}
|
||||
output_path += relative_path;
|
||||
output_path += PATH_SEPARATOR;
|
||||
|
||||
last_found = found;
|
||||
found = cur_path.find_first_of(PATH_SEPARATOR, found + 1);
|
||||
}
|
||||
|
||||
// If there's something remaining in the string, copy it over
|
||||
size_t last_char = cur_path.size() - 1;
|
||||
if (last_found != last_char) {
|
||||
output_path += cur_path.substr(last_found);
|
||||
if (is_directory_list && (cur_path[last_char] != '\\' && cur_path[last_char] != '/')) {
|
||||
output_path += DIRECTORY_SYMBOL;
|
||||
}
|
||||
output_path += relative_path;
|
||||
output_path += PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for data files in the provided paths, but first check the environment override to determine if we should use that instead.
|
||||
static void ReadDataFilesInSearchPaths(const std::string &override_env_var, const std::string &relative_path, bool &override_active,
|
||||
std::vector<std::string> &manifest_files) {
|
||||
std::string override_path;
|
||||
std::string search_path;
|
||||
|
||||
if (!override_env_var.empty()) {
|
||||
bool permit_override = true;
|
||||
#ifndef XR_OS_WINDOWS
|
||||
if (geteuid() != getuid() || getegid() != getgid()) {
|
||||
// Don't allow setuid apps to use the env var
|
||||
permit_override = false;
|
||||
}
|
||||
#endif
|
||||
if (permit_override) {
|
||||
override_path = PlatformUtilsGetSecureEnv(override_env_var.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (!override_path.empty()) {
|
||||
CopyIncludedPaths(true, override_path, "", search_path);
|
||||
override_active = true;
|
||||
} else {
|
||||
override_active = false;
|
||||
#if !defined(XR_OS_WINDOWS) && !defined(XR_OS_ANDROID)
|
||||
const char home_additional[] = ".local/share/";
|
||||
|
||||
// Determine how much space is needed to generate the full search path
|
||||
// for the current manifest files.
|
||||
std::string xdg_conf_dirs = PlatformUtilsGetSecureEnv("XDG_CONFIG_DIRS");
|
||||
std::string xdg_data_dirs = PlatformUtilsGetSecureEnv("XDG_DATA_DIRS");
|
||||
std::string xdg_data_home = PlatformUtilsGetSecureEnv("XDG_DATA_HOME");
|
||||
std::string home = PlatformUtilsGetSecureEnv("HOME");
|
||||
|
||||
if (xdg_conf_dirs.empty()) {
|
||||
CopyIncludedPaths(true, FALLBACK_CONFIG_DIRS, relative_path, search_path);
|
||||
} else {
|
||||
CopyIncludedPaths(true, xdg_conf_dirs, relative_path, search_path);
|
||||
}
|
||||
|
||||
CopyIncludedPaths(true, SYSCONFDIR, relative_path, search_path);
|
||||
#if defined(EXTRASYSCONFDIR)
|
||||
CopyIncludedPaths(true, EXTRASYSCONFDIR, relative_path, search_path);
|
||||
#endif
|
||||
|
||||
if (xdg_data_dirs.empty()) {
|
||||
CopyIncludedPaths(true, FALLBACK_DATA_DIRS, relative_path, search_path);
|
||||
} else {
|
||||
CopyIncludedPaths(true, xdg_data_dirs, relative_path, search_path);
|
||||
}
|
||||
|
||||
if (!xdg_data_home.empty()) {
|
||||
CopyIncludedPaths(true, xdg_data_home, relative_path, search_path);
|
||||
} else if (!home.empty()) {
|
||||
std::string relative_home_path = home_additional;
|
||||
relative_home_path += relative_path;
|
||||
CopyIncludedPaths(true, home, relative_home_path, search_path);
|
||||
}
|
||||
#else
|
||||
(void)relative_path;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Now, parse the paths and add any manifest files found in them.
|
||||
AddFilesInPath(search_path, true, manifest_files);
|
||||
}
|
||||
|
||||
#ifdef XR_OS_LINUX
|
||||
|
||||
// Get an XDG environment variable with a $HOME-relative default
|
||||
static std::string GetXDGEnvHome(const char *name, const char *fallback_path) {
|
||||
std::string result = PlatformUtilsGetSecureEnv(name);
|
||||
if (!result.empty()) {
|
||||
return result;
|
||||
}
|
||||
result = PlatformUtilsGetSecureEnv("HOME");
|
||||
if (result.empty()) {
|
||||
return result;
|
||||
}
|
||||
result += "/";
|
||||
result += fallback_path;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get an XDG environment variable with absolute defaults
|
||||
static std::string GetXDGEnvAbsolute(const char *name, const char *fallback_paths) {
|
||||
std::string result = PlatformUtilsGetSecureEnv(name);
|
||||
if (!result.empty()) {
|
||||
return result;
|
||||
}
|
||||
return fallback_paths;
|
||||
}
|
||||
|
||||
// Return the first instance of relative_path occurring in an XDG config dir according to standard
|
||||
// precedence order.
|
||||
static bool FindXDGConfigFile(const std::string &relative_path, std::string &out) {
|
||||
out = GetXDGEnvHome("XDG_CONFIG_HOME", ".config");
|
||||
if (!out.empty()) {
|
||||
out += "/";
|
||||
out += relative_path;
|
||||
|
||||
LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in XDG_CONFIG_HOME: " + out);
|
||||
if (FileSysUtilsPathExists(out)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::istringstream iss(GetXDGEnvAbsolute("XDG_CONFIG_DIRS", FALLBACK_CONFIG_DIRS));
|
||||
std::string path;
|
||||
while (std::getline(iss, path, PATH_SEPARATOR)) {
|
||||
if (path.empty()) {
|
||||
continue;
|
||||
}
|
||||
out = path;
|
||||
out += "/";
|
||||
out += relative_path;
|
||||
LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in an entry of XDG_CONFIG_DIRS: " + out);
|
||||
if (FileSysUtilsPathExists(out)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
out = SYSCONFDIR;
|
||||
out += "/";
|
||||
out += relative_path;
|
||||
LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in compiled-in SYSCONFDIR: " + out);
|
||||
if (FileSysUtilsPathExists(out)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(EXTRASYSCONFDIR)
|
||||
out = EXTRASYSCONFDIR;
|
||||
out += "/";
|
||||
out += relative_path;
|
||||
LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in compiled-in EXTRASYSCONFDIR: " + out);
|
||||
if (FileSysUtilsPathExists(out)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
out.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef XR_OS_WINDOWS
|
||||
|
||||
// Look for runtime data files in the provided paths, but first check the environment override to determine
|
||||
// if we should use that instead.
|
||||
static void ReadRuntimeDataFilesInRegistry(const std::string &runtime_registry_location,
|
||||
const std::string &default_runtime_value_name,
|
||||
std::vector<std::string> &manifest_files) {
|
||||
HKEY hkey;
|
||||
DWORD access_flags;
|
||||
wchar_t value_w[1024];
|
||||
DWORD value_size_w = sizeof(value_w); // byte size of the buffer.
|
||||
|
||||
// Generate the full registry location for the registry information
|
||||
std::string full_registry_location = OPENXR_REGISTRY_LOCATION;
|
||||
full_registry_location += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION));
|
||||
full_registry_location += runtime_registry_location;
|
||||
|
||||
const std::wstring full_registry_location_w = utf8_to_wide(full_registry_location);
|
||||
const std::wstring default_runtime_value_name_w = utf8_to_wide(default_runtime_value_name);
|
||||
|
||||
// Use 64 bit regkey for 64bit application, and use 32 bit regkey in WOW for 32bit application.
|
||||
access_flags = KEY_QUERY_VALUE;
|
||||
LONG open_value = RegOpenKeyExW(HKEY_LOCAL_MACHINE, full_registry_location_w.c_str(), 0, access_flags, &hkey);
|
||||
|
||||
if (ERROR_SUCCESS != open_value) {
|
||||
LoaderLogger::LogWarningMessage("",
|
||||
"ReadRuntimeDataFilesInRegistry - failed to open registry key " + full_registry_location);
|
||||
} else if (ERROR_SUCCESS != RegGetValueW(hkey, nullptr, default_runtime_value_name_w.c_str(),
|
||||
RRF_RT_REG_SZ | REG_EXPAND_SZ | RRF_ZEROONFAILURE, NULL,
|
||||
reinterpret_cast<LPBYTE>(&value_w), &value_size_w)) {
|
||||
LoaderLogger::LogWarningMessage(
|
||||
"", "ReadRuntimeDataFilesInRegistry - failed to read registry value " + default_runtime_value_name);
|
||||
} else {
|
||||
AddFilesInPath(wide_to_utf8(value_w), false, manifest_files);
|
||||
}
|
||||
}
|
||||
|
||||
// Look for layer data files in the provided paths, but first check the environment override to determine
|
||||
// if we should use that instead.
|
||||
static void ReadLayerDataFilesInRegistry(const std::string ®istry_location, std::vector<std::string> &manifest_files) {
|
||||
const std::wstring full_registry_location_w =
|
||||
utf8_to_wide(OPENXR_REGISTRY_LOCATION + std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) + registry_location);
|
||||
|
||||
auto ReadLayerDataFilesInHive = [&](HKEY hive) {
|
||||
HKEY hkey;
|
||||
LONG open_value = RegOpenKeyExW(hive, full_registry_location_w.c_str(), 0, KEY_QUERY_VALUE, &hkey);
|
||||
if (ERROR_SUCCESS != open_value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t name_w[1024]{};
|
||||
LONG rtn_value;
|
||||
DWORD name_size = 1023;
|
||||
DWORD value;
|
||||
DWORD value_size = sizeof(value);
|
||||
DWORD key_index = 0;
|
||||
while (ERROR_SUCCESS ==
|
||||
(rtn_value = RegEnumValueW(hkey, key_index++, name_w, &name_size, NULL, NULL, (LPBYTE)&value, &value_size))) {
|
||||
if (value_size == sizeof(value) && value == 0) {
|
||||
const std::string filename = wide_to_utf8(name_w);
|
||||
AddFilesInPath(filename, false, manifest_files);
|
||||
}
|
||||
// Reset some items for the next loop
|
||||
name_size = 1023;
|
||||
}
|
||||
|
||||
RegCloseKey(hkey);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Do not allow high integrity processes to act on data that can be controlled by medium integrity processes.
|
||||
const bool readFromCurrentUser = !IsHighIntegrityLevel();
|
||||
|
||||
bool found = ReadLayerDataFilesInHive(HKEY_LOCAL_MACHINE);
|
||||
if (readFromCurrentUser) {
|
||||
found |= ReadLayerDataFilesInHive(HKEY_CURRENT_USER);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
std::string warning_message = "ReadLayerDataFilesInRegistry - failed to read registry location ";
|
||||
warning_message += registry_location;
|
||||
warning_message += (readFromCurrentUser ? " in either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER" : " in HKEY_LOCAL_MACHINE");
|
||||
LoaderLogger::LogWarningMessage("", warning_message);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // XR_OS_WINDOWS
|
||||
|
||||
ManifestFile::ManifestFile(ManifestFileType type, const std::string &filename, const std::string &library_path)
|
||||
: _filename(filename), _type(type), _library_path(library_path) {}
|
||||
|
||||
bool ManifestFile::IsValidJson(const Json::Value &root_node, JsonVersion &version) {
|
||||
if (root_node["file_format_version"].isNull() || !root_node["file_format_version"].isString()) {
|
||||
LoaderLogger::LogErrorMessage("", "ManifestFile::IsValidJson - JSON file missing \"file_format_version\"");
|
||||
return false;
|
||||
}
|
||||
std::string file_format = root_node["file_format_version"].asString();
|
||||
const int num_fields = sscanf(file_format.c_str(), "%u.%u.%u", &version.major, &version.minor, &version.patch);
|
||||
|
||||
// Only version 1.0.0 is defined currently. Eventually we may have more version, but
|
||||
// some of the versions may only be valid for layers or runtimes specifically.
|
||||
if (num_fields != 3 || version.major != 1 || version.minor != 0 || version.patch != 0) {
|
||||
std::ostringstream error_ss;
|
||||
error_ss << "ManifestFile::IsValidJson - JSON \"file_format_version\" " << version.major << "." << version.minor << "."
|
||||
<< version.patch << " is not supported";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GetExtensionProperties(const std::vector<ExtensionListing> &extensions, std::vector<XrExtensionProperties> &props) {
|
||||
for (const auto &ext : extensions) {
|
||||
auto it =
|
||||
std::find_if(props.begin(), props.end(), [&](XrExtensionProperties &prop) { return prop.extensionName == ext.name; });
|
||||
if (it != props.end()) {
|
||||
it->extensionVersion = std::max(it->extensionVersion, ext.extension_version);
|
||||
} else {
|
||||
XrExtensionProperties prop = {};
|
||||
prop.type = XR_TYPE_EXTENSION_PROPERTIES;
|
||||
prop.next = nullptr;
|
||||
strncpy(prop.extensionName, ext.name.c_str(), XR_MAX_EXTENSION_NAME_SIZE - 1);
|
||||
prop.extensionName[XR_MAX_EXTENSION_NAME_SIZE - 1] = '\0';
|
||||
prop.extensionVersion = ext.extension_version;
|
||||
props.push_back(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return any instance extensions found in the manifest files in the proper form for
|
||||
// OpenXR (XrExtensionProperties).
|
||||
void ManifestFile::GetInstanceExtensionProperties(std::vector<XrExtensionProperties> &props) {
|
||||
GetExtensionProperties(_instance_extensions, props);
|
||||
}
|
||||
|
||||
const std::string &ManifestFile::GetFunctionName(const std::string &func_name) const {
|
||||
if (!_functions_renamed.empty()) {
|
||||
auto found = _functions_renamed.find(func_name);
|
||||
if (found != _functions_renamed.end()) {
|
||||
return found->second;
|
||||
}
|
||||
}
|
||||
return func_name;
|
||||
}
|
||||
|
||||
RuntimeManifestFile::RuntimeManifestFile(const std::string &filename, const std::string &library_path)
|
||||
: ManifestFile(MANIFEST_TYPE_RUNTIME, filename, library_path) {}
|
||||
|
||||
static void ParseExtension(Json::Value const &ext, std::vector<ExtensionListing> &extensions) {
|
||||
Json::Value ext_name = ext["name"];
|
||||
Json::Value ext_version = ext["extension_version"];
|
||||
|
||||
// Allow "extension_version" as a String or a UInt to maintain backwards compatibility, even though it should be a String.
|
||||
// Internal Issue 1411: https://gitlab.khronos.org/openxr/openxr/-/issues/1411
|
||||
// Internal MR !1867: https://gitlab.khronos.org/openxr/openxr/-/merge_requests/1867
|
||||
if (ext_name.isString() && (ext_version.isString() || ext_version.isUInt())) {
|
||||
ExtensionListing ext_listing = {};
|
||||
ext_listing.name = ext_name.asString();
|
||||
if (ext_version.isUInt()) {
|
||||
ext_listing.extension_version = ext_version.asUInt();
|
||||
} else {
|
||||
ext_listing.extension_version = atoi(ext_version.asString().c_str());
|
||||
}
|
||||
extensions.push_back(ext_listing);
|
||||
}
|
||||
}
|
||||
|
||||
void ManifestFile::ParseCommon(Json::Value const &root_node) {
|
||||
const Json::Value &inst_exts = root_node["instance_extensions"];
|
||||
if (!inst_exts.isNull() && inst_exts.isArray()) {
|
||||
for (const auto &ext : inst_exts) {
|
||||
ParseExtension(ext, _instance_extensions);
|
||||
}
|
||||
}
|
||||
const Json::Value &funcs_renamed = root_node["functions"];
|
||||
if (!funcs_renamed.isNull() && !funcs_renamed.empty()) {
|
||||
for (Json::ValueConstIterator func_it = funcs_renamed.begin(); func_it != funcs_renamed.end(); ++func_it) {
|
||||
if (!(*func_it).isString()) {
|
||||
LoaderLogger::LogWarningMessage(
|
||||
"", "ManifestFile::ParseCommon " + _filename + " \"functions\" section contains non-string values.");
|
||||
continue;
|
||||
}
|
||||
std::string original_name = func_it.key().asString();
|
||||
std::string new_name = (*func_it).asString();
|
||||
_functions_renamed.emplace(original_name, new_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeManifestFile::CreateIfValid(std::string const &filename,
|
||||
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {
|
||||
std::ifstream json_stream(filename, std::ifstream::in);
|
||||
|
||||
LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::CreateIfValid - attempting to load " + filename);
|
||||
std::ostringstream error_ss("RuntimeManifestFile::CreateIfValid ");
|
||||
if (!json_stream.is_open()) {
|
||||
error_ss << "failed to open " << filename << ". Does it exist?";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
Json::CharReaderBuilder builder;
|
||||
std::string errors;
|
||||
Json::Value root_node = Json::nullValue;
|
||||
if (!Json::parseFromStream(builder, json_stream, &root_node, &errors) || !root_node.isObject()) {
|
||||
error_ss << "failed to parse " << filename << ".";
|
||||
if (!errors.empty()) {
|
||||
error_ss << " (Error message: " << errors << ")";
|
||||
}
|
||||
error_ss << " Is it a valid runtime manifest file?";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
|
||||
CreateIfValid(root_node, filename, manifest_files);
|
||||
}
|
||||
|
||||
void RuntimeManifestFile::CreateIfValid(const Json::Value &root_node, const std::string &filename,
|
||||
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {
|
||||
std::ostringstream error_ss("RuntimeManifestFile::CreateIfValid ");
|
||||
JsonVersion file_version = {};
|
||||
if (!ManifestFile::IsValidJson(root_node, file_version)) {
|
||||
error_ss << "isValidJson indicates " << filename << " is not a valid manifest file.";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
const Json::Value &runtime_root_node = root_node["runtime"];
|
||||
// The Runtime manifest file needs the "runtime" root as well as a sub-node for "library_path". If any of those aren't there,
|
||||
// fail.
|
||||
if (runtime_root_node.isNull() || runtime_root_node["library_path"].isNull() || !runtime_root_node["library_path"].isString()) {
|
||||
error_ss << filename << " is missing required fields. Verify all proper fields exist.";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::string lib_path = runtime_root_node["library_path"].asString();
|
||||
|
||||
// If the library_path variable has no directory symbol, it's just a file name and should be accessible on the
|
||||
// global library path.
|
||||
if (lib_path.find('\\') != std::string::npos || lib_path.find('/') != std::string::npos) {
|
||||
// If the library_path is an absolute path, just use that if it exists
|
||||
if (FileSysUtilsIsAbsolutePath(lib_path)) {
|
||||
if (!FileSysUtilsPathExists(lib_path)) {
|
||||
error_ss << filename << " library " << lib_path << " does not appear to exist";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Otherwise, treat the library path as a relative path based on the JSON file.
|
||||
std::string canonical_path;
|
||||
std::string combined_path;
|
||||
std::string file_parent;
|
||||
// Search relative to the real manifest file, not relative to the symlink
|
||||
if (!FileSysUtilsGetCanonicalPath(filename, canonical_path)) {
|
||||
// Give relative to the non-canonical path a chance
|
||||
canonical_path = filename;
|
||||
}
|
||||
if (!FileSysUtilsGetParentPath(canonical_path, file_parent) ||
|
||||
!FileSysUtilsCombinePaths(file_parent, lib_path, combined_path) || !FileSysUtilsPathExists(combined_path)) {
|
||||
error_ss << filename << " library " << combined_path << " does not appear to exist";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
lib_path = combined_path;
|
||||
}
|
||||
}
|
||||
|
||||
// Add this runtime manifest file
|
||||
manifest_files.emplace_back(new RuntimeManifestFile(filename, lib_path));
|
||||
|
||||
// Add any extensions to it after the fact.
|
||||
// Handle any renamed functions
|
||||
manifest_files.back()->ParseCommon(runtime_root_node);
|
||||
}
|
||||
|
||||
// Find all manifest files in the appropriate search paths/registries for the given type.
|
||||
XrResult RuntimeManifestFile::FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {
|
||||
XrResult result = XR_SUCCESS;
|
||||
std::string filename = PlatformUtilsGetSecureEnv(OPENXR_RUNTIME_JSON_ENV_VAR);
|
||||
if (!filename.empty()) {
|
||||
LoaderLogger::LogInfoMessage(
|
||||
"", "RuntimeManifestFile::FindManifestFiles - using environment variable override runtime file " + filename);
|
||||
} else {
|
||||
#ifdef XR_OS_WINDOWS
|
||||
std::vector<std::string> filenames;
|
||||
ReadRuntimeDataFilesInRegistry("", "ActiveRuntime", filenames);
|
||||
if (filenames.size() == 0) {
|
||||
LoaderLogger::LogErrorMessage(
|
||||
"", "RuntimeManifestFile::FindManifestFiles - failed to find active runtime file in registry");
|
||||
return XR_ERROR_RUNTIME_UNAVAILABLE;
|
||||
}
|
||||
if (filenames.size() > 1) {
|
||||
LoaderLogger::LogWarningMessage(
|
||||
"", "RuntimeManifestFile::FindManifestFiles - found too many default runtime files in registry");
|
||||
}
|
||||
filename = filenames[0];
|
||||
LoaderLogger::LogInfoMessage("",
|
||||
"RuntimeManifestFile::FindManifestFiles - using registry-specified runtime file " + filename);
|
||||
#elif defined(XR_OS_LINUX)
|
||||
const std::string relative_path =
|
||||
"openxr/" + std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) + "/active_runtime.json";
|
||||
if (!FindXDGConfigFile(relative_path, filename)) {
|
||||
LoaderLogger::LogErrorMessage(
|
||||
"", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment");
|
||||
return XR_ERROR_RUNTIME_UNAVAILABLE;
|
||||
}
|
||||
#else
|
||||
|
||||
#if defined(XR_KHR_LOADER_INIT_SUPPORT)
|
||||
Json::Value virtualManifest;
|
||||
result = GetPlatformRuntimeVirtualManifest(virtualManifest);
|
||||
if (XR_SUCCESS == result) {
|
||||
RuntimeManifestFile::CreateIfValid(virtualManifest, "", manifest_files);
|
||||
return result;
|
||||
}
|
||||
#endif // defined(XR_KHR_LOADER_INIT_SUPPORT)
|
||||
if (!PlatformGetGlobalRuntimeFileName(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) {
|
||||
LoaderLogger::LogErrorMessage(
|
||||
"", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment");
|
||||
return XR_ERROR_RUNTIME_UNAVAILABLE;
|
||||
}
|
||||
result = XR_SUCCESS;
|
||||
LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::FindManifestFiles - using global runtime file " + filename);
|
||||
#endif
|
||||
}
|
||||
RuntimeManifestFile::CreateIfValid(filename, manifest_files);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ApiLayerManifestFile::ApiLayerManifestFile(ManifestFileType type, const std::string &filename, const std::string &layer_name,
|
||||
const std::string &description, const JsonVersion &api_version,
|
||||
const uint32_t &implementation_version, const std::string &library_path)
|
||||
: ManifestFile(type, filename, library_path),
|
||||
_api_version(api_version),
|
||||
_layer_name(layer_name),
|
||||
_description(description),
|
||||
_implementation_version(implementation_version) {}
|
||||
|
||||
void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename,
|
||||
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
|
||||
std::ifstream json_stream(filename, std::ifstream::in);
|
||||
|
||||
std::ostringstream error_ss("ApiLayerManifestFile::CreateIfValid ");
|
||||
if (!json_stream.is_open()) {
|
||||
error_ss << "failed to open " << filename << ". Does it exist?";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
|
||||
Json::CharReaderBuilder builder;
|
||||
std::string errors;
|
||||
Json::Value root_node = Json::nullValue;
|
||||
if (!Json::parseFromStream(builder, json_stream, &root_node, &errors) || !root_node.isObject()) {
|
||||
error_ss << "failed to parse " << filename << ".";
|
||||
if (!errors.empty()) {
|
||||
error_ss << " (Error message: " << errors << ")";
|
||||
}
|
||||
error_ss << " Is it a valid layer manifest file?";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
JsonVersion file_version = {};
|
||||
if (!ManifestFile::IsValidJson(root_node, file_version)) {
|
||||
error_ss << "isValidJson indicates " << filename << " is not a valid manifest file.";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
|
||||
Json::Value layer_root_node = root_node["api_layer"];
|
||||
|
||||
// The API Layer manifest file needs the "api_layer" root as well as other sub-nodes.
|
||||
// If any of those aren't there, fail.
|
||||
if (layer_root_node.isNull() || layer_root_node["name"].isNull() || !layer_root_node["name"].isString() ||
|
||||
layer_root_node["api_version"].isNull() || !layer_root_node["api_version"].isString() ||
|
||||
layer_root_node["library_path"].isNull() || !layer_root_node["library_path"].isString() ||
|
||||
layer_root_node["implementation_version"].isNull() || !layer_root_node["implementation_version"].isString()) {
|
||||
error_ss << filename << " is missing required fields. Verify all proper fields exist.";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
if (MANIFEST_TYPE_IMPLICIT_API_LAYER == type) {
|
||||
bool enabled = true;
|
||||
// Implicit layers require the disable environment variable.
|
||||
if (layer_root_node["disable_environment"].isNull() || !layer_root_node["disable_environment"].isString()) {
|
||||
error_ss << "Implicit layer " << filename << " is missing \"disable_environment\"";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
// Check if there's an enable environment variable provided
|
||||
if (!layer_root_node["enable_environment"].isNull() && layer_root_node["enable_environment"].isString()) {
|
||||
std::string env_var = layer_root_node["enable_environment"].asString();
|
||||
// If it's not set in the environment, disable the layer
|
||||
if (!PlatformUtilsGetEnvSet(env_var.c_str())) {
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
// Check for the disable environment variable, which must be provided in the JSON
|
||||
std::string env_var = layer_root_node["disable_environment"].asString();
|
||||
// If the env var is set, disable the layer. Disable env var overrides enable above
|
||||
if (PlatformUtilsGetEnvSet(env_var.c_str())) {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
// Not enabled, so pretend like it isn't even there.
|
||||
if (!enabled) {
|
||||
error_ss << "Implicit layer " << filename << " is disabled";
|
||||
LoaderLogger::LogInfoMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::string layer_name = layer_root_node["name"].asString();
|
||||
std::string api_version_string = layer_root_node["api_version"].asString();
|
||||
JsonVersion api_version = {};
|
||||
const int num_fields = sscanf(api_version_string.c_str(), "%u.%u", &api_version.major, &api_version.minor);
|
||||
api_version.patch = 0;
|
||||
|
||||
if ((num_fields != 2) || (api_version.major == 0 && api_version.minor == 0) ||
|
||||
api_version.major > XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) {
|
||||
error_ss << "layer " << filename << " has invalid API Version. Skipping layer.";
|
||||
LoaderLogger::LogWarningMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t implementation_version = atoi(layer_root_node["implementation_version"].asString().c_str());
|
||||
std::string library_path = layer_root_node["library_path"].asString();
|
||||
|
||||
// If the library_path variable has no directory symbol, it's just a file name and should be accessible on the
|
||||
// global library path.
|
||||
if (library_path.find('\\') != std::string::npos || library_path.find('/') != std::string::npos) {
|
||||
// If the library_path is an absolute path, just use that if it exists
|
||||
if (FileSysUtilsIsAbsolutePath(library_path)) {
|
||||
if (!FileSysUtilsPathExists(library_path)) {
|
||||
error_ss << filename << " library " << library_path << " does not appear to exist";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Otherwise, treat the library path as a relative path based on the JSON file.
|
||||
std::string combined_path;
|
||||
std::string file_parent;
|
||||
if (!FileSysUtilsGetParentPath(filename, file_parent) ||
|
||||
!FileSysUtilsCombinePaths(file_parent, library_path, combined_path) || !FileSysUtilsPathExists(combined_path)) {
|
||||
error_ss << filename << " library " << combined_path << " does not appear to exist";
|
||||
LoaderLogger::LogErrorMessage("", error_ss.str());
|
||||
return;
|
||||
}
|
||||
library_path = combined_path;
|
||||
}
|
||||
}
|
||||
|
||||
std::string description;
|
||||
if (!layer_root_node["description"].isNull() && layer_root_node["description"].isString()) {
|
||||
description = layer_root_node["description"].asString();
|
||||
}
|
||||
|
||||
// Add this layer manifest file
|
||||
manifest_files.emplace_back(
|
||||
new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path));
|
||||
|
||||
// Add any extensions to it after the fact.
|
||||
manifest_files.back()->ParseCommon(layer_root_node);
|
||||
}
|
||||
|
||||
void ApiLayerManifestFile::PopulateApiLayerProperties(XrApiLayerProperties &props) const {
|
||||
props.layerVersion = _implementation_version;
|
||||
props.specVersion = XR_MAKE_VERSION(_api_version.major, _api_version.minor, _api_version.patch);
|
||||
strncpy(props.layerName, _layer_name.c_str(), XR_MAX_API_LAYER_NAME_SIZE - 1);
|
||||
if (_layer_name.size() >= XR_MAX_API_LAYER_NAME_SIZE - 1) {
|
||||
props.layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';
|
||||
}
|
||||
strncpy(props.description, _description.c_str(), XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1);
|
||||
if (_description.size() >= XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1) {
|
||||
props.description[XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Find all layer manifest files in the appropriate search paths/registries for the given type.
|
||||
XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type,
|
||||
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
|
||||
std::string relative_path;
|
||||
std::string override_env_var;
|
||||
std::string registry_location;
|
||||
|
||||
// Add the appropriate top-level folders for the relative path. These should be
|
||||
// the string "openxr/" followed by the API major version as a string.
|
||||
relative_path = OPENXR_RELATIVE_PATH;
|
||||
relative_path += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION));
|
||||
|
||||
switch (type) {
|
||||
case MANIFEST_TYPE_IMPLICIT_API_LAYER:
|
||||
relative_path += OPENXR_IMPLICIT_API_LAYER_RELATIVE_PATH;
|
||||
override_env_var = "";
|
||||
#ifdef XR_OS_WINDOWS
|
||||
registry_location = OPENXR_IMPLICIT_API_LAYER_REGISTRY_LOCATION;
|
||||
#endif
|
||||
break;
|
||||
case MANIFEST_TYPE_EXPLICIT_API_LAYER:
|
||||
relative_path += OPENXR_EXPLICIT_API_LAYER_RELATIVE_PATH;
|
||||
override_env_var = OPENXR_API_LAYER_PATH_ENV_VAR;
|
||||
#ifdef XR_OS_WINDOWS
|
||||
registry_location = OPENXR_EXPLICIT_API_LAYER_REGISTRY_LOCATION;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
LoaderLogger::LogErrorMessage("", "ApiLayerManifestFile::FindManifestFiles - unknown manifest file requested");
|
||||
return XR_ERROR_FILE_ACCESS_ERROR;
|
||||
}
|
||||
|
||||
bool override_active = false;
|
||||
std::vector<std::string> filenames;
|
||||
ReadDataFilesInSearchPaths(override_env_var, relative_path, override_active, filenames);
|
||||
|
||||
#ifdef XR_OS_WINDOWS
|
||||
// Read the registry if the override wasn't active.
|
||||
if (!override_active) {
|
||||
ReadLayerDataFilesInRegistry(registry_location, filenames);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (std::string &cur_file : filenames) {
|
||||
ApiLayerManifestFile::CreateIfValid(type, cur_file, manifest_files);
|
||||
}
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
103
thirdparty/openxr/src/loader/manifest_file.hpp
vendored
Normal file
103
thirdparty/openxr/src/loader/manifest_file.hpp
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2017 The Khronos Group Inc.
|
||||
// Copyright (c) 2017 Valve Corporation
|
||||
// Copyright (c) 2017 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Json {
|
||||
class Value;
|
||||
}
|
||||
|
||||
enum ManifestFileType {
|
||||
MANIFEST_TYPE_UNDEFINED = 0,
|
||||
MANIFEST_TYPE_RUNTIME,
|
||||
MANIFEST_TYPE_IMPLICIT_API_LAYER,
|
||||
MANIFEST_TYPE_EXPLICIT_API_LAYER,
|
||||
};
|
||||
|
||||
struct JsonVersion {
|
||||
uint32_t major;
|
||||
uint32_t minor;
|
||||
uint32_t patch;
|
||||
};
|
||||
|
||||
struct ExtensionListing {
|
||||
std::string name;
|
||||
uint32_t extension_version;
|
||||
};
|
||||
|
||||
// ManifestFile class -
|
||||
// Base class responsible for finding and parsing manifest files.
|
||||
class ManifestFile {
|
||||
public:
|
||||
// Non-copyable
|
||||
ManifestFile(const ManifestFile &) = delete;
|
||||
ManifestFile &operator=(const ManifestFile &) = delete;
|
||||
|
||||
ManifestFileType Type() const { return _type; }
|
||||
const std::string &Filename() const { return _filename; }
|
||||
const std::string &LibraryPath() const { return _library_path; }
|
||||
void GetInstanceExtensionProperties(std::vector<XrExtensionProperties> &props);
|
||||
const std::string &GetFunctionName(const std::string &func_name) const;
|
||||
|
||||
protected:
|
||||
ManifestFile(ManifestFileType type, const std::string &filename, const std::string &library_path);
|
||||
void ParseCommon(Json::Value const &root_node);
|
||||
static bool IsValidJson(const Json::Value &root, JsonVersion &version);
|
||||
|
||||
private:
|
||||
std::string _filename;
|
||||
ManifestFileType _type;
|
||||
std::string _library_path;
|
||||
std::vector<ExtensionListing> _instance_extensions;
|
||||
std::unordered_map<std::string, std::string> _functions_renamed;
|
||||
};
|
||||
|
||||
// RuntimeManifestFile class -
|
||||
// Responsible for finding and parsing Runtime-specific manifest files.
|
||||
class RuntimeManifestFile : public ManifestFile {
|
||||
public:
|
||||
// Factory method
|
||||
static XrResult FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
|
||||
|
||||
private:
|
||||
RuntimeManifestFile(const std::string &filename, const std::string &library_path);
|
||||
static void CreateIfValid(const std::string &filename, std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
|
||||
static void CreateIfValid(const Json::Value &root_node, const std::string &filename,
|
||||
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
|
||||
};
|
||||
|
||||
// ApiLayerManifestFile class -
|
||||
// Responsible for finding and parsing API Layer-specific manifest files.
|
||||
class ApiLayerManifestFile : public ManifestFile {
|
||||
public:
|
||||
// Factory method
|
||||
static XrResult FindManifestFiles(ManifestFileType type, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
|
||||
|
||||
const std::string &LayerName() const { return _layer_name; }
|
||||
void PopulateApiLayerProperties(XrApiLayerProperties &props) const;
|
||||
|
||||
private:
|
||||
ApiLayerManifestFile(ManifestFileType type, const std::string &filename, const std::string &layer_name,
|
||||
const std::string &description, const JsonVersion &api_version, const uint32_t &implementation_version,
|
||||
const std::string &library_path);
|
||||
static void CreateIfValid(ManifestFileType type, const std::string &filename,
|
||||
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
|
||||
|
||||
JsonVersion _api_version;
|
||||
std::string _layer_name;
|
||||
std::string _description;
|
||||
uint32_t _implementation_version;
|
||||
};
|
||||
493
thirdparty/openxr/src/loader/runtime_interface.cpp
vendored
Normal file
493
thirdparty/openxr/src/loader/runtime_interface.cpp
vendored
Normal file
@@ -0,0 +1,493 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#include "runtime_interface.hpp"
|
||||
|
||||
#include "manifest_file.hpp"
|
||||
#include "loader_interfaces.h"
|
||||
#include "loader_logger.hpp"
|
||||
#include "loader_platform.hpp"
|
||||
#include "xr_generated_dispatch_table.h"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef XR_USE_PLATFORM_ANDROID
|
||||
#include "android_utilities.h"
|
||||
#include <json/value.h>
|
||||
#endif // XR_USE_PLATFORM_ANDROID
|
||||
|
||||
#ifdef XR_KHR_LOADER_INIT_SUPPORT
|
||||
namespace {
|
||||
/*!
|
||||
* Stores a copy of the data passed to the xrInitializeLoaderKHR function in a singleton.
|
||||
*/
|
||||
class LoaderInitData {
|
||||
public:
|
||||
/*!
|
||||
* Singleton accessor.
|
||||
*/
|
||||
static LoaderInitData& instance() {
|
||||
static LoaderInitData obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
#ifdef XR_USE_PLATFORM_ANDROID
|
||||
/*!
|
||||
* Type alias for the platform-specific structure type.
|
||||
*/
|
||||
using StructType = XrLoaderInitInfoAndroidKHR;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Get our copy of the data, casted to pass to the runtime's matching method.
|
||||
*/
|
||||
const XrLoaderInitInfoBaseHeaderKHR* getParam() const { return reinterpret_cast<const XrLoaderInitInfoBaseHeaderKHR*>(&_data); }
|
||||
|
||||
/*!
|
||||
* Get the data via its real structure type.
|
||||
*/
|
||||
const StructType& getData() const { return _data; }
|
||||
|
||||
/*!
|
||||
* Has this been correctly initialized?
|
||||
*/
|
||||
bool initialized() const noexcept { return _initialized; }
|
||||
|
||||
/*!
|
||||
* Initialize loader data - called by InitializeLoader() and thus ultimately by the loader's xrInitializeLoaderKHR
|
||||
* implementation. Each platform that needs this extension will provide an implementation of this.
|
||||
*/
|
||||
XrResult initialize(const XrLoaderInitInfoBaseHeaderKHR* info);
|
||||
|
||||
private:
|
||||
//! Private constructor, forces use of singleton accessor.
|
||||
LoaderInitData() = default;
|
||||
//! Platform-specific init data
|
||||
StructType _data = {};
|
||||
//! Flag for indicating whether _data is valid.
|
||||
bool _initialized = false;
|
||||
};
|
||||
|
||||
#ifdef XR_USE_PLATFORM_ANDROID
|
||||
// Check and copy the Android-specific init data.
|
||||
XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) {
|
||||
if (info->type != XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) {
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
auto cast_info = reinterpret_cast<XrLoaderInitInfoAndroidKHR const*>(info);
|
||||
|
||||
if (cast_info->applicationVM == nullptr) {
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
if (cast_info->applicationContext == nullptr) {
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
_data = *cast_info;
|
||||
jni::init((jni::JavaVM*)_data.applicationVM);
|
||||
_data.next = nullptr;
|
||||
_initialized = true;
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
#endif // XR_USE_PLATFORM_ANDROID
|
||||
} // namespace
|
||||
|
||||
XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo) {
|
||||
return LoaderInitData::instance().initialize(loaderInitInfo);
|
||||
}
|
||||
|
||||
#endif // XR_KHR_LOADER_INIT_SUPPORT
|
||||
|
||||
#ifdef XR_USE_PLATFORM_ANDROID
|
||||
XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) {
|
||||
using wrap::android::content::Context;
|
||||
auto& initData = LoaderInitData::instance();
|
||||
if (!initData.initialized()) {
|
||||
return XR_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
auto context = Context(reinterpret_cast<jobject>(initData.getData().applicationContext));
|
||||
if (context.isNull()) {
|
||||
return XR_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
Json::Value virtualManifest;
|
||||
if (0 != openxr_android::getActiveRuntimeVirtualManifest(context, virtualManifest)) {
|
||||
return XR_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
out_manifest = virtualManifest;
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
#endif // XR_USE_PLATFORM_ANDROID
|
||||
|
||||
XrResult RuntimeInterface::TryLoadingSingleRuntime(const std::string& openxr_command,
|
||||
std::unique_ptr<RuntimeManifestFile>& manifest_file) {
|
||||
LoaderPlatformLibraryHandle runtime_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());
|
||||
if (nullptr == runtime_library) {
|
||||
std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());
|
||||
std::string warning_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
|
||||
warning_message += manifest_file->Filename();
|
||||
warning_message += ", failed to load with message \"";
|
||||
warning_message += library_message;
|
||||
warning_message += "\"";
|
||||
LoaderLogger::LogErrorMessage(openxr_command, warning_message);
|
||||
return XR_ERROR_FILE_ACCESS_ERROR;
|
||||
}
|
||||
#ifdef XR_KHR_LOADER_INIT_SUPPORT
|
||||
if (!LoaderInitData::instance().initialized()) {
|
||||
LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntime skipping manifest file " +
|
||||
manifest_file->Filename() +
|
||||
" because xrInitializeLoaderKHR was not yet called.");
|
||||
|
||||
LoaderPlatformLibraryClose(runtime_library);
|
||||
return XR_ERROR_VALIDATION_FAILURE;
|
||||
}
|
||||
bool forwardedInitLoader = false;
|
||||
{
|
||||
// If we have xrInitializeLoaderKHR exposed as an export, forward call to it.
|
||||
const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR");
|
||||
auto initLoader =
|
||||
reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(runtime_library, function_name));
|
||||
if (initLoader != nullptr) {
|
||||
// we found the entry point one way or another.
|
||||
LoaderLogger::LogInfoMessage(openxr_command,
|
||||
"RuntimeInterface::LoadRuntime forwarding xrInitializeLoaderKHR call to runtime before "
|
||||
"calling xrNegotiateLoaderRuntimeInterface.");
|
||||
XrResult res = initLoader(LoaderInitData::instance().getParam());
|
||||
if (!XR_SUCCEEDED(res)) {
|
||||
LoaderLogger::LogErrorMessage(openxr_command,
|
||||
"RuntimeInterface::LoadRuntime forwarded call to xrInitializeLoaderKHR failed.");
|
||||
|
||||
LoaderPlatformLibraryClose(runtime_library);
|
||||
return res;
|
||||
}
|
||||
forwardedInitLoader = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get and settle on an runtime interface version (using any provided name if required).
|
||||
std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderRuntimeInterface");
|
||||
auto negotiate =
|
||||
reinterpret_cast<PFN_xrNegotiateLoaderRuntimeInterface>(LoaderPlatformLibraryGetProcAddr(runtime_library, function_name));
|
||||
|
||||
// Loader info for negotiation
|
||||
XrNegotiateLoaderInfo loader_info = {};
|
||||
loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;
|
||||
loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;
|
||||
loader_info.structSize = sizeof(XrNegotiateLoaderInfo);
|
||||
loader_info.minInterfaceVersion = 1;
|
||||
loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_RUNTIME_VERSION;
|
||||
loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);
|
||||
loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.
|
||||
|
||||
// Set up the runtime return structure
|
||||
XrNegotiateRuntimeRequest runtime_info = {};
|
||||
runtime_info.structType = XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST;
|
||||
runtime_info.structVersion = XR_RUNTIME_INFO_STRUCT_VERSION;
|
||||
runtime_info.structSize = sizeof(XrNegotiateRuntimeRequest);
|
||||
|
||||
// Skip calling the negotiate function and fail if the function pointer
|
||||
// could not get loaded
|
||||
XrResult res = XR_ERROR_RUNTIME_FAILURE;
|
||||
if (nullptr != negotiate) {
|
||||
res = negotiate(&loader_info, &runtime_info);
|
||||
}
|
||||
// If we supposedly succeeded, but got a nullptr for GetInstanceProcAddr
|
||||
// then something still went wrong, so return with an error.
|
||||
if (XR_SUCCEEDED(res)) {
|
||||
uint32_t runtime_major = XR_VERSION_MAJOR(runtime_info.runtimeApiVersion);
|
||||
uint32_t runtime_minor = XR_VERSION_MINOR(runtime_info.runtimeApiVersion);
|
||||
uint32_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION);
|
||||
if (nullptr == runtime_info.getInstanceProcAddr) {
|
||||
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
|
||||
error_message += manifest_file->Filename();
|
||||
error_message += ", negotiation succeeded but returned NULL getInstanceProcAddr";
|
||||
LoaderLogger::LogErrorMessage(openxr_command, error_message);
|
||||
res = XR_ERROR_FILE_CONTENTS_INVALID;
|
||||
} else if (0 >= runtime_info.runtimeInterfaceVersion ||
|
||||
XR_CURRENT_LOADER_RUNTIME_VERSION < runtime_info.runtimeInterfaceVersion) {
|
||||
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
|
||||
error_message += manifest_file->Filename();
|
||||
error_message += ", negotiation succeeded but returned invalid interface version";
|
||||
LoaderLogger::LogErrorMessage(openxr_command, error_message);
|
||||
res = XR_ERROR_FILE_CONTENTS_INVALID;
|
||||
} else if (runtime_major != loader_major || (runtime_major == 0 && runtime_minor == 0)) {
|
||||
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
|
||||
error_message += manifest_file->Filename();
|
||||
error_message += ", OpenXR version returned not compatible with this loader";
|
||||
LoaderLogger::LogErrorMessage(openxr_command, error_message);
|
||||
res = XR_ERROR_FILE_CONTENTS_INVALID;
|
||||
}
|
||||
}
|
||||
#ifdef XR_KHR_LOADER_INIT_SUPPORT
|
||||
if (XR_SUCCEEDED(res) && !forwardedInitLoader) {
|
||||
// Forward initialize loader call, where possible and if we did not do so before.
|
||||
PFN_xrVoidFunction initializeVoid = nullptr;
|
||||
PFN_xrInitializeLoaderKHR initialize = nullptr;
|
||||
|
||||
// Now we may try asking xrGetInstanceProcAddr
|
||||
if (XR_SUCCEEDED(runtime_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) {
|
||||
if (initializeVoid == nullptr) {
|
||||
LoaderLogger::LogErrorMessage(openxr_command,
|
||||
"RuntimeInterface::LoadRuntime got success from xrGetInstanceProcAddr "
|
||||
"for xrInitializeLoaderKHR, but output a null pointer.");
|
||||
res = XR_ERROR_RUNTIME_FAILURE;
|
||||
} else {
|
||||
initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid);
|
||||
}
|
||||
}
|
||||
if (initialize != nullptr) {
|
||||
// we found the entry point one way or another.
|
||||
LoaderLogger::LogInfoMessage(openxr_command,
|
||||
"RuntimeInterface::LoadRuntime forwarding xrInitializeLoaderKHR call to runtime after "
|
||||
"calling xrNegotiateLoaderRuntimeInterface.");
|
||||
res = initialize(LoaderInitData::instance().getParam());
|
||||
if (!XR_SUCCEEDED(res)) {
|
||||
LoaderLogger::LogErrorMessage(openxr_command,
|
||||
"RuntimeInterface::LoadRuntime forwarded call to xrInitializeLoaderKHR failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (XR_FAILED(res)) {
|
||||
std::string warning_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
|
||||
warning_message += manifest_file->Filename();
|
||||
warning_message += ", negotiation failed with error ";
|
||||
warning_message += std::to_string(res);
|
||||
LoaderLogger::LogErrorMessage(openxr_command, warning_message);
|
||||
LoaderPlatformLibraryClose(runtime_library);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string info_message = "RuntimeInterface::LoadRuntime succeeded loading runtime defined in manifest file ";
|
||||
info_message += manifest_file->Filename();
|
||||
info_message += " using interface version ";
|
||||
info_message += std::to_string(runtime_info.runtimeInterfaceVersion);
|
||||
info_message += " and OpenXR API version ";
|
||||
info_message += std::to_string(XR_VERSION_MAJOR(runtime_info.runtimeApiVersion));
|
||||
info_message += ".";
|
||||
info_message += std::to_string(XR_VERSION_MINOR(runtime_info.runtimeApiVersion));
|
||||
LoaderLogger::LogInfoMessage(openxr_command, info_message);
|
||||
|
||||
// Use this runtime
|
||||
GetInstance().reset(new RuntimeInterface(runtime_library, runtime_info.getInstanceProcAddr));
|
||||
|
||||
// Grab the list of extensions this runtime supports for easy filtering after the
|
||||
// xrCreateInstance call
|
||||
std::vector<std::string> supported_extensions;
|
||||
std::vector<XrExtensionProperties> extension_properties;
|
||||
GetInstance()->GetInstanceExtensionProperties(extension_properties);
|
||||
supported_extensions.reserve(extension_properties.size());
|
||||
for (XrExtensionProperties ext_prop : extension_properties) {
|
||||
supported_extensions.emplace_back(ext_prop.extensionName);
|
||||
}
|
||||
GetInstance()->SetSupportedExtensions(supported_extensions);
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
XrResult RuntimeInterface::LoadRuntime(const std::string& openxr_command) {
|
||||
// If something's already loaded, we're done here.
|
||||
if (GetInstance() != nullptr) {
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
#ifdef XR_KHR_LOADER_INIT_SUPPORT
|
||||
|
||||
if (!LoaderInitData::instance().initialized()) {
|
||||
LoaderLogger::LogErrorMessage(
|
||||
openxr_command, "RuntimeInterface::LoadRuntime cannot run because xrInitializeLoaderKHR was not successfully called.");
|
||||
return XR_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
#endif // XR_KHR_LOADER_INIT_SUPPORT
|
||||
|
||||
std::vector<std::unique_ptr<RuntimeManifestFile>> runtime_manifest_files = {};
|
||||
|
||||
// Find the available runtimes which we may need to report information for.
|
||||
XrResult last_error = RuntimeManifestFile::FindManifestFiles(runtime_manifest_files);
|
||||
if (XR_FAILED(last_error)) {
|
||||
LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - unknown error");
|
||||
} else {
|
||||
last_error = XR_ERROR_RUNTIME_UNAVAILABLE;
|
||||
for (std::unique_ptr<RuntimeManifestFile>& manifest_file : runtime_manifest_files) {
|
||||
last_error = RuntimeInterface::TryLoadingSingleRuntime(openxr_command, manifest_file);
|
||||
if (XR_SUCCEEDED(last_error)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unsuccessful in loading any runtime, throw the runtime unavailable message.
|
||||
if (XR_FAILED(last_error)) {
|
||||
LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - failed to load a runtime");
|
||||
last_error = XR_ERROR_RUNTIME_UNAVAILABLE;
|
||||
}
|
||||
|
||||
return last_error;
|
||||
}
|
||||
|
||||
void RuntimeInterface::UnloadRuntime(const std::string& openxr_command) {
|
||||
if (GetInstance()) {
|
||||
LoaderLogger::LogInfoMessage(openxr_command, "RuntimeInterface::UnloadRuntime - Unloading RuntimeInterface");
|
||||
GetInstance().reset();
|
||||
}
|
||||
}
|
||||
|
||||
XrResult RuntimeInterface::GetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function) {
|
||||
return GetInstance()->_get_instance_proc_addr(instance, name, function);
|
||||
}
|
||||
|
||||
const XrGeneratedDispatchTable* RuntimeInterface::GetDispatchTable(XrInstance instance) {
|
||||
XrGeneratedDispatchTable* table = nullptr;
|
||||
std::lock_guard<std::mutex> mlock(GetInstance()->_dispatch_table_mutex);
|
||||
auto it = GetInstance()->_dispatch_table_map.find(instance);
|
||||
if (it != GetInstance()->_dispatch_table_map.end()) {
|
||||
table = it->second.get();
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
const XrGeneratedDispatchTable* RuntimeInterface::GetDebugUtilsMessengerDispatchTable(XrDebugUtilsMessengerEXT messenger) {
|
||||
XrInstance runtime_instance = XR_NULL_HANDLE;
|
||||
{
|
||||
std::lock_guard<std::mutex> mlock(GetInstance()->_messenger_to_instance_mutex);
|
||||
auto it = GetInstance()->_messenger_to_instance_map.find(messenger);
|
||||
if (it != GetInstance()->_messenger_to_instance_map.end()) {
|
||||
runtime_instance = it->second;
|
||||
}
|
||||
}
|
||||
return GetDispatchTable(runtime_instance);
|
||||
}
|
||||
|
||||
RuntimeInterface::RuntimeInterface(LoaderPlatformLibraryHandle runtime_library, PFN_xrGetInstanceProcAddr get_instance_proc_addr)
|
||||
: _runtime_library(runtime_library), _get_instance_proc_addr(get_instance_proc_addr) {}
|
||||
|
||||
RuntimeInterface::~RuntimeInterface() {
|
||||
std::string info_message = "RuntimeInterface being destroyed.";
|
||||
LoaderLogger::LogInfoMessage("", info_message);
|
||||
{
|
||||
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
|
||||
_dispatch_table_map.clear();
|
||||
}
|
||||
LoaderPlatformLibraryClose(_runtime_library);
|
||||
}
|
||||
|
||||
void RuntimeInterface::GetInstanceExtensionProperties(std::vector<XrExtensionProperties>& extension_properties) {
|
||||
std::vector<XrExtensionProperties> runtime_extension_properties;
|
||||
PFN_xrEnumerateInstanceExtensionProperties rt_xrEnumerateInstanceExtensionProperties;
|
||||
_get_instance_proc_addr(XR_NULL_HANDLE, "xrEnumerateInstanceExtensionProperties",
|
||||
reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrEnumerateInstanceExtensionProperties));
|
||||
uint32_t count = 0;
|
||||
uint32_t count_output = 0;
|
||||
// Get the count from the runtime
|
||||
rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, nullptr);
|
||||
if (count_output > 0) {
|
||||
runtime_extension_properties.resize(count_output);
|
||||
count = count_output;
|
||||
for (XrExtensionProperties& ext_prop : runtime_extension_properties) {
|
||||
ext_prop.type = XR_TYPE_EXTENSION_PROPERTIES;
|
||||
ext_prop.next = nullptr;
|
||||
}
|
||||
rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, runtime_extension_properties.data());
|
||||
}
|
||||
size_t ext_count = runtime_extension_properties.size();
|
||||
size_t props_count = extension_properties.size();
|
||||
for (size_t ext = 0; ext < ext_count; ++ext) {
|
||||
bool found = false;
|
||||
for (size_t prop = 0; prop < props_count; ++prop) {
|
||||
// If we find it, then make sure the spec version matches that of the runtime instead of the
|
||||
// layer.
|
||||
if (strcmp(extension_properties[prop].extensionName, runtime_extension_properties[ext].extensionName) == 0) {
|
||||
// Make sure the spec version used is the runtime's
|
||||
extension_properties[prop].extensionVersion = runtime_extension_properties[ext].extensionVersion;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
extension_properties.push_back(runtime_extension_properties[ext]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XrResult RuntimeInterface::CreateInstance(const XrInstanceCreateInfo* info, XrInstance* instance) {
|
||||
XrResult res = XR_SUCCESS;
|
||||
bool create_succeeded = false;
|
||||
PFN_xrCreateInstance rt_xrCreateInstance;
|
||||
_get_instance_proc_addr(XR_NULL_HANDLE, "xrCreateInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrCreateInstance));
|
||||
res = rt_xrCreateInstance(info, instance);
|
||||
if (XR_SUCCEEDED(res)) {
|
||||
create_succeeded = true;
|
||||
std::unique_ptr<XrGeneratedDispatchTable> dispatch_table(new XrGeneratedDispatchTable());
|
||||
GeneratedXrPopulateDispatchTable(dispatch_table.get(), *instance, _get_instance_proc_addr);
|
||||
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
|
||||
_dispatch_table_map[*instance] = std::move(dispatch_table);
|
||||
}
|
||||
|
||||
// If the failure occurred during the populate, clean up the instance we had picked up from the runtime
|
||||
if (XR_FAILED(res) && create_succeeded) {
|
||||
PFN_xrDestroyInstance rt_xrDestroyInstance;
|
||||
_get_instance_proc_addr(*instance, "xrDestroyInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrDestroyInstance));
|
||||
rt_xrDestroyInstance(*instance);
|
||||
*instance = XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
XrResult RuntimeInterface::DestroyInstance(XrInstance instance) {
|
||||
if (XR_NULL_HANDLE != instance) {
|
||||
// Destroy the dispatch table for this instance first
|
||||
{
|
||||
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
|
||||
auto map_iter = _dispatch_table_map.find(instance);
|
||||
if (map_iter != _dispatch_table_map.end()) {
|
||||
_dispatch_table_map.erase(map_iter);
|
||||
}
|
||||
}
|
||||
// Now delete the instance
|
||||
PFN_xrDestroyInstance rt_xrDestroyInstance;
|
||||
_get_instance_proc_addr(instance, "xrDestroyInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrDestroyInstance));
|
||||
rt_xrDestroyInstance(instance);
|
||||
}
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
bool RuntimeInterface::TrackDebugMessenger(XrInstance instance, XrDebugUtilsMessengerEXT messenger) {
|
||||
std::lock_guard<std::mutex> mlock(_messenger_to_instance_mutex);
|
||||
_messenger_to_instance_map[messenger] = instance;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RuntimeInterface::ForgetDebugMessenger(XrDebugUtilsMessengerEXT messenger) {
|
||||
if (XR_NULL_HANDLE != messenger) {
|
||||
std::lock_guard<std::mutex> mlock(_messenger_to_instance_mutex);
|
||||
_messenger_to_instance_map.erase(messenger);
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeInterface::SetSupportedExtensions(std::vector<std::string>& supported_extensions) {
|
||||
_supported_extensions = supported_extensions;
|
||||
}
|
||||
|
||||
bool RuntimeInterface::SupportsExtension(const std::string& extension_name) {
|
||||
bool found_prop = false;
|
||||
for (const std::string& supported_extension : _supported_extensions) {
|
||||
if (supported_extension == extension_name) {
|
||||
found_prop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found_prop;
|
||||
}
|
||||
84
thirdparty/openxr/src/loader/runtime_interface.hpp
vendored
Normal file
84
thirdparty/openxr/src/loader/runtime_interface.hpp
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
//
|
||||
// Initial Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "loader_platform.hpp"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#ifdef XR_USE_PLATFORM_ANDROID
|
||||
#define XR_KHR_LOADER_INIT_SUPPORT
|
||||
#endif
|
||||
|
||||
namespace Json {
|
||||
class Value;
|
||||
}
|
||||
|
||||
#ifdef XR_KHR_LOADER_INIT_SUPPORT
|
||||
//! Initialize loader, where required.
|
||||
XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo);
|
||||
XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest);
|
||||
#endif
|
||||
|
||||
class RuntimeManifestFile;
|
||||
struct XrGeneratedDispatchTable;
|
||||
|
||||
class RuntimeInterface {
|
||||
public:
|
||||
virtual ~RuntimeInterface();
|
||||
|
||||
// Helper functions for loading and unloading the runtime (but only when necessary)
|
||||
static XrResult LoadRuntime(const std::string& openxr_command);
|
||||
static void UnloadRuntime(const std::string& openxr_command);
|
||||
static RuntimeInterface& GetRuntime() { return *(GetInstance().get()); }
|
||||
static XrResult GetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function);
|
||||
|
||||
// Get the direct dispatch table to this runtime, without API layers or loader terminators.
|
||||
static const XrGeneratedDispatchTable* GetDispatchTable(XrInstance instance);
|
||||
static const XrGeneratedDispatchTable* GetDebugUtilsMessengerDispatchTable(XrDebugUtilsMessengerEXT messenger);
|
||||
|
||||
void GetInstanceExtensionProperties(std::vector<XrExtensionProperties>& extension_properties);
|
||||
bool SupportsExtension(const std::string& extension_name);
|
||||
XrResult CreateInstance(const XrInstanceCreateInfo* info, XrInstance* instance);
|
||||
XrResult DestroyInstance(XrInstance instance);
|
||||
bool TrackDebugMessenger(XrInstance instance, XrDebugUtilsMessengerEXT messenger);
|
||||
void ForgetDebugMessenger(XrDebugUtilsMessengerEXT messenger);
|
||||
|
||||
// No default construction
|
||||
RuntimeInterface() = delete;
|
||||
|
||||
// Non-copyable
|
||||
RuntimeInterface(const RuntimeInterface&) = delete;
|
||||
RuntimeInterface& operator=(const RuntimeInterface&) = delete;
|
||||
|
||||
private:
|
||||
RuntimeInterface(LoaderPlatformLibraryHandle runtime_library, PFN_xrGetInstanceProcAddr get_instance_proc_addr);
|
||||
void SetSupportedExtensions(std::vector<std::string>& supported_extensions);
|
||||
static XrResult TryLoadingSingleRuntime(const std::string& openxr_command, std::unique_ptr<RuntimeManifestFile>& manifest_file);
|
||||
|
||||
static std::unique_ptr<RuntimeInterface>& GetInstance() {
|
||||
static std::unique_ptr<RuntimeInterface> instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
LoaderPlatformLibraryHandle _runtime_library;
|
||||
PFN_xrGetInstanceProcAddr _get_instance_proc_addr;
|
||||
std::unordered_map<XrInstance, std::unique_ptr<XrGeneratedDispatchTable>> _dispatch_table_map;
|
||||
std::mutex _dispatch_table_mutex;
|
||||
std::unordered_map<XrDebugUtilsMessengerEXT, XrInstance> _messenger_to_instance_map;
|
||||
std::mutex _messenger_to_instance_mutex;
|
||||
std::vector<std::string> _supported_extensions;
|
||||
};
|
||||
700
thirdparty/openxr/src/loader/xr_generated_loader.cpp
vendored
Normal file
700
thirdparty/openxr/src/loader/xr_generated_loader.cpp
vendored
Normal file
@@ -0,0 +1,700 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
|
||||
// See loader_source_generator.py for modifications
|
||||
// ************************************************************
|
||||
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#include "xr_generated_loader.hpp"
|
||||
|
||||
#include "api_layer_interface.hpp"
|
||||
#include "exception_handling.hpp"
|
||||
#include "hex_and_handles.h"
|
||||
#include "loader_instance.hpp"
|
||||
#include "loader_logger.hpp"
|
||||
#include "loader_platform.hpp"
|
||||
#include "runtime_interface.hpp"
|
||||
#include "xr_generated_dispatch_table.h"
|
||||
|
||||
#include "xr_dependencies.h"
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
// Automatically generated instance trampolines and terminators
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties(
|
||||
XrInstance instance,
|
||||
XrInstanceProperties* instanceProperties) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProperties");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetInstanceProperties(instance, instanceProperties);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent(
|
||||
XrInstance instance,
|
||||
XrEventDataBuffer* eventData) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrPollEvent");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->PollEvent(instance, eventData);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrResultToString(
|
||||
XrInstance instance,
|
||||
XrResult value,
|
||||
char buffer[XR_MAX_RESULT_STRING_SIZE]) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrResultToString");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->ResultToString(instance, value, buffer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString(
|
||||
XrInstance instance,
|
||||
XrStructureType value,
|
||||
char buffer[XR_MAX_STRUCTURE_NAME_SIZE]) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStructureTypeToString");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->StructureTypeToString(instance, value, buffer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem(
|
||||
XrInstance instance,
|
||||
const XrSystemGetInfo* getInfo,
|
||||
XrSystemId* systemId) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetSystem");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetSystem(instance, getInfo, systemId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
XrSystemProperties* properties) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetSystemProperties");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetSystemProperties(instance, systemId, properties);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
XrViewConfigurationType viewConfigurationType,
|
||||
uint32_t environmentBlendModeCapacityInput,
|
||||
uint32_t* environmentBlendModeCountOutput,
|
||||
XrEnvironmentBlendMode* environmentBlendModes) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateEnvironmentBlendModes");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EnumerateEnvironmentBlendModes(instance, systemId, viewConfigurationType, environmentBlendModeCapacityInput, environmentBlendModeCountOutput, environmentBlendModes);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession(
|
||||
XrInstance instance,
|
||||
const XrSessionCreateInfo* createInfo,
|
||||
XrSession* session) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateSession");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->CreateSession(instance, createInfo, session);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession(
|
||||
XrSession session) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySession");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->DestroySession(session);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces(
|
||||
XrSession session,
|
||||
uint32_t spaceCapacityInput,
|
||||
uint32_t* spaceCountOutput,
|
||||
XrReferenceSpaceType* spaces) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateReferenceSpaces");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EnumerateReferenceSpaces(session, spaceCapacityInput, spaceCountOutput, spaces);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace(
|
||||
XrSession session,
|
||||
const XrReferenceSpaceCreateInfo* createInfo,
|
||||
XrSpace* space) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateReferenceSpace");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->CreateReferenceSpace(session, createInfo, space);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect(
|
||||
XrSession session,
|
||||
XrReferenceSpaceType referenceSpaceType,
|
||||
XrExtent2Df* bounds) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetReferenceSpaceBoundsRect");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetReferenceSpaceBoundsRect(session, referenceSpaceType, bounds);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace(
|
||||
XrSession session,
|
||||
const XrActionSpaceCreateInfo* createInfo,
|
||||
XrSpace* space) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateActionSpace");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->CreateActionSpace(session, createInfo, space);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace(
|
||||
XrSpace space,
|
||||
XrSpace baseSpace,
|
||||
XrTime time,
|
||||
XrSpaceLocation* location) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrLocateSpace");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->LocateSpace(space, baseSpace, time, location);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace(
|
||||
XrSpace space) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySpace");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->DestroySpace(space);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
uint32_t viewConfigurationTypeCapacityInput,
|
||||
uint32_t* viewConfigurationTypeCountOutput,
|
||||
XrViewConfigurationType* viewConfigurationTypes) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateViewConfigurations");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EnumerateViewConfigurations(instance, systemId, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput, viewConfigurationTypes);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
XrViewConfigurationType viewConfigurationType,
|
||||
XrViewConfigurationProperties* configurationProperties) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetViewConfigurationProperties");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetViewConfigurationProperties(instance, systemId, viewConfigurationType, configurationProperties);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
XrViewConfigurationType viewConfigurationType,
|
||||
uint32_t viewCapacityInput,
|
||||
uint32_t* viewCountOutput,
|
||||
XrViewConfigurationView* views) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateViewConfigurationViews");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EnumerateViewConfigurationViews(instance, systemId, viewConfigurationType, viewCapacityInput, viewCountOutput, views);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats(
|
||||
XrSession session,
|
||||
uint32_t formatCapacityInput,
|
||||
uint32_t* formatCountOutput,
|
||||
int64_t* formats) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateSwapchainFormats");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EnumerateSwapchainFormats(session, formatCapacityInput, formatCountOutput, formats);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain(
|
||||
XrSession session,
|
||||
const XrSwapchainCreateInfo* createInfo,
|
||||
XrSwapchain* swapchain) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateSwapchain");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->CreateSwapchain(session, createInfo, swapchain);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain(
|
||||
XrSwapchain swapchain) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySwapchain");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->DestroySwapchain(swapchain);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages(
|
||||
XrSwapchain swapchain,
|
||||
uint32_t imageCapacityInput,
|
||||
uint32_t* imageCountOutput,
|
||||
XrSwapchainImageBaseHeader* images) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateSwapchainImages");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EnumerateSwapchainImages(swapchain, imageCapacityInput, imageCountOutput, images);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage(
|
||||
XrSwapchain swapchain,
|
||||
const XrSwapchainImageAcquireInfo* acquireInfo,
|
||||
uint32_t* index) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrAcquireSwapchainImage");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->AcquireSwapchainImage(swapchain, acquireInfo, index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage(
|
||||
XrSwapchain swapchain,
|
||||
const XrSwapchainImageWaitInfo* waitInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrWaitSwapchainImage");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->WaitSwapchainImage(swapchain, waitInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage(
|
||||
XrSwapchain swapchain,
|
||||
const XrSwapchainImageReleaseInfo* releaseInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrReleaseSwapchainImage");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->ReleaseSwapchainImage(swapchain, releaseInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession(
|
||||
XrSession session,
|
||||
const XrSessionBeginInfo* beginInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrBeginSession");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->BeginSession(session, beginInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndSession(
|
||||
XrSession session) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEndSession");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EndSession(session);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession(
|
||||
XrSession session) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrRequestExitSession");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->RequestExitSession(session);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame(
|
||||
XrSession session,
|
||||
const XrFrameWaitInfo* frameWaitInfo,
|
||||
XrFrameState* frameState) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrWaitFrame");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->WaitFrame(session, frameWaitInfo, frameState);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame(
|
||||
XrSession session,
|
||||
const XrFrameBeginInfo* frameBeginInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrBeginFrame");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->BeginFrame(session, frameBeginInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame(
|
||||
XrSession session,
|
||||
const XrFrameEndInfo* frameEndInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEndFrame");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EndFrame(session, frameEndInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews(
|
||||
XrSession session,
|
||||
const XrViewLocateInfo* viewLocateInfo,
|
||||
XrViewState* viewState,
|
||||
uint32_t viewCapacityInput,
|
||||
uint32_t* viewCountOutput,
|
||||
XrView* views) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrLocateViews");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->LocateViews(session, viewLocateInfo, viewState, viewCapacityInput, viewCountOutput, views);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath(
|
||||
XrInstance instance,
|
||||
const char* pathString,
|
||||
XrPath* path) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStringToPath");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->StringToPath(instance, pathString, path);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPathToString(
|
||||
XrInstance instance,
|
||||
XrPath path,
|
||||
uint32_t bufferCapacityInput,
|
||||
uint32_t* bufferCountOutput,
|
||||
char* buffer) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrPathToString");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->PathToString(instance, path, bufferCapacityInput, bufferCountOutput, buffer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet(
|
||||
XrInstance instance,
|
||||
const XrActionSetCreateInfo* createInfo,
|
||||
XrActionSet* actionSet) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateActionSet");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->CreateActionSet(instance, createInfo, actionSet);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet(
|
||||
XrActionSet actionSet) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyActionSet");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->DestroyActionSet(actionSet);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction(
|
||||
XrActionSet actionSet,
|
||||
const XrActionCreateInfo* createInfo,
|
||||
XrAction* action) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateAction");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->CreateAction(actionSet, createInfo, action);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction(
|
||||
XrAction action) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyAction");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->DestroyAction(action);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings(
|
||||
XrInstance instance,
|
||||
const XrInteractionProfileSuggestedBinding* suggestedBindings) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSuggestInteractionProfileBindings");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->SuggestInteractionProfileBindings(instance, suggestedBindings);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets(
|
||||
XrSession session,
|
||||
const XrSessionActionSetsAttachInfo* attachInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrAttachSessionActionSets");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->AttachSessionActionSets(session, attachInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile(
|
||||
XrSession session,
|
||||
XrPath topLevelUserPath,
|
||||
XrInteractionProfileState* interactionProfile) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetCurrentInteractionProfile");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetCurrentInteractionProfile(session, topLevelUserPath, interactionProfile);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean(
|
||||
XrSession session,
|
||||
const XrActionStateGetInfo* getInfo,
|
||||
XrActionStateBoolean* state) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateBoolean");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetActionStateBoolean(session, getInfo, state);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat(
|
||||
XrSession session,
|
||||
const XrActionStateGetInfo* getInfo,
|
||||
XrActionStateFloat* state) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateFloat");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetActionStateFloat(session, getInfo, state);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f(
|
||||
XrSession session,
|
||||
const XrActionStateGetInfo* getInfo,
|
||||
XrActionStateVector2f* state) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateVector2f");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetActionStateVector2f(session, getInfo, state);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose(
|
||||
XrSession session,
|
||||
const XrActionStateGetInfo* getInfo,
|
||||
XrActionStatePose* state) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStatePose");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetActionStatePose(session, getInfo, state);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions(
|
||||
XrSession session,
|
||||
const XrActionsSyncInfo* syncInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSyncActions");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->SyncActions(session, syncInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction(
|
||||
XrSession session,
|
||||
const XrBoundSourcesForActionEnumerateInfo* enumerateInfo,
|
||||
uint32_t sourceCapacityInput,
|
||||
uint32_t* sourceCountOutput,
|
||||
XrPath* sources) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateBoundSourcesForAction");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->EnumerateBoundSourcesForAction(session, enumerateInfo, sourceCapacityInput, sourceCountOutput, sources);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName(
|
||||
XrSession session,
|
||||
const XrInputSourceLocalizedNameGetInfo* getInfo,
|
||||
uint32_t bufferCapacityInput,
|
||||
uint32_t* bufferCountOutput,
|
||||
char* buffer) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInputSourceLocalizedName");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->GetInputSourceLocalizedName(session, getInfo, bufferCapacityInput, bufferCountOutput, buffer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback(
|
||||
XrSession session,
|
||||
const XrHapticActionInfo* hapticActionInfo,
|
||||
const XrHapticBaseHeader* hapticFeedback) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrApplyHapticFeedback");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->ApplyHapticFeedback(session, hapticActionInfo, hapticFeedback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback(
|
||||
XrSession session,
|
||||
const XrHapticActionInfo* hapticActionInfo) XRLOADER_ABI_TRY {
|
||||
LoaderInstance* loader_instance;
|
||||
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStopHapticFeedback");
|
||||
if (XR_SUCCEEDED(result)) {
|
||||
result = loader_instance->DispatchTable()->StopHapticFeedback(session, hapticActionInfo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
XRLOADER_ABI_CATCH_FALLBACK
|
||||
|
||||
|
||||
252
thirdparty/openxr/src/loader/xr_generated_loader.hpp
vendored
Normal file
252
thirdparty/openxr/src/loader/xr_generated_loader.hpp
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
|
||||
// See loader_source_generator.py for modifications
|
||||
// ************************************************************
|
||||
|
||||
// Copyright (c) 2017-2022, The Khronos Group Inc.
|
||||
// Copyright (c) 2017-2019 Valve Corporation
|
||||
// Copyright (c) 2017-2019 LunarG, Inc.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Author: Mark Young <marky@lunarg.com>
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
#include "xr_dependencies.h"
|
||||
#include "openxr/openxr.h"
|
||||
#include "openxr/openxr_platform.h"
|
||||
|
||||
#include "loader_interfaces.h"
|
||||
|
||||
#include "loader_instance.hpp"
|
||||
|
||||
#include "loader_platform.hpp"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Loader manually generated function prototypes
|
||||
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties(
|
||||
XrInstance instance,
|
||||
XrInstanceProperties* instanceProperties);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent(
|
||||
XrInstance instance,
|
||||
XrEventDataBuffer* eventData);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrResultToString(
|
||||
XrInstance instance,
|
||||
XrResult value,
|
||||
char buffer[XR_MAX_RESULT_STRING_SIZE]);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString(
|
||||
XrInstance instance,
|
||||
XrStructureType value,
|
||||
char buffer[XR_MAX_STRUCTURE_NAME_SIZE]);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem(
|
||||
XrInstance instance,
|
||||
const XrSystemGetInfo* getInfo,
|
||||
XrSystemId* systemId);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
XrSystemProperties* properties);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
XrViewConfigurationType viewConfigurationType,
|
||||
uint32_t environmentBlendModeCapacityInput,
|
||||
uint32_t* environmentBlendModeCountOutput,
|
||||
XrEnvironmentBlendMode* environmentBlendModes);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession(
|
||||
XrInstance instance,
|
||||
const XrSessionCreateInfo* createInfo,
|
||||
XrSession* session);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession(
|
||||
XrSession session);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces(
|
||||
XrSession session,
|
||||
uint32_t spaceCapacityInput,
|
||||
uint32_t* spaceCountOutput,
|
||||
XrReferenceSpaceType* spaces);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace(
|
||||
XrSession session,
|
||||
const XrReferenceSpaceCreateInfo* createInfo,
|
||||
XrSpace* space);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect(
|
||||
XrSession session,
|
||||
XrReferenceSpaceType referenceSpaceType,
|
||||
XrExtent2Df* bounds);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace(
|
||||
XrSession session,
|
||||
const XrActionSpaceCreateInfo* createInfo,
|
||||
XrSpace* space);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace(
|
||||
XrSpace space,
|
||||
XrSpace baseSpace,
|
||||
XrTime time,
|
||||
XrSpaceLocation* location);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace(
|
||||
XrSpace space);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
uint32_t viewConfigurationTypeCapacityInput,
|
||||
uint32_t* viewConfigurationTypeCountOutput,
|
||||
XrViewConfigurationType* viewConfigurationTypes);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
XrViewConfigurationType viewConfigurationType,
|
||||
XrViewConfigurationProperties* configurationProperties);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews(
|
||||
XrInstance instance,
|
||||
XrSystemId systemId,
|
||||
XrViewConfigurationType viewConfigurationType,
|
||||
uint32_t viewCapacityInput,
|
||||
uint32_t* viewCountOutput,
|
||||
XrViewConfigurationView* views);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats(
|
||||
XrSession session,
|
||||
uint32_t formatCapacityInput,
|
||||
uint32_t* formatCountOutput,
|
||||
int64_t* formats);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain(
|
||||
XrSession session,
|
||||
const XrSwapchainCreateInfo* createInfo,
|
||||
XrSwapchain* swapchain);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain(
|
||||
XrSwapchain swapchain);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages(
|
||||
XrSwapchain swapchain,
|
||||
uint32_t imageCapacityInput,
|
||||
uint32_t* imageCountOutput,
|
||||
XrSwapchainImageBaseHeader* images);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage(
|
||||
XrSwapchain swapchain,
|
||||
const XrSwapchainImageAcquireInfo* acquireInfo,
|
||||
uint32_t* index);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage(
|
||||
XrSwapchain swapchain,
|
||||
const XrSwapchainImageWaitInfo* waitInfo);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage(
|
||||
XrSwapchain swapchain,
|
||||
const XrSwapchainImageReleaseInfo* releaseInfo);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession(
|
||||
XrSession session,
|
||||
const XrSessionBeginInfo* beginInfo);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndSession(
|
||||
XrSession session);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession(
|
||||
XrSession session);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame(
|
||||
XrSession session,
|
||||
const XrFrameWaitInfo* frameWaitInfo,
|
||||
XrFrameState* frameState);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame(
|
||||
XrSession session,
|
||||
const XrFrameBeginInfo* frameBeginInfo);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame(
|
||||
XrSession session,
|
||||
const XrFrameEndInfo* frameEndInfo);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews(
|
||||
XrSession session,
|
||||
const XrViewLocateInfo* viewLocateInfo,
|
||||
XrViewState* viewState,
|
||||
uint32_t viewCapacityInput,
|
||||
uint32_t* viewCountOutput,
|
||||
XrView* views);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath(
|
||||
XrInstance instance,
|
||||
const char* pathString,
|
||||
XrPath* path);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPathToString(
|
||||
XrInstance instance,
|
||||
XrPath path,
|
||||
uint32_t bufferCapacityInput,
|
||||
uint32_t* bufferCountOutput,
|
||||
char* buffer);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet(
|
||||
XrInstance instance,
|
||||
const XrActionSetCreateInfo* createInfo,
|
||||
XrActionSet* actionSet);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet(
|
||||
XrActionSet actionSet);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction(
|
||||
XrActionSet actionSet,
|
||||
const XrActionCreateInfo* createInfo,
|
||||
XrAction* action);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction(
|
||||
XrAction action);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings(
|
||||
XrInstance instance,
|
||||
const XrInteractionProfileSuggestedBinding* suggestedBindings);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets(
|
||||
XrSession session,
|
||||
const XrSessionActionSetsAttachInfo* attachInfo);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile(
|
||||
XrSession session,
|
||||
XrPath topLevelUserPath,
|
||||
XrInteractionProfileState* interactionProfile);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean(
|
||||
XrSession session,
|
||||
const XrActionStateGetInfo* getInfo,
|
||||
XrActionStateBoolean* state);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat(
|
||||
XrSession session,
|
||||
const XrActionStateGetInfo* getInfo,
|
||||
XrActionStateFloat* state);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f(
|
||||
XrSession session,
|
||||
const XrActionStateGetInfo* getInfo,
|
||||
XrActionStateVector2f* state);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose(
|
||||
XrSession session,
|
||||
const XrActionStateGetInfo* getInfo,
|
||||
XrActionStatePose* state);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions(
|
||||
XrSession session,
|
||||
const XrActionsSyncInfo* syncInfo);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction(
|
||||
XrSession session,
|
||||
const XrBoundSourcesForActionEnumerateInfo* enumerateInfo,
|
||||
uint32_t sourceCapacityInput,
|
||||
uint32_t* sourceCountOutput,
|
||||
XrPath* sources);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName(
|
||||
XrSession session,
|
||||
const XrInputSourceLocalizedNameGetInfo* getInfo,
|
||||
uint32_t bufferCapacityInput,
|
||||
uint32_t* bufferCountOutput,
|
||||
char* buffer);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback(
|
||||
XrSession session,
|
||||
const XrHapticActionInfo* hapticActionInfo,
|
||||
const XrHapticBaseHeader* hapticFeedback);
|
||||
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback(
|
||||
XrSession session,
|
||||
const XrHapticActionInfo* hapticActionInfo);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user