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 | |
27 | struct 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 | |
55 | struct 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 |
94 | static inline bool Equivalent(XrSdkLogObjectInfo const& a, XrSdkLogObjectInfo const& b) { |
95 | return a.handle == b.handle && a.type == b.type; |
96 | } |
97 | |
98 | //! @overload |
99 | static inline bool Equivalent(XrDebugUtilsObjectNameInfoEXT const& a, XrSdkLogObjectInfo const& b) { |
100 | return a.objectHandle == b.handle && a.objectType == b.type; |
101 | } |
102 | |
103 | //! @overload |
104 | static inline bool Equivalent(XrSdkLogObjectInfo const& a, XrDebugUtilsObjectNameInfoEXT const& b) { return Equivalent(b, a); } |
105 | |
106 | /// Object info registered with calls to xrSetDebugUtilsObjectNameEXT |
107 | class 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 | |
143 | struct XrSdkSessionLabel; |
144 | using XrSdkSessionLabelPtr = std::unique_ptr<XrSdkSessionLabel>; |
145 | using XrSdkSessionLabelList = std::vector<XrSdkSessionLabelPtr>; |
146 | |
147 | struct 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! |
159 | struct 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 | |
173 | struct 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. |
181 | class 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 | |