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 SetBufferDamagedRects( damagedRects, clippingRect );
513 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
515 // Inform the gl implementation that rendering has finished before informing the surface
516 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
519 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
529 if( resizingSurface )
531 if( !mRotationFinished )
533 if( mThreadSynchronization )
535 // Enable PostRender flag
536 mThreadSynchronization->PostRenderStarted();
539 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
541 mRotationTrigger->Trigger();
543 if( mThreadSynchronization )
545 // Wait until the event-thread complete the rotation event processing
546 mThreadSynchronization->PostRenderWaitForCompletion();
552 SwapBuffers( damagedRects );
554 if( mRenderNotification )
556 mRenderNotification->Trigger();
561 void WindowRenderSurface::StopRender()
565 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
567 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
569 mThreadSynchronization = &threadSynchronization;
572 void WindowRenderSurface::ReleaseLock()
577 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
579 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
582 void WindowRenderSurface::MakeContextCurrent()
584 if ( mEGL != nullptr )
586 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
590 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
592 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
595 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
597 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
600 void WindowRenderSurface::OutputTransformed()
602 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
604 if( mScreenRotationAngle != screenRotationAngle )
606 mScreenRotationAngle = screenRotationAngle;
607 mScreenRotationFinished = false;
608 mResizeFinished = false;
610 mOutputTransformedSignal.Emit();
612 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
616 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
620 void WindowRenderSurface::ProcessRotationRequest()
622 mRotationFinished = true;
624 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
626 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
628 if( mThreadSynchronization )
630 mThreadSynchronization->PostRenderComplete();
634 void WindowRenderSurface::ProcessFrameCallback()
636 Dali::Mutex::ScopedLock lock( mMutex );
638 for( auto&& iter : mFrameCallbackInfoContainer )
640 if( !iter->fileDescriptorMonitor )
642 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
643 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
645 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
650 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
652 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
654 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
655 close( fileDescriptor );
659 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
661 std::unique_ptr< FrameCallbackInfo > callbackInfo;
663 Dali::Mutex::ScopedLock lock( mMutex );
664 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
665 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
667 return callbackInfo->fileDescriptor == fileDescriptor;
669 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
671 callbackInfo = std::move( *frameCallbackInfo );
673 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
677 // Call the connected callback
680 for( auto&& iter : ( callbackInfo )->callbacks )
682 CallbackBase::Execute( *( iter.first ), iter.second );
687 void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
689 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
692 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
693 if( !eglImpl.IsPartialUpdateRequired() )
698 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
700 if( mFullSwapNextFrame )
702 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
703 clippingRect = Rect< int >();
707 EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
709 // Buffer age 0 means the back buffer in invalid and requires full swap
710 if( !damagedRects.size() || bufferAge == 0 )
712 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
713 clippingRect = Rect< int >();
717 // We push current frame damaged rects here, zero index for current frame
718 InsertRects( mBufferDamagedRects, damagedRects );
720 // Merge damaged rects into clipping rect
721 auto bufferDamagedRects = mBufferDamagedRects.begin();
722 while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
724 const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
725 MergeRects( clippingRect, rects );
728 if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
730 // clipping area too big or doesn't intersect surface rect
731 clippingRect = Rect< int >();
735 std::vector< Rect< int > > damagedRegion;
736 damagedRegion.push_back( clippingRect );
738 eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
742 void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
744 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
747 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
749 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
751 if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
753 mFullSwapNextFrame = false;
754 eglImpl.SwapBuffers( mEGLSurface );
758 mFullSwapNextFrame = false;
760 std::vector< Rect< int > > mergedRects = damagedRects;
762 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
763 // Could be optional and can be removed, needs to be checked with and without on platform
764 const int n = mergedRects.size();
765 for( int i = 0; i < n - 1; i++ )
767 if( mergedRects[i].IsEmpty() )
772 for( int j = i + 1; j < n; j++ )
774 if( mergedRects[j].IsEmpty() )
779 if( mergedRects[i].Intersects( mergedRects[j] ) )
781 mergedRects[i].Merge( mergedRects[j] );
782 mergedRects[j].width = 0;
783 mergedRects[j].height = 0;
789 for( int i = 0; i < n; i++ )
791 if( !mergedRects[i].IsEmpty() )
793 mergedRects[j++] = mergedRects[i];
799 mergedRects.resize( j );
802 if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
804 eglImpl.SwapBuffers( mEGLSurface );
808 eglImpl.SwapBuffers( mEGLSurface, mergedRects );
813 } // namespace Adaptor
815 } // namespace internal