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