diff options
Diffstat (limited to 'extern/openxr/src/loader/loader_logger.cpp')
-rw-r--r-- | extern/openxr/src/loader/loader_logger.cpp | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/extern/openxr/src/loader/loader_logger.cpp b/extern/openxr/src/loader/loader_logger.cpp new file mode 100644 index 00000000000..9e4a9bdbed4 --- /dev/null +++ b/extern/openxr/src/loader/loader_logger.cpp @@ -0,0 +1,405 @@ +// 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 "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> + +std::unique_ptr<LoaderLogger> LoaderLogger::_instance; +std::once_flag LoaderLogger::_once_flag; + +std::string XrLoaderLogObjectInfo::ToString() const { + std::ostringstream oss; + oss << Uint64ToHexString(handle); + if (!name.empty()) { + oss << " (" << name << ")"; + } + return oss.str(); +} + +bool LoaderLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT /*message_severity*/, + XrDebugUtilsMessageTypeFlagsEXT /*message_type*/, + const XrDebugUtilsMessengerCallbackDataEXT* /*callback_data*/) { + return false; +} + +void ObjectInfoCollection::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) { + // If name is empty, we should erase it + if (object_name.empty()) { + vector_remove_if_and_erase(_object_info, [=](XrLoaderLogObjectInfo const& info) { return info.handle == object_handle; }); + return; + } + // Otherwise, add it or update the name + + XrLoaderLogObjectInfo new_obj = {object_handle, object_type}; + + // If it already exists, update the name + auto lookup_info = LookUpStoredObjectInfo(new_obj); + if (lookup_info != nullptr) { + lookup_info->name = object_name; + return; + } + + // It doesn't exist, so add a new info block + new_obj.name = object_name; + _object_info.push_back(new_obj); +} + +XrLoaderLogObjectInfo const* ObjectInfoCollection::LookUpStoredObjectInfo(XrLoaderLogObjectInfo const& info) const { + auto e = _object_info.end(); + auto it = std::find_if(_object_info.begin(), e, [&](XrLoaderLogObjectInfo const& stored) { return Equivalent(stored, info); }); + if (it != e) { + return &(*it); + } + return nullptr; +} + +XrLoaderLogObjectInfo* ObjectInfoCollection::LookUpStoredObjectInfo(XrLoaderLogObjectInfo const& info) { + auto e = _object_info.end(); + auto it = std::find_if(_object_info.begin(), e, [&](XrLoaderLogObjectInfo const& stored) { return Equivalent(stored, info); }); + if (it != e) { + return &(*it); + } + return nullptr; +} + +bool ObjectInfoCollection::LookUpObjectName(XrDebugUtilsObjectNameInfoEXT& info) const { + auto info_lookup = LookUpStoredObjectInfo(info.objectHandle, info.objectType); + if (info_lookup != nullptr) { + info.objectName = info_lookup->name.c_str(); + return true; + } + return false; +} + +bool ObjectInfoCollection::LookUpObjectName(XrLoaderLogObjectInfo& info) const { + auto info_lookup = LookUpStoredObjectInfo(info); + if (info_lookup != nullptr) { + info.name = info_lookup->name; + return true; + } + 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() { + // Add an error logger by default so that we at least get errors out to std::cerr. + AddLogRecorder(MakeStdErrLoaderLogRecorder(nullptr)); + + // If the environment variable to enable loader debugging is set, then enable the + // appropriate logging out to std::cout. + char* loader_debug = PlatformUtilsGetSecureEnv("XR_LOADER_DEBUG"); + if (nullptr != loader_debug) { + std::string debug_string = loader_debug; + PlatformUtilsFreeEnv(loader_debug); + 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) { _recorders.push_back(std::move(recorder)); } + +void LoaderLogger::RemoveLogRecorder(uint64_t unique_id) { + vector_remove_if_and_erase( + _recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) { return recorder->UniqueId() == unique_id; }); +} + +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<XrLoaderLogObjectInfo>& 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(); + + std::vector<XrDebugUtilsLabelEXT> labels; + + // Copy objects into a vector we can modify and will keep around past the callback. + std::vector<XrLoaderLogObjectInfo> object_vector = objects; + for (auto& obj : object_vector) { + // Check for any names that have been associated with the objects and set them up here + _object_names.LookUpObjectName(obj); + // If this is a session, see if there are any labels associated with it for us to add + // to the callback content. + if (XR_OBJECT_TYPE_SESSION == obj.type) { + LookUpSessionLabels(obj.GetTypedHandle<XrSession>(), labels); + } + } + callback_data.objects = object_vector.empty() ? nullptr : object_vector.data(); + callback_data.object_count = static_cast<uint8_t>(object_vector.size()); + + callback_data.session_labels = labels.empty() ? nullptr : labels.data(); + callback_data.session_labels_count = static_cast<uint8_t>(labels.size()); + + 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; +} + +void LoaderLogger::LookUpSessionLabels(XrSession session, std::vector<XrDebugUtilsLabelEXT>& labels) const { + auto session_label_iterator = _session_labels.find(session); + if (session_label_iterator != _session_labels.end()) { + auto& internalSessionLabels = *session_label_iterator->second; + // Copy the debug utils labels in reverse order in the the labels vector. + std::transform(internalSessionLabels.rbegin(), internalSessionLabels.rend(), std::back_inserter(labels), + [](InternalSessionLabelPtr const& label) { return label->debug_utils_label; }); + } +} + +// 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); + + bool obj_name_found = false; + std::vector<XrDebugUtilsLabelEXT> labels; + if (!_object_names.Empty() && callback_data->objectCount > 0) { + for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) { + auto& current_obj = callback_data->objects[obj]; + auto stored_info = _object_names.LookUpStoredObjectInfo(current_obj.objectHandle, current_obj.objectType); + if (stored_info != nullptr) { + obj_name_found = true; + } + + // If this is a session, see if there are any labels associated with it for us to add + // to the callback content. + if (XR_OBJECT_TYPE_SESSION == current_obj.objectType) { + XrSession session = TreatIntegerAsHandle<XrSession>(current_obj.objectHandle); + LookUpSessionLabels(session, labels); + } + } + } + // Use unmodified ones by default. + XrDebugUtilsMessengerCallbackDataEXT const* callback_data_to_use = callback_data; + + XrDebugUtilsMessengerCallbackDataEXT new_callback_data = *callback_data; + std::vector<XrDebugUtilsObjectNameInfoEXT> new_objects; + + // If a name or a label has been found, we should update it in a new version of the callback + if (obj_name_found || !labels.empty()) { + // Copy objects + new_objects = + std::vector<XrDebugUtilsObjectNameInfoEXT>(callback_data->objects, callback_data->objects + callback_data->objectCount); + for (auto& obj : new_objects) { + // Check for any names that have been associated with the objects and set them up here + _object_names.LookUpObjectName(obj); + } + new_callback_data.objects = new_objects.data(); + new_callback_data.sessionLabelCount = static_cast<uint32_t>(labels.size()); + new_callback_data.sessionLabels = labels.empty() ? nullptr : labels.data(); + callback_data_to_use = &new_callback_data; + } + + // Loop through the recorders + 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, callback_data_to_use); + } + return exit_app; +} + +void LoaderLogger::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) { + _object_names.AddObjectName(object_handle, object_type, object_name); +} + +// We always want to remove the old individual label before we do anything else. +// So, do that in it's own method +void LoaderLogger::RemoveIndividualLabel(InternalSessionLabelList& label_vec) { + if (!label_vec.empty() && label_vec.back()->is_individual_label) { + label_vec.pop_back(); + } +} + +InternalSessionLabelList* LoaderLogger::GetSessionLabelList(XrSession session) { + auto session_label_iterator = _session_labels.find(session); + if (session_label_iterator == _session_labels.end()) { + return nullptr; + } + return session_label_iterator->second.get(); +} + +InternalSessionLabelList& LoaderLogger::GetOrCreateSessionLabelList(XrSession session) { + InternalSessionLabelList* vec_ptr = GetSessionLabelList(session); + if (vec_ptr == nullptr) { + std::unique_ptr<InternalSessionLabelList> vec(new InternalSessionLabelList); + vec_ptr = vec.get(); + _session_labels[session] = std::move(vec); + } + return *vec_ptr; +} + +void LoaderLogger::BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info) { + auto& vec = GetOrCreateSessionLabelList(session); + + // Individual labels do not stay around in the transition into a new label region + RemoveIndividualLabel(vec); + + // Start the new label region + InternalSessionLabelPtr new_session_label(new InternalSessionLabel); + 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.emplace_back(std::move(new_session_label)); +} + +void LoaderLogger::EndLabelRegion(XrSession session) { + InternalSessionLabelList* vec_ptr = GetSessionLabelList(session); + if (vec_ptr == nullptr) { + return; + } + + // Individual labels do not stay around in the transition out of label region + RemoveIndividualLabel(*vec_ptr); + + // Remove the last label region + if (!vec_ptr->empty()) { + vec_ptr->pop_back(); + } +} + +void LoaderLogger::InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info) { + //! @todo only difference from BeginLabelRegion is value of is_individual_label + auto& vec = GetOrCreateSessionLabelList(session); + + // Remove any individual layer that might already be there + RemoveIndividualLabel(vec); + + // Insert a new individual label + InternalSessionLabelPtr new_session_label(new InternalSessionLabel); + 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.emplace_back(std::move(new_session_label)); +} + +// Called during xrDestroySession. We need to delete all session related labels. +void LoaderLogger::DeleteSessionLabels(XrSession session) { + InternalSessionLabelList* vec_ptr = GetSessionLabelList(session); + if (vec_ptr == nullptr) { + return; + } + _session_labels.erase(session); +} |