2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/window-system/common/window-render-surface.h>
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/debug.h>
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>
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
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
54 void MergeRects( Rect< int >& mergingRect, const std::vector< Rect< int > >& rects )
57 if( mergingRect.IsEmpty() )
59 for( ; i < rects.size(); i++ )
61 if( !rects[i].IsEmpty() )
63 mergingRect = rects[i];
69 for( ; i < rects.size(); i++ )
71 mergingRect.Merge( rects[i] );
75 void InsertRects( WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const std::vector< Rect< int > >& damagedRects )
77 damagedRectsList.push_front( damagedRects );
78 if( damagedRectsList.size() > 4 ) // past triple buffers + current
80 damagedRectsList.pop_back();
84 } // unnamed namespace
86 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
88 mDisplayConnection( nullptr ),
89 mPositionSize( positionSize ),
91 mThreadSynchronization( NULL ),
92 mRenderNotification( NULL ),
93 mRotationTrigger( NULL ),
94 mFrameRenderedTrigger(),
96 mEGLSurface( nullptr ),
97 mEGLContext( nullptr ),
98 mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
99 mOutputTransformedSignal(),
100 mFrameCallbackInfoContainer(),
101 mBufferDamagedRects(),
104 mScreenRotationAngle( 0 ),
107 mOwnSurface( false ),
108 mRotationSupported( false ),
109 mRotationFinished( true ),
110 mScreenRotationFinished( true ),
111 mResizeFinished( true ),
112 mDefaultScreenRotationAvailable( false )
114 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
115 Initialize( surface );
118 WindowRenderSurface::~WindowRenderSurface()
120 if( mRotationTrigger )
122 delete mRotationTrigger;
126 void WindowRenderSurface::Initialize( Any surface )
128 // If width or height are zero, go full screen.
129 if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
131 // Default window size == screen size
134 WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
137 // Create a window base
138 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
139 mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
142 mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
144 // Check screen rotation
145 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
146 if( mScreenRotationAngle != 0 )
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 );
155 Any WindowRenderSurface::GetNativeWindow()
157 return mWindowBase->GetNativeWindow();
160 int WindowRenderSurface::GetNativeWindowId()
162 return mWindowBase->GetNativeWindowId();
165 void WindowRenderSurface::Map()
170 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
172 mRenderNotification = renderNotification;
175 void WindowRenderSurface::SetTransparency( bool transparent )
177 mWindowBase->SetTransparency( transparent );
180 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
182 if( !mRotationTrigger )
184 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
187 mPositionSize.width = width;
188 mPositionSize.height = height;
190 mRotationAngle = angle;
191 mRotationFinished = false;
193 mWindowBase->SetWindowRotationAngle( mRotationAngle );
195 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
198 WindowBase* WindowRenderSurface::GetWindowBase()
200 return mWindowBase.get();
203 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
205 return mOutputTransformedSignal;
208 PositionSize WindowRenderSurface::GetPositionSize() const
210 return mPositionSize;
213 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
215 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
217 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
218 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
220 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
221 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
223 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
225 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
229 dpiHorizontal = mDpiHorizontal;
230 dpiVertical = mDpiVertical;
233 int WindowRenderSurface::GetOrientation() const
235 return mWindowBase->GetOrientation();
238 void WindowRenderSurface::InitializeGraphics()
240 mGraphics = &mAdaptor->GetGraphicsInterface();
242 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
244 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
245 mEGL = &eglGraphics->GetEglInterface();
247 if ( mEGLContext == NULL )
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 );
254 // Create the OpenGL surface
259 void WindowRenderSurface::CreateSurface()
261 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
264 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
266 width = mPositionSize.width;
267 height = mPositionSize.height;
271 width = mPositionSize.height;
272 height = mPositionSize.width;
275 // Create the EGL window
276 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
278 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
280 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
281 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
283 // Check rotation capability
284 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
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 );
290 void WindowRenderSurface::DestroySurface()
292 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
294 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
297 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
299 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
301 eglImpl.DestroySurface( mEGLSurface );
302 mEGLSurface = nullptr;
304 // Destroy context also
305 eglImpl.DestroyContext( mEGLContext );
306 mEGLContext = nullptr;
308 mWindowBase->DestroyEglWindow();
312 bool WindowRenderSurface::ReplaceGraphicsSurface()
314 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
316 // Destroy the old one
317 mWindowBase->DestroyEglWindow();
320 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
322 width = mPositionSize.width;
323 height = mPositionSize.height;
327 width = mPositionSize.height;
328 height = mPositionSize.width;
331 // Create the EGL window
332 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
334 // Set screen rotation
335 mScreenRotationFinished = false;
337 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
339 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
340 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
343 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
345 bool needToMove = false;
346 bool needToResize = false;
349 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
350 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
356 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
357 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
366 mWindowBase->MoveResize( positionSize );
370 mWindowBase->Resize( positionSize );
373 mResizeFinished = false;
374 mPositionSize = positionSize;
380 mWindowBase->Move( positionSize );
382 mPositionSize = positionSize;
386 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
389 void WindowRenderSurface::StartRender()
393 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
395 Dali::Integration::Scene::FrameCallbackContainer callbacks;
397 Dali::Integration::Scene scene = mScene.GetHandle();
400 bool needFrameRenderedTrigger = false;
402 scene.GetFrameRenderedCallback( callbacks );
403 if( !callbacks.empty() )
405 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
406 if( frameRenderedSync != -1 )
408 Dali::Mutex::ScopedLock lock( mMutex );
410 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
412 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
414 needFrameRenderedTrigger = true;
418 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
425 scene.GetFramePresentedCallback( callbacks );
426 if( !callbacks.empty() )
428 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
429 if( framePresentedSync != -1 )
431 Dali::Mutex::ScopedLock lock( mMutex );
433 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
435 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
437 needFrameRenderedTrigger = true;
441 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
448 if( needFrameRenderedTrigger )
450 if( !mFrameRenderedTrigger )
452 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
453 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
455 mFrameRenderedTrigger->Trigger();
459 MakeContextCurrent();
461 if( resizingSurface || mDefaultScreenRotationAvailable )
463 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
465 // Window rotate or screen rotate
466 if( !mRotationFinished || !mScreenRotationFinished )
468 mWindowBase->SetEglWindowRotation( totalAngle );
469 mWindowBase->SetEglWindowBufferTransform( totalAngle );
471 // Reset only screen rotation flag
472 mScreenRotationFinished = true;
474 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
477 // Only window rotate
478 if( !mRotationFinished )
480 mWindowBase->SetEglWindowTransform( mRotationAngle );
484 if ( !mResizeFinished )
486 Dali::PositionSize positionSize;
487 positionSize.x = mPositionSize.x;
488 positionSize.y = mPositionSize.y;
489 if( totalAngle == 0 || totalAngle == 180 )
491 positionSize.width = mPositionSize.width;
492 positionSize.height = mPositionSize.height;
496 positionSize.width = mPositionSize.height;
497 positionSize.height = mPositionSize.width;
499 mWindowBase->ResizeEglWindow( positionSize );
500 mResizeFinished = true;
502 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: Set resize\n" );
505 SetFullSwapNextFrame();
506 mDefaultScreenRotationAvailable = false;
509 SetBufferDamagedRects( damagedRects, clippingRect );
514 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
516 // Inform the gl implementation that rendering has finished before informing the surface
517 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
520 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
530 if( resizingSurface )
532 if( !mRotationFinished )
534 if( mThreadSynchronization )
536 // Enable PostRender flag
537 mThreadSynchronization->PostRenderStarted();
540 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
542 mRotationTrigger->Trigger();
544 if( mThreadSynchronization )
546 // Wait until the event-thread complete the rotation event processing
547 mThreadSynchronization->PostRenderWaitForCompletion();
553 SwapBuffers( damagedRects );
555 if( mRenderNotification )
557 mRenderNotification->Trigger();
562 void WindowRenderSurface::StopRender()
566 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
568 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
570 mThreadSynchronization = &threadSynchronization;
573 void WindowRenderSurface::ReleaseLock()
578 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
580 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
583 void WindowRenderSurface::MakeContextCurrent()
585 if ( mEGL != nullptr )
587 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
591 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
593 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
596 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
598 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
601 void WindowRenderSurface::OutputTransformed()
603 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
605 if( mScreenRotationAngle != screenRotationAngle )
607 mScreenRotationAngle = screenRotationAngle;
608 mScreenRotationFinished = false;
609 mResizeFinished = false;
611 mOutputTransformedSignal.Emit();
613 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
617 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
621 void WindowRenderSurface::ProcessRotationRequest()
623 mRotationFinished = true;
625 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
627 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
629 if( mThreadSynchronization )
631 mThreadSynchronization->PostRenderComplete();
635 void WindowRenderSurface::ProcessFrameCallback()
637 Dali::Mutex::ScopedLock lock( mMutex );
639 for( auto&& iter : mFrameCallbackInfoContainer )
641 if( !iter->fileDescriptorMonitor )
643 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
644 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
646 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
651 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
653 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
655 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
656 close( fileDescriptor );
660 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
662 std::unique_ptr< FrameCallbackInfo > callbackInfo;
664 Dali::Mutex::ScopedLock lock( mMutex );
665 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
666 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
668 return callbackInfo->fileDescriptor == fileDescriptor;
670 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
672 callbackInfo = std::move( *frameCallbackInfo );
674 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
678 // Call the connected callback
681 for( auto&& iter : ( callbackInfo )->callbacks )
683 CallbackBase::Execute( *( iter.first ), iter.second );
688 void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
690 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
693 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
694 if( !eglImpl.IsPartialUpdateRequired() )
699 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
701 if( mFullSwapNextFrame )
703 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
704 clippingRect = Rect< int >();
708 EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
710 // Buffer age 0 means the back buffer in invalid and requires full swap
711 if( !damagedRects.size() || bufferAge == 0 )
713 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
714 clippingRect = Rect< int >();
718 // We push current frame damaged rects here, zero index for current frame
719 InsertRects( mBufferDamagedRects, damagedRects );
721 // Merge damaged rects into clipping rect
722 auto bufferDamagedRects = mBufferDamagedRects.begin();
723 while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
725 const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
726 MergeRects( clippingRect, rects );
729 if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
731 // clipping area too big or doesn't intersect surface rect
732 clippingRect = Rect< int >();
736 std::vector< Rect< int > > damagedRegion;
737 damagedRegion.push_back( clippingRect );
739 eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
743 void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
745 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
748 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
750 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
752 if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
754 mFullSwapNextFrame = false;
755 eglImpl.SwapBuffers( mEGLSurface );
759 mFullSwapNextFrame = false;
761 std::vector< Rect< int > > mergedRects = damagedRects;
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++ )
768 if( mergedRects[i].IsEmpty() )
773 for( int j = i + 1; j < n; j++ )
775 if( mergedRects[j].IsEmpty() )
780 if( mergedRects[i].Intersects( mergedRects[j] ) )
782 mergedRects[i].Merge( mergedRects[j] );
783 mergedRects[j].width = 0;
784 mergedRects[j].height = 0;
790 for( int i = 0; i < n; i++ )
792 if( !mergedRects[i].IsEmpty() )
794 mergedRects[j++] = mergedRects[i];
800 mergedRects.resize( j );
803 if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
805 eglImpl.SwapBuffers( mEGLSurface );
809 eglImpl.SwapBuffers( mEGLSurface, mergedRects );
814 } // namespace Adaptor
816 } // namespace internal