[Tizen] Add screen and client rotation itself function
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / common / window-render-surface.cpp
1 /*
2  * Copyright (c) 2020 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/internal/window-system/common/window-render-surface.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
27 #include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
28 #include <dali/internal/adaptor/common/adaptor-impl.h>
29 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
30 #include <dali/internal/graphics/gles/egl-graphics.h>
31 #include <dali/internal/graphics/gles/egl-implementation.h>
32 #include <dali/internal/window-system/common/window-base.h>
33 #include <dali/internal/window-system/common/window-factory.h>
34 #include <dali/internal/window-system/common/window-system.h>
35 #include <dali/internal/system/common/environment-variables.h>
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace Adaptor
42 {
43
44 namespace
45 {
46
47 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
48
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
51 #endif
52
53 } // unnamed namespace
54
55 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
56 : mEGL( nullptr ),
57   mDisplayConnection( nullptr ),
58   mPositionSize( positionSize ),
59   mWindowBase(),
60   mThreadSynchronization( NULL ),
61   mRenderNotification( NULL ),
62   mRotationTrigger( NULL ),
63   mFrameRenderedTrigger(),
64   mGraphics( nullptr ),
65   mEGLSurface( nullptr ),
66   mEGLContext( nullptr ),
67   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
68   mOutputTransformedSignal(),
69   mFrameCallbackInfoContainer(),
70   mRotationAngle( 0 ),
71   mScreenRotationAngle( 0 ),
72   mOwnSurface( false ),
73   mRotationSupported( false ),
74   mRotationFinished( true ),
75   mScreenRotationFinished( true ),
76   mResizeFinished( true ),
77   mDpiHorizontal( 0 ),
78   mDpiVertical( 0 )
79 {
80   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
81   Initialize( surface );
82 }
83
84 WindowRenderSurface::~WindowRenderSurface()
85 {
86   if( mRotationTrigger )
87   {
88     delete mRotationTrigger;
89   }
90 }
91
92 void WindowRenderSurface::Initialize( Any surface )
93 {
94   // If width or height are zero, go full screen.
95   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
96   {
97     // Default window size == screen size
98     mPositionSize.x = 0;
99     mPositionSize.y = 0;
100     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
101   }
102
103   // Create a window base
104   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
105   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
106
107   // Connect signals
108   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
109
110   // Check screen rotation
111   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
112   if( mScreenRotationAngle != 0 )
113   {
114     mScreenRotationFinished = false;
115     mResizeFinished = false;
116   }
117 }
118
119 Any WindowRenderSurface::GetNativeWindow()
120 {
121   return mWindowBase->GetNativeWindow();
122 }
123
124 int WindowRenderSurface::GetNativeWindowId()
125 {
126   return mWindowBase->GetNativeWindowId();
127 }
128
129 void WindowRenderSurface::Map()
130 {
131   mWindowBase->Show();
132 }
133
134 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
135 {
136   mRenderNotification = renderNotification;
137 }
138
139 void WindowRenderSurface::SetTransparency( bool transparent )
140 {
141   mWindowBase->SetTransparency( transparent );
142 }
143
144 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
145 {
146   if( !mRotationTrigger )
147   {
148     mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
149   }
150
151   mPositionSize.width = width;
152   mPositionSize.height = height;
153
154   mRotationAngle = angle;
155   mRotationFinished = false;
156
157   mWindowBase->SetWindowRotationAngle( mRotationAngle );
158
159   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
160 }
161
162 WindowBase* WindowRenderSurface::GetWindowBase()
163 {
164   return mWindowBase.get();
165 }
166
167 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
168 {
169   return mOutputTransformedSignal;
170 }
171
172 PositionSize WindowRenderSurface::GetPositionSize() const
173 {
174   return mPositionSize;
175 }
176
177 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
178 {
179   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
180   {
181     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
182     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
183
184     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
185     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
186
187     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
188     {
189       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
190     }
191   }
192
193   dpiHorizontal = mDpiHorizontal;
194   dpiVertical = mDpiVertical;
195 }
196
197 int WindowRenderSurface::GetOrientation() const
198 {
199   return mWindowBase->GetOrientation();
200 }
201
202 void WindowRenderSurface::InitializeGraphics()
203 {
204   mGraphics = &mAdaptor->GetGraphicsInterface();
205
206   DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
207
208   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
209   mEGL = &eglGraphics->GetEglInterface();
210
211   if ( mEGLContext == NULL )
212   {
213     // Create the OpenGL context for this window
214     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
215     eglImpl.ChooseConfig(true, mColorDepth);
216     eglImpl.CreateWindowContext( mEGLContext );
217
218     // Create the OpenGL surface
219     CreateSurface();
220   }
221 }
222
223 void WindowRenderSurface::CreateSurface()
224 {
225   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
226
227   int width, height;
228   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
229   {
230     width = mPositionSize.width;
231     height = mPositionSize.height;
232   }
233   else
234   {
235     width = mPositionSize.height;
236     height = mPositionSize.width;
237   }
238
239   // Create the EGL window
240   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
241
242   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
243
244   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
245   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
246
247   // Check rotation capability
248   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
249
250   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
251       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
252 }
253
254 void WindowRenderSurface::DestroySurface()
255 {
256   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
257
258   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
259   if( eglGraphics )
260   {
261     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
262
263     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
264
265     eglImpl.DestroySurface( mEGLSurface );
266     mEGLSurface = nullptr;
267
268     // Destroy context also
269     eglImpl.DestroyContext( mEGLContext );
270     mEGLContext = nullptr;
271
272     mWindowBase->DestroyEglWindow();
273   }
274 }
275
276 bool WindowRenderSurface::ReplaceGraphicsSurface()
277 {
278   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
279
280   // Destroy the old one
281   mWindowBase->DestroyEglWindow();
282
283   int width, height;
284   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
285   {
286     width = mPositionSize.width;
287     height = mPositionSize.height;
288   }
289   else
290   {
291     width = mPositionSize.height;
292     height = mPositionSize.width;
293   }
294
295   // Create the EGL window
296   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
297
298   // Set screen rotation
299   mScreenRotationFinished = false;
300
301   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
302
303   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
304   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
305 }
306
307 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
308 {
309   bool needToMove = false;
310   bool needToResize = false;
311
312   // Check moving
313   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
314       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
315   {
316     needToMove = true;
317   }
318
319   // Check resizing
320   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
321       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
322   {
323     needToResize = true;
324   }
325
326   if( needToResize )
327   {
328     if( needToMove )
329     {
330       mWindowBase->MoveResize( positionSize );
331     }
332     else
333     {
334       mWindowBase->Resize( positionSize );
335     }
336
337     mResizeFinished = false;
338     mPositionSize = positionSize;
339   }
340   else
341   {
342     if( needToMove )
343     {
344       mWindowBase->Move( positionSize );
345
346       mPositionSize = positionSize;
347     }
348   }
349
350   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
351 }
352
353 void WindowRenderSurface::StartRender()
354 {
355 }
356
357 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
358 {
359   Dali::Integration::Scene::FrameCallbackContainer callbacks;
360
361   Dali::Integration::Scene scene = mScene.GetHandle();
362   if( scene )
363   {
364     scene.GetFrameRenderedCallback( callbacks );
365     if( !callbacks.empty() )
366     {
367       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
368       if( frameRenderedSync != -1 )
369       {
370         DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
371
372         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
373
374         if( !mFrameRenderedTrigger )
375         {
376           mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
377                                                                                                                      TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
378         }
379         mFrameRenderedTrigger->Trigger();
380       }
381       else
382       {
383         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
384       }
385
386       // Clear callbacks
387       callbacks.clear();
388     }
389
390     scene.GetFramePresentedCallback( callbacks );
391     if( !callbacks.empty() )
392     {
393       int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
394       if( framePresentedSync != -1 )
395       {
396         DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
397
398         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
399
400         if( !mFrameRenderedTrigger )
401         {
402           mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
403                                                                                                                      TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
404         }
405         mFrameRenderedTrigger->Trigger();
406       }
407       else
408       {
409         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
410       }
411
412       // Clear callbacks
413       callbacks.clear();
414     }
415   }
416
417   MakeContextCurrent();
418
419   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
420
421   if( resizingSurface )
422   {
423     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
424
425     // Window rotate or screen rotate
426     if( !mRotationFinished || !mScreenRotationFinished )
427     {
428       mWindowBase->SetEglWindowRotation( totalAngle );
429       mWindowBase->SetEglWindowBufferTransform( totalAngle );
430
431       // Reset only screen rotation flag
432       mScreenRotationFinished = true;
433
434       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
435     }
436
437     // Only window rotate
438     if( !mRotationFinished )
439     {
440       mWindowBase->SetEglWindowTransform( mRotationAngle );
441     }
442
443     // Resize case
444     if ( !mResizeFinished )
445     {
446       Dali::PositionSize positionSize;
447       positionSize.x = mPositionSize.x;
448       positionSize.y = mPositionSize.y;
449       if( totalAngle == 0 || totalAngle == 180 )
450       {
451         positionSize.width = mPositionSize.width;
452         positionSize.height = mPositionSize.height;
453       }
454       else
455       {
456         positionSize.width = mPositionSize.height;
457         positionSize.height = mPositionSize.width;
458       }
459       mWindowBase->ResizeEglWindow( positionSize );
460       mResizeFinished = true;
461
462       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
463     }
464
465     if (eglGraphics)
466     {
467       Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
468       eglImpl.SetFullSwapNextFrame();
469     }
470   }
471
472   if (eglGraphics)
473   {
474     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
475     eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
476   }
477
478   return true;
479 }
480
481 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
482 {
483   // Inform the gl implementation that rendering has finished before informing the surface
484   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
485   if ( eglGraphics )
486   {
487     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
488     mGLES.PostRender();
489
490     if( renderToFbo )
491     {
492       mGLES.Flush();
493       mGLES.Finish();
494     }
495     else
496     {
497       if( resizingSurface )
498       {
499         if( !mRotationFinished )
500         {
501           if( mThreadSynchronization )
502           {
503             // Enable PostRender flag
504             mThreadSynchronization->PostRenderStarted();
505           }
506
507           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
508
509           mRotationTrigger->Trigger();
510
511           if( mThreadSynchronization )
512           {
513             // Wait until the event-thread complete the rotation event processing
514             mThreadSynchronization->PostRenderWaitForCompletion();
515           }
516         }
517       }
518     }
519
520     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
521     eglImpl.SwapBuffers( mEGLSurface, damagedRects );
522
523     if( mRenderNotification )
524     {
525       mRenderNotification->Trigger();
526     }
527   }
528 }
529
530 void WindowRenderSurface::StopRender()
531 {
532 }
533
534 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
535 {
536   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
537
538   mThreadSynchronization = &threadSynchronization;
539 }
540
541 void WindowRenderSurface::ReleaseLock()
542 {
543   // Nothing to do.
544 }
545
546 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
547 {
548   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
549 }
550
551 void WindowRenderSurface::MakeContextCurrent()
552 {
553   if ( mEGL != nullptr )
554   {
555     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
556   }
557 }
558
559 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
560 {
561   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
562 }
563
564 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
565 {
566   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
567 }
568
569 void WindowRenderSurface::OutputTransformed()
570 {
571   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
572
573   if( mScreenRotationAngle != screenRotationAngle )
574   {
575     mScreenRotationAngle = screenRotationAngle;
576     mScreenRotationFinished = false;
577     mResizeFinished = false;
578
579     mOutputTransformedSignal.Emit();
580
581     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
582   }
583   else
584   {
585     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
586   }
587 }
588
589 void WindowRenderSurface::ProcessRotationRequest()
590 {
591   mRotationFinished = true;
592
593   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
594
595   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
596
597   if( mThreadSynchronization )
598   {
599     mThreadSynchronization->PostRenderComplete();
600   }
601 }
602
603 void WindowRenderSurface::ProcessFrameCallback()
604 {
605   for( auto&& iter : mFrameCallbackInfoContainer )
606   {
607     if( !iter->fileDescriptorMonitor )
608     {
609       iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
610                                                                              MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
611
612       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
613     }
614   }
615 }
616
617 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
618 {
619   if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
620   {
621     DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
622     close( fileDescriptor );
623     return;
624   }
625
626   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
627
628   auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
629                                     [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
630                                     {
631                                       return callbackInfo->fileDescriptor == fileDescriptor;
632                                     } );
633   if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
634   {
635     // Call the connected callback
636     for( auto&& iter : ( *frameCallbackInfo )->callbacks )
637     {
638       CallbackBase::Execute( *( iter.first ), iter.second );
639     }
640     mFrameCallbackInfoContainer.erase( frameCallbackInfo );
641   }
642 }
643
644 } // namespace Adaptor
645
646 } // namespace internal
647
648 } // namespace Dali