2 * Copyright (c) 2022 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 InsertRects(WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const Rect<int>& damagedRects)
54 damagedRectsList.insert(damagedRectsList.begin(), damagedRects);
55 if(damagedRectsList.size() > 4) // past triple buffers + current
57 damagedRectsList.pop_back();
61 Rect<int32_t> RecalculateRect0(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
66 Rect<int32_t> RecalculateRect90(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
68 Rect<int32_t> newRect;
69 newRect.x = surfaceSize.height - (rect.y + rect.height);
71 newRect.width = rect.height;
72 newRect.height = rect.width;
76 Rect<int32_t> RecalculateRect180(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
78 Rect<int32_t> newRect;
79 newRect.x = surfaceSize.width - (rect.x + rect.width);
80 newRect.y = surfaceSize.height - (rect.y + rect.height);
81 newRect.width = rect.width;
82 newRect.height = rect.height;
86 Rect<int32_t> RecalculateRect270(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
88 Rect<int32_t> newRect;
90 newRect.y = surfaceSize.width - (rect.x + rect.width);
91 newRect.width = rect.height;
92 newRect.height = rect.width;
96 using RecalculateRectFunction = Rect<int32_t> (*)(Rect<int32_t>&, const Rect<int32_t>&);
98 RecalculateRectFunction RecalculateRect[4] = {RecalculateRect0, RecalculateRect90, RecalculateRect180, RecalculateRect270};
100 void MergeIntersectingRectsAndRotate(Rect<int>& mergingRect, std::vector<Rect<int>>& damagedRects, int orientation, const Rect<int32_t>& surfaceRect)
102 const int n = damagedRects.size();
103 for(int i = 0; i < n - 1; i++)
105 if(damagedRects[i].IsEmpty())
110 for(int j = i + 1; j < n; j++)
112 if(damagedRects[j].IsEmpty())
117 if(damagedRects[i].Intersects(damagedRects[j]))
119 damagedRects[i].Merge(damagedRects[j]);
120 damagedRects[j].width = 0;
121 damagedRects[j].height = 0;
127 for(int i = 0; i < n; i++)
129 if(!damagedRects[i].IsEmpty())
131 // Merge rects before rotate
132 if(mergingRect.IsEmpty())
134 mergingRect = damagedRects[i];
138 mergingRect.Merge(damagedRects[i]);
141 damagedRects[j++] = RecalculateRect[orientation](damagedRects[i], surfaceRect);
147 damagedRects.resize(j);
151 } // unnamed namespace
153 WindowRenderSurface::WindowRenderSurface(Dali::PositionSize positionSize, Any surface, bool isTransparent)
155 mDisplayConnection(nullptr),
156 mPositionSize(positionSize),
158 mThreadSynchronization(nullptr),
159 mRenderNotification(nullptr),
160 mPostRenderTrigger(),
161 mFrameRenderedTrigger(),
163 mEGLSurface(nullptr),
164 mEGLContext(nullptr),
165 mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
166 mOutputTransformedSignal(),
167 mFrameCallbackInfoContainer(),
168 mBufferDamagedRects(),
170 mWindowRotationAngle(0),
171 mScreenRotationAngle(0),
175 mWindowRotationFinished(true),
176 mScreenRotationFinished(true),
177 mResizeFinished(true),
178 mDefaultScreenRotationAvailable(false),
179 mIsImeWindowSurface(false),
180 mNeedWindowRotationAcknowledgement(false)
182 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n");
186 WindowRenderSurface::~WindowRenderSurface()
190 void WindowRenderSurface::Initialize(Any surface)
192 // If width or height are zero, go full screen.
193 if((mPositionSize.width == 0) || (mPositionSize.height == 0))
195 // Default window size == screen size
198 WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height);
201 // Create a window base
202 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
203 mWindowBase = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false));
206 mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed);
208 // Check screen rotation
209 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
210 if(mScreenRotationAngle != 0)
212 mScreenRotationFinished = false;
213 mResizeFinished = false;
214 mDefaultScreenRotationAvailable = true;
215 DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle);
219 Any WindowRenderSurface::GetNativeWindow()
221 return mWindowBase->GetNativeWindow();
224 int WindowRenderSurface::GetNativeWindowId()
226 return mWindowBase->GetNativeWindowId();
229 void WindowRenderSurface::Map()
234 void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
236 mRenderNotification = renderNotification;
239 void WindowRenderSurface::SetTransparency(bool transparent)
241 mWindowBase->SetTransparency(transparent);
244 void WindowRenderSurface::RequestRotation(int angle, PositionSize positionSize)
246 if(!mPostRenderTrigger)
248 mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
249 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
252 mPositionSize = positionSize;
254 mWindowRotationAngle = angle;
255 mWindowRotationFinished = false;
256 mResizeFinished = false;
258 mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
260 DALI_LOG_RELEASE_INFO("angle = %d screen rotation = %d, flag = %d\n", mWindowRotationAngle, mScreenRotationAngle, mWindowRotationFinished);
263 WindowBase* WindowRenderSurface::GetWindowBase()
265 return mWindowBase.get();
268 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
270 return mOutputTransformedSignal;
273 PositionSize WindowRenderSurface::GetPositionSize() const
275 return mPositionSize;
278 void WindowRenderSurface::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
280 if(mDpiHorizontal == 0 || mDpiVertical == 0)
282 const char* environmentDpiHorizontal = std::getenv(DALI_ENV_DPI_HORIZONTAL);
283 mDpiHorizontal = environmentDpiHorizontal ? std::atoi(environmentDpiHorizontal) : 0;
285 const char* environmentDpiVertical = std::getenv(DALI_ENV_DPI_VERTICAL);
286 mDpiVertical = environmentDpiVertical ? std::atoi(environmentDpiVertical) : 0;
288 if(mDpiHorizontal == 0 || mDpiVertical == 0)
290 mWindowBase->GetDpi(mDpiHorizontal, mDpiVertical);
294 dpiHorizontal = mDpiHorizontal;
295 dpiVertical = mDpiVertical;
298 int WindowRenderSurface::GetOrientation() const
300 return mWindowBase->GetOrientation();
303 void WindowRenderSurface::InitializeGraphics()
305 if(mEGLContext == NULL)
307 mGraphics = &mAdaptor->GetGraphicsInterface();
309 DALI_ASSERT_ALWAYS(mGraphics && "Graphics interface is not created");
311 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
312 mEGL = &eglGraphics->GetEglInterface();
314 // Create the OpenGL context for this window
315 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
316 eglImpl.ChooseConfig(true, mColorDepth);
317 eglImpl.CreateWindowContext(mEGLContext);
319 // Create the OpenGL surface
324 void WindowRenderSurface::CreateSurface()
326 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
329 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
331 width = mPositionSize.width;
332 height = mPositionSize.height;
336 width = mPositionSize.height;
337 height = mPositionSize.width;
340 // Create the EGL window
341 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
343 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
345 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
346 mEGLSurface = eglImpl.CreateSurfaceWindow(window, mColorDepth);
348 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), EGLSurface (%p), w = %d h = %d angle = %d screen rotation = %d\n",
349 mWindowBase->GetNativeWindowId(),
352 mPositionSize.height,
353 mWindowRotationAngle,
354 mScreenRotationAngle);
357 void WindowRenderSurface::DestroySurface()
359 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
361 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
364 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId());
366 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
368 eglImpl.DestroySurface(mEGLSurface);
369 mEGLSurface = nullptr;
371 // Destroy context also
372 eglImpl.DestroyContext(mEGLContext);
373 mEGLContext = nullptr;
375 mWindowBase->DestroyEglWindow();
379 bool WindowRenderSurface::ReplaceGraphicsSurface()
381 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
383 // Destroy the old one
384 mWindowBase->DestroyEglWindow();
387 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
389 width = mPositionSize.width;
390 height = mPositionSize.height;
394 width = mPositionSize.height;
395 height = mPositionSize.width;
398 // Create the EGL window
399 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
401 // Set screen rotation
402 mScreenRotationFinished = false;
404 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
406 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
407 return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext);
410 void WindowRenderSurface::UpdatePositionSize(Dali::PositionSize positionSize)
412 bool needToMove = false;
413 bool needToResize = false;
416 if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
417 (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
423 if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
424 (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
431 mResizeFinished = false;
432 mPositionSize = positionSize;
438 mPositionSize = positionSize;
442 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
445 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
447 bool needToMove = false;
448 bool needToResize = false;
451 if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
452 (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
458 if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
459 (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
468 mWindowBase->MoveResize(positionSize);
472 mWindowBase->Resize(positionSize);
475 mResizeFinished = false;
476 mPositionSize = positionSize;
482 mWindowBase->Move(positionSize);
484 mPositionSize = positionSize;
488 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
491 void WindowRenderSurface::StartRender()
495 bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
497 InitializeGraphics();
499 Dali::Integration::Scene::FrameCallbackContainer callbacks;
501 Dali::Integration::Scene scene = mScene.GetHandle();
504 bool needFrameRenderedTrigger = false;
506 scene.GetFrameRenderedCallback(callbacks);
507 if(!callbacks.empty())
509 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
510 if(frameRenderedSync != -1)
512 Dali::Mutex::ScopedLock lock(mMutex);
514 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
516 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
518 needFrameRenderedTrigger = true;
522 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
529 scene.GetFramePresentedCallback(callbacks);
530 if(!callbacks.empty())
532 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
533 if(framePresentedSync != -1)
535 Dali::Mutex::ScopedLock lock(mMutex);
537 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
539 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
541 needFrameRenderedTrigger = true;
545 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
552 if(needFrameRenderedTrigger)
554 if(!mFrameRenderedTrigger)
556 mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
557 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
559 mFrameRenderedTrigger->Trigger();
564 * wl_egl_window_tizen_set_rotation(SetEglWindowRotation) -> PreRotation
565 * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
566 * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform) -> Window Rotation
567 * These function should be called before calling first drawing gl Function.
568 * Notice : PreRotation is not used in the latest tizen,
569 * because output transform event should be occured before egl window is not created.
572 if(mIsResizing || mDefaultScreenRotationAvailable)
574 int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
576 // Window rotate or screen rotate
577 if(!mWindowRotationFinished || !mScreenRotationFinished)
579 mWindowBase->SetEglWindowBufferTransform(totalAngle);
581 // Reset only screen rotation flag
582 mScreenRotationFinished = true;
584 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
587 // Only window rotate
588 if(!mWindowRotationFinished)
590 mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
596 Dali::PositionSize positionSize;
597 positionSize.x = mPositionSize.x;
598 positionSize.y = mPositionSize.y;
599 if(totalAngle == 0 || totalAngle == 180)
601 positionSize.width = mPositionSize.width;
602 positionSize.height = mPositionSize.height;
606 positionSize.width = mPositionSize.height;
607 positionSize.height = mPositionSize.width;
609 mWindowBase->ResizeEglWindow(positionSize);
610 mResizeFinished = true;
612 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set resize, totalAngle: %d, x: %d, y: %d, w: %d, h:%d\n", totalAngle, positionSize.x, positionSize.y, positionSize.width, positionSize.height);
615 SetFullSwapNextFrame();
616 mDefaultScreenRotationAvailable = false;
619 SetBufferDamagedRects(damagedRects, clippingRect);
623 Rect<int> surfaceRect = scene.GetCurrentSurfaceRect();
624 if(clippingRect == surfaceRect)
626 mDamagedRects.assign(1, RecalculateRect[std::min(scene.GetCurrentSurfaceOrientation() / 90, 3)](surfaceRect, surfaceRect));
630 // This is now done when the render pass for the render surface begins
631 // MakeContextCurrent();
636 void WindowRenderSurface::PostRender()
638 // Inform the gl implementation that rendering has finished before informing the surface
639 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
642 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
645 bool needWindowRotationCompleted = false;
647 if(!mWindowRotationFinished)
649 if(mNeedWindowRotationAcknowledgement)
651 Dali::Integration::Scene scene = mScene.GetHandle();
654 if(scene.IsRotationCompletedAcknowledgementSet())
656 needWindowRotationCompleted = true;
664 needWindowRotationCompleted = true;
669 if(needWindowRotationCompleted || mIsImeWindowSurface)
671 if(mThreadSynchronization)
673 // Enable PostRender flag
674 mThreadSynchronization->PostRenderStarted();
677 if(!mWindowRotationFinished || mIsImeWindowSurface)
679 mPostRenderTrigger->Trigger();
682 if(mThreadSynchronization)
684 // Wait until the event-thread complete the rotation event processing
685 mThreadSynchronization->PostRenderWaitForCompletion();
689 SwapBuffers(mDamagedRects);
691 if(mRenderNotification)
693 mRenderNotification->Trigger();
698 void WindowRenderSurface::StopRender()
702 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
704 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
706 mThreadSynchronization = &threadSynchronization;
709 void WindowRenderSurface::ReleaseLock()
714 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
716 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
719 void WindowRenderSurface::MakeContextCurrent()
723 mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
727 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
729 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
732 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
734 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
737 void WindowRenderSurface::InitializeImeSurface()
739 mIsImeWindowSurface = true;
740 if(!mPostRenderTrigger)
742 mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
743 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
747 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
749 mNeedWindowRotationAcknowledgement = needAcknowledgement;
752 void WindowRenderSurface::OutputTransformed()
754 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
756 if(mScreenRotationAngle != screenRotationAngle)
758 mScreenRotationAngle = screenRotationAngle;
759 mScreenRotationFinished = false;
760 mResizeFinished = false;
762 mOutputTransformedSignal.Emit();
764 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
768 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
772 bool WindowRenderSurface::IsWindowRotating() const
774 return !(mWindowRotationFinished);
777 void WindowRenderSurface::ProcessPostRender()
779 if(!mWindowRotationFinished)
781 mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
782 mWindowRotationFinished = true;
783 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mWindowRotationFinished);
786 if(mIsImeWindowSurface)
788 mWindowBase->ImeWindowReadyToRender();
791 if(mThreadSynchronization)
793 mThreadSynchronization->PostRenderComplete();
797 void WindowRenderSurface::ProcessFrameCallback()
799 Dali::Mutex::ScopedLock lock(mMutex);
801 for(auto&& iter : mFrameCallbackInfoContainer)
803 if(!iter->fileDescriptorMonitor)
805 iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
806 MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
807 FileDescriptorMonitor::FD_READABLE));
809 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
814 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
816 if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
818 DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
819 close(fileDescriptor);
823 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
825 std::unique_ptr<FrameCallbackInfo> callbackInfo;
827 Dali::Mutex::ScopedLock lock(mMutex);
828 auto frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
829 return callbackInfo->fileDescriptor == fileDescriptor;
831 if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
833 callbackInfo = std::move(*frameCallbackInfo);
835 mFrameCallbackInfoContainer.erase(frameCallbackInfo);
839 // Call the connected callback
842 for(auto&& iter : (callbackInfo)->callbacks)
844 CallbackBase::Execute(*(iter.first), iter.second);
849 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
851 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
854 // If scene is not exist, just use stored mPositionSize.
855 Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
856 int32_t orientation = 0;
858 Dali::Integration::Scene scene = mScene.GetHandle();
861 surfaceRect = scene.GetCurrentSurfaceRect();
862 orientation = std::min(scene.GetCurrentSurfaceOrientation() / 90, 3);
865 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
866 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
868 InsertRects(mBufferDamagedRects, surfaceRect);
869 clippingRect = surfaceRect;
873 if(damagedRects.empty())
875 // Empty damaged rect. We don't need rendering
876 clippingRect = Rect<int>();
877 // Clean up current damanged rects.
878 mDamagedRects.clear();
882 mGraphics->ActivateSurfaceContext(this);
884 EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
886 // Buffer age 0 means the back buffer in invalid and requires full swap
889 InsertRects(mBufferDamagedRects, surfaceRect);
890 clippingRect = surfaceRect;
894 mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
896 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
897 // Could be optional and can be removed, needs to be checked with and without on platform
898 // And then, Make one clipping rect, and rotate rects by orientation.
899 MergeIntersectingRectsAndRotate(clippingRect, mDamagedRects, orientation, surfaceRect);
901 // We push current frame damaged rects here, zero index for current frame
902 InsertRects(mBufferDamagedRects, clippingRect);
904 // Merge damaged rects into clipping rect
905 if(bufferAge <= static_cast<EGLint>(mBufferDamagedRects.size()))
907 // clippingRect is already the current frame's damaged rect. Merge from the second
908 for(int i = 1; i < bufferAge; i++)
910 clippingRect.Merge(mBufferDamagedRects[i]);
915 // The buffer age is too old. Need full update.
916 clippingRect = surfaceRect;
920 if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
922 // clipping area too big or doesn't intersect surface rect
923 clippingRect = surfaceRect;
927 if(!clippingRect.IsEmpty())
929 std::vector<Rect<int>> damagedRegion;
932 damagedRegion.push_back(RecalculateRect[orientation](clippingRect, surfaceRect));
936 damagedRegion.push_back(clippingRect);
939 eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
944 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
946 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
949 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
951 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
953 mFullSwapNextFrame = false;
954 eglImpl.SwapBuffers(mEGLSurface);
958 mFullSwapNextFrame = false;
960 Rect<int32_t> surfaceRect;
961 Dali::Integration::Scene scene = mScene.GetHandle();
964 surfaceRect = scene.GetCurrentSurfaceRect();
967 if(!damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
969 // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
970 // For exceptional cases, swap full area.
971 eglImpl.SwapBuffers(mEGLSurface);
975 eglImpl.SwapBuffers(mEGLSurface, damagedRects);
980 } // namespace Adaptor
982 } // namespace Internal