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_RELEASE_INFO( "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_RELEASE_INFO( "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->SetEglWindowBufferTransform( totalAngle );
470 // Reset only screen rotation flag
471 mScreenRotationFinished = true;
473 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
476 // Only window rotate
477 if( !mRotationFinished )
479 mWindowBase->SetEglWindowTransform( mRotationAngle );
483 if ( !mResizeFinished )
485 Dali::PositionSize positionSize;
486 positionSize.x = mPositionSize.x;
487 positionSize.y = mPositionSize.y;
488 if( totalAngle == 0 || totalAngle == 180 )
490 positionSize.width = mPositionSize.width;
491 positionSize.height = mPositionSize.height;
495 positionSize.width = mPositionSize.height;
496 positionSize.height = mPositionSize.width;
498 mWindowBase->ResizeEglWindow( positionSize );
499 mResizeFinished = true;
501 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: Set resize\n" );
504 SetFullSwapNextFrame();
505 mDefaultScreenRotationAvailable = false;
508 if(!mRotationFinished)
510 SetFullSwapNextFrame();
513 SetBufferDamagedRects( damagedRects, clippingRect );
518 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
520 // Inform the gl implementation that rendering has finished before informing the surface
521 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
524 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
534 if( resizingSurface )
536 if( !mRotationFinished )
538 if( mThreadSynchronization )
540 // Enable PostRender flag
541 mThreadSynchronization->PostRenderStarted();
544 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
546 mRotationTrigger->Trigger();
548 if( mThreadSynchronization )
550 // Wait until the event-thread complete the rotation event processing
551 mThreadSynchronization->PostRenderWaitForCompletion();
557 SwapBuffers( damagedRects );
559 if( mRenderNotification )
561 mRenderNotification->Trigger();
566 void WindowRenderSurface::StopRender()
570 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
572 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
574 mThreadSynchronization = &threadSynchronization;
577 void WindowRenderSurface::ReleaseLock()
582 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
584 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
587 void WindowRenderSurface::MakeContextCurrent()
589 if ( mEGL != nullptr )
591 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
595 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
597 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
600 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
602 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
605 void WindowRenderSurface::OutputTransformed()
607 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
609 if( mScreenRotationAngle != screenRotationAngle )
611 mScreenRotationAngle = screenRotationAngle;
612 mScreenRotationFinished = false;
613 mResizeFinished = false;
615 mOutputTransformedSignal.Emit();
617 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
621 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
625 void WindowRenderSurface::ProcessRotationRequest()
627 mRotationFinished = true;
629 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
631 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
633 if( mThreadSynchronization )
635 mThreadSynchronization->PostRenderComplete();
639 void WindowRenderSurface::ProcessFrameCallback()
641 Dali::Mutex::ScopedLock lock( mMutex );
643 for( auto&& iter : mFrameCallbackInfoContainer )
645 if( !iter->fileDescriptorMonitor )
647 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
648 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
650 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
655 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
657 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
659 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
660 close( fileDescriptor );
664 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
666 std::unique_ptr< FrameCallbackInfo > callbackInfo;
668 Dali::Mutex::ScopedLock lock( mMutex );
669 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
670 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
672 return callbackInfo->fileDescriptor == fileDescriptor;
674 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
676 callbackInfo = std::move( *frameCallbackInfo );
678 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
682 // Call the connected callback
685 for( auto&& iter : ( callbackInfo )->callbacks )
687 CallbackBase::Execute( *( iter.first ), iter.second );
692 void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
694 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
697 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
698 if( !eglImpl.IsPartialUpdateRequired() )
703 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
705 if( mFullSwapNextFrame )
707 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
708 clippingRect = Rect< int >();
712 EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
714 // Buffer age 0 means the back buffer in invalid and requires full swap
715 if( !damagedRects.size() || bufferAge == 0 )
717 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
718 clippingRect = Rect< int >();
722 // We push current frame damaged rects here, zero index for current frame
723 InsertRects( mBufferDamagedRects, damagedRects );
725 // Merge damaged rects into clipping rect
726 auto bufferDamagedRects = mBufferDamagedRects.begin();
727 while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
729 const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
730 MergeRects( clippingRect, rects );
733 if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
735 // clipping area too big or doesn't intersect surface rect
736 clippingRect = Rect< int >();
740 std::vector< Rect< int > > damagedRegion;
741 damagedRegion.push_back( clippingRect );
743 eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
747 void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
749 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
752 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
754 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
756 if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
758 mFullSwapNextFrame = false;
759 eglImpl.SwapBuffers( mEGLSurface );
763 mFullSwapNextFrame = false;
765 std::vector< Rect< int > > mergedRects = damagedRects;
767 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
768 // Could be optional and can be removed, needs to be checked with and without on platform
769 const int n = mergedRects.size();
770 for( int i = 0; i < n - 1; i++ )
772 if( mergedRects[i].IsEmpty() )
777 for( int j = i + 1; j < n; j++ )
779 if( mergedRects[j].IsEmpty() )
784 if( mergedRects[i].Intersects( mergedRects[j] ) )
786 mergedRects[i].Merge( mergedRects[j] );
787 mergedRects[j].width = 0;
788 mergedRects[j].height = 0;
794 for( int i = 0; i < n; i++ )
796 if( !mergedRects[i].IsEmpty() )
798 mergedRects[j++] = mergedRects[i];
804 mergedRects.resize( j );
807 if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
809 eglImpl.SwapBuffers( mEGLSurface );
813 eglImpl.SwapBuffers( mEGLSurface, mergedRects );
818 } // namespace Adaptor
820 } // namespace internal