2 * Copyright (c) 2021 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/debug.h>
23 #include <dali/integration-api/gl-abstraction.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/system/common/environment-variables.h>
33 #include <dali/internal/window-system/common/window-base.h>
34 #include <dali/internal/window-system/common/window-factory.h>
35 #include <dali/internal/window-system/common/window-system.h>
45 const int MINIMUM_DIMENSION_CHANGE(1); ///< Minimum change for window to be considered to have moved
46 const float FULL_UPDATE_RATIO(0.8f); ///< Force full update when the dirty area is larget than this ratio
48 #if defined(DEBUG_ENABLED)
49 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
52 void MergeRects(Rect<int>& mergingRect, const std::vector<Rect<int>>& rects)
55 if(mergingRect.IsEmpty())
57 for(; i < rects.size(); i++)
59 if(!rects[i].IsEmpty())
61 mergingRect = rects[i];
67 for(; i < rects.size(); i++)
69 mergingRect.Merge(rects[i]);
73 void InsertRects(WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const std::vector<Rect<int>>& damagedRects)
75 damagedRectsList.push_front(damagedRects);
76 if(damagedRectsList.size() > 4) // past triple buffers + current
78 damagedRectsList.pop_back();
82 } // unnamed namespace
84 WindowRenderSurface::WindowRenderSurface(Dali::PositionSize positionSize, Any surface, bool isTransparent)
86 mDisplayConnection(nullptr),
87 mPositionSize(positionSize),
89 mThreadSynchronization(nullptr),
90 mRenderNotification(nullptr),
91 mRotationTrigger(nullptr),
92 mFrameRenderedTrigger(),
96 mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
97 mOutputTransformedSignal(),
98 mFrameCallbackInfoContainer(),
99 mBufferDamagedRects(),
101 mWindowRotationAngle(0),
102 mScreenRotationAngle(0),
106 mWindowRotationFinished(true),
107 mScreenRotationFinished(true),
108 mResizeFinished(true),
109 mDefaultScreenRotationAvailable(false)
111 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n");
115 WindowRenderSurface::~WindowRenderSurface()
119 delete mRotationTrigger;
123 void WindowRenderSurface::Initialize(Any surface)
125 // If width or height are zero, go full screen.
126 if((mPositionSize.width == 0) || (mPositionSize.height == 0))
128 // Default window size == screen size
131 WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height);
134 // Create a window base
135 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
136 mWindowBase = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false));
139 mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed);
141 // Check screen rotation
142 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
143 if(mScreenRotationAngle != 0)
145 mScreenRotationFinished = false;
146 mResizeFinished = false;
147 mDefaultScreenRotationAvailable = true;
148 DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle);
152 Any WindowRenderSurface::GetNativeWindow()
154 return mWindowBase->GetNativeWindow();
157 int WindowRenderSurface::GetNativeWindowId()
159 return mWindowBase->GetNativeWindowId();
162 void WindowRenderSurface::Map()
167 void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
169 mRenderNotification = renderNotification;
172 void WindowRenderSurface::SetTransparency(bool transparent)
174 mWindowBase->SetTransparency(transparent);
177 void WindowRenderSurface::RequestRotation(int angle, int width, int height)
179 if(!mRotationTrigger)
181 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessRotationRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
184 mPositionSize.width = width;
185 mPositionSize.height = height;
187 mWindowRotationAngle = angle;
188 mWindowRotationFinished = false;
190 mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
192 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mWindowRotationAngle, mScreenRotationAngle);
195 WindowBase* WindowRenderSurface::GetWindowBase()
197 return mWindowBase.get();
200 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
202 return mOutputTransformedSignal;
205 PositionSize WindowRenderSurface::GetPositionSize() const
207 return mPositionSize;
210 void WindowRenderSurface::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
212 if(mDpiHorizontal == 0 || mDpiVertical == 0)
214 const char* environmentDpiHorizontal = std::getenv(DALI_ENV_DPI_HORIZONTAL);
215 mDpiHorizontal = environmentDpiHorizontal ? std::atoi(environmentDpiHorizontal) : 0;
217 const char* environmentDpiVertical = std::getenv(DALI_ENV_DPI_VERTICAL);
218 mDpiVertical = environmentDpiVertical ? std::atoi(environmentDpiVertical) : 0;
220 if(mDpiHorizontal == 0 || mDpiVertical == 0)
222 mWindowBase->GetDpi(mDpiHorizontal, mDpiVertical);
226 dpiHorizontal = mDpiHorizontal;
227 dpiVertical = mDpiVertical;
230 int WindowRenderSurface::GetOrientation() const
232 return mWindowBase->GetOrientation();
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 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
281 mWindowBase->GetNativeWindowId(),
283 mPositionSize.height,
284 mWindowRotationAngle,
285 mScreenRotationAngle);
288 void WindowRenderSurface::DestroySurface()
290 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
292 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
295 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId());
297 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
299 eglImpl.DestroySurface(mEGLSurface);
300 mEGLSurface = nullptr;
302 // Destroy context also
303 eglImpl.DestroyContext(mEGLContext);
304 mEGLContext = nullptr;
306 mWindowBase->DestroyEglWindow();
310 bool WindowRenderSurface::ReplaceGraphicsSurface()
312 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
314 // Destroy the old one
315 mWindowBase->DestroyEglWindow();
318 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
320 width = mPositionSize.width;
321 height = mPositionSize.height;
325 width = mPositionSize.height;
326 height = mPositionSize.width;
329 // Create the EGL window
330 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
332 // Set screen rotation
333 mScreenRotationFinished = false;
335 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
337 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
338 return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext);
341 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
343 bool needToMove = false;
344 bool needToResize = false;
347 if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
348 (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
354 if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
355 (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
364 mWindowBase->MoveResize(positionSize);
368 mWindowBase->Resize(positionSize);
371 mResizeFinished = false;
372 mPositionSize = positionSize;
378 mWindowBase->Move(positionSize);
380 mPositionSize = positionSize;
384 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
387 void WindowRenderSurface::StartRender()
391 bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
393 Dali::Integration::Scene::FrameCallbackContainer callbacks;
395 Dali::Integration::Scene scene = mScene.GetHandle();
398 bool needFrameRenderedTrigger = false;
400 scene.GetFrameRenderedCallback(callbacks);
401 if(!callbacks.empty())
403 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
404 if(frameRenderedSync != -1)
406 Dali::Mutex::ScopedLock lock(mMutex);
408 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
410 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
412 needFrameRenderedTrigger = true;
416 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
423 scene.GetFramePresentedCallback(callbacks);
424 if(!callbacks.empty())
426 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
427 if(framePresentedSync != -1)
429 Dali::Mutex::ScopedLock lock(mMutex);
431 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
433 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
435 needFrameRenderedTrigger = true;
439 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
446 if(needFrameRenderedTrigger)
448 if(!mFrameRenderedTrigger)
450 mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
451 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
453 mFrameRenderedTrigger->Trigger();
457 MakeContextCurrent();
460 * wl_egl_window_tizen_set_rotation(SetEglWindowRotation) -> PreRotation
461 * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
462 * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform) -> Window Rotation
463 * These function should be called before calling first drawing gl Function.
464 * Notice : PreRotation is not used in the latest tizen,
465 * because output transform event should be occured before egl window is not created.
468 if(resizingSurface || mDefaultScreenRotationAvailable)
470 int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
472 // Window rotate or screen rotate
473 if(!mWindowRotationFinished || !mScreenRotationFinished)
475 mWindowBase->SetEglWindowBufferTransform(totalAngle);
477 // Reset only screen rotation flag
478 mScreenRotationFinished = true;
480 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
483 // Only window rotate
484 if(!mWindowRotationFinished)
486 mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
492 Dali::PositionSize positionSize;
493 positionSize.x = mPositionSize.x;
494 positionSize.y = mPositionSize.y;
495 if(totalAngle == 0 || totalAngle == 180)
497 positionSize.width = mPositionSize.width;
498 positionSize.height = mPositionSize.height;
502 positionSize.width = mPositionSize.height;
503 positionSize.height = mPositionSize.width;
505 mWindowBase->ResizeEglWindow(positionSize);
506 mResizeFinished = true;
508 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set resize\n");
511 SetFullSwapNextFrame();
512 mDefaultScreenRotationAvailable = false;
515 SetBufferDamagedRects(damagedRects, clippingRect);
520 void WindowRenderSurface::PostRender(bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects)
522 // Inform the gl implementation that rendering has finished before informing the surface
523 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
526 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
538 if(!mWindowRotationFinished)
540 if(mThreadSynchronization)
542 // Enable PostRender flag
543 mThreadSynchronization->PostRenderStarted();
546 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n");
548 mRotationTrigger->Trigger();
550 if(mThreadSynchronization)
552 // Wait until the event-thread complete the rotation event processing
553 mThreadSynchronization->PostRenderWaitForCompletion();
559 SwapBuffers(damagedRects);
561 if(mRenderNotification)
563 mRenderNotification->Trigger();
568 void WindowRenderSurface::StopRender()
572 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
574 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
576 mThreadSynchronization = &threadSynchronization;
579 void WindowRenderSurface::ReleaseLock()
584 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
586 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
589 void WindowRenderSurface::MakeContextCurrent()
593 mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
597 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
599 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
602 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
604 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
607 void WindowRenderSurface::OutputTransformed()
609 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
611 if(mScreenRotationAngle != screenRotationAngle)
613 mScreenRotationAngle = screenRotationAngle;
614 mScreenRotationFinished = false;
615 mResizeFinished = false;
617 mOutputTransformedSignal.Emit();
619 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
623 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
627 void WindowRenderSurface::ProcessRotationRequest()
629 mWindowRotationFinished = true;
631 mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
633 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n");
635 if(mThreadSynchronization)
637 mThreadSynchronization->PostRenderComplete();
641 void WindowRenderSurface::ProcessFrameCallback()
643 Dali::Mutex::ScopedLock lock(mMutex);
645 for(auto&& iter : mFrameCallbackInfoContainer)
647 if(!iter->fileDescriptorMonitor)
649 iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
650 MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
651 FileDescriptorMonitor::FD_READABLE));
653 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
658 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
660 if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
662 DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
663 close(fileDescriptor);
667 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
669 std::unique_ptr<FrameCallbackInfo> callbackInfo;
671 Dali::Mutex::ScopedLock lock(mMutex);
672 auto frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
673 return callbackInfo->fileDescriptor == fileDescriptor;
675 if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
677 callbackInfo = std::move(*frameCallbackInfo);
679 mFrameCallbackInfoContainer.erase(frameCallbackInfo);
683 // Call the connected callback
686 for(auto&& iter : (callbackInfo)->callbacks)
688 CallbackBase::Execute(*(iter.first), iter.second);
693 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
695 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
698 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
699 if(!eglImpl.IsPartialUpdateRequired())
704 Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
706 if(mFullSwapNextFrame)
708 InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
709 clippingRect = Rect<int>();
713 EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
715 // Buffer age 0 means the back buffer in invalid and requires full swap
716 if(!damagedRects.size() || bufferAge == 0)
718 InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
719 clippingRect = Rect<int>();
723 // We push current frame damaged rects here, zero index for current frame
724 InsertRects(mBufferDamagedRects, damagedRects);
726 // Merge damaged rects into clipping rect
727 auto bufferDamagedRects = mBufferDamagedRects.begin();
728 while(bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
730 const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
731 MergeRects(clippingRect, rects);
734 if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
736 // clipping area too big or doesn't intersect surface rect
737 clippingRect = Rect<int>();
741 std::vector<Rect<int>> damagedRegion;
742 damagedRegion.push_back(clippingRect);
744 eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
748 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
750 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
753 Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
755 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
757 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
759 mFullSwapNextFrame = false;
760 eglImpl.SwapBuffers(mEGLSurface);
764 mFullSwapNextFrame = false;
766 std::vector<Rect<int>> mergedRects = damagedRects;
768 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
769 // Could be optional and can be removed, needs to be checked with and without on platform
770 const int n = mergedRects.size();
771 for(int i = 0; i < n - 1; i++)
773 if(mergedRects[i].IsEmpty())
778 for(int j = i + 1; j < n; j++)
780 if(mergedRects[j].IsEmpty())
785 if(mergedRects[i].Intersects(mergedRects[j]))
787 mergedRects[i].Merge(mergedRects[j]);
788 mergedRects[j].width = 0;
789 mergedRects[j].height = 0;
795 for(int i = 0; i < n; i++)
797 if(!mergedRects[i].IsEmpty())
799 mergedRects[j++] = mergedRects[i];
805 mergedRects.resize(j);
808 if(!mergedRects.size() || (mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
810 eglImpl.SwapBuffers(mEGLSurface);
814 eglImpl.SwapBuffers(mEGLSurface, mergedRects);
819 } // namespace Adaptor
821 } // namespace Internal