[Tizen] Disable PreRotation 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 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   SetBufferDamagedRects( damagedRects, clippingRect );
509
510   return true;
511 }
512
513 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
514 {
515   // Inform the gl implementation that rendering has finished before informing the surface
516   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
517   if ( eglGraphics )
518   {
519     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
520     mGLES.PostRender();
521
522     if( renderToFbo )
523     {
524       mGLES.Flush();
525       mGLES.Finish();
526     }
527     else
528     {
529       if( resizingSurface )
530       {
531         if( !mRotationFinished )
532         {
533           if( mThreadSynchronization )
534           {
535             // Enable PostRender flag
536             mThreadSynchronization->PostRenderStarted();
537           }
538
539           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
540
541           mRotationTrigger->Trigger();
542
543           if( mThreadSynchronization )
544           {
545             // Wait until the event-thread complete the rotation event processing
546             mThreadSynchronization->PostRenderWaitForCompletion();
547           }
548         }
549       }
550     }
551
552     SwapBuffers( damagedRects );
553
554     if( mRenderNotification )
555     {
556       mRenderNotification->Trigger();
557     }
558   }
559 }
560
561 void WindowRenderSurface::StopRender()
562 {
563 }
564
565 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
566 {
567   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
568
569   mThreadSynchronization = &threadSynchronization;
570 }
571
572 void WindowRenderSurface::ReleaseLock()
573 {
574   // Nothing to do.
575 }
576
577 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
578 {
579   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
580 }
581
582 void WindowRenderSurface::MakeContextCurrent()
583 {
584   if ( mEGL != nullptr )
585   {
586     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
587   }
588 }
589
590 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
591 {
592   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
593 }
594
595 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
596 {
597   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
598 }
599
600 void WindowRenderSurface::OutputTransformed()
601 {
602   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
603
604   if( mScreenRotationAngle != screenRotationAngle )
605   {
606     mScreenRotationAngle = screenRotationAngle;
607     mScreenRotationFinished = false;
608     mResizeFinished = false;
609
610     mOutputTransformedSignal.Emit();
611
612     DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
613   }
614   else
615   {
616     DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
617   }
618 }
619
620 void WindowRenderSurface::ProcessRotationRequest()
621 {
622   mRotationFinished = true;
623
624   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
625
626   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
627
628   if( mThreadSynchronization )
629   {
630     mThreadSynchronization->PostRenderComplete();
631   }
632 }
633
634 void WindowRenderSurface::ProcessFrameCallback()
635 {
636   Dali::Mutex::ScopedLock lock( mMutex );
637
638   for( auto&& iter : mFrameCallbackInfoContainer )
639   {
640     if( !iter->fileDescriptorMonitor )
641     {
642       iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
643                                                                              MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
644
645       DALI_LOG_RELEASE_INFO( "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
646     }
647   }
648 }
649
650 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
651 {
652   if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
653   {
654     DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
655     close( fileDescriptor );
656     return;
657   }
658
659   DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
660
661   std::unique_ptr< FrameCallbackInfo > callbackInfo;
662   {
663     Dali::Mutex::ScopedLock lock( mMutex );
664     auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
665                                       [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
666                                       {
667                                         return callbackInfo->fileDescriptor == fileDescriptor;
668                                       } );
669     if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
670     {
671       callbackInfo = std::move( *frameCallbackInfo );
672
673       mFrameCallbackInfoContainer.erase( frameCallbackInfo );
674     }
675   }
676
677   // Call the connected callback
678   if( callbackInfo )
679   {
680     for( auto&& iter : ( callbackInfo )->callbacks )
681     {
682       CallbackBase::Execute( *( iter.first ), iter.second );
683     }
684   }
685 }
686
687 void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
688 {
689   auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
690   if ( eglGraphics )
691   {
692     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
693     if( !eglImpl.IsPartialUpdateRequired() )
694     {
695       return;
696     }
697
698     Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
699
700     if( mFullSwapNextFrame )
701     {
702       InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
703       clippingRect = Rect< int >();
704       return;
705     }
706
707     EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
708
709     // Buffer age 0 means the back buffer in invalid and requires full swap
710     if( !damagedRects.size() || bufferAge == 0 )
711     {
712       InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
713       clippingRect = Rect< int >();
714       return;
715     }
716
717     // We push current frame damaged rects here, zero index for current frame
718     InsertRects( mBufferDamagedRects, damagedRects );
719
720     // Merge damaged rects into clipping rect
721     auto bufferDamagedRects = mBufferDamagedRects.begin();
722     while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
723     {
724       const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
725       MergeRects( clippingRect, rects );
726     }
727
728     if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
729     {
730       // clipping area too big or doesn't intersect surface rect
731       clippingRect = Rect< int >();
732       return;
733     }
734
735     std::vector< Rect< int > > damagedRegion;
736     damagedRegion.push_back( clippingRect );
737
738     eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
739   }
740 }
741
742 void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
743 {
744   auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
745   if( eglGraphics )
746   {
747     Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
748
749     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
750
751     if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
752     {
753       mFullSwapNextFrame = false;
754       eglImpl.SwapBuffers( mEGLSurface );
755       return;
756     }
757
758     mFullSwapNextFrame = false;
759
760     std::vector< Rect< int > > mergedRects = damagedRects;
761
762     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
763     // Could be optional and can be removed, needs to be checked with and without on platform
764     const int n = mergedRects.size();
765     for( int i = 0; i < n - 1; i++ )
766     {
767       if( mergedRects[i].IsEmpty() )
768       {
769         continue;
770       }
771
772       for( int j = i + 1; j < n; j++ )
773       {
774         if( mergedRects[j].IsEmpty() )
775         {
776           continue;
777         }
778
779         if( mergedRects[i].Intersects( mergedRects[j] ) )
780         {
781           mergedRects[i].Merge( mergedRects[j] );
782           mergedRects[j].width = 0;
783           mergedRects[j].height = 0;
784         }
785       }
786     }
787
788     int j = 0;
789     for( int i = 0; i < n; i++ )
790     {
791       if( !mergedRects[i].IsEmpty() )
792       {
793         mergedRects[j++] = mergedRects[i];
794       }
795     }
796
797     if( j != 0 )
798     {
799       mergedRects.resize( j );
800     }
801
802     if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
803     {
804       eglImpl.SwapBuffers( mEGLSurface );
805     }
806     else
807     {
808       eglImpl.SwapBuffers( mEGLSurface, mergedRects );
809     }
810   }
811 }
812
813 } // namespace Adaptor
814
815 } // namespace internal
816
817 } // namespace Dali