1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Debug.h: Defines debug state used for GL_KHR_debug
8
9 #ifndef LIBANGLE_DEBUG_H_
10 #define LIBANGLE_DEBUG_H_
11
12 #include "angle_gl.h"
13 #include "common/PackedEnums.h"
14 #include "common/SimpleMutex.h"
15 #include "common/angleutils.h"
16 #include "libANGLE/AttributeMap.h"
17 #include "libANGLE/Error.h"
18
19 #include <atomic>
20 #include <deque>
21 #include <string>
22 #include <vector>
23
24 namespace gl
25 {
26 class Context;
27
28 class LabeledObject
29 {
30 public:
~LabeledObject()31 virtual ~LabeledObject() {}
32 virtual angle::Result setLabel(const Context *context, const std::string &label) = 0;
33 virtual const std::string &getLabel() const = 0;
34 };
35
36 class Debug : angle::NonCopyable
37 {
38 public:
39 Debug(bool initialDebugState);
40 ~Debug();
41
42 void setMaxLoggedMessages(GLuint maxLoggedMessages);
43
44 void setOutputEnabled(bool enabled);
45 bool isOutputEnabled() const;
46
47 void setOutputSynchronous(bool synchronous);
48 bool isOutputSynchronous() const;
49
50 void setCallback(GLDEBUGPROCKHR callback, const void *userParam);
51 GLDEBUGPROCKHR getCallback() const;
52 const void *getUserParam() const;
53
54 void insertMessage(GLenum source,
55 GLenum type,
56 GLuint id,
57 GLenum severity,
58 const std::string &message,
59 gl::LogSeverity logSeverity,
60 angle::EntryPoint entryPoint) const;
61 void insertMessage(GLenum source,
62 GLenum type,
63 GLuint id,
64 GLenum severity,
65 std::string &&message,
66 gl::LogSeverity logSeverity,
67 angle::EntryPoint entryPoint) const;
68
69 void setMessageControl(GLenum source,
70 GLenum type,
71 GLenum severity,
72 std::vector<GLuint> &&ids,
73 bool enabled);
74 size_t getMessages(GLuint count,
75 GLsizei bufSize,
76 GLenum *sources,
77 GLenum *types,
78 GLuint *ids,
79 GLenum *severities,
80 GLsizei *lengths,
81 GLchar *messageLog);
82 size_t getNextMessageLength() const;
83 size_t getMessageCount() const;
84
85 void pushGroup(GLenum source, GLuint id, std::string &&message);
86 void popGroup();
87 size_t getGroupStackDepth() const;
88
89 // Helper for ANGLE_PERF_WARNING
90 void insertPerfWarning(GLenum severity, bool isLastRepeat, const char *message) const;
91
92 private:
93 bool isMessageEnabled(GLenum source, GLenum type, GLuint id, GLenum severity) const;
94
95 void pushDefaultGroup();
96
97 struct Message
98 {
99 GLenum source;
100 GLenum type;
101 GLuint id;
102 GLenum severity;
103 std::string message;
104 };
105
106 struct Control
107 {
108 Control();
109 ~Control();
110 Control(const Control &other);
111
112 GLenum source;
113 GLenum type;
114 GLenum severity;
115 std::vector<GLuint> ids;
116 bool enabled;
117 };
118
119 struct Group
120 {
121 Group();
122 ~Group();
123 Group(const Group &other);
124
125 GLenum source;
126 GLuint id;
127 std::string message;
128
129 std::vector<Control> controls;
130 };
131
132 bool mOutputEnabled;
133 mutable angle::SimpleMutex mMutex;
134 GLDEBUGPROCKHR mCallbackFunction;
135 const void *mCallbackUserParam;
136 mutable std::deque<Message> mMessages;
137 GLuint mMaxLoggedMessages;
138 bool mOutputSynchronous;
139 std::vector<Group> mGroups;
140 };
141 } // namespace gl
142
143 namespace egl
144 {
145 class LabeledObject
146 {
147 public:
~LabeledObject()148 virtual ~LabeledObject() {}
149 virtual void setLabel(EGLLabelKHR label) = 0;
150 virtual EGLLabelKHR getLabel() const = 0;
151 };
152
153 class Debug : angle::NonCopyable
154 {
155 public:
156 Debug();
157
158 void setCallback(EGLDEBUGPROCKHR callback, const AttributeMap &attribs);
159 EGLDEBUGPROCKHR getCallback() const;
160 bool isMessageTypeEnabled(MessageType type) const;
161
162 void insertMessage(EGLenum error,
163 const char *command,
164 MessageType messageType,
165 EGLLabelKHR threadLabel,
166 EGLLabelKHR objectLabel,
167 const std::string &message) const;
168
169 private:
170 EGLDEBUGPROCKHR mCallback;
171 angle::PackedEnumBitSet<MessageType> mEnabledMessageTypes;
172 };
173 } // namespace egl
174
175 namespace
176 {
PerfCounterBelowMaxRepeat(std::atomic<uint32_t> * counter,bool * isLastRepeat)177 ANGLE_INLINE bool PerfCounterBelowMaxRepeat(std::atomic<uint32_t> *counter, bool *isLastRepeat)
178 {
179 constexpr uint32_t kMaxPerfRepeat = 4;
180 // Stop incrementing the counter after max value to avoid unnecessary cache effects
181 if (counter->load(std::memory_order_relaxed) < kMaxPerfRepeat)
182 {
183 uint32_t count = counter->fetch_add(1, std::memory_order_relaxed);
184 // Check not strictly necessary as worst case is an additional log, but is good practice.
185 if (count < kMaxPerfRepeat)
186 {
187 if (count == kMaxPerfRepeat - 1)
188 {
189 *isLastRepeat = true;
190 }
191 return true;
192 }
193 }
194 return false;
195 }
196 } // namespace
197
198 // Generate a perf warning. Only outputs the same message a few times to avoid spamming the logs.
199 #define ANGLE_PERF_WARNING(debug, severity, ...) \
200 do \
201 { \
202 static std::atomic<uint32_t> sRepeatCount = 0; \
203 bool isLastRepeat = false; \
204 if (PerfCounterBelowMaxRepeat(&sRepeatCount, &isLastRepeat)) \
205 { \
206 char ANGLE_MESSAGE[200]; \
207 snprintf(ANGLE_MESSAGE, sizeof(ANGLE_MESSAGE), __VA_ARGS__); \
208 (debug).insertPerfWarning(severity, isLastRepeat, ANGLE_MESSAGE); \
209 } \
210 } while (0)
211
212 #endif // LIBANGLE_DEBUG_H_
213