2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 // http://floralicense.org/license/
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.
18 #include <dali/integration-api/debug.h>
28 # include <boost/thread/tss.hpp>
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>
43 namespace // unnamed namespace
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
55 std::string Array2DToString(const float *data, unsigned int rows, unsigned int cols, size_t precision, size_t indent)
57 std::ostringstream oss;
59 std::ios_base::fmtflags mask = oss.flags();
60 mask &= ~std::ios_base::scientific;
61 mask |= std::ios_base::fixed;
63 for(unsigned int rowIdx = 0; rowIdx < rows; rowIdx++)
65 oss << std::setw(indent) << std::setfill(' ') << ' ' << "[ ";
66 oss << std::setfill(' ') << std::setprecision(precision) << std::right << std::setiosflags(mask);
68 for(unsigned int colIdx = 0; colIdx < cols; colIdx++)
70 oss << std::setw(precision + 6) << (*data++) << ' ';
73 oss << ']' << std::endl;
87 typedef LogFunction* LogFunctionPtr; ///< LogFunction pointer
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
94 struct ThreadLocalLogging
96 ThreadLocalLogging(LogFunction func, unsigned int opts)
102 LogFunction function;
103 unsigned int logOptions;
106 #ifndef EMSCRIPTEN // single threaded
107 boost::thread_specific_ptr<ThreadLocalLogging> threadLocal;
109 std::auto_ptr<ThreadLocalLogging> threadLocal;
112 /* Forward declarations */
113 std::string FormatToString(const char *format, ...);
114 std::string ArgListToString(const char *format, va_list args);
116 unsigned int ParseLogOptions (const char* logOptString)
118 unsigned int ret = LogNone;
119 if (logOptString == NULL)
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;
129 std::string setting(logOptString);
130 if (!setting.compare(DALI_LOG_OFF))
132 // leave as "LogNone"
134 else if (!setting.compare(DALI_LOG_EVENT_THREAD))
136 ret |= LogEventThread;
138 else if (!setting.compare(DALI_LOG_UPDATE_THREAD))
140 ret |= LogUpdateThread;
142 else if (!setting.compare(DALI_LOG_RENDER_THREAD))
144 ret |= LogRenderThread;
146 else if (!setting.compare(DALI_LOG_RESOURCE_THREADS))
148 ret |= LogResourceThreads;
150 else if (!setting.compare(DALI_LOG_ALL_THREADS))
152 ret |= LogEventThread;
153 ret |= LogUpdateThread;
154 ret |= LogRenderThread;
155 ret |= LogResourceThreads;
157 else if (!setting.compare(DALI_LOG_RESOURCE_LIFETIME))
159 ret |= LogEventThread;
160 ret |= LogUpdateThread;
161 ret |= LogRenderThread;
162 ret |= LogResourceThreads;
163 ret |= LogResourceLifetime;
169 void LogMessage(DebugPriority priority, const char* format, ...)
171 ThreadLocalLogging* threadLogging = threadLocal.get();
172 // see if there is a log function for this thread
177 const LogFunction& logfunction = threadLogging->function;
183 // avoid string operations and function call if trying to log resources when not requested
184 if (priority == DebugResources && !(threadLogging->logOptions & LogResourceLifetime))
189 va_start(arg, format);
190 std::string message = ArgListToString(format, arg);
193 logfunction(priority,message);
196 void InstallLogFunction(const LogFunction& logFunction, unsigned int logOpts)
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.
201 ThreadLocalLogging* logStruct = new ThreadLocalLogging(logFunction, logOpts);
203 threadLocal.reset(logStruct);
206 void UninstallLogFunction()
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");
226 Filter::FilterList* Filter::GetActiveFilters()
228 static Filter::FilterList* activeFilters = new FilterList;
229 return activeFilters;
232 Filter* Filter::New( LogLevel level, bool trace, const char * environmentVariableName )
234 char * environmentVariableValue = getenv( environmentVariableName );
235 if ( environmentVariableValue )
237 unsigned int envLevel(0);
238 char envTraceString(0);
239 sscanf( environmentVariableValue, "%u,%c", &envLevel, &envTraceString );
241 if ( envLevel > Verbose )
245 level = LogLevel( envLevel );
247 // Just use 'f' and 't' as it's faster than doing full string comparisons
248 if ( envTraceString == 't' )
252 else if ( envTraceString == 'f' )
258 Filter* filter = new Filter(level, trace);
260 GetActiveFilters()->push_back(filter);
265 * Enable trace on all filters.
267 void Filter::EnableGlobalTrace()
269 for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
271 (*iter)->EnableTrace();
276 * Disable trace on all filters.
278 void Filter::DisableGlobalTrace()
280 for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
282 (*iter)->DisableTrace();
287 void Filter::Log(LogLevel level, const char* format, ...)
289 if(level <= mLoggingLevel)
292 va_start(arg, format);
295 int numChars = asprintf(&buffer, "%-*c %s", mNesting, ':', format);
296 if(numChars >= 0) // No error
298 std::string message = ArgListToString(buffer, arg);
299 LogMessage(DebugInfo, message.c_str());
307 TraceObj::TraceObj(Filter* filter, const char*format, ...) : mFilter(filter)
309 if(mFilter && mFilter->IsTraceEnabled())
312 va_start(arg, format);
313 mMessage = ArgListToString(format, arg);
316 LogMessage(DebugInfo, "Entr%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
321 TraceObj::~TraceObj()
323 if(mFilter && mFilter->IsTraceEnabled())
325 if (mFilter->mNesting)
329 LogMessage(DebugInfo, "Exit%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
333 #endif // DEBUG_ENABLED
336 std::string ArgListToString(const char *format, va_list args)
338 std::string str; // empty string
342 int err = vasprintf(&buffer, format, args);
343 if(err >= 0) // No error
352 std::string FormatToString(const char *format, ...)
355 va_start(arg, format);
356 std::string s = ArgListToString(format, arg);
361 std::string ColorToString(const Vector4& color)
363 std::ostringstream oss;
364 oss << "<R:" << color.r << " G:" << color.g << " B:" << color.b << " A:" << color.a << ">";
368 std::string Vector4ToString(const Vector4& v, size_t precision, size_t indent)
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 << ">";
379 std::string Vector3ToString(const Vector3& v, size_t precision, size_t indent)
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 << ">";
389 std::string QuaternionToString(const Quaternion& q, size_t precision, size_t indent)
391 std::ostringstream oss;
395 q.ToAxisAngle(axis, angle);
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) << ">";
403 std::string Matrix3ToString(const Matrix3& m, size_t precision, size_t indent)
405 return Array2DToString(m.AsFloat(), 3, 3, precision, indent);
408 std::string MatrixToString(const Matrix& m, size_t precision, size_t indent)
410 return Array2DToString(m.AsFloat(), 4, 4, precision, indent);
415 } // namespace Integration