Merge "Clean up the code to build successfully on macOS" into devel/master
[platform/core/uifw/dali-core.git] / dali / integration-api / debug.h
1 #ifndef DALI_INTEGRATION_DEBUG_H
2 #define DALI_INTEGRATION_DEBUG_H
3
4 /*
5  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <stdint.h>
23 #include <iostream>
24 #include <list>
25 #include <sstream>
26 #include <string>
27
28 #include <dali/public-api/common/vector-wrapper.h>
29 #include <dali/public-api/object/property-map.h>
30
31 // INTERNAL INCLUDES
32 #include <dali/public-api/common/dali-common.h>
33
34 // Using Debug namespace alias shortens the log usage significantly
35 namespace Dali
36 {
37 namespace Integration
38 {
39 namespace Log
40 {
41 }
42 } // namespace Integration
43 } // namespace Dali
44 namespace Debug = Dali::Integration::Log;
45
46 namespace Dali
47 {
48 struct Vector2;
49 struct Vector3;
50 struct Vector4;
51 class Matrix3;
52 class Matrix;
53 class Quaternion;
54
55 #if defined(DEBUG_ENABLED)
56
57 // Less opaque types for debugger
58 typedef std::vector<Dali::Property::Value> DebugPropertyValueArray;
59 using DebugIndexValuePair       = std::pair<Property::Index, Property::Value>;
60 using DebugStringValueContainer = std::vector<Dali::StringValuePair>;
61 using DebugIndexValueContainer  = std::vector<DebugIndexValuePair>;
62
63 struct DebugPropertyValueMap
64 {
65   DebugStringValueContainer stringValues;
66   DebugIndexValueContainer  intValues;
67 };
68
69 // Fake globals for gdb typedefs
70 extern Dali::DebugPropertyValueArray gValueArray;
71 extern Dali::DebugPropertyValueMap   gValueMap;
72
73 #endif
74
75 namespace Integration
76 {
77 namespace Log
78 {
79 enum DebugPriority
80 {
81   DebugInfo,
82   DebugWarning,
83   DebugError
84 };
85
86 /**
87  * Used by logging macros to log a message along with function/class name
88  * @param level debug level
89  * @param format string format
90  */
91 DALI_CORE_API void LogMessage(enum DebugPriority level, const char* format, ...);
92
93 /**
94  * typedef for the logging function.
95  */
96 using LogFunction = void (*)(DebugPriority, std::string&);
97
98 /**
99  * A log function has to be installed for every thread that wants to use logging.
100  * This should be done by the adaptor.
101  * The log function can be different for each thread.
102  * @param logFunction the log function to install
103  * @param logOpts the log options to save in thread
104  */
105 DALI_CORE_API void InstallLogFunction(const LogFunction& logFunction);
106
107 /**
108  * A log function has to be uninstalled for every thread that wants to use logging.
109  * The log function can be different for each thread.
110  */
111 DALI_CORE_API void UninstallLogFunction();
112
113 /********************************************************************************
114  *                            Error/Warning  macros.                            *
115  ********************************************************************************/
116
117 /**
118  * Provides unfiltered logging for global error level messages
119  */
120 #define DALI_LOG_ERROR(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugError, "%s " format, __FUNCTION__, ##__VA_ARGS__)
121
122 #define DALI_LOG_ERROR_NOFN(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugError, format, ##__VA_ARGS__)
123
124 #define DALI_LOG_WARNING_NOFN(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugWarning, format, ##__VA_ARGS__)
125
126 /**
127  * Provides unfiltered logging for fps monitor
128  */
129 #define DALI_LOG_FPS(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, format, ##__VA_ARGS__)
130
131 /**
132  * Provides unfiltered logging for update status
133  */
134 #define DALI_LOG_UPDATE_STATUS(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, format, ##__VA_ARGS__)
135
136 /**
137  * Provides unfiltered logging for render information
138  */
139 #define DALI_LOG_RENDER_INFO(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, format, ##__VA_ARGS__)
140
141 /**
142  * Provides unfiltered logging for release
143  */
144 #define DALI_LOG_RELEASE_INFO(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, format, ##__VA_ARGS__)
145
146 #ifdef DEBUG_ENABLED
147
148 /**
149  * Provides unfiltered logging for global warning level messages
150  */
151 #define DALI_LOG_WARNING(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugWarning, "%s " format, ASSERT_LOCATION, ##__VA_ARGS__)
152
153 #else // DEBUG_ENABLED
154
155 // Don't warn on release build
156 #define DALI_LOG_WARNING(format, ...)
157
158 #endif
159
160 /********************************************************************************
161  *                                    Filter                                    *
162  ********************************************************************************/
163
164 #ifdef DEBUG_ENABLED
165
166 /**
167  * Enumeration of logging levels.
168  * Used by the filters to provide multiple log levels.
169  * In general, the higher the value, the more debug is available for that filter.
170  */
171 enum LogLevel
172 {
173   NoLogging = 0,
174   Concise   = 1,
175   General   = 2,
176   Verbose   = 3
177 };
178
179 /**
180  * The Filter object is used by the DALI_LOG_INFO macro and others to determine if the logging
181  * should take place, and routes the logging via the platform abstraction's LogMessage.
182  *
183  * It provides a logging level. If this is set to zero, then DALI_LOG_INFO won't log anything.
184  * It provides the ability to turn tracing on or off.
185  *
186  */
187 class DALI_CORE_API Filter
188 {
189 public:
190   using FilterList = std::list<Filter*>;
191   using FilterIter = std::list<Filter*>::iterator;
192
193 public:
194   /**
195    * Test if the filter is enabled for the given logging level
196    * @param[in] level - the level to test.
197    * @return true if this level of logging is enabled.
198    */
199   bool IsEnabledFor(LogLevel level)
200   {
201     return level != Debug::NoLogging && level <= mLoggingLevel;
202   }
203
204   /**
205    * Test if trace is enabled for this filter.
206    * @return true if trace is enabled;
207    */
208   bool IsTraceEnabled()
209   {
210     return mTraceEnabled;
211   }
212
213   /**
214    * Enable tracing on this filter.
215    */
216   void EnableTrace()
217   {
218     mTraceEnabled = true;
219   }
220
221   /**
222    * Disable tracing on this filter.
223    */
224   void DisableTrace()
225   {
226     mTraceEnabled = false;
227   }
228
229   /**
230    * Set the log level for this filter. Setting to a higher value than Debug::General also
231    * enables General;
232    */
233   void SetLogLevel(LogLevel level)
234   {
235     mLoggingLevel = level;
236   }
237
238   /**
239    * Perform the logging for this filter.
240    */
241   void Log(LogLevel level, const char* format, ...);
242
243   /**
244    * Create a new filter whose debug level and trace can be modified through the use of an
245    * environment variable.
246    *
247    * @param[in] level The default log level
248    * @param[in] trace The default trace level. If true, function tracing is on.
249    * @param[in] environmentVariableName The environment variable name used in order to change the
250    *                                    log level or trace.
251    *
252    * @info To modify logg level/trace at runtime, you can should define your filter as shown below:
253    *
254    * @code
255    * Debug::Filter* filter = Debug::Filter::New( Debug::NoLogging, false, "FILTER_ENV" );
256    * @endcode
257    *
258    * And to use it when running an executable:
259    * @code
260    * FILTER_ENV=3 dali-demo        // LogLevel Verbose,   Trace using default
261    * FILTER_ENV=1,true dali-demo   // LogLevel Concise,   Trace ON
262    * FILTER_ENV=2,false dali-demo  // LogLevel General,   Trace OFF
263    * FILTER_ENV=0,true dali-demo   // LogLevel NoLogging, Trace ON
264    * @endcode
265    */
266   static Filter* New(LogLevel level, bool trace, const char* environmentVariableName);
267
268   /**
269    * Enable trace on all filters.
270    */
271   static void EnableGlobalTrace();
272
273   /**
274    * Disable trace on all filters.
275    */
276   static void DisableGlobalTrace();
277
278   /**
279    * Set log level for all filters.
280    *
281    * @param[in] level The log level
282    */
283   static void SetGlobalLogLevel(LogLevel level);
284
285 private:
286   /**
287    * Constructor.
288    * @param[in] level - the highest log level.
289    * @param[in] trace - whether this filter allows tracing.
290    */
291   Filter(LogLevel level, bool trace)
292   : mLoggingLevel(level),
293     mTraceEnabled(trace),
294     mNesting(0)
295   {
296   }
297
298   static FilterList* GetActiveFilters();
299
300 public:
301   // High level filters. If these filters are too broad for your current requirement, then
302   // you can add a filter to your own class or source file. If you do, use Filter::New()
303   // to tell this class about it.
304
305   static Filter* gRender;
306   static Filter* gResource;
307   static Filter* gGLResource;
308   static Filter* gObject;
309   static Filter* gImage;
310   static Filter* gModel;
311   static Filter* gNode;
312   static Filter* gElement;
313   static Filter* gActor;
314   static Filter* gShader;
315
316 private:
317   LogLevel mLoggingLevel;
318   bool     mTraceEnabled;
319
320 public:
321   int mNesting;
322 };
323
324 #define DALI_LOG_FILTER_SET_LEVEL(filter, level) filter->SetLogLevel(level)
325 #define DALI_LOG_FILTER_ENABLE_TRACE(filter) filter->EnableTrace()
326 #define DALI_LOG_FILTER_DISABLE_TRACE(filter) filter->DisableTrace()
327
328 #else
329
330 #define DALI_LOG_FILTER_SET_LEVEL(filter, level)
331 #define DALI_LOG_FILTER_ENABLE_TRACE(filter)
332 #define DALI_LOG_FILTER_DISABLE_TRACE(filter)
333
334 #endif
335
336 /********************************************************************************
337  *                            General Logging macros                            *
338  ********************************************************************************/
339
340 #ifdef DEBUG_ENABLED
341
342 #define DALI_LOG_INFO(filter, level, format, ...) \
343   if(filter && filter->IsEnabledFor(level))       \
344   {                                               \
345     filter->Log(level, format, ##__VA_ARGS__);    \
346   }
347
348 #define DALI_LOG_STREAM(filter, level, stream) \
349   if(filter && filter->IsEnabledFor(level))    \
350   {                                            \
351     std::ostringstream o;                      \
352     o << stream << std::endl;                  \
353     filter->Log(level, "%s", o.str().c_str()); \
354   }
355
356 #else // DEBUG_ENABLED
357
358 #define DALI_LOG_INFO(filter, level, format, ...)
359 #define DALI_LOG_STREAM(filter, level, stream)
360
361 #endif // DEBUG_ENABLED
362
363 /********************************************************************************
364  *                                  Trace Macros                                *
365  ********************************************************************************/
366
367 /*
368  * These macros allow the instrumentation of methods. These translate into calls
369  * to LogMessage(DebugInfo).
370  */
371
372 #ifdef DEBUG_ENABLED
373
374 class DALI_CORE_API TraceObj
375 {
376 public:
377   TraceObj(Filter* filter, const char* fmt, ...);
378   ~TraceObj();
379
380 public:
381   std::string mMessage;
382   Filter*     mFilter;
383 };
384
385 #define DALI_LOG_TRACE_METHOD_FMT(filter, format, ...) \
386   Dali::Integration::Log::TraceObj debugTraceObj(filter, "%s: " format, ASSERT_LOCATION, ##__VA_ARGS__)
387
388 #define DALI_LOG_TRACE_METHOD(filter) \
389   Dali::Integration::Log::TraceObj debugTraceObj(filter, ASSERT_LOCATION)
390
391 #else // DEBUG_ENABLED
392
393 #define DALI_LOG_TRACE_METHOD_FMT(filter, format, ...)
394 #define DALI_LOG_TRACE_METHOD(filter)
395
396 #endif
397
398 /********************************************************************************
399  *                              Extra object debug                              *
400  ********************************************************************************/
401
402 #ifdef DEBUG_ENABLED
403
404 /**
405  * Warning, this macro changes the current scope, so should usually be put at the
406  * end of the class definition.
407  *
408  * Suggest that the value is usually set to the object's name.
409  * Warning - this will increase the size of the object for a debug build.
410  */
411 #define DALI_LOG_OBJECT_STRING_DECLARATION \
412 public:                                    \
413   std::string mDebugString;
414
415 /**
416  * Print all the actor tree names
417  **/
418 #define DALI_LOG_ACTOR_TREE(node)                                  \
419   {                                                                \
420     std::stringstream branch;                                      \
421     Node*             tempNode = node;                             \
422     while(tempNode)                                                \
423     {                                                              \
424       branch << "<" << tempNode->mDebugString << ">::";            \
425       tempNode = tempNode->GetParent();                            \
426     }                                                              \
427     DALI_LOG_ERROR_NOFN("Actor tree: %s\n", branch.str().c_str()); \
428   }
429
430 /**
431  * Allows one object to set another object's debug string
432  */
433 #define DALI_LOG_SET_OBJECT_STRING(object, string) (object->mDebugString = string)
434
435 /**
436  * Allows one object to set another object's std::string easily
437  */
438 #define DALI_LOG_FMT_OBJECT_STRING(object, fmt, ...) (object->mDebugString = FormatToString(fmt, ##__VA_ARGS__))
439
440 /**
441  * Allows one object to get another object's debug string
442  */
443 #define DALI_LOG_GET_OBJECT_STRING(object) (object->mDebugString)
444
445 /**
446  * Get the C string (for use in formatted logging)
447  */
448 #define DALI_LOG_GET_OBJECT_C_STR(object) (object->mDebugString.c_str())
449
450 /**
451  * Filtered logging of the object's debug string
452  */
453 #define DALI_LOG_OBJECT(filter, object) DALI_LOG_INFO(filter, Debug::General, object->mDebugString)
454
455 #else // DEBUG_ENABLED
456
457 #define DALI_LOG_OBJECT_STRING_DECLARATION
458 #define DALI_LOG_ACTOR_TREE(node)
459 #define DALI_LOG_SET_OBJECT_STRING(object, string)
460 #define DALI_LOG_FMT_OBJECT_STRING(object, fmt, ...)
461 #define DALI_LOG_GET_OBJECT_STRING(object)
462 #define DALI_LOG_GET_OBJECT_C_STR(object) ""
463 #define DALI_LOG_OBJECT(filter, object)
464
465 #endif
466
467 /********************************************************************************
468  *                            Time instrumentation                              *
469  ********************************************************************************/
470 #if defined(DEBUG_ENABLED)
471
472  /**
473   * @brief Get the monotonic time since the clock's epoch.
474   *
475   * @param[out]  timeInNanoseconds  The time in nanoseconds since the reference point.
476   *
477   * @note The maximum value timeInNanoseconds can hold is 0xFFFFFFFFFFFFFFFF which is 1.844674407e+19. Therefore, this can overflow after approximately 584 years.
478   */
479 void GetNanoseconds(uint64_t& timeInNanoseconds);
480
481 #define DALI_LOG_TIMER_START(timeVariable) \
482   uint64_t timeVariable##1;                \
483   Debug::GetNanoseconds(timeVariable##1);
484
485 #define DALI_LOG_TIMER_END(timeVariable, filter, level, preString) \
486   uint64_t timeVariable##2;                                        \
487   Debug::GetNanoseconds(timeVariable##2);                          \
488   DALI_LOG_INFO(filter, level, preString " %ld uSec\n", ((timeVariable##2 - timeVariable##1) / 1000));
489
490 #else // DEBUG_ENABLED
491
492 #define DALI_LOG_TIMER_START(timeVariable)
493 #define DALI_LOG_TIMER_END(timeVariable, filter, level, preString)
494
495 #endif
496
497 } // namespace Log
498 } // namespace Integration
499 } // namespace Dali
500
501 #endif // DALI_INTEGRATION_DEBUG_H