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