Dali 3D User Interface Engine
vsync-notifier.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 "vsync-notifier.h"
20 
21 // EXTERNAL INCLUDES
22 #include <unistd.h>
25 
26 // INTERNAL INCLUDES
30 #include <base/time-service.h>
31 
32 namespace Dali
33 {
34 
35 namespace Internal
36 {
37 
38 namespace Adaptor
39 {
40 
41 namespace
42 {
43 
44 const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
45 const unsigned int NANOSECONDS_PER_MICROSECOND( 1000u );
46 const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
47 const unsigned int TIME_PER_FRAME_IN_MICROSECONDS( 16667u );
48 
49 #if defined(DEBUG_ENABLED)
50 Integration::Log::Filter* gSyncLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_VSYNC_NOTIFIER");
51 #endif
52 
53 } // unnamed namespace
54 
56  AdaptorInternalServices& adaptorInterfaces,
57  const EnvironmentOptions& environmentOptions )
58 : mThreadSynchronization( sync ),
59  mCore( adaptorInterfaces.GetCore() ),
60  mVSyncMonitor( adaptorInterfaces.GetVSyncMonitorInterface() ),
61  mThread( NULL ),
62  mEnvironmentOptions( environmentOptions ),
63  mNumberOfVSyncsPerRender(1)
64 {
65 }
66 
68 {
69  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
70 
71  Stop();
72 }
73 
75 {
76  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
77 
78  if ( !mThread )
79  {
81 
82  mThread = new pthread_t();
83  int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
84  DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in VSyncNotifier" );
85  }
86 }
87 
89 {
90  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
91 
92  if( mThread )
93  {
94  // wait for the thread to finish
95  pthread_join(*mThread, NULL);
96 
97  delete mThread;
98  mThread = NULL;
99  }
100 
102 }
103 
106 // The following is executed inside the notifier thread !!!
109 
111 {
112  // install a function for logging
114 
115  unsigned int frameNumber( 0u ); // frameCount, updated when the thread is paused
116  unsigned int currentSequenceNumber( 0u ); // platform specific vsync sequence number (increments with each vsync)
117  unsigned int currentSeconds( 0u ); // timestamp at latest sync
118  unsigned int currentMicroseconds( 0u ); // timestamp at latest sync
119  uint64_t seconds( 0u );
120  uint64_t microseconds( 0u );
121 
122  bool validSync( true );
123  while( mThreadSynchronization.VSyncReady( validSync, frameNumber++, currentSeconds, currentMicroseconds, mNumberOfVSyncsPerRender ) )
124  {
125  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 1 SyncWithUpdateAndRender(frame#:%d, current Sec:%u current uSec:%u)\n", frameNumber-1, currentSeconds, currentMicroseconds);
126 
127  // Hardware VSyncs available?
128  if( mVSyncMonitor->UseHardware() )
129  {
130  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 2 Start hardware sync (%d frames) \n", mNumberOfVSyncsPerRender);
131 
132  for( unsigned int i=0; i<mNumberOfVSyncsPerRender; ++i )
133  {
134  // Yes..wait for N hardware VSync ticks
135  validSync = mVSyncMonitor->DoSync( currentSequenceNumber, currentSeconds, currentMicroseconds );
136  }
137  }
138  else
139  {
140  // No..use software timer
141  uint64_t nanoseconds = 0;
142  TimeService::GetNanoseconds( nanoseconds );
143 
144  seconds = nanoseconds / NANOSECONDS_PER_SECOND; // Convert to seconds
145  nanoseconds -= seconds * NANOSECONDS_PER_SECOND; // Only want remainder nanoseconds
146  microseconds = nanoseconds / NANOSECONDS_PER_MICROSECOND; // Convert to microseconds
147 
148  unsigned int timeDelta( MICROSECONDS_PER_SECOND * (seconds - currentSeconds) );
149  if( microseconds < currentMicroseconds)
150  {
151  timeDelta += (microseconds + MICROSECONDS_PER_SECOND) - currentMicroseconds;
152  }
153  else
154  {
155  timeDelta += microseconds - currentMicroseconds;
156  }
157 
158  currentSeconds = seconds;
159  currentMicroseconds = microseconds;
160 
161  unsigned int sleepTimeInMicroseconds = 0;
162 
163  if( timeDelta < TIME_PER_FRAME_IN_MICROSECONDS )
164  {
165  sleepTimeInMicroseconds = TIME_PER_FRAME_IN_MICROSECONDS - timeDelta;
166  }
167  sleepTimeInMicroseconds += mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS;
168 
169  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 2 Start software sync (%d frames, %u microseconds) \n", mNumberOfVSyncsPerRender, sleepTimeInMicroseconds);
170 
171  timespec sleepTime;
172  sleepTime.tv_sec = 0;
173  sleepTime.tv_nsec = sleepTimeInMicroseconds * 1000;
174  nanosleep( &sleepTime, NULL );
175  }
177  }
178 
179  // uninstall a function for logging
181 
182 }
183 
184 } // namespace Adaptor
185 
186 } // namespace Internal
187 
188 } // namespace Dali
Dali Docs Home
Read more about Dali