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