(PanGesture)Added environment variable to change pan gesture prediction mode
[platform/core/uifw/dali-adaptor.git] / adaptors / base / render-thread.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
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
7 //
8 //     http://floralicense.org/license/
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 // CLASS HEADER
18 #include "render-thread.h"
19
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <base/interfaces/adaptor-internal-services.h>
24 #include <base/update-render-synchronization.h>
25 #include <base/environment-options.h>
26
27
28 namespace Dali
29 {
30
31 namespace Internal
32 {
33
34 namespace Adaptor
35 {
36
37 namespace
38 {
39
40 const unsigned int TIME_PER_FRAME_IN_MICROSECONDS = 16667;
41
42 } // unnamed namespace
43
44 RenderThread::RenderThread( UpdateRenderSynchronization& sync,
45                             AdaptorInternalServices& adaptorInterfaces,
46                             const EnvironmentOptions& environmentOptions )
47 : mUpdateRenderSync( sync ),
48   mCore( adaptorInterfaces.GetCore() ),
49   mGLES( adaptorInterfaces.GetGlesInterface() ),
50   mEglFactory( &adaptorInterfaces.GetEGLFactoryInterface()),
51   mEGL( NULL ),
52   mThread( NULL ),
53   mSurfaceReplacing( false ),
54   mNewDataAvailable( false ),
55   mSurfaceReplaceCompleted( false ),
56   mEnvironmentOptions( environmentOptions )
57 {
58   // set the initial values before render thread starts
59   mCurrent.surface = adaptorInterfaces.GetRenderSurfaceInterface();
60 }
61
62 RenderThread::~RenderThread()
63 {
64   DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
65   mEglFactory->Destroy();
66 }
67
68 void RenderThread::Start()
69 {
70   // initialise GL and kick off render thread
71   DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
72
73   // Tell core what the minimum frame interval is
74   mCore.SetMinimumFrameTimeInterval( mCurrent.syncMode * TIME_PER_FRAME_IN_MICROSECONDS );
75
76   // create the render thread, initially we are rendering
77   mThread = new boost::thread(boost::bind(&RenderThread::Run, this));
78
79   // Inform surface to block waiting for RenderSync
80   mCurrent.surface->SetSyncMode( RenderSurface::SYNC_MODE_WAIT );
81  }
82
83 void RenderThread::Stop()
84 {
85   // shutdown the render thread and destroy the opengl context
86   if( mThread )
87   {
88     // Tell surface we have stopped rendering
89     mCurrent.surface->StopRender();
90
91     // wait for the thread to finish
92     mThread->join();
93
94     delete mThread;
95     mThread = NULL;
96   }
97 }
98
99 void RenderThread::ReplaceSurface( RenderSurface* surface )
100 {
101   // Make sure it's a new surface. Note! we are reading the current value of render thread here, but reading is ok
102   DALI_ASSERT_ALWAYS( surface != mCurrent.surface && "Trying to replace surface with itself" );
103
104   // lock and set to false
105   {
106     boost::unique_lock<boost::mutex> lock( mSurfaceChangedMutex );
107     mSurfaceReplaceCompleted = false;
108   }
109
110   // lock cache and set update flag at the end of function
111   {
112     SendMessageGuard msg( *this );
113     // set new values to cache
114     mNewValues.replaceSurface = true;
115     mNewValues.surface = surface;
116   }
117
118   /*
119    * Reset the mPixmapFlushed condition if surface was changed.
120    * : in this case, client can not handle the previous damage because surface was changed.
121    */
122   RenderSync();
123 }
124
125 void RenderThread::WaitForSurfaceReplaceComplete()
126 {
127   boost::unique_lock<boost::mutex> lock( mSurfaceChangedMutex );
128
129   // if already completed no need to wait
130   while( !mSurfaceReplaceCompleted )
131   {
132     mSurfaceChangedNotify.wait( lock ); // Block the main thread here and releases mSurfaceChangedMutex so the render-thread can notify us
133   }
134 }
135
136 void RenderThread::SetVSyncMode( EglInterface::SyncMode syncMode )
137 {
138   // lock cache and set update flag at the end of function
139   SendMessageGuard msg( *this );
140   // set new values to cache
141   mNewValues.syncMode = syncMode;
142 }
143
144 void RenderThread::RenderSync()
145 {
146   mCurrent.surface->RenderSync();
147 }
148
149 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
150 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
151 // The following methods are all executed inside render thread !!!
152 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
153 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
154
155 bool RenderThread::Run()
156 {
157   // install a function for logging
158   mEnvironmentOptions.InstallLogFunction();
159
160   InitializeEgl();
161
162   bool running( true );
163
164   // Wait for first update
165   mUpdateRenderSync.RenderSyncWithUpdate();
166
167   Dali::Integration::RenderStatus renderStatus;
168
169   uint64_t currentTime( 0 );
170
171   // render loop, we stay inside here when rendering
172   while( running )
173   {
174     // Consume any pending events
175     ConsumeEvents();
176
177     // Check if we've got updates from the main thread
178     CheckForUpdates();
179
180     // perform any pre-render operations
181     if(PreRender() == true)
182     {
183        // Render
184       mCore.Render( renderStatus );
185
186       // Notify the update-thread that a render has completed
187       mUpdateRenderSync.RenderFinished( renderStatus.NeedsUpdate() );
188
189       uint64_t newTime( mUpdateRenderSync.GetTimeMicroseconds() );
190
191       // perform any post-render operations
192       if ( renderStatus.HasRendered() )
193       {
194         PostRender( static_cast< unsigned int >(newTime - currentTime) );
195       }
196
197       if(mSurfaceReplacing)
198       {
199         // Notify main thread that surface was changed so it can release the old one
200         NotifySurfaceChangeCompleted();
201         mSurfaceReplacing = false;
202       }
203
204       currentTime = newTime;
205     }
206
207     // Wait until another frame has been updated
208     running = mUpdateRenderSync.RenderSyncWithUpdate();
209   }
210
211   // shut down egl
212   ShutdownEgl();
213
214   // install a function for logging
215   mEnvironmentOptions.UnInstallLogFunction();
216
217   return true;
218 }
219
220 void RenderThread::InitializeEgl()
221 {
222   mEGL = mEglFactory->Create();
223
224   DALI_ASSERT_ALWAYS( mCurrent.surface && "NULL surface" );
225
226   // initialize egl & OpenGL
227   mCurrent.surface->InitializeEgl( *mEGL );
228
229   // create the OpenGL context
230   mEGL->CreateContext();
231
232   // create the OpenGL surface
233   mCurrent.surface->CreateEglSurface( *mEGL );
234
235   // Make it current
236   mEGL->MakeContextCurrent();
237
238   // set the initial sync mode
239   mEGL->SetRefreshSync( mCurrent.syncMode );
240
241   // tell core it has a context
242   mCore.ContextCreated();
243
244   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", mGLES.GetString(GL_VENDOR));
245   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", mGLES.GetString(GL_RENDERER));
246   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", mGLES.GetString(GL_VERSION));
247   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", mGLES.GetString(GL_SHADING_LANGUAGE_VERSION));
248   DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", mGLES.GetString(GL_EXTENSIONS));
249 }
250
251 void RenderThread::ConsumeEvents()
252 {
253   // tell surface to consume any events to avoid memory leaks
254   mCurrent.surface->ConsumeEvents();
255 }
256
257 void RenderThread::CheckForUpdates()
258 {
259   // atomic check to see if we've got updates, resets the flag int
260   if( __sync_fetch_and_and( &mNewDataAvailable, 0 ) )
261   {
262     // scope for lock
263     // NOTE! This block is the only place in render side where mNewValues can be used inside render thread !!!
264     {
265       // need to lock to access new values
266       boost::unique_lock< boost::mutex > lock( mThreadDataLock );
267
268       // did the sync mode change
269       if( mCurrent.syncMode != mNewValues.syncMode )
270       {
271         mCurrent.syncMode = mNewValues.syncMode;
272         mEGL->SetRefreshSync( mCurrent.syncMode );
273       }
274
275       // check if the surface needs replacing
276       if( mNewValues.replaceSurface )
277       {
278         mNewValues.replaceSurface = false; // reset the flag
279         // change the surface
280         ChangeSurface( mNewValues.surface );
281         mNewValues.surface = NULL;
282       }
283     }
284   }
285 }
286
287 void RenderThread::ChangeSurface( RenderSurface* newSurface )
288 {
289   // This is designed for replacing pixmap surfaces, but should work for window as well
290   // we need to delete the egl surface and renderable (pixmap / window)
291   // Then create a new pixmap/window and new egl surface
292   // If the new surface has a different display connection, then the context will be lost
293   DALI_ASSERT_ALWAYS( newSurface && "NULL surface" )
294   bool contextLost = newSurface->ReplaceEGLSurface( *mEGL );
295
296   if( contextLost )
297   {
298     DALI_LOG_WARNING("Context lost\n");
299     mCore.ContextToBeDestroyed();
300     mCore.ContextCreated();
301   }
302
303   // if both new and old surface are using the same display, and the display
304   // connection was created by Dali, then transfer
305   // display owner ship to the new surface.
306   mCurrent.surface->TransferDisplayOwner( *newSurface );
307
308   // use the new surface from now on
309   mCurrent.surface = newSurface;
310
311   // after rendering, NotifySurfaceChangeCompleted will be called
312   mSurfaceReplacing = true;
313 }
314
315 void RenderThread::NotifySurfaceChangeCompleted()
316 {
317   {
318     boost::unique_lock< boost::mutex > lock( mSurfaceChangedMutex );
319     mSurfaceReplaceCompleted = true;
320   }
321   // notify main thread
322   mSurfaceChangedNotify.notify_all();
323 }
324
325 void RenderThread::ShutdownEgl()
326 {
327   // inform core the context is about to be destroyed,
328   mCore.ContextToBeDestroyed();
329
330   // give a chance to destroy the OpenGL surface that created externally
331   mCurrent.surface->DestroyEglSurface( *mEGL );
332
333   // delete the GL context / egl surface
334   mEGL->TerminateGles();
335 }
336
337 bool RenderThread::PreRender()
338 {
339   return mCurrent.surface->PreRender( *mEGL, mGLES );
340 }
341
342 void RenderThread::PostRender( unsigned int timeDelta )
343 {
344   mCurrent.surface->PostRender( *mEGL, mGLES, timeDelta,
345                                 mSurfaceReplacing ? RenderSurface::SYNC_MODE_NONE : RenderSurface::SYNC_MODE_WAIT );
346 }
347
348 } // namespace Adaptor
349
350 } // namespace Internal
351
352 } // namespace Dali