[Tizen] Ensure to update full region until rotation is finished
[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 const float FULL_UPDATE_RATIO( 0.8f );   ///< Force full update when the dirty area is larget than this ratio
49
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
52 #endif
53
54 void MergeRects( Rect< int >& mergingRect, const std::vector< Rect< int > >& rects )
55 {
56   uint32_t i = 0;
57   if( mergingRect.IsEmpty() )
58   {
59     for( ; i < rects.size(); i++ )
60     {
61       if( !rects[i].IsEmpty() )
62       {
63         mergingRect = rects[i];
64         break;
65       }
66     }
67   }
68
69   for( ; i < rects.size(); i++ )
70   {
71     mergingRect.Merge( rects[i] );
72   }
73 }
74
75 void InsertRects( WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const std::vector< Rect< int > >& damagedRects )
76 {
77   damagedRectsList.push_front( damagedRects );
78   if( damagedRectsList.size() > 4 ) // past triple buffers + current
79   {
80     damagedRectsList.pop_back();
81   }
82 }
83
84 } // unnamed namespace
85
86 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
87 : mEGL( nullptr ),
88   mDisplayConnection( nullptr ),
89   mPositionSize( positionSize ),
90   mWindowBase(),
91   mThreadSynchronization( NULL ),
92   mRenderNotification( NULL ),
93   mRotationTrigger( NULL ),
94   mFrameRenderedTrigger(),
95   mGraphics( nullptr ),
96   mEGLSurface( nullptr ),
97   mEGLContext( nullptr ),
98   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
99   mOutputTransformedSignal(),
100   mFrameCallbackInfoContainer(),
101   mBufferDamagedRects(),
102   mMutex(),
103   mRotationAngle( 0 ),
104   mScreenRotationAngle( 0 ),
105   mDpiHorizontal( 0 ),
106   mDpiVertical( 0 ),
107   mOwnSurface( false ),
108   mRotationSupported( false ),
109   mRotationFinished( true ),
110   mScreenRotationFinished( true ),
111   mResizeFinished( true ),
112   mDefaultScreenRotationAvailable( false )
113 {
114   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
115   Initialize( surface );
116 }
117
118 WindowRenderSurface::~WindowRenderSurface()
119 {
120   if( mRotationTrigger )
121   {
122     delete mRotationTrigger;
123   }
124 }
125
126 void WindowRenderSurface::Initialize( Any surface )
127 {
128   // If width or height are zero, go full screen.
129   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
130   {
131     // Default window size == screen size
132     mPositionSize.x = 0;
133     mPositionSize.y = 0;
134     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
135   }
136
137   // Create a window base
138   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
139   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
140
141   // Connect signals
142   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
143
144   // Check screen rotation
145   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
146   if( mScreenRotationAngle != 0 )
147   {
148     mScreenRotationFinished = false;
149     mResizeFinished = false;
150     mDefaultScreenRotationAvailable = true;
151     DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle );
152   }
153 }
154
155 Any WindowRenderSurface::GetNativeWindow()
156 {
157   return mWindowBase->GetNativeWindow();
158 }
159
160 int WindowRenderSurface::GetNativeWindowId()
161 {
162   return mWindowBase->GetNativeWindowId();
163 }
164
165 void WindowRenderSurface::Map()
166 {
167   mWindowBase->Show();
168 }
169
170 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
171 {
172   mRenderNotification = renderNotification;
173 }
174
175 void WindowRenderSurface::SetTransparency( bool transparent )
176 {
177   mWindowBase->SetTransparency( transparent );
178 }
179
180 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
181 {
182   if( !mRotationTrigger )
183   {
184     mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
185   }
186
187   mPositionSize.width = width;
188   mPositionSize.height = height;
189
190   mRotationAngle = angle;
191   mRotationFinished = false;
192
193   mWindowBase->SetWindowRotationAngle( mRotationAngle );
194
195   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
196 }
197
198 WindowBase* WindowRenderSurface::GetWindowBase()
199 {
200   return mWindowBase.get();
201 }
202
203 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
204 {
205   return mOutputTransformedSignal;
206 }
207
208 PositionSize WindowRenderSurface::GetPositionSize() const
209 {
210   return mPositionSize;
211 }
212
213 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
214 {
215   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
216   {
217     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
218     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
219
220     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
221     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
222
223     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
224     {
225       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
226     }
227   }
228
229   dpiHorizontal = mDpiHorizontal;
230   dpiVertical = mDpiVertical;
231 }
232
233 int WindowRenderSurface::GetOrientation() const
234 {
235   return mWindowBase->GetOrientation();
236 }
237
238 void WindowRenderSurface::InitializeGraphics()
239 {
240   mGraphics = &mAdaptor->GetGraphicsInterface();
241
242   DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
243
244   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
245   mEGL = &eglGraphics->GetEglInterface();
246
247   if ( mEGLContext == NULL )
248   {
249     // Create the OpenGL context for this window
250     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
251     eglImpl.ChooseConfig(true, mColorDepth);
252     eglImpl.CreateWindowContext( mEGLContext );
253
254     // Create the OpenGL surface
255     CreateSurface();
256   }
257 }
258
259 void WindowRenderSurface::CreateSurface()
260 {
261   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
262
263   int width, height;
264   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
265   {
266     width = mPositionSize.width;
267     height = mPositionSize.height;
268   }
269   else
270   {
271     width = mPositionSize.height;
272     height = mPositionSize.width;
273   }
274
275   // Create the EGL window
276   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
277
278   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
279
280   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
281   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
282
283   // Check rotation capability
284   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
285
286   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
287       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
288 }
289
290 void WindowRenderSurface::DestroySurface()
291 {
292   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
293
294   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
295   if( eglGraphics )
296   {
297     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
298
299     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
300
301     eglImpl.DestroySurface( mEGLSurface );
302     mEGLSurface = nullptr;
303
304     // Destroy context also
305     eglImpl.DestroyContext( mEGLContext );
306     mEGLContext = nullptr;
307
308     mWindowBase->DestroyEglWindow();
309   }
310 }
311
312 bool WindowRenderSurface::ReplaceGraphicsSurface()
313 {
314   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
315
316   // Destroy the old one
317   mWindowBase->DestroyEglWindow();
318
319   int width, height;
320   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
321   {
322     width = mPositionSize.width;
323     height = mPositionSize.height;
324   }
325   else
326   {
327     width = mPositionSize.height;
328     height = mPositionSize.width;
329   }
330
331   // Create the EGL window
332   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
333
334   // Set screen rotation
335   mScreenRotationFinished = false;
336
337   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
338
339   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
340   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
341 }
342
343 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
344 {
345   bool needToMove = false;
346   bool needToResize = false;
347
348   // Check moving
349   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
350       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
351   {
352     needToMove = true;
353   }
354
355   // Check resizing
356   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
357       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
358   {
359     needToResize = true;
360   }
361
362   if( needToResize )
363   {
364     if( needToMove )
365     {
366       mWindowBase->MoveResize( positionSize );
367     }
368     else
369     {
370       mWindowBase->Resize( positionSize );
371     }
372
373     mResizeFinished = false;
374     mPositionSize = positionSize;
375   }
376   else
377   {
378     if( needToMove )
379     {
380       mWindowBase->Move( positionSize );
381
382       mPositionSize = positionSize;
383     }
384   }
385
386   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
387 }
388
389 void WindowRenderSurface::StartRender()
390 {
391 }
392
393 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
394 {
395   Dali::Integration::Scene::FrameCallbackContainer callbacks;
396
397   Dali::Integration::Scene scene = mScene.GetHandle();
398   if( scene )
399   {
400     bool needFrameRenderedTrigger = false;
401
402     scene.GetFrameRenderedCallback( callbacks );
403     if( !callbacks.empty() )
404     {
405       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
406       if( frameRenderedSync != -1 )
407       {
408         Dali::Mutex::ScopedLock lock( mMutex );
409
410         DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
411
412         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
413
414         needFrameRenderedTrigger = true;
415       }
416       else
417       {
418         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
419       }
420
421       // Clear callbacks
422       callbacks.clear();
423     }
424
425     scene.GetFramePresentedCallback( callbacks );
426     if( !callbacks.empty() )
427     {
428       int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
429       if( framePresentedSync != -1 )
430       {
431         Dali::Mutex::ScopedLock lock( mMutex );
432
433         DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
434
435         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
436
437         needFrameRenderedTrigger = true;
438       }
439       else
440       {
441         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
442       }
443
444       // Clear callbacks
445       callbacks.clear();
446     }
447
448     if( needFrameRenderedTrigger )
449     {
450       if( !mFrameRenderedTrigger )
451       {
452         mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
453                                                                                                                    TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
454       }
455       mFrameRenderedTrigger->Trigger();
456     }
457   }
458
459   MakeContextCurrent();
460
461   if( resizingSurface || mDefaultScreenRotationAvailable )
462   {
463     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
464
465     // Window rotate or screen rotate
466     if( !mRotationFinished || !mScreenRotationFinished )
467     {
468       mWindowBase->SetEglWindowBufferTransform( totalAngle );
469
470       // Reset only screen rotation flag
471       mScreenRotationFinished = true;
472
473       DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
474     }
475
476     // Only window rotate
477     if( !mRotationFinished )
478     {
479       mWindowBase->SetEglWindowTransform( mRotationAngle );
480     }
481
482     // Resize case
483     if ( !mResizeFinished )
484     {
485       Dali::PositionSize positionSize;
486       positionSize.x = mPositionSize.x;
487       positionSize.y = mPositionSize.y;
488       if( totalAngle == 0 || totalAngle == 180 )
489       {
490         positionSize.width = mPositionSize.width;
491         positionSize.height = mPositionSize.height;
492       }
493       else
494       {
495         positionSize.width = mPositionSize.height;
496         positionSize.height = mPositionSize.width;
497       }
498       mWindowBase->ResizeEglWindow( positionSize );
499       mResizeFinished = true;
500
501       DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: Set resize\n" );
502     }
503
504     SetFullSwapNextFrame();
505     mDefaultScreenRotationAvailable = false;
506   }
507
508   if(!mRotationFinished)
509   {
510     SetFullSwapNextFrame();
511   }
512
513   SetBufferDamagedRects( damagedRects, clippingRect );
514
515   return true;
516 }
517
518 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
519 {
520   // Inform the gl implementation that rendering has finished before informing the surface
521   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
522   if ( eglGraphics )
523   {
524     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
525     mGLES.PostRender();
526
527     if( renderToFbo )
528     {
529       mGLES.Flush();
530       mGLES.Finish();
531     }
532     else
533     {
534       if( resizingSurface )
535       {
536         if( !mRotationFinished )
537         {
538           if( mThreadSynchronization )
539           {
540             // Enable PostRender flag
541             mThreadSynchronization->PostRenderStarted();
542           }
543
544           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
545
546           mRotationTrigger->Trigger();
547
548           if( mThreadSynchronization )
549           {
550             // Wait until the event-thread complete the rotation event processing
551             mThreadSynchronization->PostRenderWaitForCompletion();
552           }
553         }
554       }
555     }
556
557     SwapBuffers( damagedRects );
558
559     if( mRenderNotification )
560     {
561       mRenderNotification->Trigger();
562     }
563   }
564 }
565
566 void WindowRenderSurface::StopRender()
567 {
568 }
569
570 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
571 {
572   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
573
574   mThreadSynchronization = &threadSynchronization;
575 }
576
577 void WindowRenderSurface::ReleaseLock()
578 {
579   // Nothing to do.
580 }
581
582 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
583 {
584   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
585 }
586
587 void WindowRenderSurface::MakeContextCurrent()
588 {
589   if ( mEGL != nullptr )
590   {
591     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
592   }
593 }
594
595 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
596 {
597   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
598 }
599
600 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
601 {
602   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
603 }
604
605 void WindowRenderSurface::OutputTransformed()
606 {
607   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
608
609   if( mScreenRotationAngle != screenRotationAngle )
610   {
611     mScreenRotationAngle = screenRotationAngle;
612     mScreenRotationFinished = false;
613     mResizeFinished = false;
614
615     mOutputTransformedSignal.Emit();
616
617     DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
618   }
619   else
620   {
621     DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
622   }
623 }
624
625 void WindowRenderSurface::ProcessRotationRequest()
626 {
627   mRotationFinished = true;
628
629   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
630
631   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
632
633   if( mThreadSynchronization )
634   {
635     mThreadSynchronization->PostRenderComplete();
636   }
637 }
638
639 void WindowRenderSurface::ProcessFrameCallback()
640 {
641   Dali::Mutex::ScopedLock lock( mMutex );
642
643   for( auto&& iter : mFrameCallbackInfoContainer )
644   {
645     if( !iter->fileDescriptorMonitor )
646     {
647       iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
648                                                                              MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
649
650       DALI_LOG_RELEASE_INFO( "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
651     }
652   }
653 }
654
655 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
656 {
657   if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
658   {
659     DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
660     close( fileDescriptor );
661     return;
662   }
663
664   DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
665
666   std::unique_ptr< FrameCallbackInfo > callbackInfo;
667   {
668     Dali::Mutex::ScopedLock lock( mMutex );
669     auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
670                                       [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
671                                       {
672                                         return callbackInfo->fileDescriptor == fileDescriptor;
673                                       } );
674     if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
675     {
676       callbackInfo = std::move( *frameCallbackInfo );
677
678       mFrameCallbackInfoContainer.erase( frameCallbackInfo );
679     }
680   }
681
682   // Call the connected callback
683   if( callbackInfo )
684   {
685     for( auto&& iter : ( callbackInfo )->callbacks )
686     {
687       CallbackBase::Execute( *( iter.first ), iter.second );
688     }
689   }
690 }
691
692 void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
693 {
694   auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
695   if ( eglGraphics )
696   {
697     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
698     if( !eglImpl.IsPartialUpdateRequired() )
699     {
700       return;
701     }
702
703     Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
704
705     if( mFullSwapNextFrame )
706     {
707       InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
708       clippingRect = Rect< int >();
709       return;
710     }
711
712     EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
713
714     // Buffer age 0 means the back buffer in invalid and requires full swap
715     if( !damagedRects.size() || bufferAge == 0 )
716     {
717       InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
718       clippingRect = Rect< int >();
719       return;
720     }
721
722     // We push current frame damaged rects here, zero index for current frame
723     InsertRects( mBufferDamagedRects, damagedRects );
724
725     // Merge damaged rects into clipping rect
726     auto bufferDamagedRects = mBufferDamagedRects.begin();
727     while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
728     {
729       const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
730       MergeRects( clippingRect, rects );
731     }
732
733     if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
734     {
735       // clipping area too big or doesn't intersect surface rect
736       clippingRect = Rect< int >();
737       return;
738     }
739
740     std::vector< Rect< int > > damagedRegion;
741     damagedRegion.push_back( clippingRect );
742
743     eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
744   }
745 }
746
747 void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
748 {
749   auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
750   if( eglGraphics )
751   {
752     Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
753
754     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
755
756     if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
757     {
758       mFullSwapNextFrame = false;
759       eglImpl.SwapBuffers( mEGLSurface );
760       return;
761     }
762
763     mFullSwapNextFrame = false;
764
765     std::vector< Rect< int > > mergedRects = damagedRects;
766
767     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
768     // Could be optional and can be removed, needs to be checked with and without on platform
769     const int n = mergedRects.size();
770     for( int i = 0; i < n - 1; i++ )
771     {
772       if( mergedRects[i].IsEmpty() )
773       {
774         continue;
775       }
776
777       for( int j = i + 1; j < n; j++ )
778       {
779         if( mergedRects[j].IsEmpty() )
780         {
781           continue;
782         }
783
784         if( mergedRects[i].Intersects( mergedRects[j] ) )
785         {
786           mergedRects[i].Merge( mergedRects[j] );
787           mergedRects[j].width = 0;
788           mergedRects[j].height = 0;
789         }
790       }
791     }
792
793     int j = 0;
794     for( int i = 0; i < n; i++ )
795     {
796       if( !mergedRects[i].IsEmpty() )
797       {
798         mergedRects[j++] = mergedRects[i];
799       }
800     }
801
802     if( j != 0 )
803     {
804       mergedRects.resize( j );
805     }
806
807     if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
808     {
809       eglImpl.SwapBuffers( mEGLSurface );
810     }
811     else
812     {
813       eglImpl.SwapBuffers( mEGLSurface, mergedRects );
814     }
815   }
816 }
817
818 } // namespace Adaptor
819
820 } // namespace internal
821
822 } // namespace Dali