(Properties) Added ability to add non-animatable event-thread only properties via...
[platform/core/uifw/dali-core.git] / dali / integration-api / debug.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali/integration-api/debug.h>
19
20 // EXTERNAL INCLUDES
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <sstream>
25 #include <iomanip>
26 #include <boost/thread/tss.hpp>
27
28 // INTERNAL INCLUDES
29 #include <dali/public-api/common/constants.h>
30 #include <dali/public-api/math/matrix3.h>
31 #include <dali/public-api/math/matrix.h>
32 #include <dali/public-api/math/vector3.h>
33 #include <dali/public-api/math/vector4.h>
34 #include <dali/public-api/math/quaternion.h>
35 #include <dali/internal/event/common/thread-local-storage.h>
36
37 namespace Dali
38 {
39
40 namespace // unnamed namespace
41 {
42
43 /**
44  * Generic function to print out any 2-Dimensional array
45  * @param[in] data pointer to the source data stored as float[rows][cols]
46  * @param[in] rows number of rows in 2D array
47  * @param[in] cols number of columns in 2D array
48  * @param[in] precision - the precision to write the float data.
49  * @param[in] indent - the indent level to use.
50  * @return string - the text representation of the 2D array
51  */
52 std::string Array2DToString(const float *data, unsigned int rows, unsigned int cols, size_t precision, size_t indent)
53 {
54   std::ostringstream oss;
55
56   std::ios_base::fmtflags mask = oss.flags();
57   mask &= ~std::ios_base::scientific;
58   mask |=  std::ios_base::fixed;
59
60   for(unsigned int rowIdx = 0; rowIdx < rows; rowIdx++)
61   {
62     oss  << std::setw(indent) << std::setfill(' ') << ' ' << "[ ";
63     oss  << std::setfill(' ') << std::setprecision(precision) << std::right << std::setiosflags(mask);
64
65     for(unsigned int colIdx = 0; colIdx < cols; colIdx++)
66     {
67       oss << std::setw(precision + 6) << (*data++) << ' ';
68     }
69
70     oss << ']' << std::endl;
71   }
72
73   return oss.str();
74 }
75
76 }
77
78 namespace Integration
79 {
80
81 namespace Log
82 {
83
84 typedef LogFunction* LogFunctionPtr; ///< LogFunction pointer
85
86 /**
87  * This stores a pointer to a log function in thread local storage.
88  * The data has to be allocated from the heap because
89  * it will automatically be deleted when the thread terminates
90  */
91 struct ThreadLocalLogging
92 {
93   ThreadLocalLogging(LogFunction func, unsigned int opts)
94   :function(func),
95    logOptions(opts)
96   {
97   }
98
99   LogFunction function;
100   unsigned int logOptions;
101 };
102
103 boost::thread_specific_ptr<ThreadLocalLogging> threadLocal;
104
105 /* Forward declarations */
106 std::string FormatToString(const char *format, ...);
107 std::string ArgListToString(const char *format, va_list args);
108
109 unsigned int ParseLogOptions (const char* logOptString)
110 {
111   unsigned int ret = LogNone;
112   if (logOptString == NULL)
113   {
114     // environment variable was not set, turn on logging for all threads by default
115     ret |= LogEventThread;
116     ret |= LogUpdateThread;
117     ret |= LogRenderThread;
118     ret |= LogResourceThreads;
119   }
120   else
121   {
122     std::string setting(logOptString);
123     if (!setting.compare(DALI_LOG_OFF))
124     {
125       // leave as "LogNone"
126     }
127     else if (!setting.compare(DALI_LOG_EVENT_THREAD))
128     {
129       ret |= LogEventThread;
130     }
131     else if (!setting.compare(DALI_LOG_UPDATE_THREAD))
132     {
133       ret |= LogUpdateThread;
134     }
135     else if (!setting.compare(DALI_LOG_RENDER_THREAD))
136     {
137       ret |= LogRenderThread;
138     }
139     else if (!setting.compare(DALI_LOG_RESOURCE_THREADS))
140     {
141       ret |= LogResourceThreads;
142     }
143     else if (!setting.compare(DALI_LOG_ALL_THREADS))
144     {
145       ret |= LogEventThread;
146       ret |= LogUpdateThread;
147       ret |= LogRenderThread;
148       ret |= LogResourceThreads;
149     }
150     else if (!setting.compare(DALI_LOG_RESOURCE_LIFETIME))
151     {
152       ret |= LogEventThread;
153       ret |= LogUpdateThread;
154       ret |= LogRenderThread;
155       ret |= LogResourceThreads;
156       ret |= LogResourceLifetime;
157     }
158   }
159   return ret;
160 }
161
162 void LogMessage(DebugPriority priority, const char* format, ...)
163 {
164   ThreadLocalLogging* threadLogging = threadLocal.get();
165   // see if there is a log function for this thread
166   if (!threadLogging)
167   {
168     return;
169   }
170   const LogFunction& logfunction = threadLogging->function;
171   if (!logfunction)
172   {
173     return;
174   }
175
176   // avoid string operations and function call if trying to log resources when not requested
177   if (priority == DebugResources && !(threadLogging->logOptions & LogResourceLifetime))
178   {
179     return;
180   }
181
182   va_list arg;
183   va_start(arg, format);
184   std::string message = ArgListToString(format, arg);
185   va_end(arg);
186
187   logfunction(priority,message);
188 }
189
190 void InstallLogFunction(const LogFunction& logFunction, unsigned int logOpts)
191 {
192   // TLS stores a pointer to an object.
193   // It needs to be allocated on the heap, because TLS will destroy it when the thread exits.
194
195   ThreadLocalLogging* logStruct = new ThreadLocalLogging(logFunction, logOpts);
196
197   threadLocal.reset(logStruct);
198 }
199
200 void UninstallLogFunction()
201 {
202   threadLocal.reset();
203 }
204
205 #ifdef DEBUG_ENABLED
206
207 /*Change false to true if trace is needed but don't commit to codeline*/
208 Filter* Filter::gRender     = Filter::New(Debug::Concise, false, "LOG_RENDER");
209 Filter* Filter::gResource   = Filter::New(Debug::Concise, false, "LOG_RESOURCE");
210 Filter* Filter::gGLResource = Filter::New(Debug::Concise, false, "LOG_GL_RESOURCE");
211 Filter* Filter::gObject     = NULL;
212 Filter* Filter::gImage      = Filter::New(Debug::Concise, false, "LOG_IMAGE");
213 Filter* Filter::gModel      = Filter::New(Debug::Concise, false, "LOG_MODEL");
214 Filter* Filter::gNode       = NULL;
215 Filter* Filter::gElement    = NULL;
216 Filter* Filter::gActor      = Filter::New(Debug::Concise, false, "LOG_ACTOR");
217 Filter* Filter::gShader     = Filter::New(Debug::Concise, false, "LOG_SHADER");
218 Filter* Filter::gDynamics   = Filter::New(Debug::Concise, false, "LOG_DYNAMICS");
219
220 Filter::FilterList* Filter::GetActiveFilters()
221 {
222   static Filter::FilterList* activeFilters = new FilterList;
223   return activeFilters;
224 }
225
226 Filter* Filter::New( LogLevel level, bool trace, const char * environmentVariableName )
227 {
228   char * environmentVariableValue = getenv( environmentVariableName );
229   if ( environmentVariableValue )
230   {
231     unsigned int envLevel(0);
232     char envTraceString(0);
233     sscanf( environmentVariableValue, "%u,%c", &envLevel, &envTraceString );
234
235     if ( envLevel > Verbose )
236     {
237       envLevel = Verbose;
238     }
239     level = LogLevel( envLevel );
240
241     // Just use 'f' and 't' as it's faster than doing full string comparisons
242     if ( envTraceString == 't' )
243     {
244       trace = true;
245     }
246     else if ( envTraceString == 'f' )
247     {
248       trace = false;
249     }
250   }
251
252   Filter* filter = new Filter(level, trace);
253   filter->mNesting++;
254   GetActiveFilters()->push_back(filter);
255   return filter;
256 }
257
258 /**
259  * Enable trace on all filters.
260  */
261 void Filter::EnableGlobalTrace()
262 {
263   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
264   {
265     (*iter)->EnableTrace();
266   }
267 }
268
269 /**
270  * Disable trace on all filters.
271  */
272 void Filter::DisableGlobalTrace()
273 {
274   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
275   {
276     (*iter)->DisableTrace();
277   }
278 }
279
280
281 void Filter::Log(LogLevel level, const char* format, ...)
282 {
283   if(level <= mLoggingLevel)
284   {
285     va_list arg;
286     va_start(arg, format);
287
288     char *buffer = NULL;
289     int numChars = asprintf(&buffer, "%-*c %s", mNesting, ':', format);
290     if(numChars >= 0) // No error
291     {
292       std::string message = ArgListToString(buffer, arg);
293       LogMessage(DebugInfo, message.c_str());
294       free(buffer);
295     }
296     va_end(arg);
297   }
298 }
299
300
301 TraceObj::TraceObj(Filter* filter, const char*format, ...) : mFilter(filter)
302 {
303   if(mFilter && mFilter->IsTraceEnabled())
304   {
305     va_list arg;
306     va_start(arg, format);
307     mMessage = ArgListToString(format, arg);
308     va_end(arg);
309
310     LogMessage(DebugInfo, "Entr%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
311     ++mFilter->mNesting;
312   }
313 }
314
315 TraceObj::~TraceObj()
316 {
317   if(mFilter && mFilter->IsTraceEnabled())
318   {
319     if (mFilter->mNesting)
320     {
321       --mFilter->mNesting;
322     }
323     LogMessage(DebugInfo, "Exit%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
324   }
325 }
326
327 #endif // DEBUG_ENABLED
328
329
330 std::string ArgListToString(const char *format, va_list args)
331 {
332   std::string str; // empty string
333   if(format != NULL)
334   {
335     char* buffer = NULL;
336     int err = vasprintf(&buffer, format, args);
337     if(err >= 0) // No error
338     {
339       str = buffer;
340       free(buffer);
341     }
342   }
343   return str;
344 }
345
346 std::string FormatToString(const char *format, ...)
347 {
348   va_list arg;
349   va_start(arg, format);
350   std::string s = ArgListToString(format, arg);
351   va_end(arg);
352   return s;
353 }
354
355 std::string ColorToString(const Vector4& color)
356 {
357   std::ostringstream oss;
358   oss << "<R:" << color.r << " G:" << color.g << " B:" << color.b << " A:" << color.a << ">";
359   return oss.str();
360 }
361
362 std::string Vector4ToString(const Vector4& v, size_t precision, size_t indent)
363 {
364   std::ostringstream oss;
365   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right;
366   oss << "<X:" << std::setw(precision+4) << v.x
367       << " Y:" << std::setw(precision+4) << v.y
368       << " Z:" << std::setw(precision+4) << v.z
369       << " W:" << std::setw(precision+4) << v.w << ">";
370   return oss.str();
371 }
372
373 std::string Vector3ToString(const Vector3& v, size_t precision, size_t indent)
374 {
375   std::ostringstream oss;
376   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right << std::setiosflags(std::ios_base::fixed);
377   oss << "<X:" << std::setw(precision+4) << v.x
378       << " Y:" << std::setw(precision+4) << v.y
379       << " Z:" << std::setw(precision+4) << v.z << ">";
380   return oss.str();
381 }
382
383 std::string QuaternionToString(const Quaternion& q, size_t precision, size_t indent)
384 {
385   std::ostringstream oss;
386
387   Vector3 axis;
388   float angle;
389   q.ToAxisAngle(axis, angle);
390
391   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right;
392   oss << "<A:" << std::setw(precision+4) << angle * 180.0 / Math::PI << ", " << Vector3ToString(axis, precision, 0) << ">";
393
394   return oss.str();
395 }
396
397 std::string Matrix3ToString(const Matrix3& m, size_t precision, size_t indent)
398 {
399   return Array2DToString(m.AsFloat(), 3, 3, precision, indent);
400 }
401
402 std::string MatrixToString(const Matrix& m, size_t precision, size_t indent)
403 {
404   return Array2DToString(m.AsFloat(), 4, 4, precision, indent);
405 }
406
407 } // namespace Log
408
409 } // namespace Integration
410
411 } // namespace Dali