[dali_1.2.53] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / integration-api / debug.cpp
1 /*
2  * Copyright (c) 2017 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  * Generic function to print out any 2-Dimensional array
58  * @param[in] data pointer to the source data stored as float[rows][cols]
59  * @param[in] rows number of rows in 2D array
60  * @param[in] cols number of columns in 2D array
61  * @param[in] precision - the precision to write the float data.
62  * @param[in] indent - the indent level to use.
63  * @return string - the text representation of the 2D array
64  */
65 std::string Array2DToString(const float *data, unsigned int rows, unsigned int cols, size_t precision, size_t indent)
66 {
67   std::ostringstream oss;
68
69   std::ios_base::fmtflags mask = oss.flags();
70   mask &= ~std::ios_base::scientific;
71   mask |=  std::ios_base::fixed;
72
73   for(unsigned int rowIdx = 0; rowIdx < rows; rowIdx++)
74   {
75     oss  << std::setw(indent) << std::setfill(' ') << ' ' << "[ ";
76     oss  << std::setfill(' ') << std::setprecision(precision) << std::right << std::setiosflags(mask);
77
78     for(unsigned int colIdx = 0; colIdx < cols; colIdx++)
79     {
80       oss << std::setw(precision + 6) << (*data++) << ' ';
81     }
82
83     oss << ']' << std::endl;
84   }
85
86   return oss.str();
87 }
88
89 }
90
91 namespace Integration
92 {
93
94 namespace Log
95 {
96
97 thread_local LogFunction gthreadLocalLogFunction = NULL;
98
99 /* Forward declarations */
100 std::string FormatToString(const char *format, ...);
101 std::string ArgListToString(const char *format, va_list args);
102
103 void LogMessage(DebugPriority priority, const char* format, ...)
104 {
105   if ( !gthreadLocalLogFunction )
106   {
107     return;
108   }
109
110   va_list arg;
111   va_start(arg, format);
112   std::string message = ArgListToString(format, arg);
113   va_end(arg);
114
115   gthreadLocalLogFunction(priority,message);
116 }
117
118 void InstallLogFunction(const LogFunction& logFunction)
119 {
120   // TLS stores a pointer to an object.
121   // It needs to be allocated on the heap, because TLS will destroy it when the thread exits.
122
123   gthreadLocalLogFunction = logFunction;
124 }
125
126 void UninstallLogFunction()
127 {
128   gthreadLocalLogFunction = NULL;
129 }
130
131 #ifdef DEBUG_ENABLED
132
133 /*Change false to true if trace is needed but don't commit to codeline*/
134 Filter* Filter::gRender     = Filter::New(Debug::Concise, false, "LOG_RENDER");
135 Filter* Filter::gResource   = Filter::New(Debug::Concise, false, "LOG_RESOURCE");
136 Filter* Filter::gGLResource = Filter::New(Debug::Concise, false, "LOG_GL_RESOURCE");
137 Filter* Filter::gObject     = NULL;
138 Filter* Filter::gImage      = Filter::New(Debug::Concise, false, "LOG_IMAGE");
139 Filter* Filter::gModel      = Filter::New(Debug::Concise, false, "LOG_MODEL");
140 Filter* Filter::gNode       = NULL;
141 Filter* Filter::gElement    = NULL;
142 Filter* Filter::gActor      = Filter::New(Debug::Concise, false, "LOG_ACTOR");
143 Filter* Filter::gShader     = Filter::New(Debug::Concise, false, "LOG_SHADER");
144
145 Filter::FilterList* Filter::GetActiveFilters()
146 {
147   static Filter::FilterList* activeFilters = new FilterList;
148   return activeFilters;
149 }
150
151 Filter* Filter::New( LogLevel level, bool trace, const char * environmentVariableName )
152 {
153   char * environmentVariableValue = getenv( environmentVariableName );
154   if ( environmentVariableValue )
155   {
156     unsigned int envLevel(0);
157     char envTraceString(0);
158     sscanf( environmentVariableValue, "%u,%c", &envLevel, &envTraceString );
159
160     if ( envLevel > Verbose )
161     {
162       envLevel = Verbose;
163     }
164     level = LogLevel( envLevel );
165
166     // Just use 'f' and 't' as it's faster than doing full string comparisons
167     if ( envTraceString == 't' )
168     {
169       trace = true;
170     }
171     else if ( envTraceString == 'f' )
172     {
173       trace = false;
174     }
175   }
176
177   Filter* filter = new Filter(level, trace);
178   filter->mNesting++;
179   GetActiveFilters()->push_back(filter);
180   return filter;
181 }
182
183 /**
184  * Enable trace on all filters.
185  */
186 void Filter::EnableGlobalTrace()
187 {
188   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
189   {
190     (*iter)->EnableTrace();
191   }
192 }
193
194 /**
195  * Disable trace on all filters.
196  */
197 void Filter::DisableGlobalTrace()
198 {
199   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
200   {
201     (*iter)->DisableTrace();
202   }
203 }
204
205
206 void Filter::Log(LogLevel level, const char* format, ...)
207 {
208   if(level <= mLoggingLevel)
209   {
210     va_list arg;
211     va_start(arg, format);
212
213     if( mTraceEnabled )
214     {
215       char *buffer = NULL;
216       int numChars = asprintf( &buffer, "    %-*c %s", mNesting, ':', format );
217       if( numChars >= 0 ) // No error
218       {
219         std::string message = ArgListToString( buffer, arg );
220         LogMessage( DebugInfo, message.c_str() );
221         free( buffer );
222       }
223     }
224     else
225     {
226       std::string message = ArgListToString( format, arg );
227       LogMessage( DebugInfo, message.c_str() );
228     }
229     va_end(arg);
230   }
231 }
232
233
234 TraceObj::TraceObj(Filter* filter, const char*format, ...) : mFilter(filter)
235 {
236   if(mFilter && mFilter->IsTraceEnabled())
237   {
238     va_list arg;
239     va_start(arg, format);
240     mMessage = ArgListToString(format, arg);
241     va_end(arg);
242
243     LogMessage(DebugInfo, "Entr%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
244     ++mFilter->mNesting;
245   }
246 }
247
248 TraceObj::~TraceObj()
249 {
250   if(mFilter && mFilter->IsTraceEnabled())
251   {
252     if (mFilter->mNesting)
253     {
254       --mFilter->mNesting;
255     }
256     LogMessage(DebugInfo, "Exit%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
257   }
258 }
259
260 #endif // DEBUG_ENABLED
261
262
263 std::string ArgListToString(const char *format, va_list args)
264 {
265   std::string str; // empty string
266   if(format != NULL)
267   {
268     char* buffer = NULL;
269     int err = vasprintf(&buffer, format, args);
270     if(err >= 0) // No error
271     {
272       str = buffer;
273       free(buffer);
274     }
275   }
276   return str;
277 }
278
279 std::string FormatToString(const char *format, ...)
280 {
281   va_list arg;
282   va_start(arg, format);
283   std::string s = ArgListToString(format, arg);
284   va_end(arg);
285   return s;
286 }
287
288 std::string ColorToString(const Vector4& color)
289 {
290   std::ostringstream oss;
291   oss << "<R:" << color.r << " G:" << color.g << " B:" << color.b << " A:" << color.a << ">";
292   return oss.str();
293 }
294
295 std::string Vector4ToString(const Vector4& v, size_t precision, size_t indent)
296 {
297   std::ostringstream oss;
298   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right;
299   oss << "<X:" << std::setw(precision+4) << v.x
300       << " Y:" << std::setw(precision+4) << v.y
301       << " Z:" << std::setw(precision+4) << v.z
302       << " W:" << std::setw(precision+4) << v.w << ">";
303   return oss.str();
304 }
305
306 std::string Vector3ToString(const Vector3& v, size_t precision, size_t indent)
307 {
308   std::ostringstream oss;
309   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right << std::setiosflags(std::ios_base::fixed);
310   oss << "<X:" << std::setw(precision+4) << v.x
311       << " Y:" << std::setw(precision+4) << v.y
312       << " Z:" << std::setw(precision+4) << v.z << ">";
313   return oss.str();
314 }
315
316 std::string QuaternionToString(const Quaternion& q, size_t precision, size_t indent)
317 {
318   std::ostringstream oss;
319
320   Vector3 axis;
321   Radian angle;
322   q.ToAxisAngle(axis, angle);
323
324   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right;
325   oss << "<A:" << std::setw(precision+4) << Degree( angle ).degree << ", " << Vector3ToString(axis, precision, 0) << ">";
326
327   return oss.str();
328 }
329
330 std::string Matrix3ToString(const Matrix3& m, size_t precision, size_t indent)
331 {
332   return Array2DToString(m.AsFloat(), 3, 3, precision, indent);
333 }
334
335 std::string MatrixToString(const Matrix& m, size_t precision, size_t indent)
336 {
337   return Array2DToString(m.AsFloat(), 4, 4, precision, indent);
338 }
339
340 void GetNanoseconds( uint64_t& timeInNanoseconds )
341 {
342   timespec timeSpec;
343   clock_gettime( CLOCK_MONOTONIC, &timeSpec );
344
345   // Convert all values to uint64_t to match our return type
346   timeInNanoseconds = ( static_cast< uint64_t >( timeSpec.tv_sec ) * NANOSECONDS_PER_SECOND ) + static_cast< uint64_t >( timeSpec.tv_nsec );
347 }
348
349 } // namespace Log
350
351 } // namespace Integration
352
353 } // namespace Dali