Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/openxr/src/api_layers/core_validation.cpp')
-rw-r--r--extern/openxr/src/api_layers/core_validation.cpp932
1 files changed, 932 insertions, 0 deletions
diff --git a/extern/openxr/src/api_layers/core_validation.cpp b/extern/openxr/src/api_layers/core_validation.cpp
new file mode 100644
index 00000000000..388359a83e6
--- /dev/null
+++ b/extern/openxr/src/api_layers/core_validation.cpp
@@ -0,0 +1,932 @@
+// Copyright (c) 2017-2019 The Khronos Group Inc.
+// Copyright (c) 2017-2019 Valve Corporation
+// Copyright (c) 2017-2019 LunarG, Inc.
+//
+// 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 "api_layer_platform_defines.h"
+#include "extra_algorithms.h"
+#include "hex_and_handles.h"
+#include "loader_interfaces.h"
+#include "platform_utils.hpp"
+#include "validation_utils.h"
+#include "xr_generated_core_validation.hpp"
+#include "xr_generated_dispatch_table.h"
+
+#include <openxr/openxr.h>
+
+#include <algorithm>
+#include <cctype>
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <mutex>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define LAYER_EXPORT __attribute__((visibility("default")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define LAYER_EXPORT __attribute__((visibility("default")))
+#else
+#define LAYER_EXPORT
+#endif
+
+// Log recording information
+enum CoreValidationRecordType {
+ RECORD_NONE = 0,
+ RECORD_TEXT_COUT,
+ RECORD_TEXT_FILE,
+ RECORD_HTML_FILE,
+};
+
+struct CoreValidationRecordInfo {
+ bool initialized;
+ CoreValidationRecordType type;
+ std::string file_name;
+};
+
+static CoreValidationRecordInfo g_record_info = {};
+static std::mutex g_record_mutex = {};
+
+// HTML utilities
+bool CoreValidationWriteHtmlHeader() {
+ try {
+ std::unique_lock<std::mutex> mlock(g_record_mutex);
+ std::ofstream html_file;
+ html_file.open(g_record_info.file_name, std::ios::out);
+ html_file
+ << "<!doctype html>\n"
+ "<html>\n"
+ " <head>\n"
+ " <title>OpenXR Core Validation</title>\n"
+ " <style type='text/css'>\n"
+ " html {\n"
+ " background-color: #0b1e48;\n"
+ " background-image: url('https://vulkan.lunarg.com/img/bg-starfield.jpg');\n"
+ " background-position: center;\n"
+ " -webkit-background-size: cover;\n"
+ " -moz-background-size: cover;\n"
+ " -o-background-size: cover;\n"
+ " background-size: cover;\n"
+ " background-attachment: fixed;\n"
+ " background-repeat: no-repeat;\n"
+ " height: 100%;\n"
+ " }\n"
+ " #header {\n"
+ " z-index: -1;\n"
+ " }\n"
+ " #header>img {\n"
+ " position: absolute;\n"
+ " width: 160px;\n"
+ " margin-left: -280px;\n"
+ " top: -10px;\n"
+ " left: 50%;\n"
+ " }\n"
+ " #header>h1 {\n"
+ " font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif;\n"
+ " font-size: 48px;\n"
+ " font-weight: 200;\n"
+ " text-shadow: 4px 4px 5px #000;\n"
+ " color: #eee;\n"
+ " position: absolute;\n"
+ " width: 600px;\n"
+ " margin-left: -80px;\n"
+ " top: 8px;\n"
+ " left: 50%;\n"
+ " }\n"
+ " body {\n"
+ " font-family: Consolas, monaco, monospace;\n"
+ " font-size: 14px;\n"
+ " line-height: 20px;\n"
+ " color: #eee;\n"
+ " height: 100%;\n"
+ " margin: 0;\n"
+ " overflow: hidden;\n"
+ " }\n"
+ " #wrapper {\n"
+ " background-color: rgba(0, 0, 0, 0.7);\n"
+ " border: 1px solid #446;\n"
+ " box-shadow: 0px 0px 10px #000;\n"
+ " padding: 8px 12px;\n"
+ " display: inline-block;\n"
+ " position: absolute;\n"
+ " top: 80px;\n"
+ " bottom: 25px;\n"
+ " left: 50px;\n"
+ " right: 50px;\n"
+ " overflow: auto;\n"
+ " }\n"
+ " details>*:not(summary) {\n"
+ " margin-left: 22px;\n"
+ " }\n"
+ " summary:only-child {\n"
+ " display: block;\n"
+ " padding-left: 15px;\n"
+ " }\n"
+ " details>summary:only-child::-webkit-details-marker {\n"
+ " display: none;\n"
+ " padding-left: 15px;\n"
+ " }\n"
+ " .headervar, .generalheadertype, .warningheadertype, .errorheadertype, .debugheadertype, .headerval {\n"
+ " display: inline;\n"
+ " margin: 0 9px;\n"
+ " }\n"
+ " .var, .type, .val {\n"
+ " display: inline;\n"
+ " margin: 0 6px;\n"
+ " }\n"
+ " .warningheadertype, .type {\n"
+ " color: #dce22f;\n"
+ " }\n"
+ " .errorheadertype, .type {\n"
+ " color: #ff1616;\n"
+ " }\n"
+ " .debugheadertype, .type {\n"
+ " color: #888;\n"
+ " }\n"
+ " .generalheadertype, .type {\n"
+ " color: #acf;\n"
+ " }\n"
+ " .headerval, .val {\n"
+ " color: #afa;\n"
+ " text-align: right;\n"
+ " }\n"
+ " .thd {\n"
+ " color: #888;\n"
+ " }\n"
+ " </style>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div id='header'>\n"
+ " <img src='https://lunarg.com/wp-content/uploads/2016/02/LunarG-wReg-150.png' />\n"
+ " <h1>OpenXR Core Validation</h1>\n"
+ " </div>\n"
+ " <div id='wrapper'>\n";
+ return true;
+ } catch (...) {
+ return false;
+ }
+}
+
+bool CoreValidationWriteHtmlFooter() {
+ try {
+ std::unique_lock<std::mutex> mlock(g_record_mutex);
+ std::ofstream html_file;
+ html_file.open(g_record_info.file_name, std::ios::out | std::ios::app);
+ html_file << " </div>\n"
+ " </body>\n"
+ "</html>";
+
+ // Writing the footer means we're done.
+ if (g_record_info.initialized) {
+ g_record_info.initialized = false;
+ g_record_info.type = RECORD_NONE;
+ }
+ return true;
+ } catch (...) {
+ return false;
+ }
+}
+
+// Function to record all the core validation information
+void CoreValidLogMessage(GenValidUsageXrInstanceInfo *instance_info, const std::string &message_id,
+ GenValidUsageDebugSeverity message_severity, const std::string &command_name,
+ std::vector<GenValidUsageXrObjectInfo> objects_info, const std::string &message) {
+ if (g_record_info.initialized) {
+ std::unique_lock<std::mutex> mlock(g_record_mutex);
+
+ // Debug Utils items (in case we need them)
+ XrDebugUtilsMessageSeverityFlagsEXT debug_utils_severity = 0;
+ std::vector<XrDebugUtilsObjectNameInfoEXT> debug_utils_objects;
+ std::vector<XrDebugUtilsLabelEXT> session_labels;
+
+ std::string severity_string;
+ switch (message_severity) {
+ case VALID_USAGE_DEBUG_SEVERITY_DEBUG:
+ severity_string = "VALID_DEBUG";
+ debug_utils_severity = XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
+ break;
+ case VALID_USAGE_DEBUG_SEVERITY_INFO:
+ severity_string = "VALID_INFO";
+ debug_utils_severity = XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
+ break;
+ case VALID_USAGE_DEBUG_SEVERITY_WARNING:
+ severity_string = "VALID_WARNING";
+ debug_utils_severity = XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+ break;
+ case VALID_USAGE_DEBUG_SEVERITY_ERROR:
+ severity_string = "VALID_ERROR";
+ debug_utils_severity = XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
+ break;
+ default:
+ severity_string = "VALID_UNKNOWN";
+ break;
+ }
+
+ // If we have instance information, see if we need to log this information out to a debug messenger
+ // callback.
+ if (nullptr != instance_info) {
+ if (!objects_info.empty()) {
+ for (auto &obj : objects_info) {
+ XrDebugUtilsObjectNameInfoEXT obj_name_info = {};
+ obj_name_info.next = nullptr;
+ obj_name_info.objectType = obj.type;
+ obj_name_info.objectHandle = obj.handle;
+ // If there's a session in the list, see if it has labels
+ if (XR_OBJECT_TYPE_SESSION == obj.type) {
+ XrSession session = TreatIntegerAsHandle<XrSession>(obj.handle);
+ auto session_label_iterator = g_xr_session_labels.find(session);
+ if (session_label_iterator != g_xr_session_labels.end()) {
+ auto rev_iter = session_label_iterator->second->rbegin();
+ for (; rev_iter != session_label_iterator->second->rend(); ++rev_iter) {
+ session_labels.push_back((*rev_iter)->debug_utils_label);
+ }
+ }
+ }
+ // Loop through all object names and see if any match
+ for (auto &object_name : instance_info->object_names) {
+ if (object_name->objectType == obj.type && object_name->objectHandle == obj.handle) {
+ obj_name_info.objectName = object_name->objectName;
+ break;
+ }
+ }
+ debug_utils_objects.push_back(obj_name_info);
+ }
+ }
+ if (!instance_info->debug_messengers.empty()) {
+ // Setup our callback data once
+ XrDebugUtilsMessengerCallbackDataEXT callback_data = {};
+ callback_data.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
+ callback_data.messageId = message_id.c_str();
+ callback_data.functionName = command_name.c_str();
+ callback_data.message = message.c_str();
+ callback_data.objectCount = static_cast<uint8_t>(debug_utils_objects.size());
+ if (debug_utils_objects.empty()) {
+ callback_data.objects = nullptr;
+ } else {
+ callback_data.objects = debug_utils_objects.data();
+ }
+ callback_data.sessionLabelCount = static_cast<uint8_t>(session_labels.size());
+ if (session_labels.empty()) {
+ callback_data.sessionLabels = nullptr;
+ } else {
+ callback_data.sessionLabels = session_labels.data();
+ }
+
+ // Loop through all active messengers and give each a chance to output information
+ for (auto &debug_messenger : instance_info->debug_messengers) {
+ CoreValidationMessengerInfo *validation_messenger_info = debug_messenger.get();
+ XrDebugUtilsMessengerCreateInfoEXT *messenger_create_info = validation_messenger_info->create_info;
+ // If a callback exists, and the message is of a type this callback cares about, call it.
+ if (nullptr != messenger_create_info->userCallback &&
+ 0 != (messenger_create_info->messageSeverities & debug_utils_severity) &&
+ 0 != (messenger_create_info->messageTypes & XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)) {
+ XrBool32 ret_val = messenger_create_info->userCallback(debug_utils_severity,
+ XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
+ &callback_data, messenger_create_info->userData);
+ }
+ }
+ }
+ }
+
+ switch (g_record_info.type) {
+ case RECORD_TEXT_COUT: {
+ std::cout << "[" << severity_string << " | " << message_id << " | " << command_name << "]: " << message
+ << std::endl;
+ if (!objects_info.empty()) {
+ std::cout << " Objects:" << std::endl;
+ uint32_t count = 0;
+ for (auto object_info : objects_info) {
+ std::string object_type = GenValidUsageXrObjectTypeToString(object_info.type);
+ std::ostringstream oss_object_handle;
+ std::cout << " [" << std::to_string(count++) << "] - " << object_type << " ("
+ << Uint64ToHexString(object_info.handle) << ")";
+ std::cout << std::endl;
+ }
+ }
+ if (!session_labels.empty()) {
+ std::cout << " Session Labels:" << std::endl;
+ uint32_t count = 0;
+ for (auto session_label : session_labels) {
+ std::cout << " [" << std::to_string(count++) << "] - " << session_label.labelName << std::endl;
+ }
+ }
+ std::cout << std::flush;
+ break;
+ }
+ case RECORD_TEXT_FILE: {
+ std::ofstream text_file;
+ text_file.open(g_record_info.file_name, std::ios::out | std::ios::app);
+ text_file << "[" << severity_string << " | " << message_id << " | " << command_name << "]: " << message
+ << std::endl;
+ if (!objects_info.empty()) {
+ text_file << " Objects:" << std::endl;
+ uint32_t count = 0;
+ for (auto object_info : objects_info) {
+ std::string object_type = GenValidUsageXrObjectTypeToString(object_info.type);
+ text_file << " [" << std::to_string(count++) << "] - " << object_type << " ("
+ << Uint64ToHexString(object_info.handle) << ")";
+ text_file << std::endl;
+ }
+ }
+ if (!session_labels.empty()) {
+ text_file << " Session Labels:" << std::endl;
+ uint32_t count = 0;
+ for (auto session_label : session_labels) {
+ text_file << " [" << std::to_string(count++) << "] - " << session_label.labelName << std::endl;
+ }
+ }
+ text_file << std::flush;
+ text_file.close();
+ break;
+ }
+ case RECORD_HTML_FILE: {
+ std::ofstream text_file;
+ text_file.open(g_record_info.file_name, std::ios::out | std::ios::app);
+ text_file << "<details class='data'>\n";
+ std::string header_type = "generalheadertype";
+ switch (message_severity) {
+ case VALID_USAGE_DEBUG_SEVERITY_DEBUG:
+ header_type = "debugheadertype";
+ severity_string = "Debug Message";
+ break;
+ case VALID_USAGE_DEBUG_SEVERITY_INFO:
+ severity_string = "Info Message";
+ break;
+ case VALID_USAGE_DEBUG_SEVERITY_WARNING:
+ header_type = "warningheadertype";
+ severity_string = "Warning Message";
+ break;
+ case VALID_USAGE_DEBUG_SEVERITY_ERROR:
+ header_type = "errorheadertype";
+ severity_string = "Error Message";
+ break;
+ default:
+ severity_string = "Unknown Message";
+ break;
+ }
+ text_file << " <summary>\n"
+ << " <div class='" << header_type << "'>" << severity_string << "</div>\n"
+ << " <div class='headerval'>" << command_name << "</div>\n"
+ << " <div class='headervar'>" << message_id << "</div>\n"
+ << " </summary>\n";
+ text_file << " <div class='data'>\n";
+ text_file << " <div class='val'>" << message << "</div>\n";
+ if (!objects_info.empty()) {
+ text_file << " <details class='data'>\n";
+ text_file << " <summary>\n";
+ text_file << " <div class='type'>Relevant OpenXR Objects</div>\n";
+ text_file << " </summary>\n";
+ uint32_t count = 0;
+ for (auto object_info : objects_info) {
+ std::string object_type = GenValidUsageXrObjectTypeToString(object_info.type);
+ text_file << " <div class='data'>\n";
+ text_file << " <div class='var'>[" << count++ << "]</div>\n";
+ text_file << " <div class='type'>" << object_type << "</div>\n";
+ text_file << " <div class='val'>" << Uint64ToHexString(object_info.handle) << "</div>\n";
+ text_file << " </div>\n";
+ }
+ text_file << " </details>\n";
+ text_file << std::flush;
+ }
+ if (!session_labels.empty()) {
+ text_file << " <details class='data'>\n";
+ text_file << " <summary>\n";
+ text_file << " <div class='type'>Relevant Session Labels</div>\n";
+ text_file << " </summary>\n";
+ uint32_t count = 0;
+ for (auto session_label : session_labels) {
+ text_file << " <div class='data'>\n";
+ text_file << " <div class='var'>[" << count++ << "]</div>\n";
+ text_file << " <div class='type'>" << session_label.labelName << "</div>\n";
+ text_file << " </div>\n";
+ }
+ text_file << " </details>\n";
+ }
+ text_file << " </div>\n";
+ text_file << "</details>\n";
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void reportInternalError(std::string const &message) {
+ std::cerr << "INTERNAL VALIDATION LAYER ERROR: " << message << std::endl;
+ throw std::runtime_error("Internal validation layer error: " + message);
+}
+
+void InvalidStructureType(GenValidUsageXrInstanceInfo *instance_info, const std::string &command_name,
+ std::vector<GenValidUsageXrObjectInfo> &objects_info, const char *structure_name, XrStructureType type,
+ const char *vuid, XrStructureType expected, const char *expected_name) {
+ std::ostringstream oss_type;
+ oss_type << structure_name << " has an invalid XrStructureType ";
+ oss_type << Uint32ToHexString(static_cast<uint32_t>(type));
+ if (expected != 0) {
+ oss_type << ", expected " << Uint32ToHexString(static_cast<uint32_t>(type));
+ oss_type << " (" << expected_name << ")";
+ }
+ if (vuid != nullptr) {
+ CoreValidLogMessage(instance_info, vuid, VALID_USAGE_DEBUG_SEVERITY_ERROR, command_name, objects_info, oss_type.str());
+ } else {
+ CoreValidLogMessage(instance_info, "VUID-" + std::string(structure_name) + "-type-type", VALID_USAGE_DEBUG_SEVERITY_ERROR,
+ command_name, objects_info, oss_type.str());
+ }
+}
+
+// NOTE: Can't validate the following VUIDs since the command never enters a layer:
+// Command: xrEnumerateApiLayerProperties
+// VUIDs: "VUID-xrEnumerateApiLayerProperties-propertyCountOutput-parameter"
+// "VUID-xrEnumerateApiLayerProperties-properties-parameter"
+// Command: xrEnumerateInstanceExtensionProperties
+// VUIDs: "VUID-xrEnumerateInstanceExtensionProperties-layerName-parameter"
+// "VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter"
+// "VUID-xrEnumerateInstanceExtensionProperties-properties-parameter"
+
+XrResult CoreValidationXrCreateInstance(const XrInstanceCreateInfo * /*info*/, XrInstance * /*instance*/) {
+ // Shouldn't be called, coreValidationXrCreateApiLayerInstance should called instead
+ return XR_SUCCESS;
+}
+
+GenValidUsageXrInstanceInfo::GenValidUsageXrInstanceInfo(XrInstance inst, PFN_xrGetInstanceProcAddr next_get_instance_proc_addr)
+ : instance(inst), dispatch_table(new XrGeneratedDispatchTable()) {
+ /// @todo smart pointer here!
+
+ // Create the dispatch table to the next levels
+ GeneratedXrPopulateDispatchTable(dispatch_table, instance, next_get_instance_proc_addr);
+}
+
+GenValidUsageXrInstanceInfo::~GenValidUsageXrInstanceInfo() { delete dispatch_table; }
+
+// See if there is a debug utils create structure in the "next" chain
+
+XrResult CoreValidationXrCreateApiLayerInstance(const XrInstanceCreateInfo *info, const struct XrApiLayerCreateInfo *apiLayerInfo,
+ XrInstance *instance) {
+ try {
+ XrApiLayerCreateInfo new_api_layer_info = {};
+ XrResult validation_result = XR_SUCCESS;
+ bool user_defined_output = false;
+ bool first_time = !g_record_info.initialized;
+
+ if (!g_record_info.initialized) {
+ g_record_info.initialized = true;
+ g_record_info.type = RECORD_NONE;
+ }
+
+ char *export_type = PlatformUtilsGetEnv("XR_CORE_VALIDATION_EXPORT_TYPE");
+ char *file_name = PlatformUtilsGetEnv("XR_CORE_VALIDATION_FILE_NAME");
+ if (nullptr != file_name) {
+ g_record_info.file_name = file_name;
+ PlatformUtilsFreeEnv(file_name);
+ }
+
+ if (nullptr != export_type) {
+ std::string string_export_type = export_type;
+ PlatformUtilsFreeEnv(export_type);
+ std::transform(string_export_type.begin(), string_export_type.end(), string_export_type.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+
+ std::cerr << "Core Validation output type: " << string_export_type << ", first time = " << std::to_string(first_time)
+ << std::endl;
+ if (string_export_type == "text") {
+ if (!g_record_info.file_name.empty()) {
+ g_record_info.type = RECORD_TEXT_FILE;
+ } else {
+ g_record_info.type = RECORD_TEXT_COUT;
+ }
+ user_defined_output = true;
+ } else if (string_export_type == "html" && first_time) {
+ g_record_info.type = RECORD_HTML_FILE;
+ if (!CoreValidationWriteHtmlHeader()) {
+ return XR_ERROR_INITIALIZATION_FAILED;
+ }
+ }
+ }
+
+ // Call the generated pre valid usage check.
+ validation_result = GenValidUsageInputsXrCreateInstance(info, instance);
+
+ // Copy the contents of the layer info struct, but then move the next info up by
+ // one slot so that the next layer gets information.
+ memcpy(&new_api_layer_info, apiLayerInfo, sizeof(XrApiLayerCreateInfo));
+ new_api_layer_info.nextInfo = apiLayerInfo->nextInfo->next;
+
+ // Get the function pointers we need
+ PFN_xrGetInstanceProcAddr next_get_instance_proc_addr = apiLayerInfo->nextInfo->nextGetInstanceProcAddr;
+ PFN_xrCreateApiLayerInstance next_create_api_layer_instance = apiLayerInfo->nextInfo->nextCreateApiLayerInstance;
+
+ // Create the instance using the layer create instance command for the next layer
+ XrInstance returned_instance = *instance;
+ XrResult next_result = next_create_api_layer_instance(info, &new_api_layer_info, &returned_instance);
+ *instance = returned_instance;
+
+ // Create the instance information
+ std::unique_ptr<GenValidUsageXrInstanceInfo> instance_info(
+ new GenValidUsageXrInstanceInfo(returned_instance, next_get_instance_proc_addr));
+
+ // Save the enabled extensions.
+ for (uint32_t extension = 0; extension < info->enabledExtensionCount; ++extension) {
+ instance_info->enabled_extensions.emplace_back(info->enabledExtensionNames[extension]);
+ }
+
+ g_instance_info.insert(returned_instance, std::move(instance_info));
+
+ // See if a debug utils messenger is supposed to be created as part of the instance
+ // NOTE: We have to wait until after the instance info is added to the map for this
+ // to work properly.
+ 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) {
+ dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);
+ // Create the debug messenger. We don't have to keep track of it because it will be tracked as part
+ // of the instance info from here on out.
+ XrDebugUtilsMessengerEXT messenger;
+ validation_result = CoreValidationXrCreateDebugUtilsMessengerEXT(*instance, dbg_utils_create_info, &messenger);
+ // If we created a debug messenger, turn off the text output unless a user indicates they wanted it
+ if (XR_SUCCESS == validation_result && !user_defined_output) {
+ g_record_info.type = RECORD_NONE;
+ }
+ break;
+ }
+ next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next);
+ }
+
+ if (XR_SUCCESS == validation_result) {
+ return next_result;
+ }
+ return validation_result;
+
+ } catch (std::bad_alloc &) {
+ return XR_ERROR_OUT_OF_MEMORY;
+ } catch (...) {
+ return XR_ERROR_INITIALIZATION_FAILED;
+ }
+}
+
+void EraseAllInstanceTableMapElements(GenValidUsageXrInstanceInfo *search_value) {
+ typedef typename InstanceHandleInfo::value_t value_t;
+ auto map_with_lock = g_instance_info.lockMap();
+ auto &map = map_with_lock.second;
+
+ map_erase_if(map, [=](value_t const &data) { return data.second.get() == search_value; });
+}
+
+XrResult CoreValidationXrDestroyInstance(XrInstance instance) {
+ GenValidUsageInputsXrDestroyInstance(instance);
+ if (XR_NULL_HANDLE != instance) {
+ auto info_with_lock = g_instance_info.getWithLock(instance);
+ GenValidUsageXrInstanceInfo *gen_instance_info = info_with_lock.second;
+ if (nullptr != gen_instance_info) {
+ gen_instance_info->object_names.clear();
+ gen_instance_info->debug_messengers.clear();
+ }
+ }
+ XrResult result = GenValidUsageNextXrDestroyInstance(instance);
+ if (!g_instance_info.empty() && g_record_info.type == RECORD_HTML_FILE) {
+ CoreValidationWriteHtmlFooter();
+ }
+ return result;
+ return XR_SUCCESS;
+}
+
+XrResult CoreValidationXrCreateSession(XrInstance instance, const XrSessionCreateInfo *createInfo, XrSession *session) {
+ try {
+ XrResult test_result = GenValidUsageInputsXrCreateSession(instance, createInfo, session);
+ if (XR_SUCCESS != test_result) {
+ return test_result;
+ }
+
+ GenValidUsageXrInstanceInfo *gen_instance_info = g_instance_info.get(instance);
+
+ // Check the next chain for a graphics binding structure, we need at least one.
+ uint32_t num_graphics_bindings_found = 0;
+ const auto *cur_ptr = reinterpret_cast<const XrBaseInStructure *>(createInfo->next);
+ while (nullptr != cur_ptr) {
+ switch (cur_ptr->type) {
+ default:
+ continue;
+#ifdef XR_USE_PLATFORM_WIN32
+ case XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR:
+ num_graphics_bindings_found++;
+ break;
+#endif
+#ifdef XR_USE_PLATFORM_XLIB
+ case XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR:
+ num_graphics_bindings_found++;
+ break;
+#endif
+#ifdef XR_USE_PLATFORM_XCB
+ case XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR:
+ num_graphics_bindings_found++;
+ break;
+#endif
+#ifdef XR_USE_PLATFORM_WAYLAND
+ case XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR:
+ num_graphics_bindings_found++;
+ break;
+#endif
+ }
+ cur_ptr = reinterpret_cast<const XrBaseInStructure *>(cur_ptr->next);
+ }
+ auto const &enabled_extensions = gen_instance_info->enabled_extensions;
+#ifdef XR_KHR_headless
+ bool has_headless = (enabled_extensions.end() !=
+ std::find(enabled_extensions.begin(), enabled_extensions.end(), XR_KHR_HEADLESS_EXTENSION_NAME));
+#else
+ bool has_headless = false;
+#endif // XR_KHR_headless
+ bool got_right_graphics_binding_count = (num_graphics_bindings_found == 1);
+ if (!got_right_graphics_binding_count && has_headless) {
+ // This permits 0 as well.
+ got_right_graphics_binding_count = (num_graphics_bindings_found == 0);
+ }
+ if (!got_right_graphics_binding_count) {
+ std::vector<GenValidUsageXrObjectInfo> objects_info;
+ objects_info.emplace_back(instance, XR_OBJECT_TYPE_INSTANCE);
+ std::ostringstream error_stream;
+ error_stream << "Invalid number of graphics binding structures provided. ";
+ error_stream << "Expected ";
+ if (has_headless) {
+ error_stream << "0 or 1";
+ } else {
+ error_stream << "1";
+ }
+ error_stream << ", but received ";
+ error_stream << num_graphics_bindings_found;
+ error_stream << ".";
+ // TODO: This needs to be updated with the actual VUID once we generate it.
+ CoreValidLogMessage(gen_instance_info, "VUID-xrCreateSession-next-parameter", VALID_USAGE_DEBUG_SEVERITY_ERROR,
+ "xrCreateSession", objects_info, error_stream.str());
+ return XR_ERROR_GRAPHICS_DEVICE_INVALID;
+ }
+ return GenValidUsageNextXrCreateSession(instance, createInfo, session);
+ } catch (...) {
+ return XR_SUCCESS;
+ }
+}
+
+// ---- XR_EXT_debug_utils extension commands
+XrResult CoreValidationXrSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) {
+ try {
+ XrResult result = GenValidUsageInputsXrSetDebugUtilsObjectNameEXT(instance, nameInfo);
+ if (!XR_UNQUALIFIED_SUCCESS(result)) {
+ return result;
+ }
+ result = GenValidUsageNextXrSetDebugUtilsObjectNameEXT(instance, nameInfo);
+ if (!XR_UNQUALIFIED_SUCCESS(result)) {
+ return result;
+ }
+ auto info_with_lock = g_instance_info.getWithLock(instance);
+ GenValidUsageXrInstanceInfo *gen_instance_info = info_with_lock.second;
+ if (nullptr != gen_instance_info) {
+ // Create a copy of the base object name info (no next items)
+ auto len = strlen(nameInfo->objectName);
+ char *name_string = new char[len + 1];
+ strncpy(name_string, nameInfo->objectName, len);
+ bool found = false;
+ for (auto &object_name : gen_instance_info->object_names) {
+ if (object_name->objectHandle == nameInfo->objectHandle && object_name->objectType == nameInfo->objectType) {
+ delete[] object_name->objectName;
+ object_name->objectName = name_string;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ UniqueXrDebugUtilsObjectNameInfoEXT new_object_name(new XrDebugUtilsObjectNameInfoEXT(*nameInfo));
+ new_object_name->next = nullptr;
+ new_object_name->objectName = name_string;
+ gen_instance_info->object_names.push_back(std::move(new_object_name));
+ }
+ }
+ return result;
+ } catch (...) {
+ return XR_ERROR_VALIDATION_FAILURE;
+ }
+}
+
+XrResult CoreValidationXrCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
+ XrDebugUtilsMessengerEXT *messenger) {
+ try {
+ XrResult result = GenValidUsageInputsXrCreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
+ if (!XR_UNQUALIFIED_SUCCESS(result)) {
+ return result;
+ }
+ result = GenValidUsageNextXrCreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
+ if (!XR_UNQUALIFIED_SUCCESS(result)) {
+ return result;
+ }
+ auto info_with_lock = g_instance_info.getWithLock(instance);
+ GenValidUsageXrInstanceInfo *gen_instance_info = info_with_lock.second;
+ if (nullptr != gen_instance_info) {
+ auto *new_create_info = new XrDebugUtilsMessengerCreateInfoEXT(*createInfo);
+ new_create_info->next = nullptr;
+ UniqueCoreValidationMessengerInfo new_messenger_info(new CoreValidationMessengerInfo);
+ new_messenger_info->messenger = *messenger;
+ new_messenger_info->create_info = new_create_info;
+ gen_instance_info->debug_messengers.push_back(std::move(new_messenger_info));
+ }
+ return result;
+ } catch (...) {
+ return XR_ERROR_VALIDATION_FAILURE;
+ }
+}
+
+XrResult CoreValidationXrDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) {
+ try {
+ XrResult result = GenValidUsageInputsXrDestroyDebugUtilsMessengerEXT(messenger);
+ if (!XR_UNQUALIFIED_SUCCESS(result)) {
+ return result;
+ }
+ result = GenValidUsageNextXrDestroyDebugUtilsMessengerEXT(messenger);
+ if (!XR_UNQUALIFIED_SUCCESS(result)) {
+ return result;
+ }
+ if (XR_NULL_HANDLE == messenger) {
+ return XR_ERROR_HANDLE_INVALID;
+ }
+ auto info_with_lock = g_debugutilsmessengerext_info.getWithLock(messenger);
+ GenValidUsageXrHandleInfo *gen_handle_info = info_with_lock.second;
+ if (nullptr != gen_handle_info) {
+ auto &debug_messengers = gen_handle_info->instance_info->debug_messengers;
+ vector_remove_if_and_erase(debug_messengers,
+ [=](UniqueCoreValidationMessengerInfo const &msg) { return msg->messenger == messenger; });
+ }
+ return result;
+ } catch (...) {
+ return XR_ERROR_VALIDATION_FAILURE;
+ }
+}
+
+// We always want to remove the old individual label before we do anything else.
+// So, do that in it's own method
+void CoreValidationRemoveIndividualLabel(std::vector<GenValidUsageXrInternalSessionLabel *> *label_vec) {
+ if (!label_vec->empty()) {
+ GenValidUsageXrInternalSessionLabel *cur_label = label_vec->back();
+ if (cur_label->is_individual_label) {
+ label_vec->pop_back();
+ delete cur_label;
+ }
+ }
+}
+
+void CoreValidationBeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT *label_info) {
+ std::vector<GenValidUsageXrInternalSessionLabel *> *vec_ptr = nullptr;
+ auto session_label_iterator = g_xr_session_labels.find(session);
+ if (session_label_iterator == g_xr_session_labels.end()) {
+ vec_ptr = new std::vector<GenValidUsageXrInternalSessionLabel *>;
+ g_xr_session_labels[session] = vec_ptr;
+ } else {
+ vec_ptr = session_label_iterator->second;
+ }
+
+ // Individual labels do not stay around in the transition into a new label region
+ CoreValidationRemoveIndividualLabel(vec_ptr);
+
+ // Start the new label region
+ auto *new_session_label = new GenValidUsageXrInternalSessionLabel;
+ new_session_label->label_name = label_info->labelName;
+ new_session_label->debug_utils_label = *label_info;
+ new_session_label->debug_utils_label.labelName = new_session_label->label_name.c_str();
+ new_session_label->is_individual_label = false;
+ vec_ptr->push_back(new_session_label);
+}
+
+void CoreValidationEndLabelRegion(XrSession session) {
+ auto session_label_iterator = g_xr_session_labels.find(session);
+ if (session_label_iterator == g_xr_session_labels.end()) {
+ return;
+ }
+
+ std::vector<GenValidUsageXrInternalSessionLabel *> *vec_ptr = session_label_iterator->second;
+
+ // Individual labels do not stay around in the transition out of label region
+ CoreValidationRemoveIndividualLabel(vec_ptr);
+
+ // Remove the last label region
+ if (!vec_ptr->empty()) {
+ GenValidUsageXrInternalSessionLabel *cur_label = vec_ptr->back();
+ vec_ptr->pop_back();
+ delete cur_label;
+ }
+}
+
+void CoreValidationInsertLabel(XrSession session, const XrDebugUtilsLabelEXT *label_info) {
+ std::vector<GenValidUsageXrInternalSessionLabel *> *vec_ptr = nullptr;
+ auto session_label_iterator = g_xr_session_labels.find(session);
+ if (session_label_iterator == g_xr_session_labels.end()) {
+ vec_ptr = new std::vector<GenValidUsageXrInternalSessionLabel *>;
+ g_xr_session_labels[session] = vec_ptr;
+ } else {
+ vec_ptr = session_label_iterator->second;
+ }
+
+ // Remove any individual layer that might already be there
+ CoreValidationRemoveIndividualLabel(vec_ptr);
+
+ // Insert a new individual label
+ auto *new_session_label = new GenValidUsageXrInternalSessionLabel;
+ new_session_label->label_name = label_info->labelName;
+ new_session_label->debug_utils_label = *label_info;
+ new_session_label->debug_utils_label.labelName = new_session_label->label_name.c_str();
+ new_session_label->is_individual_label = true;
+ vec_ptr->push_back(new_session_label);
+}
+
+// Called during xrDestroySession. We need to delete all session related labels.
+void CoreValidationDeleteSessionLabels(XrSession session) {
+ std::vector<GenValidUsageXrInternalSessionLabel *> *vec_ptr = nullptr;
+ auto session_label_iterator = g_xr_session_labels.find(session);
+ if (session_label_iterator == g_xr_session_labels.end()) {
+ return;
+ }
+ vec_ptr = session_label_iterator->second;
+ while (!vec_ptr->empty()) {
+ delete vec_ptr->back();
+ vec_ptr->pop_back();
+ }
+ delete vec_ptr;
+ g_xr_session_labels.erase(session);
+}
+
+XrResult CoreValidationXrSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) {
+ XrResult test_result = GenValidUsageInputsXrSessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);
+ if (XR_SUCCESS != test_result) {
+ return test_result;
+ }
+ CoreValidationBeginLabelRegion(session, labelInfo);
+ return GenValidUsageNextXrSessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);
+}
+
+XrResult CoreValidationXrSessionEndDebugUtilsLabelRegionEXT(XrSession session) {
+ XrResult test_result = GenValidUsageInputsXrSessionEndDebugUtilsLabelRegionEXT(session);
+ if (XR_SUCCESS != test_result) {
+ return test_result;
+ }
+ CoreValidationEndLabelRegion(session);
+ return GenValidUsageNextXrSessionEndDebugUtilsLabelRegionEXT(session);
+}
+
+XrResult CoreValidationXrSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) {
+ XrResult test_result = GenValidUsageInputsXrSessionInsertDebugUtilsLabelEXT(session, labelInfo);
+ if (XR_SUCCESS != test_result) {
+ return test_result;
+ }
+ CoreValidationInsertLabel(session, labelInfo);
+ return GenValidUsageNextXrSessionInsertDebugUtilsLabelEXT(session, labelInfo);
+}
+
+// ############################################################
+// NOTE: Add new validation checking above this comment block
+// ############################################################
+
+extern "C" {
+
+// Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or
+// more API layers needs to expose at least this function.
+LAYER_EXPORT XrResult xrNegotiateLoaderApiLayerInterface(const XrNegotiateLoaderInfo *loaderInfo, const char * /*apiLayerName*/,
+ XrNegotiateApiLayerRequest *apiLayerRequest) {
+ if (nullptr == loaderInfo || nullptr == apiLayerRequest || loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO ||
+ loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION || loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo) ||
+ apiLayerRequest->structType != XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST ||
+ apiLayerRequest->structVersion != XR_API_LAYER_INFO_STRUCT_VERSION ||
+ apiLayerRequest->structSize != sizeof(XrNegotiateApiLayerRequest) ||
+ loaderInfo->minInterfaceVersion > XR_CURRENT_LOADER_API_LAYER_VERSION ||
+ loaderInfo->maxInterfaceVersion < XR_CURRENT_LOADER_API_LAYER_VERSION ||
+ loaderInfo->maxInterfaceVersion > XR_CURRENT_LOADER_API_LAYER_VERSION ||
+ loaderInfo->maxApiVersion < XR_CORE_VALIDATION_API_VERSION || loaderInfo->minApiVersion > XR_CORE_VALIDATION_API_VERSION) {
+ return XR_ERROR_INITIALIZATION_FAILED;
+ }
+
+ apiLayerRequest->layerInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;
+ apiLayerRequest->layerApiVersion = XR_CORE_VALIDATION_API_VERSION;
+ apiLayerRequest->getInstanceProcAddr = reinterpret_cast<PFN_xrGetInstanceProcAddr>(GenValidUsageXrGetInstanceProcAddr);
+ apiLayerRequest->createApiLayerInstance =
+ reinterpret_cast<PFN_xrCreateApiLayerInstance>(CoreValidationXrCreateApiLayerInstance);
+
+ return XR_SUCCESS;
+}
+
+} // extern "C"