Uses TextArray new type definition.
[platform/core/uifw/dali-adaptor.git] / adaptors / base / update-thread.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 "update-thread.h"
20
21 // EXTERNAL INCLUDES
22 #include <cstdlib>
23 #include <fstream>
24 #include <sstream>
25 #include <boost/thread.hpp>
26
27 // INTERNAL INCLUDES
28 #include <dali/integration-api/debug.h>
29 #include <base/interfaces/adaptor-internal-services.h>
30 #include <base/update-render-synchronization.h>
31 #include <base/environment-options.h>
32
33 namespace Dali
34 {
35
36 namespace Internal
37 {
38
39 namespace Adaptor
40 {
41
42 namespace
43 {
44
45 const unsigned int MICROSECONDS_PER_MILLISECOND( 1000 );
46
47 } // unnamed namespace
48
49 UpdateThread::UpdateThread( UpdateRenderSynchronization& sync,
50                             AdaptorInternalServices& adaptorInterfaces,
51                             const EnvironmentOptions& environmentOptions )
52 : mUpdateRenderSync( sync ),
53   mCore( adaptorInterfaces.GetCore()),
54   mFpsTrackingSeconds( environmentOptions.GetFrameRateLoggingFrequency() ),
55   mElapsedTime( 0.0f ),
56   mElapsedSeconds( 0u ),
57   mStatusLogInterval( environmentOptions.GetUpdateStatusLoggingFrequency() ),
58   mStatusLogCount( 0u ),
59   mNotificationTrigger( adaptorInterfaces.GetTriggerEventInterface() ),
60   mThread( NULL ),
61   mEnvironmentOptions( environmentOptions )
62 {
63   if( mFpsTrackingSeconds > 0 )
64   {
65     mFpsRecord.resize( mFpsTrackingSeconds, 0.0f );
66   }
67 }
68
69 UpdateThread::~UpdateThread()
70 {
71   if(mFpsTrackingSeconds > 0)
72   {
73     OutputFPSRecord();
74   }
75   Stop();
76 }
77
78 void UpdateThread::Start()
79 {
80   if ( !mThread )
81   {
82     // Create and run the update-thread
83     mThread = new boost::thread( boost::bind( &UpdateThread::Run, this ) );
84   }
85 }
86
87 void UpdateThread::Stop()
88 {
89   if( mThread )
90   {
91     // wait for the thread to finish
92     mThread->join();
93
94     delete mThread;
95     mThread = NULL;
96   }
97 }
98
99 bool UpdateThread::Run()
100 {
101   Integration::UpdateStatus status;
102
103   // install a function for logging
104   mEnvironmentOptions.InstallLogFunction();
105
106   bool running( true );
107
108   // Update loop, we stay inside here while the update-thread is running
109   while ( running )
110   {
111     // Inform synchronization object update is ready to run, this will pause update thread if required.
112     mUpdateRenderSync.UpdateReadyToRun();
113
114     // Do the update
115     mCore.Update( status );
116
117     if( mFpsTrackingSeconds > 0 )
118     {
119       FPSTracking(status.SecondsFromLastFrame());
120     }
121
122     // Do the notifications first so the actor-thread can start processing them
123     if( status.NeedsNotification() )
124     {
125       // Tell the event-thread to wake up (if asleep) and send a notification event to Core
126       mNotificationTrigger.Trigger();
127     }
128
129     bool renderNeedsUpdate;
130
131     // tell the synchronisation class that a buffer has been written to,
132     // and to wait until there is a free buffer to write to
133     running = mUpdateRenderSync.UpdateSyncWithRender( renderNeedsUpdate );
134
135     if( running )
136     {
137       unsigned int keepUpdatingStatus = status.KeepUpdating();
138
139       // Optional logging of update/render status
140       if ( mStatusLogInterval )
141       {
142         UpdateStatusLogging( keepUpdatingStatus, renderNeedsUpdate );
143       }
144
145       //  2 things can keep update running.
146       // - The status of the last update
147       // - The status of the last render
148       bool runUpdate = (Integration::KeepUpdating::NOT_REQUESTED != keepUpdatingStatus) || renderNeedsUpdate;
149
150       if( !runUpdate )
151       {
152         running = mUpdateRenderSync.UpdateTryToSleep();
153       }
154     }
155   }
156
157   // uninstall a function for logging
158   mEnvironmentOptions.UnInstallLogFunction();
159
160   return true;
161 }
162
163 void UpdateThread::FPSTracking(float secondsFromLastFrame)
164 {
165   if (mElapsedSeconds < mFpsTrackingSeconds)
166   {
167     mElapsedTime += secondsFromLastFrame;
168     if( secondsFromLastFrame  > 1.0 )
169     {
170       int seconds = floor(mElapsedTime);
171       mElapsedSeconds += seconds;
172       mElapsedTime -= static_cast<float>(seconds);
173     }
174     else
175     {
176       if( mElapsedTime>=1.0f )
177       {
178         mElapsedTime -= 1.0f;
179         mFpsRecord[mElapsedSeconds] += 1.0f - mElapsedTime/secondsFromLastFrame;
180         mElapsedSeconds++;
181         mFpsRecord[mElapsedSeconds] += mElapsedTime/secondsFromLastFrame;
182       }
183       else
184       {
185         mFpsRecord[mElapsedSeconds] += 1.0f;
186       }
187     }
188   }
189   else
190   {
191     OutputFPSRecord();
192     mFpsRecord.clear();
193     mFpsTrackingSeconds = 0;
194   }
195 }
196
197 void UpdateThread::OutputFPSRecord()
198 {
199   for(unsigned int i = 0; i < mElapsedSeconds; i++)
200   {
201     DALI_LOG_FPS("fps( %d ):%f\n",i ,mFpsRecord[i]);
202   }
203   std::ofstream outFile("/tmp/dalifps.txt");
204   if(outFile.is_open())
205   {
206     for(unsigned int i = 0; i < mElapsedSeconds; i++)
207     {
208       outFile << mFpsRecord[i]<<std::endl;
209     }
210     outFile.close();
211   }
212 }
213
214 void UpdateThread::UpdateStatusLogging( unsigned int keepUpdatingStatus, bool renderNeedsUpdate )
215 {
216   DALI_ASSERT_ALWAYS( mStatusLogInterval );
217
218   std::ostringstream oss;
219
220   if ( !(++mStatusLogCount % mStatusLogInterval) )
221   {
222     oss << "UpdateStatusLogging keepUpdating: " << (bool)keepUpdatingStatus << " ";
223
224     if ( keepUpdatingStatus )
225     {
226       oss << "because: ";
227     }
228
229     if ( keepUpdatingStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING )
230     {
231       oss << "<Stage::KeepRendering() used> ";
232     }
233
234     if ( keepUpdatingStatus & Integration::KeepUpdating::INCOMING_MESSAGES )
235     {
236       oss << "<Messages sent to Update> ";
237     }
238
239     if ( keepUpdatingStatus & Integration::KeepUpdating::ANIMATIONS_RUNNING )
240     {
241       oss << "<Animations running> ";
242     }
243
244     if ( keepUpdatingStatus & Integration::KeepUpdating::DYNAMICS_CHANGED )
245     {
246       oss << "<Dynamics running> ";
247     }
248
249     if ( keepUpdatingStatus & Integration::KeepUpdating::LOADING_RESOURCES )
250     {
251       oss << "<Resources loading> ";
252     }
253
254     if ( keepUpdatingStatus & Integration::KeepUpdating::NOTIFICATIONS_PENDING )
255     {
256       oss << "<Notifications pending> ";
257     }
258
259     if ( renderNeedsUpdate )
260     {
261       oss << "<Render needs Update> ";
262     }
263
264     DALI_LOG_UPDATE_STATUS( "%s\n", oss.str().c_str() );
265   }
266 }
267
268 } // namespace Adaptor
269
270 } // namespace Internal
271
272 } // namespace Dali