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