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 )
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;
151 Any WindowRenderSurface::GetNativeWindow()
153 return mWindowBase->GetNativeWindow();
156 int WindowRenderSurface::GetNativeWindowId()
158 return mWindowBase->GetNativeWindowId();
161 void WindowRenderSurface::Map()
166 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
168 mRenderNotification = renderNotification;
171 void WindowRenderSurface::SetTransparency( bool transparent )
173 mWindowBase->SetTransparency( transparent );
176 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
178 if( !mRotationSupported )
180 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
184 if( !mRotationTrigger )
186 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
189 mPositionSize.width = width;
190 mPositionSize.height = height;
192 mRotationAngle = angle;
193 mRotationFinished = false;
195 mWindowBase->SetWindowRotationAngle( mRotationAngle );
197 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
200 WindowBase* WindowRenderSurface::GetWindowBase()
202 return mWindowBase.get();
205 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
207 return mOutputTransformedSignal;
210 PositionSize WindowRenderSurface::GetPositionSize() const
212 return mPositionSize;
215 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
217 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
219 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
220 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
222 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
223 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
225 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
227 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
231 dpiHorizontal = mDpiHorizontal;
232 dpiVertical = mDpiVertical;
235 void WindowRenderSurface::InitializeGraphics()
237 mGraphics = &mAdaptor->GetGraphicsInterface();
239 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
241 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
242 mEGL = &eglGraphics->GetEglInterface();
244 if ( mEGLContext == NULL )
246 // Create the OpenGL context for this window
247 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
248 eglImpl.ChooseConfig(true, mColorDepth);
249 eglImpl.CreateWindowContext( mEGLContext );
251 // Create the OpenGL surface
256 void WindowRenderSurface::CreateSurface()
258 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
261 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
263 width = mPositionSize.width;
264 height = mPositionSize.height;
268 width = mPositionSize.height;
269 height = mPositionSize.width;
272 // Create the EGL window
273 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
275 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
277 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
278 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
280 // Check rotation capability
281 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
283 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
284 mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
287 void WindowRenderSurface::DestroySurface()
289 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
291 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
294 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
296 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
298 eglImpl.DestroySurface( mEGLSurface );
299 mEGLSurface = nullptr;
301 // Destroy context also
302 eglImpl.DestroyContext( mEGLContext );
303 mEGLContext = nullptr;
305 mWindowBase->DestroyEglWindow();
309 bool WindowRenderSurface::ReplaceGraphicsSurface()
311 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
313 // Destroy the old one
314 mWindowBase->DestroyEglWindow();
317 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
319 width = mPositionSize.width;
320 height = mPositionSize.height;
324 width = mPositionSize.height;
325 height = mPositionSize.width;
328 // Create the EGL window
329 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
331 // Set screen rotation
332 mScreenRotationFinished = false;
334 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
336 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
337 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
340 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
342 bool needToMove = false;
343 bool needToResize = false;
346 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
347 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
353 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
354 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
363 mWindowBase->MoveResize( positionSize );
367 mWindowBase->Resize( positionSize );
370 mResizeFinished = false;
371 mPositionSize = positionSize;
377 mWindowBase->Move( positionSize );
379 mPositionSize = positionSize;
383 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
386 void WindowRenderSurface::StartRender()
390 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
392 Dali::Integration::Scene::FrameCallbackContainer callbacks;
394 Dali::Integration::Scene scene = mScene.GetHandle();
397 bool needFrameRenderedTrigger = false;
399 scene.GetFrameRenderedCallback( callbacks );
400 if( !callbacks.empty() )
402 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
403 if( frameRenderedSync != -1 )
405 Dali::Mutex::ScopedLock lock( mMutex );
407 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
409 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
411 needFrameRenderedTrigger = true;
415 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
422 scene.GetFramePresentedCallback( callbacks );
423 if( !callbacks.empty() )
425 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
426 if( framePresentedSync != -1 )
428 Dali::Mutex::ScopedLock lock( mMutex );
430 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
432 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
434 needFrameRenderedTrigger = true;
438 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
445 if( needFrameRenderedTrigger )
447 if( !mFrameRenderedTrigger )
449 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
450 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
452 mFrameRenderedTrigger->Trigger();
456 MakeContextCurrent();
458 if( resizingSurface )
460 // Window rotate or screen rotate
461 if( !mRotationFinished || !mScreenRotationFinished )
463 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
465 mWindowBase->SetEglWindowRotation( totalAngle );
466 mWindowBase->SetEglWindowBufferTransform( totalAngle );
468 // Reset only screen rotation flag
469 mScreenRotationFinished = true;
471 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
474 // Only window rotate
475 if( !mRotationFinished )
477 mWindowBase->SetEglWindowTransform( mRotationAngle );
481 if( !mResizeFinished )
483 mWindowBase->ResizeEglWindow( mPositionSize );
484 mResizeFinished = true;
486 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
489 SetFullSwapNextFrame();
492 SetBufferDamagedRects( damagedRects, clippingRect );
497 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
499 // Inform the gl implementation that rendering has finished before informing the surface
500 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
503 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
513 if( resizingSurface )
515 if( !mRotationFinished )
517 if( mThreadSynchronization )
519 // Enable PostRender flag
520 mThreadSynchronization->PostRenderStarted();
523 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
525 mRotationTrigger->Trigger();
527 if( mThreadSynchronization )
529 // Wait until the event-thread complete the rotation event processing
530 mThreadSynchronization->PostRenderWaitForCompletion();
536 SwapBuffers( damagedRects );
538 if( mRenderNotification )
540 mRenderNotification->Trigger();
545 void WindowRenderSurface::StopRender()
549 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
551 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
553 mThreadSynchronization = &threadSynchronization;
556 void WindowRenderSurface::ReleaseLock()
561 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
563 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
566 void WindowRenderSurface::MakeContextCurrent()
568 if ( mEGL != nullptr )
570 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
574 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
576 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
579 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
581 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
584 void WindowRenderSurface::OutputTransformed()
586 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
588 if( mScreenRotationAngle != screenRotationAngle )
590 mScreenRotationAngle = screenRotationAngle;
591 mScreenRotationFinished = false;
593 mOutputTransformedSignal.Emit();
595 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
599 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
603 void WindowRenderSurface::ProcessRotationRequest()
605 mRotationFinished = true;
607 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
609 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
611 if( mThreadSynchronization )
613 mThreadSynchronization->PostRenderComplete();
617 void WindowRenderSurface::ProcessFrameCallback()
619 Dali::Mutex::ScopedLock lock( mMutex );
621 for( auto&& iter : mFrameCallbackInfoContainer )
623 if( !iter->fileDescriptorMonitor )
625 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
626 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
628 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
633 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
635 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
637 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
638 close( fileDescriptor );
642 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
644 std::unique_ptr< FrameCallbackInfo > callbackInfo;
646 Dali::Mutex::ScopedLock lock( mMutex );
647 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
648 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
650 return callbackInfo->fileDescriptor == fileDescriptor;
652 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
654 callbackInfo = std::move( *frameCallbackInfo );
656 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
660 // Call the connected callback
663 for( auto&& iter : ( callbackInfo )->callbacks )
665 CallbackBase::Execute( *( iter.first ), iter.second );
670 void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
672 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
675 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
676 if( !eglImpl.IsPartialUpdateRequired() )
681 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
683 if( mFullSwapNextFrame )
685 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
686 clippingRect = Rect< int >();
690 EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
692 // Buffer age 0 means the back buffer in invalid and requires full swap
693 if( !damagedRects.size() || bufferAge == 0 )
695 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
696 clippingRect = Rect< int >();
700 // We push current frame damaged rects here, zero index for current frame
701 InsertRects( mBufferDamagedRects, damagedRects );
703 // Merge damaged rects into clipping rect
704 auto bufferDamagedRects = mBufferDamagedRects.begin();
705 while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
707 const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
708 MergeRects( clippingRect, rects );
711 if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
713 // clipping area too big or doesn't intersect surface rect
714 clippingRect = Rect< int >();
718 std::vector< Rect< int > > damagedRegion;
719 damagedRegion.push_back( clippingRect );
721 eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
725 void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
727 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
730 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
732 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
734 if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
736 mFullSwapNextFrame = false;
737 eglImpl.SwapBuffers( mEGLSurface );
741 mFullSwapNextFrame = false;
743 std::vector< Rect< int > > mergedRects = damagedRects;
745 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
746 // Could be optional and can be removed, needs to be checked with and without on platform
747 const int n = mergedRects.size();
748 for( int i = 0; i < n - 1; i++ )
750 if( mergedRects[i].IsEmpty() )
755 for( int j = i + 1; j < n; j++ )
757 if( mergedRects[j].IsEmpty() )
762 if( mergedRects[i].Intersects( mergedRects[j] ) )
764 mergedRects[i].Merge( mergedRects[j] );
765 mergedRects[j].width = 0;
766 mergedRects[j].height = 0;
772 for( int i = 0; i < n; i++ )
774 if( !mergedRects[i].IsEmpty() )
776 mergedRects[j++] = mergedRects[i];
782 mergedRects.resize( j );
785 if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
787 eglImpl.SwapBuffers( mEGLSurface );
791 eglImpl.SwapBuffers( mEGLSurface, mergedRects );
796 } // namespace Adaptor
798 } // namespace internal