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 );
144 Any WindowRenderSurface::GetNativeWindow()
146 return mWindowBase->GetNativeWindow();
149 int WindowRenderSurface::GetNativeWindowId()
151 return mWindowBase->GetNativeWindowId();
154 void WindowRenderSurface::Map()
159 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
161 mRenderNotification = renderNotification;
164 void WindowRenderSurface::SetTransparency( bool transparent )
166 mWindowBase->SetTransparency( transparent );
169 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
171 if( !mRotationTrigger )
173 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
176 mPositionSize.width = width;
177 mPositionSize.height = height;
179 mRotationAngle = angle;
180 mRotationFinished = false;
182 mWindowBase->SetWindowRotationAngle( mRotationAngle );
184 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
187 WindowBase* WindowRenderSurface::GetWindowBase()
189 return mWindowBase.get();
192 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
194 return mOutputTransformedSignal;
197 PositionSize WindowRenderSurface::GetPositionSize() const
199 return mPositionSize;
202 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
204 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
206 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
207 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
209 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
210 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
212 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
214 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
218 dpiHorizontal = mDpiHorizontal;
219 dpiVertical = mDpiVertical;
222 int WindowRenderSurface::GetOrientation() const
224 return mWindowBase->GetOrientation();
227 void WindowRenderSurface::InitializeGraphics()
229 mGraphics = &mAdaptor->GetGraphicsInterface();
231 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
233 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
234 mEGL = &eglGraphics->GetEglInterface();
236 if ( mEGLContext == NULL )
238 // Create the OpenGL context for this window
239 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
240 eglImpl.ChooseConfig(true, mColorDepth);
241 eglImpl.CreateWindowContext( mEGLContext );
243 // Create the OpenGL surface
248 void WindowRenderSurface::CreateSurface()
250 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
252 // Create the EGL window
253 EGLNativeWindowType window = mWindowBase->CreateEglWindow( mPositionSize.width, mPositionSize.height );
255 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
257 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
258 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
260 // Check rotation capability
261 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
263 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
264 mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
267 void WindowRenderSurface::DestroySurface()
269 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
271 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
274 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
276 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
278 eglImpl.DestroySurface( mEGLSurface );
279 mEGLSurface = nullptr;
281 // Destroy context also
282 eglImpl.DestroyContext( mEGLContext );
283 mEGLContext = nullptr;
285 mWindowBase->DestroyEglWindow();
289 bool WindowRenderSurface::ReplaceGraphicsSurface()
291 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
293 // Destroy the old one
294 mWindowBase->DestroyEglWindow();
297 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
299 width = mPositionSize.width;
300 height = mPositionSize.height;
304 width = mPositionSize.height;
305 height = mPositionSize.width;
308 // Create the EGL window
309 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
311 // Set screen rotation
312 mScreenRotationFinished = false;
314 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
316 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
317 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
320 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
322 bool needToMove = false;
323 bool needToResize = false;
326 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
327 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
333 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
334 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
343 mWindowBase->MoveResize( positionSize );
347 mWindowBase->Resize( positionSize );
350 mResizeFinished = false;
351 mPositionSize = positionSize;
357 mWindowBase->Move( positionSize );
359 mPositionSize = positionSize;
363 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
366 void WindowRenderSurface::StartRender()
370 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
372 Dali::Integration::Scene::FrameCallbackContainer callbacks;
374 Dali::Integration::Scene scene = mScene.GetHandle();
377 bool needFrameRenderedTrigger = false;
379 scene.GetFrameRenderedCallback( callbacks );
380 if( !callbacks.empty() )
382 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
383 if( frameRenderedSync != -1 )
385 Dali::Mutex::ScopedLock lock( mMutex );
387 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
389 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
391 needFrameRenderedTrigger = true;
395 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
402 scene.GetFramePresentedCallback( callbacks );
403 if( !callbacks.empty() )
405 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
406 if( framePresentedSync != -1 )
408 Dali::Mutex::ScopedLock lock( mMutex );
410 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
412 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
414 needFrameRenderedTrigger = true;
418 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
425 if( needFrameRenderedTrigger )
427 if( !mFrameRenderedTrigger )
429 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
430 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
432 mFrameRenderedTrigger->Trigger();
436 MakeContextCurrent();
438 if( resizingSurface )
440 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
442 // Window rotate or screen rotate
443 if( !mRotationFinished || !mScreenRotationFinished )
445 mWindowBase->SetEglWindowRotation( totalAngle );
446 mWindowBase->SetEglWindowBufferTransform( totalAngle );
448 // Reset only screen rotation flag
449 mScreenRotationFinished = true;
451 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
454 // Only window rotate
455 if( !mRotationFinished )
457 mWindowBase->SetEglWindowTransform( mRotationAngle );
461 if ( !mResizeFinished )
463 Dali::PositionSize positionSize;
464 positionSize.x = mPositionSize.x;
465 positionSize.y = mPositionSize.y;
466 if( totalAngle == 0 || totalAngle == 180 )
468 positionSize.width = mPositionSize.width;
469 positionSize.height = mPositionSize.height;
473 positionSize.width = mPositionSize.height;
474 positionSize.height = mPositionSize.width;
476 mWindowBase->ResizeEglWindow( positionSize );
477 mResizeFinished = true;
479 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
482 SetFullSwapNextFrame();
485 SetBufferDamagedRects( damagedRects, clippingRect );
490 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
492 // Inform the gl implementation that rendering has finished before informing the surface
493 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
496 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
506 if( resizingSurface )
508 if( !mRotationFinished )
510 if( mThreadSynchronization )
512 // Enable PostRender flag
513 mThreadSynchronization->PostRenderStarted();
516 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
518 mRotationTrigger->Trigger();
520 if( mThreadSynchronization )
522 // Wait until the event-thread complete the rotation event processing
523 mThreadSynchronization->PostRenderWaitForCompletion();
529 SwapBuffers( damagedRects );
531 if( mRenderNotification )
533 mRenderNotification->Trigger();
538 void WindowRenderSurface::StopRender()
542 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
544 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
546 mThreadSynchronization = &threadSynchronization;
549 void WindowRenderSurface::ReleaseLock()
554 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
556 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
559 void WindowRenderSurface::MakeContextCurrent()
561 if ( mEGL != nullptr )
563 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
567 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
569 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
572 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
574 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
577 void WindowRenderSurface::OutputTransformed()
579 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
581 if( mScreenRotationAngle != screenRotationAngle )
583 mScreenRotationAngle = screenRotationAngle;
584 mScreenRotationFinished = false;
585 mResizeFinished = false;
587 mOutputTransformedSignal.Emit();
589 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
593 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
597 void WindowRenderSurface::ProcessRotationRequest()
599 mRotationFinished = true;
601 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
603 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
605 if( mThreadSynchronization )
607 mThreadSynchronization->PostRenderComplete();
611 void WindowRenderSurface::ProcessFrameCallback()
613 Dali::Mutex::ScopedLock lock( mMutex );
615 for( auto&& iter : mFrameCallbackInfoContainer )
617 if( !iter->fileDescriptorMonitor )
619 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
620 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
622 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
627 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
629 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
631 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
632 close( fileDescriptor );
636 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
638 std::unique_ptr< FrameCallbackInfo > callbackInfo;
640 Dali::Mutex::ScopedLock lock( mMutex );
641 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
642 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
644 return callbackInfo->fileDescriptor == fileDescriptor;
646 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
648 callbackInfo = std::move( *frameCallbackInfo );
650 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
654 // Call the connected callback
657 for( auto&& iter : ( callbackInfo )->callbacks )
659 CallbackBase::Execute( *( iter.first ), iter.second );
664 void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect )
666 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
669 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
670 if( !eglImpl.IsPartialUpdateRequired() )
675 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
677 if( mFullSwapNextFrame )
679 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
680 clippingRect = Rect< int >();
684 EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface );
686 // Buffer age 0 means the back buffer in invalid and requires full swap
687 if( !damagedRects.size() || bufferAge == 0 )
689 InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) );
690 clippingRect = Rect< int >();
694 // We push current frame damaged rects here, zero index for current frame
695 InsertRects( mBufferDamagedRects, damagedRects );
697 // Merge damaged rects into clipping rect
698 auto bufferDamagedRects = mBufferDamagedRects.begin();
699 while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() )
701 const std::vector< Rect< int > >& rects = *bufferDamagedRects++;
702 MergeRects( clippingRect, rects );
705 if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO )
707 // clipping area too big or doesn't intersect surface rect
708 clippingRect = Rect< int >();
712 std::vector< Rect< int > > damagedRegion;
713 damagedRegion.push_back( clippingRect );
715 eglImpl.SetDamageRegion( mEGLSurface, damagedRegion );
719 void WindowRenderSurface::SwapBuffers( const std::vector<Rect<int>>& damagedRects )
721 auto eglGraphics = static_cast< EglGraphics* >( mGraphics );
724 Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height );
726 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
728 if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) )
730 mFullSwapNextFrame = false;
731 eglImpl.SwapBuffers( mEGLSurface );
735 mFullSwapNextFrame = false;
737 std::vector< Rect< int > > mergedRects = damagedRects;
739 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
740 // Could be optional and can be removed, needs to be checked with and without on platform
741 const int n = mergedRects.size();
742 for( int i = 0; i < n - 1; i++ )
744 if( mergedRects[i].IsEmpty() )
749 for( int j = i + 1; j < n; j++ )
751 if( mergedRects[j].IsEmpty() )
756 if( mergedRects[i].Intersects( mergedRects[j] ) )
758 mergedRects[i].Merge( mergedRects[j] );
759 mergedRects[j].width = 0;
760 mergedRects[j].height = 0;
766 for( int i = 0; i < n; i++ )
768 if( !mergedRects[i].IsEmpty() )
770 mergedRects[j++] = mergedRects[i];
776 mergedRects.resize( j );
779 if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) )
781 eglImpl.SwapBuffers( mEGLSurface );
785 eglImpl.SwapBuffers( mEGLSurface, mergedRects );
790 } // namespace Adaptor
792 } // namespace internal