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