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(nullptr),
92 mRenderNotification(nullptr),
93 mRotationTrigger(nullptr),
94 mFrameRenderedTrigger(),
98 mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
99 mOutputTransformedSignal(),
100 mFrameCallbackInfoContainer(),
101 mBufferDamagedRects(),
103 mWindowRotationAngle(0),
104 mScreenRotationAngle(0),
108 mWindowRotationFinished(true),
109 mScreenRotationFinished(true),
110 mResizeFinished(true),
111 mDefaultScreenRotationAvailable(false)
113 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
114 Initialize( surface );
117 WindowRenderSurface::~WindowRenderSurface()
119 if( mRotationTrigger )
121 delete mRotationTrigger;
125 void WindowRenderSurface::Initialize( Any surface )
127 // If width or height are zero, go full screen.
128 if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
130 // Default window size == screen size
133 WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
136 // Create a window base
137 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
138 mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
141 mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
143 // Check screen rotation
144 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
145 if( mScreenRotationAngle != 0 )
147 mScreenRotationFinished = false;
148 mResizeFinished = false;
149 mDefaultScreenRotationAvailable = true;
150 DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle );
154 Any WindowRenderSurface::GetNativeWindow()
156 return mWindowBase->GetNativeWindow();
159 int WindowRenderSurface::GetNativeWindowId()
161 return mWindowBase->GetNativeWindowId();
164 void WindowRenderSurface::Map()
169 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
171 mRenderNotification = renderNotification;
174 void WindowRenderSurface::SetTransparency( bool transparent )
176 mWindowBase->SetTransparency( transparent );
179 void WindowRenderSurface::RequestRotation(int angle, int width, int height)
181 if(!mRotationTrigger)
183 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessRotationRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
186 mPositionSize.width = width;
187 mPositionSize.height = height;
189 mWindowRotationAngle = angle;
190 mWindowRotationFinished = false;
192 mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
194 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mWindowRotationAngle, mScreenRotationAngle);
197 WindowBase* WindowRenderSurface::GetWindowBase()
199 return mWindowBase.get();
202 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
204 return mOutputTransformedSignal;
207 PositionSize WindowRenderSurface::GetPositionSize() const
209 return mPositionSize;
212 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
214 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
216 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
217 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
219 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
220 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
222 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
224 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
228 dpiHorizontal = mDpiHorizontal;
229 dpiVertical = mDpiVertical;
232 int WindowRenderSurface::GetOrientation() const
234 return mWindowBase->GetOrientation();
237 void WindowRenderSurface::InitializeGraphics()
239 mGraphics = &mAdaptor->GetGraphicsInterface();
241 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
243 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
244 mEGL = &eglGraphics->GetEglInterface();
246 if ( mEGLContext == NULL )
248 // Create the OpenGL context for this window
249 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
250 eglImpl.ChooseConfig(true, mColorDepth);
251 eglImpl.CreateWindowContext( mEGLContext );
253 // Create the OpenGL surface
258 void WindowRenderSurface::CreateSurface()
260 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
263 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
265 width = mPositionSize.width;
266 height = mPositionSize.height;
270 width = mPositionSize.height;
271 height = mPositionSize.width;
274 // Create the EGL window
275 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
277 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
279 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
280 mEGLSurface = eglImpl.CreateSurfaceWindow(window, mColorDepth);
282 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
283 mWindowBase->GetNativeWindowId(),
285 mPositionSize.height,
286 mWindowRotationAngle,
287 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();
462 * wl_egl_window_tizen_set_rotation(SetEglWindowRotation) -> PreRotation
463 * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
464 * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform) -> Window Rotation
465 * These function should be called before calling first drawing gl Function.
466 * Notice : PreRotation is not used in the latest tizen,
467 * because output transform event should be occured before egl window is not created.
470 if(resizingSurface || mDefaultScreenRotationAvailable)
472 int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
474 // Window rotate or screen rotate
475 if(!mWindowRotationFinished || !mScreenRotationFinished)
477 mWindowBase->SetEglWindowBufferTransform(totalAngle);
479 // Reset only screen rotation flag
480 mScreenRotationFinished = true;
482 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
485 // Only window rotate
486 if(!mWindowRotationFinished)
488 mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
494 Dali::PositionSize positionSize;
495 positionSize.x = mPositionSize.x;
496 positionSize.y = mPositionSize.y;
497 if(totalAngle == 0 || totalAngle == 180)
499 positionSize.width = mPositionSize.width;
500 positionSize.height = mPositionSize.height;
504 positionSize.width = mPositionSize.height;
505 positionSize.height = mPositionSize.width;
507 mWindowBase->ResizeEglWindow(positionSize);
508 mResizeFinished = true;
510 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set resize\n");
513 SetFullSwapNextFrame();
514 mDefaultScreenRotationAvailable = false;
517 SetBufferDamagedRects(damagedRects, clippingRect);
522 void WindowRenderSurface::PostRender(bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects)
524 // Inform the gl implementation that rendering has finished before informing the surface
525 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
528 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
540 if(!mWindowRotationFinished)
542 if(mThreadSynchronization)
544 // Enable PostRender flag
545 mThreadSynchronization->PostRenderStarted();
548 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n");
550 mRotationTrigger->Trigger();
552 if(mThreadSynchronization)
554 // Wait until the event-thread complete the rotation event processing
555 mThreadSynchronization->PostRenderWaitForCompletion();
561 SwapBuffers(damagedRects);
563 if(mRenderNotification)
565 mRenderNotification->Trigger();
570 void WindowRenderSurface::StopRender()
574 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
576 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
578 mThreadSynchronization = &threadSynchronization;
581 void WindowRenderSurface::ReleaseLock()
586 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
588 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
591 void WindowRenderSurface::MakeContextCurrent()
593 if ( mEGL != nullptr )
595 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
599 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
601 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
604 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
606 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
609 void WindowRenderSurface::OutputTransformed()
611 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
613 if(mScreenRotationAngle != screenRotationAngle)
615 mScreenRotationAngle = screenRotationAngle;
616 mScreenRotationFinished = false;
617 mResizeFinished = false;
619 mOutputTransformedSignal.Emit();
621 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
625 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
629 void WindowRenderSurface::ProcessRotationRequest()
631 mWindowRotationFinished = true;
633 mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
635 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n");
637 if(mThreadSynchronization)
639 mThreadSynchronization->PostRenderComplete();
643 void WindowRenderSurface::ProcessFrameCallback()
645 Dali::Mutex::ScopedLock lock( mMutex );
647 for( auto&& iter : mFrameCallbackInfoContainer )
649 if( !iter->fileDescriptorMonitor )
651 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
652 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
654 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
659 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
661 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
663 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
664 close( fileDescriptor );
668 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
670 std::unique_ptr< FrameCallbackInfo > callbackInfo;
672 Dali::Mutex::ScopedLock lock( mMutex );
673 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
674 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
676 return callbackInfo->fileDescriptor == fileDescriptor;
678 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
680 callbackInfo = std::move( *frameCallbackInfo );
682 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
686 // Call the connected callback
689 for( auto&& iter : ( callbackInfo )->callbacks )
691 CallbackBase::Execute( *( iter.first ), iter.second );
696 void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
698 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
701 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
702 if( !eglImpl.IsPartialUpdateRequired() )
707 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
709 if( mFullSwapNextFrame )
711 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
712 clippingRect = Rect< int >();
716 EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
718 // Buffer age 0 means the back buffer in invalid and requires full swap
719 if( !damagedRects.size() || bufferAge == 0 )
721 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
722 clippingRect = Rect< int >();
726 // We push current frame damaged rects here, zero index for current frame
727 InsertRects( mBufferDamagedRects, damagedRects );
729 // Merge damaged rects into clipping rect
730 auto bufferDamagedRects = mBufferDamagedRects.begin();
731 while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
733 const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
734 MergeRects( clippingRect, rects );
737 if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
739 // clipping area too big or doesn't intersect surface rect
740 clippingRect = Rect< int >();
744 std::vector< Rect< int > > damagedRegion;
745 damagedRegion.push_back( clippingRect );
747 eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
751 void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
753 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
756 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
758 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
760 if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
762 mFullSwapNextFrame = false;
763 eglImpl.SwapBuffers( mEGLSurface );
767 mFullSwapNextFrame = false;
769 std::vector< Rect< int > > mergedRects = damagedRects;
771 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
772 // Could be optional and can be removed, needs to be checked with and without on platform
773 const int n = mergedRects.size();
774 for( int i = 0; i < n - 1; i++ )
776 if( mergedRects[i].IsEmpty() )
781 for( int j = i + 1; j < n; j++ )
783 if( mergedRects[j].IsEmpty() )
788 if( mergedRects[i].Intersects( mergedRects[j] ) )
790 mergedRects[i].Merge( mergedRects[j] );
791 mergedRects[j].width = 0;
792 mergedRects[j].height = 0;
798 for( int i = 0; i < n; i++ )
800 if( !mergedRects[i].IsEmpty() )
802 mergedRects[j++] = mergedRects[i];
808 mergedRects.resize( j );
811 if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
813 eglImpl.SwapBuffers( mEGLSurface );
817 eglImpl.SwapBuffers( mEGLSurface, mergedRects );
822 } // namespace Adaptor
824 } // namespace internal