1// Copyright (c) 2017-2023, The Khronos Group Inc.
2// Copyright (c) 2017-2019 Valve Corporation
3// Copyright (c) 2017-2019 LunarG, Inc.
4// Copyright (c) 2019 Collabora, Ltd.
5//
6// SPDX-License-Identifier: Apache-2.0 OR MIT
7//
8// Initial Authors: Mark Young <marky@lunarg.com>, Ryan Pavlik <ryan.pavlik@collabora.com
9//
10/*!
11 * @file
12 *
13 * The core of an XR_EXT_debug_utils implementation, used/shared by the loader and several SDK layers.
14 */
15
16#pragma once
17
18#include "hex_and_handles.h"
19
20#include <openxr/openxr.h>
21
22#include <memory>
23#include <string>
24#include <unordered_map>
25#include <vector>
26
27struct XrSdkGenericObject {
28 //! Type-erased handle value
29 uint64_t handle;
30
31 //! Kind of object this handle refers to
32 XrObjectType type;
33 /// Un-erase the type of the handle and get it properly typed again.
34 ///
35 /// Note: Does not check the type before doing it!
36 template <typename HandleType>
37 HandleType& GetTypedHandle() {
38 return TreatIntegerAsHandle<HandleType&>(handle);
39 }
40
41 //! @overload
42 template <typename HandleType>
43 HandleType const& GetTypedHandle() const {
44 return TreatIntegerAsHandle<HandleType&>(handle);
45 }
46
47 //! Create from a typed handle and object type
48 template <typename T>
49 XrSdkGenericObject(T h, XrObjectType t) : handle(MakeHandleGeneric(h)), type(t) {}
50
51 //! Create from an untyped handle value (integer) and object type
52 XrSdkGenericObject(uint64_t h, XrObjectType t) : handle(h), type(t) {}
53};
54
55struct XrSdkLogObjectInfo {
56 //! Type-erased handle value
57 uint64_t handle;
58
59 //! Kind of object this handle refers to
60 XrObjectType type;
61
62 //! To be assigned by the application - not part of this object's identity
63 std::string name;
64
65 /// Un-erase the type of the handle and get it properly typed again.
66 ///
67 /// Note: Does not check the type before doing it!
68 template <typename HandleType>
69 HandleType& GetTypedHandle() {
70 return TreatIntegerAsHandle<HandleType&>(handle);
71 }
72
73 //! @overload
74 template <typename HandleType>
75 HandleType const& GetTypedHandle() const {
76 return TreatIntegerAsHandle<HandleType&>(handle);
77 }
78
79 XrSdkLogObjectInfo() = default;
80
81 //! Create from a typed handle and object type
82 template <typename T>
83 XrSdkLogObjectInfo(T h, XrObjectType t) : handle(MakeHandleGeneric(h)), type(t) {}
84
85 //! Create from an untyped handle value (integer) and object type
86 XrSdkLogObjectInfo(uint64_t h, XrObjectType t) : handle(h), type(t) {}
87 //! Create from an untyped handle value (integer), object type, and name
88 XrSdkLogObjectInfo(uint64_t h, XrObjectType t, const char* n) : handle(h), type(t), name(n == nullptr ? "" : n) {}
89
90 std::string ToString() const;
91};
92
93//! True if the two object infos have the same handle value and handle type
94static inline bool Equivalent(XrSdkLogObjectInfo const& a, XrSdkLogObjectInfo const& b) {
95 return a.handle == b.handle && a.type == b.type;
96}
97
98//! @overload
99static inline bool Equivalent(XrDebugUtilsObjectNameInfoEXT const& a, XrSdkLogObjectInfo const& b) {
100 return a.objectHandle == b.handle && a.objectType == b.type;
101}
102
103//! @overload
104static inline bool Equivalent(XrSdkLogObjectInfo const& a, XrDebugUtilsObjectNameInfoEXT const& b) { return Equivalent(b, a); }
105
106/// Object info registered with calls to xrSetDebugUtilsObjectNameEXT
107class ObjectInfoCollection {
108 public:
109 void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
110
111 void RemoveObject(uint64_t object_handle, XrObjectType object_type);
112
113 //! Find the stored object info, if any, matching handle and type.
114 //! Return nullptr if not found.
115 XrSdkLogObjectInfo const* LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info) const;
116
117 //! Find the stored object info, if any, matching handle and type.
118 //! Return nullptr if not found.
119 XrSdkLogObjectInfo* LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info);
120
121 //! Find the stored object info, if any.
122 //! Return nullptr if not found.
123 XrSdkLogObjectInfo const* LookUpStoredObjectInfo(uint64_t handle, XrObjectType type) const {
124 return LookUpStoredObjectInfo({handle, type});
125 }
126
127 //! Find the object name, if any, and update debug utils info accordingly.
128 //! Return true if found and updated.
129 bool LookUpObjectName(XrDebugUtilsObjectNameInfoEXT& info) const;
130
131 //! Find the object name, if any, and update logging info accordingly.
132 //! Return true if found and updated.
133 bool LookUpObjectName(XrSdkLogObjectInfo& info) const;
134
135 //! Is the collection empty?
136 bool Empty() const { return object_info_.empty(); }
137
138 private:
139 // Object names that have been set for given objects
140 std::vector<XrSdkLogObjectInfo> object_info_;
141};
142
143struct XrSdkSessionLabel;
144using XrSdkSessionLabelPtr = std::unique_ptr<XrSdkSessionLabel>;
145using XrSdkSessionLabelList = std::vector<XrSdkSessionLabelPtr>;
146
147struct XrSdkSessionLabel {
148 static XrSdkSessionLabelPtr make(const XrDebugUtilsLabelEXT& label_info, bool individual);
149
150 std::string label_name;
151 XrDebugUtilsLabelEXT debug_utils_label;
152 bool is_individual_label;
153
154 private:
155 XrSdkSessionLabel(const XrDebugUtilsLabelEXT& label_info, bool individual);
156};
157
158/// The metadata for a collection of objects. Must persist unmodified during the entire debug messenger call!
159struct NamesAndLabels {
160 NamesAndLabels() = default;
161 NamesAndLabels(std::vector<XrSdkLogObjectInfo> obj, std::vector<XrDebugUtilsLabelEXT> lab);
162 /// C++ structure owning the data (strings) backing the objects vector.
163 std::vector<XrSdkLogObjectInfo> sdk_objects;
164
165 std::vector<XrDebugUtilsObjectNameInfoEXT> objects;
166 std::vector<XrDebugUtilsLabelEXT> labels;
167
168 /// Populate the debug utils callback data structure.
169 void PopulateCallbackData(XrDebugUtilsMessengerCallbackDataEXT& data) const;
170 // XrDebugUtilsMessengerCallbackDataEXT MakeCallbackData() const;
171};
172
173struct AugmentedCallbackData {
174 std::vector<XrDebugUtilsLabelEXT> labels;
175 std::vector<XrDebugUtilsObjectNameInfoEXT> new_objects;
176 XrDebugUtilsMessengerCallbackDataEXT modified_data;
177 const XrDebugUtilsMessengerCallbackDataEXT* exported_data;
178};
179
180/// Tracks all the data (handle names and session labels) required to fully augment XR_EXT_debug_utils-related calls.
181class DebugUtilsData {
182 public:
183 DebugUtilsData() = default;
184
185 DebugUtilsData(const DebugUtilsData&) = delete;
186 DebugUtilsData& operator=(const DebugUtilsData&) = delete;
187
188 bool Empty() const { return object_info_.Empty() && session_labels_.empty(); }
189
190 //! Core of implementation for xrSetDebugUtilsObjectNameEXT
191 void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
192
193 /// Core of implementation for xrSessionBeginDebugUtilsLabelRegionEXT
194 void BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT& label_info);
195
196 /// Core of implementation for xrSessionEndDebugUtilsLabelRegionEXT
197 void EndLabelRegion(XrSession session);
198
199 /// Core of implementation for xrSessionInsertDebugUtilsLabelEXT
200 void InsertLabel(XrSession session, const XrDebugUtilsLabelEXT& label_info);
201
202 /// Removes all labels associated with a session - call in xrDestroySession and xrDestroyInstance (for all child sessions)
203 void DeleteSessionLabels(XrSession session);
204
205 /// Retrieve labels for the given session, if any, and push them in reverse order on the vector.
206 void LookUpSessionLabels(XrSession session, std::vector<XrDebugUtilsLabelEXT>& labels) const;
207
208 /// Removes all data related to this object - including session labels if it's a session.
209 ///
210 /// Does not take care of handling child objects - you must do this yourself.
211 void DeleteObject(uint64_t object_handle, XrObjectType object_type);
212
213 /// Given the collection of objects, populate their names and list of labels
214 NamesAndLabels PopulateNamesAndLabels(std::vector<XrSdkLogObjectInfo> objects) const;
215
216 void WrapCallbackData(AugmentedCallbackData* aug_data,
217 const XrDebugUtilsMessengerCallbackDataEXT* provided_callback_data) const;
218
219 private:
220 void RemoveIndividualLabel(XrSdkSessionLabelList& label_vec);
221 XrSdkSessionLabelList* GetSessionLabelList(XrSession session);
222 XrSdkSessionLabelList& GetOrCreateSessionLabelList(XrSession session);
223
224 // Session labels: one vector of them per session.
225 std::unordered_map<XrSession, std::unique_ptr<XrSdkSessionLabelList>> session_labels_;
226
227 // Names for objects.
228 ObjectInfoCollection object_info_;
229};
230