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