1// Copyright (c) 2017-2023, The Khronos Group Inc.
2// Copyright (c) 2017-2019 Valve Corporation
3// Copyright (c) 2017-2019 LunarG, Inc.
4//
5// SPDX-License-Identifier: Apache-2.0 OR MIT
6//
7// Initial Author: Mark Young <marky@lunarg.com>
8//
9
10#pragma once
11
12#include <memory>
13#include <mutex>
14#include <string>
15#include <unordered_map>
16#include <unordered_set>
17#include <vector>
18#include <set>
19#include <map>
20#include <shared_mutex>
21
22#include <openxr/openxr.h>
23
24#include "hex_and_handles.h"
25#include "object_info.h"
26
27// Use internal versions of flags similar to XR_EXT_debug_utils so that
28// we're not tightly coupled to that extension. This way, if the extension
29// changes or gets replaced, we can be flexible in the loader.
30#define XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT 0x00000001
31#define XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT 0x00000010
32#define XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT 0x00000100
33#define XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT 0x00001000
34#define XR_LOADER_LOG_MESSAGE_SEVERITY_DEFAULT_BITS 0x00000000
35typedef XrFlags64 XrLoaderLogMessageSeverityFlagBits;
36typedef XrFlags64 XrLoaderLogMessageSeverityFlags;
37
38#define XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT 0x00000001
39#define XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT 0x00000002
40#define XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT 0x00000004
41#define XR_LOADER_LOG_MESSAGE_TYPE_DEFAULT_BITS 0xffffffff
42typedef XrFlags64 XrLoaderLogMessageTypeFlagBits;
43typedef XrFlags64 XrLoaderLogMessageTypeFlags;
44
45struct XrLoaderLogMessengerCallbackData {
46 const char* message_id;
47 const char* command_name;
48 const char* message;
49 uint8_t object_count;
50 XrSdkLogObjectInfo* objects;
51 uint8_t session_labels_count;
52 XrDebugUtilsLabelEXT* session_labels;
53};
54
55enum XrLoaderLogType {
56 XR_LOADER_LOG_UNKNOWN = 0,
57 XR_LOADER_LOG_STDERR,
58 XR_LOADER_LOG_STDOUT,
59 XR_LOADER_LOG_DEBUG_UTILS,
60 XR_LOADER_LOG_DEBUGGER,
61 XR_LOADER_LOG_LOGCAT,
62};
63
64class LoaderLogRecorder {
65 public:
66 LoaderLogRecorder(XrLoaderLogType type, void* user_data, XrLoaderLogMessageSeverityFlags message_severities,
67 XrLoaderLogMessageTypeFlags message_types) {
68 _active = false;
69 _user_data = user_data;
70 _type = type;
71 _unique_id = 0;
72 _message_severities = message_severities;
73 _message_types = message_types;
74 }
75 virtual ~LoaderLogRecorder() = default;
76
77 XrLoaderLogType Type() { return _type; }
78
79 uint64_t UniqueId() { return _unique_id; }
80
81 XrLoaderLogMessageSeverityFlags MessageSeverities() { return _message_severities; }
82
83 XrLoaderLogMessageTypeFlags MessageTypes() { return _message_types; }
84
85 virtual void Start() { _active = true; }
86
87 bool IsPaused() { return _active; }
88
89 virtual void Pause() { _active = false; }
90
91 virtual void Resume() { _active = true; }
92
93 virtual void Stop() { _active = false; }
94
95 virtual bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
96 const XrLoaderLogMessengerCallbackData* callback_data) = 0;
97
98 // Extension-specific logging functions - defaults to do nothing.
99 virtual bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
100 XrDebugUtilsMessageTypeFlagsEXT message_type,
101 const XrDebugUtilsMessengerCallbackDataEXT* callback_data);
102
103 protected:
104 bool _active;
105 XrLoaderLogType _type;
106 uint64_t _unique_id;
107 void* _user_data;
108 XrLoaderLogMessageSeverityFlags _message_severities;
109 XrLoaderLogMessageTypeFlags _message_types;
110};
111
112class LoaderLogger {
113 public:
114 static LoaderLogger& GetInstance() {
115 static LoaderLogger instance;
116 return instance;
117 }
118
119 void AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder);
120 void RemoveLogRecorder(uint64_t unique_id);
121
122 void AddLogRecorderForXrInstance(XrInstance instance, std::unique_ptr<LoaderLogRecorder>&& recorder);
123 void RemoveLogRecordersForXrInstance(XrInstance instance);
124
125 //! Called from LoaderXrTermSetDebugUtilsObjectNameEXT - an empty name means remove
126 void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
127 void BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info);
128 void EndLabelRegion(XrSession session);
129 void InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info);
130 void DeleteSessionLabels(XrSession session);
131
132 bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
133 const std::string& message_id, const std::string& command_name, const std::string& message,
134 const std::vector<XrSdkLogObjectInfo>& objects = {});
135 static bool LogErrorMessage(const std::string& command_name, const std::string& message,
136 const std::vector<XrSdkLogObjectInfo>& objects = {}) {
137 return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
138 "OpenXR-Loader", command_name, message, objects);
139 }
140 static bool LogWarningMessage(const std::string& command_name, const std::string& message,
141 const std::vector<XrSdkLogObjectInfo>& objects = {}) {
142 return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
143 "OpenXR-Loader", command_name, message, objects);
144 }
145 static bool LogInfoMessage(const std::string& command_name, const std::string& message,
146 const std::vector<XrSdkLogObjectInfo>& objects = {}) {
147 return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
148 "OpenXR-Loader", command_name, message, objects);
149 }
150 static bool LogVerboseMessage(const std::string& command_name, const std::string& message,
151 const std::vector<XrSdkLogObjectInfo>& objects = {}) {
152 return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
153 "OpenXR-Loader", command_name, message, objects);
154 }
155 static bool LogValidationErrorMessage(const std::string& vuid, const std::string& command_name, const std::string& message,
156 const std::vector<XrSdkLogObjectInfo>& objects = {}) {
157 return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT,
158 vuid, command_name, message, objects);
159 }
160 static bool LogValidationWarningMessage(const std::string& vuid, const std::string& command_name, const std::string& message,
161 const std::vector<XrSdkLogObjectInfo>& objects = {}) {
162 return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT,
163 vuid, command_name, message, objects);
164 }
165
166 // Extension-specific logging functions
167 bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type,
168 const XrDebugUtilsMessengerCallbackDataEXT* callback_data);
169
170 // Non-copyable
171 LoaderLogger(const LoaderLogger&) = delete;
172 LoaderLogger& operator=(const LoaderLogger&) = delete;
173
174 private:
175 LoaderLogger();
176
177 std::shared_timed_mutex _mutex;
178
179 // List of *all* available recorder objects (including created specifically for an Instance)
180 std::vector<std::unique_ptr<LoaderLogRecorder>> _recorders;
181
182 // List of recorder objects only created specifically for an XrInstance
183 std::unordered_map<XrInstance, std::unordered_set<uint64_t>> _recordersByInstance;
184
185 DebugUtilsData data_;
186};
187
188// Utility functions for converting to/from XR_EXT_debug_utils values
189XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities(
190 XrDebugUtilsMessageSeverityFlagsEXT utils_severities);
191XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities(
192 XrLoaderLogMessageSeverityFlags log_severities);
193XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types);
194XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types);
195