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 Rect<int32_t> RecalculateRect0(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
87 Rect<int32_t> RecalculateRect90(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
89 Rect<int32_t> newRect;
90 newRect.x = surfaceSize.height - (rect.y + rect.height);
92 newRect.width = rect.height;
93 newRect.height = rect.width;
97 Rect<int32_t> RecalculateRect180(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
99 Rect<int32_t> newRect;
100 newRect.x = surfaceSize.width - (rect.x + rect.width);
101 newRect.y = surfaceSize.height - (rect.y + rect.height);
102 newRect.width = rect.width;
103 newRect.height = rect.height;
107 Rect<int32_t> RecalculateRect270(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
109 Rect<int32_t> newRect;
111 newRect.y = surfaceSize.width - (rect.x + rect.width);
112 newRect.width = rect.height;
113 newRect.height = rect.width;
117 using RecalculateRectFunction = Rect<int32_t> (*)(Rect<int32_t>&, const Rect<int32_t>&);
119 RecalculateRectFunction RecalculateRect[4] = {RecalculateRect0, RecalculateRect90, RecalculateRect180, RecalculateRect270};
121 } // unnamed namespace
123 WindowRenderSurface::WindowRenderSurface(Dali::PositionSize positionSize, Any surface, bool isTransparent)
125 mDisplayConnection(nullptr),
126 mPositionSize(positionSize),
128 mThreadSynchronization(nullptr),
129 mRenderNotification(nullptr),
130 mPostRenderTrigger(),
131 mFrameRenderedTrigger(),
133 mEGLSurface(nullptr),
134 mEGLContext(nullptr),
135 mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
136 mOutputTransformedSignal(),
137 mFrameCallbackInfoContainer(),
138 mBufferDamagedRects(),
140 mWindowRotationAngle(0),
141 mScreenRotationAngle(0),
145 mWindowRotationFinished(true),
146 mScreenRotationFinished(true),
147 mResizeFinished(true),
148 mDefaultScreenRotationAvailable(false),
149 mIsImeWindowSurface(false),
150 mNeedWindowRotationAcknowledgement(false)
152 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n");
156 WindowRenderSurface::~WindowRenderSurface()
160 void WindowRenderSurface::Initialize(Any surface)
162 // If width or height are zero, go full screen.
163 if((mPositionSize.width == 0) || (mPositionSize.height == 0))
165 // Default window size == screen size
168 WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height);
171 // Create a window base
172 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
173 mWindowBase = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false));
176 mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed);
178 // Check screen rotation
179 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
180 if(mScreenRotationAngle != 0)
182 mScreenRotationFinished = false;
183 mResizeFinished = false;
184 mDefaultScreenRotationAvailable = true;
185 DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle);
189 Any WindowRenderSurface::GetNativeWindow()
191 return mWindowBase->GetNativeWindow();
194 int WindowRenderSurface::GetNativeWindowId()
196 return mWindowBase->GetNativeWindowId();
199 void WindowRenderSurface::Map()
204 void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
206 mRenderNotification = renderNotification;
209 void WindowRenderSurface::SetTransparency(bool transparent)
211 mWindowBase->SetTransparency(transparent);
214 void WindowRenderSurface::RequestRotation(int angle, int width, int height)
216 if(!mPostRenderTrigger)
218 mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
219 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
222 mPositionSize.width = width;
223 mPositionSize.height = height;
225 mWindowRotationAngle = angle;
226 mWindowRotationFinished = false;
227 mResizeFinished = false;
229 mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
231 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mWindowRotationAngle, mScreenRotationAngle);
234 WindowBase* WindowRenderSurface::GetWindowBase()
236 return mWindowBase.get();
239 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
241 return mOutputTransformedSignal;
244 PositionSize WindowRenderSurface::GetPositionSize() const
246 return mPositionSize;
249 void WindowRenderSurface::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
251 if(mDpiHorizontal == 0 || mDpiVertical == 0)
253 const char* environmentDpiHorizontal = std::getenv(DALI_ENV_DPI_HORIZONTAL);
254 mDpiHorizontal = environmentDpiHorizontal ? std::atoi(environmentDpiHorizontal) : 0;
256 const char* environmentDpiVertical = std::getenv(DALI_ENV_DPI_VERTICAL);
257 mDpiVertical = environmentDpiVertical ? std::atoi(environmentDpiVertical) : 0;
259 if(mDpiHorizontal == 0 || mDpiVertical == 0)
261 mWindowBase->GetDpi(mDpiHorizontal, mDpiVertical);
265 dpiHorizontal = mDpiHorizontal;
266 dpiVertical = mDpiVertical;
269 int WindowRenderSurface::GetOrientation() const
271 return mWindowBase->GetOrientation();
274 void WindowRenderSurface::InitializeGraphics()
276 if(mEGLContext == NULL)
278 mGraphics = &mAdaptor->GetGraphicsInterface();
280 DALI_ASSERT_ALWAYS(mGraphics && "Graphics interface is not created");
282 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
283 mEGL = &eglGraphics->GetEglInterface();
285 // Create the OpenGL context for this window
286 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
287 eglImpl.ChooseConfig(true, mColorDepth);
288 eglImpl.CreateWindowContext(mEGLContext);
290 // Create the OpenGL surface
295 void WindowRenderSurface::CreateSurface()
297 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
300 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
302 width = mPositionSize.width;
303 height = mPositionSize.height;
307 width = mPositionSize.height;
308 height = mPositionSize.width;
311 // Create the EGL window
312 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
314 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
316 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
317 mEGLSurface = eglImpl.CreateSurfaceWindow(window, mColorDepth);
319 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), EGLSurface (%p), w = %d h = %d angle = %d screen rotation = %d\n",
320 mWindowBase->GetNativeWindowId(),
323 mPositionSize.height,
324 mWindowRotationAngle,
325 mScreenRotationAngle);
328 void WindowRenderSurface::DestroySurface()
330 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
332 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
335 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId());
337 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
339 eglImpl.DestroySurface(mEGLSurface);
340 mEGLSurface = nullptr;
342 // Destroy context also
343 eglImpl.DestroyContext(mEGLContext);
344 mEGLContext = nullptr;
346 mWindowBase->DestroyEglWindow();
350 bool WindowRenderSurface::ReplaceGraphicsSurface()
352 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
354 // Destroy the old one
355 mWindowBase->DestroyEglWindow();
358 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
360 width = mPositionSize.width;
361 height = mPositionSize.height;
365 width = mPositionSize.height;
366 height = mPositionSize.width;
369 // Create the EGL window
370 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
372 // Set screen rotation
373 mScreenRotationFinished = false;
375 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
377 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
378 return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext);
381 void WindowRenderSurface::UpdatePositionSize(Dali::PositionSize positionSize)
383 bool needToMove = false;
384 bool needToResize = false;
387 if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
388 (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
394 if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
395 (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
402 mResizeFinished = false;
403 mPositionSize = positionSize;
409 mPositionSize = positionSize;
413 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
416 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
418 bool needToMove = false;
419 bool needToResize = false;
422 if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
423 (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
429 if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
430 (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
439 mWindowBase->MoveResize(positionSize);
443 mWindowBase->Resize(positionSize);
446 mResizeFinished = false;
447 mPositionSize = positionSize;
453 mWindowBase->Move(positionSize);
455 mPositionSize = positionSize;
459 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
462 void WindowRenderSurface::StartRender()
466 bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
468 InitializeGraphics();
470 mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
472 Dali::Integration::Scene::FrameCallbackContainer callbacks;
474 Dali::Integration::Scene scene = mScene.GetHandle();
477 bool needFrameRenderedTrigger = false;
479 scene.GetFrameRenderedCallback(callbacks);
480 if(!callbacks.empty())
482 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
483 if(frameRenderedSync != -1)
485 Dali::Mutex::ScopedLock lock(mMutex);
487 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
489 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
491 needFrameRenderedTrigger = true;
495 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
502 scene.GetFramePresentedCallback(callbacks);
503 if(!callbacks.empty())
505 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
506 if(framePresentedSync != -1)
508 Dali::Mutex::ScopedLock lock(mMutex);
510 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
512 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
514 needFrameRenderedTrigger = true;
518 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
525 if(needFrameRenderedTrigger)
527 if(!mFrameRenderedTrigger)
529 mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
530 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
532 mFrameRenderedTrigger->Trigger();
537 * wl_egl_window_tizen_set_rotation(SetEglWindowRotation) -> PreRotation
538 * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
539 * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform) -> Window Rotation
540 * These function should be called before calling first drawing gl Function.
541 * Notice : PreRotation is not used in the latest tizen,
542 * because output transform event should be occured before egl window is not created.
545 if(mIsResizing || mDefaultScreenRotationAvailable)
547 int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
549 // Window rotate or screen rotate
550 if(!mWindowRotationFinished || !mScreenRotationFinished)
552 mWindowBase->SetEglWindowBufferTransform(totalAngle);
554 // Reset only screen rotation flag
555 mScreenRotationFinished = true;
557 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
560 // Only window rotate
561 if(!mWindowRotationFinished)
563 mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
569 Dali::PositionSize positionSize;
570 positionSize.x = mPositionSize.x;
571 positionSize.y = mPositionSize.y;
572 if(totalAngle == 0 || totalAngle == 180)
574 positionSize.width = mPositionSize.width;
575 positionSize.height = mPositionSize.height;
579 positionSize.width = mPositionSize.height;
580 positionSize.height = mPositionSize.width;
582 mWindowBase->ResizeEglWindow(positionSize);
583 mResizeFinished = true;
585 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set resize, x: %d, y: %d, w: %d, h:%d\n", positionSize.x, positionSize.y, positionSize.width, positionSize.height);
588 SetFullSwapNextFrame();
589 mDefaultScreenRotationAvailable = false;
592 SetBufferDamagedRects(mDamagedRects, clippingRect);
596 Rect<int> surfaceRect = scene.GetCurrentSurfaceRect();
597 if(clippingRect == surfaceRect)
599 mDamagedRects.assign(1, surfaceRect);
601 else if(mDamagedRects.empty() && !clippingRect.IsEmpty())
603 // We will render clippingRect area but mDamagedRects is empty.
604 // So make mDamagedRects same with clippingRect to swap buffers.
605 mDamagedRects.assign(1, clippingRect);
609 // This is now done when the render pass for the render surface begins
610 // MakeContextCurrent();
615 void WindowRenderSurface::PostRender()
617 // Inform the gl implementation that rendering has finished before informing the surface
618 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
621 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
624 bool needWindowRotationCompleted = false;
626 if(!mWindowRotationFinished)
628 if(mNeedWindowRotationAcknowledgement)
630 Dali::Integration::Scene scene = mScene.GetHandle();
633 if(scene.IsRotationCompletedAcknowledgementSet())
635 needWindowRotationCompleted = true;
643 needWindowRotationCompleted = true;
648 if(needWindowRotationCompleted || mIsImeWindowSurface)
650 if(mThreadSynchronization)
652 // Enable PostRender flag
653 mThreadSynchronization->PostRenderStarted();
656 if(!mWindowRotationFinished || mIsImeWindowSurface)
658 mPostRenderTrigger->Trigger();
661 if(mThreadSynchronization)
663 // Wait until the event-thread complete the rotation event processing
664 mThreadSynchronization->PostRenderWaitForCompletion();
668 SwapBuffers(mDamagedRects);
670 if(mRenderNotification)
672 mRenderNotification->Trigger();
677 void WindowRenderSurface::StopRender()
681 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
683 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
685 mThreadSynchronization = &threadSynchronization;
688 void WindowRenderSurface::ReleaseLock()
693 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
695 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
698 void WindowRenderSurface::MakeContextCurrent()
702 mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
706 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
708 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
711 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
713 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
716 void WindowRenderSurface::InitializeImeSurface()
718 mIsImeWindowSurface = true;
719 if(!mPostRenderTrigger)
721 mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
722 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
726 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
728 mNeedWindowRotationAcknowledgement = needAcknowledgement;
731 void WindowRenderSurface::OutputTransformed()
733 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
735 if(mScreenRotationAngle != screenRotationAngle)
737 mScreenRotationAngle = screenRotationAngle;
738 mScreenRotationFinished = false;
739 mResizeFinished = false;
741 mOutputTransformedSignal.Emit();
743 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
747 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
751 void WindowRenderSurface::ProcessPostRender()
753 if(!mWindowRotationFinished)
755 mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
756 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done\n");
757 mWindowRotationFinished = true;
760 if(mIsImeWindowSurface)
762 mWindowBase->ImeWindowReadyToRender();
765 if(mThreadSynchronization)
767 mThreadSynchronization->PostRenderComplete();
771 void WindowRenderSurface::ProcessFrameCallback()
773 Dali::Mutex::ScopedLock lock(mMutex);
775 for(auto&& iter : mFrameCallbackInfoContainer)
777 if(!iter->fileDescriptorMonitor)
779 iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
780 MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
781 FileDescriptorMonitor::FD_READABLE));
783 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
788 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
790 if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
792 DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
793 close(fileDescriptor);
797 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
799 std::unique_ptr<FrameCallbackInfo> callbackInfo;
801 Dali::Mutex::ScopedLock lock(mMutex);
802 auto frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
803 return callbackInfo->fileDescriptor == fileDescriptor;
805 if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
807 callbackInfo = std::move(*frameCallbackInfo);
809 mFrameCallbackInfoContainer.erase(frameCallbackInfo);
813 // Call the connected callback
816 for(auto&& iter : (callbackInfo)->callbacks)
818 CallbackBase::Execute(*(iter.first), iter.second);
823 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
825 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
828 // If scene is not exist, just use stored mPositionSize.
829 Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
831 Dali::Integration::Scene scene = mScene.GetHandle();
834 surfaceRect = scene.GetCurrentSurfaceRect();
837 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
838 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
840 InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
841 clippingRect = surfaceRect;
845 mGraphics->ActivateSurfaceContext(this);
847 EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
849 // Buffer age 0 means the back buffer in invalid and requires full swap
852 InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
853 clippingRect = surfaceRect;
857 // We push current frame damaged rects here, zero index for current frame
858 InsertRects(mBufferDamagedRects, damagedRects);
860 // Merge damaged rects into clipping rect
861 auto bufferDamagedRects = mBufferDamagedRects.begin();
862 while(bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
864 const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
865 MergeRects(clippingRect, rects);
868 if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
870 // clipping area too big or doesn't intersect surface rect
871 clippingRect = surfaceRect;
875 if(!clippingRect.IsEmpty())
877 std::vector<Rect<int>> damagedRegion;
880 damagedRegion.push_back(RecalculateRect[std::min(scene.GetCurrentSurfaceOrientation() / 90, 3)](clippingRect, scene.GetCurrentSurfaceRect()));
884 damagedRegion.push_back(clippingRect);
887 eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
892 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
894 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
897 Rect<int32_t> surfaceRect;
898 int32_t orientation = 0;
900 Dali::Integration::Scene scene = mScene.GetHandle();
903 surfaceRect = scene.GetCurrentSurfaceRect();
904 orientation = std::min(scene.GetCurrentSurfaceOrientation() / 90, 3);
907 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
909 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || (damagedRects.size() != 0 && damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
911 mFullSwapNextFrame = false;
912 eglImpl.SwapBuffers(mEGLSurface);
916 mFullSwapNextFrame = false;
918 std::vector<Rect<int>> mergedRects = damagedRects;
920 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
921 // Could be optional and can be removed, needs to be checked with and without on platform
922 const int n = mergedRects.size();
923 for(int i = 0; i < n - 1; i++)
925 if(mergedRects[i].IsEmpty())
930 for(int j = i + 1; j < n; j++)
932 if(mergedRects[j].IsEmpty())
937 if(mergedRects[i].Intersects(mergedRects[j]))
939 mergedRects[i].Merge(mergedRects[j]);
940 mergedRects[j].width = 0;
941 mergedRects[j].height = 0;
947 for(int i = 0; i < n; i++)
949 if(!mergedRects[i].IsEmpty())
951 mergedRects[j++] = RecalculateRect[orientation](mergedRects[i], surfaceRect);
957 mergedRects.resize(j);
960 if(!mergedRects.size() || (mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
962 // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
963 // For exceptional cases, swap full area.
964 eglImpl.SwapBuffers(mEGLSurface);
968 eglImpl.SwapBuffers(mEGLSurface, mergedRects);
973 } // namespace Adaptor
975 } // namespace Internal