Merge "Remove use of boost thread local storage from debug" into tizen
[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 // 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 __thread LogFunction gthreadLocalLogFunction = NULL;
85
86 /* Forward declarations */
87 std::string FormatToString(const char *format, ...);
88 std::string ArgListToString(const char *format, va_list args);
89
90 void LogMessage(DebugPriority priority, const char* format, ...)
91 {
92   if ( !gthreadLocalLogFunction )
93   {
94     return;
95   }
96
97   va_list arg;
98   va_start(arg, format);
99   std::string message = ArgListToString(format, arg);
100   va_end(arg);
101
102   gthreadLocalLogFunction(priority,message);
103 }
104
105 void InstallLogFunction(const LogFunction& logFunction)
106 {
107   // TLS stores a pointer to an object.
108   // It needs to be allocated on the heap, because TLS will destroy it when the thread exits.
109
110   gthreadLocalLogFunction = logFunction;
111 }
112
113 void UninstallLogFunction()
114 {
115   gthreadLocalLogFunction = NULL;
116 }
117
118 #ifdef DEBUG_ENABLED
119
120 /*Change false to true if trace is needed but don't commit to codeline*/
121 Filter* Filter::gRender     = Filter::New(Debug::Concise, false, "LOG_RENDER");
122 Filter* Filter::gResource   = Filter::New(Debug::Concise, false, "LOG_RESOURCE");
123 Filter* Filter::gGLResource = Filter::New(Debug::Concise, false, "LOG_GL_RESOURCE");
124 Filter* Filter::gObject     = NULL;
125 Filter* Filter::gImage      = Filter::New(Debug::Concise, false, "LOG_IMAGE");
126 Filter* Filter::gModel      = Filter::New(Debug::Concise, false, "LOG_MODEL");
127 Filter* Filter::gNode       = NULL;
128 Filter* Filter::gElement    = NULL;
129 Filter* Filter::gActor      = Filter::New(Debug::Concise, false, "LOG_ACTOR");
130 Filter* Filter::gShader     = Filter::New(Debug::Concise, false, "LOG_SHADER");
131 Filter* Filter::gDynamics   = Filter::New(Debug::Concise, false, "LOG_DYNAMICS");
132
133 Filter::FilterList* Filter::GetActiveFilters()
134 {
135   static Filter::FilterList* activeFilters = new FilterList;
136   return activeFilters;
137 }
138
139 Filter* Filter::New( LogLevel level, bool trace, const char * environmentVariableName )
140 {
141   char * environmentVariableValue = getenv( environmentVariableName );
142   if ( environmentVariableValue )
143   {
144     unsigned int envLevel(0);
145     char envTraceString(0);
146     sscanf( environmentVariableValue, "%u,%c", &envLevel, &envTraceString );
147
148     if ( envLevel > Verbose )
149     {
150       envLevel = Verbose;
151     }
152     level = LogLevel( envLevel );
153
154     // Just use 'f' and 't' as it's faster than doing full string comparisons
155     if ( envTraceString == 't' )
156     {
157       trace = true;
158     }
159     else if ( envTraceString == 'f' )
160     {
161       trace = false;
162     }
163   }
164
165   Filter* filter = new Filter(level, trace);
166   filter->mNesting++;
167   GetActiveFilters()->push_back(filter);
168   return filter;
169 }
170
171 /**
172  * Enable trace on all filters.
173  */
174 void Filter::EnableGlobalTrace()
175 {
176   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
177   {
178     (*iter)->EnableTrace();
179   }
180 }
181
182 /**
183  * Disable trace on all filters.
184  */
185 void Filter::DisableGlobalTrace()
186 {
187   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
188   {
189     (*iter)->DisableTrace();
190   }
191 }
192
193
194 void Filter::Log(LogLevel level, const char* format, ...)
195 {
196   if(level <= mLoggingLevel)
197   {
198     va_list arg;
199     va_start(arg, format);
200
201     char *buffer = NULL;
202     int numChars = asprintf(&buffer, "%-*c %s", mNesting, ':', format);
203     if(numChars >= 0) // No error
204     {
205       std::string message = ArgListToString(buffer, arg);
206       LogMessage(DebugInfo, message.c_str());
207       free(buffer);
208     }
209     va_end(arg);
210   }
211 }
212
213
214 TraceObj::TraceObj(Filter* filter, const char*format, ...) : mFilter(filter)
215 {
216   if(mFilter && mFilter->IsTraceEnabled())
217   {
218     va_list arg;
219     va_start(arg, format);
220     mMessage = ArgListToString(format, arg);
221     va_end(arg);
222
223     LogMessage(DebugInfo, "Entr%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
224     ++mFilter->mNesting;
225   }
226 }
227
228 TraceObj::~TraceObj()
229 {
230   if(mFilter && mFilter->IsTraceEnabled())
231   {
232     if (mFilter->mNesting)
233     {
234       --mFilter->mNesting;
235     }
236     LogMessage(DebugInfo, "Exit%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
237   }
238 }
239
240 #endif // DEBUG_ENABLED
241
242
243 std::string ArgListToString(const char *format, va_list args)
244 {
245   std::string str; // empty string
246   if(format != NULL)
247   {
248     char* buffer = NULL;
249     int err = vasprintf(&buffer, format, args);
250     if(err >= 0) // No error
251     {
252       str = buffer;
253       free(buffer);
254     }
255   }
256   return str;
257 }
258
259 std::string FormatToString(const char *format, ...)
260 {
261   va_list arg;
262   va_start(arg, format);
263   std::string s = ArgListToString(format, arg);
264   va_end(arg);
265   return s;
266 }
267
268 std::string ColorToString(const Vector4& color)
269 {
270   std::ostringstream oss;
271   oss << "<R:" << color.r << " G:" << color.g << " B:" << color.b << " A:" << color.a << ">";
272   return oss.str();
273 }
274
275 std::string Vector4ToString(const Vector4& v, size_t precision, size_t indent)
276 {
277   std::ostringstream oss;
278   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right;
279   oss << "<X:" << std::setw(precision+4) << v.x
280       << " Y:" << std::setw(precision+4) << v.y
281       << " Z:" << std::setw(precision+4) << v.z
282       << " W:" << std::setw(precision+4) << v.w << ">";
283   return oss.str();
284 }
285
286 std::string Vector3ToString(const Vector3& v, size_t precision, size_t indent)
287 {
288   std::ostringstream oss;
289   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right << std::setiosflags(std::ios_base::fixed);
290   oss << "<X:" << std::setw(precision+4) << v.x
291       << " Y:" << std::setw(precision+4) << v.y
292       << " Z:" << std::setw(precision+4) << v.z << ">";
293   return oss.str();
294 }
295
296 std::string QuaternionToString(const Quaternion& q, size_t precision, size_t indent)
297 {
298   std::ostringstream oss;
299
300   Vector3 axis;
301   float angle;
302   q.ToAxisAngle(axis, angle);
303
304   oss << std::setw(indent+3) << std::setfill(' ') << std::setprecision(precision) << std::right;
305   oss << "<A:" << std::setw(precision+4) << angle * 180.0 / Math::PI << ", " << Vector3ToString(axis, precision, 0) << ">";
306
307   return oss.str();
308 }
309
310 std::string Matrix3ToString(const Matrix3& m, size_t precision, size_t indent)
311 {
312   return Array2DToString(m.AsFloat(), 3, 3, precision, indent);
313 }
314
315 std::string MatrixToString(const Matrix& m, size_t precision, size_t indent)
316 {
317   return Array2DToString(m.AsFloat(), 4, 4, precision, indent);
318 }
319
320 } // namespace Log
321
322 } // namespace Integration
323
324 } // namespace Dali