use modern construct 'nullptr' instead of 'NULL' or '0'
[platform/core/uifw/dali-core.git] / dali / integration-api / debug.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/integration-api/debug.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstdio>
23 #include <cstdarg>
24 #include <cstring>
25 #include <cstdlib>
26 #include <sstream>
27 #include <iomanip>
28 #include <ctime>
29
30 // INTERNAL INCLUDES
31 #include <dali/public-api/common/constants.h>
32 #include <dali/public-api/math/matrix3.h>
33 #include <dali/public-api/math/matrix.h>
34 #include <dali/public-api/math/vector3.h>
35 #include <dali/public-api/math/vector4.h>
36 #include <dali/public-api/math/quaternion.h>
37 #include <dali/internal/event/common/thread-local-storage.h>
38
39 namespace Dali
40 {
41
42 #ifdef DEBUG_ENABLED
43
44 // Fake globals for gdb typedefs
45 Dali::DebugPropertyValueArray gValueArray;
46 Dali::DebugPropertyValueMap   gValueMap;
47
48 #endif
49
50
51 namespace // unnamed namespace
52 {
53
54 const uint64_t NANOSECONDS_PER_SECOND = 1e+9;
55
56 }
57
58 namespace Integration
59 {
60
61 namespace Log
62 {
63
64 thread_local LogFunction gthreadLocalLogFunction = nullptr;
65
66 /* Forward declarations */
67 std::string FormatToString(const char *format, ...);
68 std::string ArgListToString(const char *format, va_list args);
69
70 void LogMessage(DebugPriority priority, const char* format, ...)
71 {
72   if ( !gthreadLocalLogFunction )
73   {
74     return;
75   }
76
77   va_list arg;
78   va_start(arg, format);
79   std::string message = ArgListToString(format, arg);
80   va_end(arg);
81
82   gthreadLocalLogFunction(priority,message);
83 }
84
85 void InstallLogFunction(const LogFunction& logFunction)
86 {
87   // TLS stores a pointer to an object.
88   // It needs to be allocated on the heap, because TLS will destroy it when the thread exits.
89
90   gthreadLocalLogFunction = logFunction;
91 }
92
93 void UninstallLogFunction()
94 {
95   gthreadLocalLogFunction = nullptr;
96 }
97
98 #ifdef DEBUG_ENABLED
99
100 /*Change false to true if trace is needed but don't commit to codeline*/
101 Filter* Filter::gRender     = Filter::New(Debug::Concise, false, "LOG_RENDER");
102 Filter* Filter::gResource   = Filter::New(Debug::Concise, false, "LOG_RESOURCE");
103 Filter* Filter::gGLResource = Filter::New(Debug::Concise, false, "LOG_GL_RESOURCE");
104 Filter* Filter::gObject     = nullptr;
105 Filter* Filter::gImage      = Filter::New(Debug::Concise, false, "LOG_IMAGE");
106 Filter* Filter::gModel      = Filter::New(Debug::Concise, false, "LOG_MODEL");
107 Filter* Filter::gNode       = nullptr;
108 Filter* Filter::gElement    = nullptr;
109 Filter* Filter::gActor      = Filter::New(Debug::Concise, false, "LOG_ACTOR");
110 Filter* Filter::gShader     = Filter::New(Debug::Concise, false, "LOG_SHADER");
111
112 Filter::FilterList* Filter::GetActiveFilters()
113 {
114   static Filter::FilterList* activeFilters = new FilterList;
115   return activeFilters;
116 }
117
118 Filter* Filter::New( LogLevel level, bool trace, const char * environmentVariableName )
119 {
120   char * environmentVariableValue = getenv( environmentVariableName );
121   if ( environmentVariableValue )
122   {
123     unsigned int envLevel(0);
124     char envTraceString(0);
125     sscanf( environmentVariableValue, "%u,%c", &envLevel, &envTraceString );
126
127     if ( envLevel > Verbose )
128     {
129       envLevel = Verbose;
130     }
131     level = LogLevel( envLevel );
132
133     // Just use 'f' and 't' as it's faster than doing full string comparisons
134     if ( envTraceString == 't' )
135     {
136       trace = true;
137     }
138     else if ( envTraceString == 'f' )
139     {
140       trace = false;
141     }
142   }
143
144   Filter* filter = new Filter(level, trace);
145   filter->mNesting++;
146   GetActiveFilters()->push_back(filter);
147   return filter;
148 }
149
150 /**
151  * Enable trace on all filters.
152  */
153 void Filter::EnableGlobalTrace()
154 {
155   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
156   {
157     (*iter)->EnableTrace();
158   }
159 }
160
161 /**
162  * Disable trace on all filters.
163  */
164 void Filter::DisableGlobalTrace()
165 {
166   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
167   {
168     (*iter)->DisableTrace();
169   }
170 }
171
172 void Filter::SetGlobalLogLevel( LogLevel level )
173 {
174   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
175   {
176     (*iter)->SetLogLevel( level );
177   }
178 }
179
180 void Filter::Log(LogLevel level, const char* format, ...)
181 {
182   if(level <= mLoggingLevel)
183   {
184     va_list arg;
185     va_start(arg, format);
186
187     if( mTraceEnabled )
188     {
189       char *buffer = nullptr;
190       int numChars = asprintf( &buffer, "    %-*c %s", mNesting, ':', format );
191       if( numChars >= 0 ) // No error
192       {
193         std::string message = ArgListToString( buffer, arg );
194         LogMessage( DebugInfo, message.c_str() );
195         free( buffer );
196       }
197     }
198     else
199     {
200       std::string message = ArgListToString( format, arg );
201       LogMessage( DebugInfo, message.c_str() );
202     }
203     va_end(arg);
204   }
205 }
206
207
208 TraceObj::TraceObj(Filter* filter, const char*format, ...) : mFilter(filter)
209 {
210   if(mFilter && mFilter->IsTraceEnabled())
211   {
212     va_list arg;
213     va_start(arg, format);
214     mMessage = ArgListToString(format, arg);
215     va_end(arg);
216
217     LogMessage(DebugInfo, "Entr%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
218     ++mFilter->mNesting;
219   }
220 }
221
222 TraceObj::~TraceObj()
223 {
224   if(mFilter && mFilter->IsTraceEnabled())
225   {
226     if (mFilter->mNesting)
227     {
228       --mFilter->mNesting;
229     }
230     LogMessage(DebugInfo, "Exit%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
231   }
232 }
233
234 #endif // DEBUG_ENABLED
235
236 std::string ArgListToString(const char *format, va_list args)
237 {
238   std::string str; // empty string
239   if(format != nullptr)
240   {
241     char* buffer = nullptr;
242     int err = vasprintf(&buffer, format, args);
243     if(err >= 0) // No error
244     {
245       str = buffer;
246       free(buffer);
247     }
248   }
249   return str;
250 }
251
252 std::string FormatToString(const char *format, ...)
253 {
254   va_list arg;
255   va_start(arg, format);
256   std::string s = ArgListToString(format, arg);
257   va_end(arg);
258   return s;
259 }
260
261 void GetNanoseconds( uint64_t& timeInNanoseconds )
262 {
263   timespec timeSpec;
264   clock_gettime( CLOCK_MONOTONIC, &timeSpec );
265
266   // Convert all values to uint64_t to match our return type
267   timeInNanoseconds = ( static_cast< uint64_t >( timeSpec.tv_sec ) * NANOSECONDS_PER_SECOND ) + static_cast< uint64_t >( timeSpec.tv_nsec );
268 }
269
270 } // namespace Log
271
272 } // namespace Integration
273
274 } // namespace Dali