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 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 Rect<int>& damagedRects)
75 damagedRectsList.insert(damagedRectsList.begin(), 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 void MergeIntersectingRects(std::vector<Rect<int>>& damagedRects, int orientation, const Rect<int32_t>& surfaceRect)
123 const int n = damagedRects.size();
124 for(int i = 0; i < n - 1; i++)
126 if(damagedRects[i].IsEmpty())
131 for(int j = i + 1; j < n; j++)
133 if(damagedRects[j].IsEmpty())
138 if(damagedRects[i].Intersects(damagedRects[j]))
140 damagedRects[i].Merge(damagedRects[j]);
141 damagedRects[j].width = 0;
142 damagedRects[j].height = 0;
148 for(int i = 0; i < n; i++)
150 if(!damagedRects[i].IsEmpty())
152 damagedRects[j++] = RecalculateRect[orientation](damagedRects[i], surfaceRect);
158 damagedRects.resize(j);
162 } // unnamed namespace
164 WindowRenderSurface::WindowRenderSurface(Dali::PositionSize positionSize, Any surface, bool isTransparent)
166 mDisplayConnection(nullptr),
167 mPositionSize(positionSize),
169 mThreadSynchronization(nullptr),
170 mRenderNotification(nullptr),
171 mPostRenderTrigger(),
172 mFrameRenderedTrigger(),
174 mEGLSurface(nullptr),
175 mEGLContext(nullptr),
176 mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
177 mOutputTransformedSignal(),
178 mFrameCallbackInfoContainer(),
179 mBufferDamagedRects(),
181 mWindowRotationAngle(0),
182 mScreenRotationAngle(0),
186 mWindowRotationFinished(true),
187 mScreenRotationFinished(true),
188 mResizeFinished(true),
189 mDefaultScreenRotationAvailable(false),
190 mIsImeWindowSurface(false),
191 mNeedWindowRotationAcknowledgement(false)
193 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n");
197 WindowRenderSurface::~WindowRenderSurface()
201 void WindowRenderSurface::Initialize(Any surface)
203 // If width or height are zero, go full screen.
204 if((mPositionSize.width == 0) || (mPositionSize.height == 0))
206 // Default window size == screen size
209 WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height);
212 // Create a window base
213 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
214 mWindowBase = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false));
217 mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed);
219 // Check screen rotation
220 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
221 if(mScreenRotationAngle != 0)
223 mScreenRotationFinished = false;
224 mResizeFinished = false;
225 mDefaultScreenRotationAvailable = true;
226 DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle);
230 Any WindowRenderSurface::GetNativeWindow()
232 return mWindowBase->GetNativeWindow();
235 int WindowRenderSurface::GetNativeWindowId()
237 return mWindowBase->GetNativeWindowId();
240 void WindowRenderSurface::Map()
245 void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
247 mRenderNotification = renderNotification;
250 void WindowRenderSurface::SetTransparency(bool transparent)
252 mWindowBase->SetTransparency(transparent);
255 void WindowRenderSurface::RequestRotation(int angle, PositionSize positionSize)
257 if(!mPostRenderTrigger)
259 mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
260 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
263 mPositionSize = positionSize;
265 mWindowRotationAngle = angle;
266 mWindowRotationFinished = false;
267 mResizeFinished = false;
269 mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
271 DALI_LOG_RELEASE_INFO("angle = %d screen rotation = %d, flag = %d\n", mWindowRotationAngle, mScreenRotationAngle, mWindowRotationFinished);
274 WindowBase* WindowRenderSurface::GetWindowBase()
276 return mWindowBase.get();
279 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
281 return mOutputTransformedSignal;
284 PositionSize WindowRenderSurface::GetPositionSize() const
286 return mPositionSize;
289 void WindowRenderSurface::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
291 if(mDpiHorizontal == 0 || mDpiVertical == 0)
293 const char* environmentDpiHorizontal = std::getenv(DALI_ENV_DPI_HORIZONTAL);
294 mDpiHorizontal = environmentDpiHorizontal ? std::atoi(environmentDpiHorizontal) : 0;
296 const char* environmentDpiVertical = std::getenv(DALI_ENV_DPI_VERTICAL);
297 mDpiVertical = environmentDpiVertical ? std::atoi(environmentDpiVertical) : 0;
299 if(mDpiHorizontal == 0 || mDpiVertical == 0)
301 mWindowBase->GetDpi(mDpiHorizontal, mDpiVertical);
305 dpiHorizontal = mDpiHorizontal;
306 dpiVertical = mDpiVertical;
309 int WindowRenderSurface::GetOrientation() const
311 return mWindowBase->GetOrientation();
314 void WindowRenderSurface::InitializeGraphics()
316 if(mEGLContext == NULL)
318 mGraphics = &mAdaptor->GetGraphicsInterface();
320 DALI_ASSERT_ALWAYS(mGraphics && "Graphics interface is not created");
322 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
323 mEGL = &eglGraphics->GetEglInterface();
325 // Create the OpenGL context for this window
326 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
327 eglImpl.ChooseConfig(true, mColorDepth);
328 eglImpl.CreateWindowContext(mEGLContext);
330 // Create the OpenGL surface
335 void WindowRenderSurface::CreateSurface()
337 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
340 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
342 width = mPositionSize.width;
343 height = mPositionSize.height;
347 width = mPositionSize.height;
348 height = mPositionSize.width;
351 // Create the EGL window
352 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
354 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
356 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
357 mEGLSurface = eglImpl.CreateSurfaceWindow(window, mColorDepth);
359 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), EGLSurface (%p), w = %d h = %d angle = %d screen rotation = %d\n",
360 mWindowBase->GetNativeWindowId(),
363 mPositionSize.height,
364 mWindowRotationAngle,
365 mScreenRotationAngle);
368 void WindowRenderSurface::DestroySurface()
370 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
372 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
375 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId());
377 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
379 eglImpl.DestroySurface(mEGLSurface);
380 mEGLSurface = nullptr;
382 // Destroy context also
383 eglImpl.DestroyContext(mEGLContext);
384 mEGLContext = nullptr;
386 mWindowBase->DestroyEglWindow();
390 bool WindowRenderSurface::ReplaceGraphicsSurface()
392 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
394 // Destroy the old one
395 mWindowBase->DestroyEglWindow();
398 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
400 width = mPositionSize.width;
401 height = mPositionSize.height;
405 width = mPositionSize.height;
406 height = mPositionSize.width;
409 // Create the EGL window
410 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
412 // Set screen rotation
413 mScreenRotationFinished = false;
415 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
417 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
418 return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext);
421 void WindowRenderSurface::UpdatePositionSize(Dali::PositionSize positionSize)
423 bool needToMove = false;
424 bool needToResize = false;
427 if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
428 (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
434 if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
435 (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
442 mResizeFinished = false;
443 mPositionSize = positionSize;
449 mPositionSize = positionSize;
453 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
456 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
458 bool needToMove = false;
459 bool needToResize = false;
462 if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
463 (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
469 if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
470 (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
479 mWindowBase->MoveResize(positionSize);
483 mWindowBase->Resize(positionSize);
486 mResizeFinished = false;
487 mPositionSize = positionSize;
493 mWindowBase->Move(positionSize);
495 mPositionSize = positionSize;
499 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
502 void WindowRenderSurface::StartRender()
506 bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
508 InitializeGraphics();
510 Dali::Integration::Scene::FrameCallbackContainer callbacks;
512 Dali::Integration::Scene scene = mScene.GetHandle();
515 bool needFrameRenderedTrigger = false;
517 scene.GetFrameRenderedCallback(callbacks);
518 if(!callbacks.empty())
520 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
521 if(frameRenderedSync != -1)
523 Dali::Mutex::ScopedLock lock(mMutex);
525 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
527 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
529 needFrameRenderedTrigger = true;
533 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
540 scene.GetFramePresentedCallback(callbacks);
541 if(!callbacks.empty())
543 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
544 if(framePresentedSync != -1)
546 Dali::Mutex::ScopedLock lock(mMutex);
548 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
550 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
552 needFrameRenderedTrigger = true;
556 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
563 if(needFrameRenderedTrigger)
565 if(!mFrameRenderedTrigger)
567 mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
568 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
570 mFrameRenderedTrigger->Trigger();
575 * wl_egl_window_tizen_set_rotation(SetEglWindowRotation) -> PreRotation
576 * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
577 * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform) -> Window Rotation
578 * These function should be called before calling first drawing gl Function.
579 * Notice : PreRotation is not used in the latest tizen,
580 * because output transform event should be occured before egl window is not created.
583 if(mIsResizing || mDefaultScreenRotationAvailable)
585 int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
587 // Window rotate or screen rotate
588 if(!mWindowRotationFinished || !mScreenRotationFinished)
590 mWindowBase->SetEglWindowBufferTransform(totalAngle);
592 // Reset only screen rotation flag
593 mScreenRotationFinished = true;
595 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
598 // Only window rotate
599 if(!mWindowRotationFinished)
601 mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
607 Dali::PositionSize positionSize;
608 positionSize.x = mPositionSize.x;
609 positionSize.y = mPositionSize.y;
610 if(totalAngle == 0 || totalAngle == 180)
612 positionSize.width = mPositionSize.width;
613 positionSize.height = mPositionSize.height;
617 positionSize.width = mPositionSize.height;
618 positionSize.height = mPositionSize.width;
620 mWindowBase->ResizeEglWindow(positionSize);
621 mResizeFinished = true;
623 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);
626 SetFullSwapNextFrame();
627 mDefaultScreenRotationAvailable = false;
630 SetBufferDamagedRects(damagedRects, clippingRect);
634 Rect<int> surfaceRect = scene.GetCurrentSurfaceRect();
635 if(clippingRect == surfaceRect)
637 mDamagedRects.assign(1, surfaceRect);
641 // This is now done when the render pass for the render surface begins
642 // MakeContextCurrent();
647 void WindowRenderSurface::PostRender()
649 // Inform the gl implementation that rendering has finished before informing the surface
650 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
653 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
656 bool needWindowRotationCompleted = false;
658 if(!mWindowRotationFinished)
660 if(mNeedWindowRotationAcknowledgement)
662 Dali::Integration::Scene scene = mScene.GetHandle();
665 if(scene.IsRotationCompletedAcknowledgementSet())
667 needWindowRotationCompleted = true;
675 needWindowRotationCompleted = true;
680 if(needWindowRotationCompleted || mIsImeWindowSurface)
682 if(mThreadSynchronization)
684 // Enable PostRender flag
685 mThreadSynchronization->PostRenderStarted();
688 if(!mWindowRotationFinished || mIsImeWindowSurface)
690 mPostRenderTrigger->Trigger();
693 if(mThreadSynchronization)
695 // Wait until the event-thread complete the rotation event processing
696 mThreadSynchronization->PostRenderWaitForCompletion();
700 SwapBuffers(mDamagedRects);
702 if(mRenderNotification)
704 mRenderNotification->Trigger();
709 void WindowRenderSurface::StopRender()
713 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
715 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
717 mThreadSynchronization = &threadSynchronization;
720 void WindowRenderSurface::ReleaseLock()
725 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
727 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
730 void WindowRenderSurface::MakeContextCurrent()
734 mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
738 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
740 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
743 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
745 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
748 void WindowRenderSurface::InitializeImeSurface()
750 mIsImeWindowSurface = true;
751 if(!mPostRenderTrigger)
753 mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
754 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
758 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
760 mNeedWindowRotationAcknowledgement = needAcknowledgement;
763 void WindowRenderSurface::OutputTransformed()
765 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
767 if(mScreenRotationAngle != screenRotationAngle)
769 mScreenRotationAngle = screenRotationAngle;
770 mScreenRotationFinished = false;
771 mResizeFinished = false;
773 mOutputTransformedSignal.Emit();
775 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
779 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
783 bool WindowRenderSurface::IsWindowRotating() const
785 return !(mWindowRotationFinished);
788 void WindowRenderSurface::ProcessPostRender()
790 if(!mWindowRotationFinished)
792 mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
793 mWindowRotationFinished = true;
794 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mWindowRotationFinished);
797 if(mIsImeWindowSurface)
799 mWindowBase->ImeWindowReadyToRender();
802 if(mThreadSynchronization)
804 mThreadSynchronization->PostRenderComplete();
808 void WindowRenderSurface::ProcessFrameCallback()
810 Dali::Mutex::ScopedLock lock(mMutex);
812 for(auto&& iter : mFrameCallbackInfoContainer)
814 if(!iter->fileDescriptorMonitor)
816 iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
817 MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
818 FileDescriptorMonitor::FD_READABLE));
820 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
825 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
827 if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
829 DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
830 close(fileDescriptor);
834 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
836 std::unique_ptr<FrameCallbackInfo> callbackInfo;
838 Dali::Mutex::ScopedLock lock(mMutex);
839 auto frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
840 return callbackInfo->fileDescriptor == fileDescriptor;
842 if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
844 callbackInfo = std::move(*frameCallbackInfo);
846 mFrameCallbackInfoContainer.erase(frameCallbackInfo);
850 // Call the connected callback
853 for(auto&& iter : (callbackInfo)->callbacks)
855 CallbackBase::Execute(*(iter.first), iter.second);
860 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
862 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
865 // If scene is not exist, just use stored mPositionSize.
866 Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
867 int32_t orientation = 0;
869 Dali::Integration::Scene scene = mScene.GetHandle();
872 surfaceRect = scene.GetCurrentSurfaceRect();
873 orientation = std::min(scene.GetCurrentSurfaceOrientation() / 90, 3);
876 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
877 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
879 InsertRects(mBufferDamagedRects, surfaceRect);
880 clippingRect = surfaceRect;
884 if(damagedRects.empty())
886 // Empty damaged rect. We don't need rendering
887 clippingRect = Rect<int>();
891 mGraphics->ActivateSurfaceContext(this);
893 EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
895 // Buffer age 0 means the back buffer in invalid and requires full swap
898 InsertRects(mBufferDamagedRects, surfaceRect);
899 clippingRect = surfaceRect;
903 mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
905 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
906 // Could be optional and can be removed, needs to be checked with and without on platform
907 MergeIntersectingRects(mDamagedRects, orientation, surfaceRect);
909 // Make one clipping rect
910 MergeRects(clippingRect, mDamagedRects);
912 // We push current frame damaged rects here, zero index for current frame
913 InsertRects(mBufferDamagedRects, clippingRect);
915 // Merge damaged rects into clipping rect
916 if(bufferAge <= static_cast<EGLint>(mBufferDamagedRects.size()))
918 // clippingRect is already the current frame's damaged rect. Merge from the second
919 for(int i = 1; i < bufferAge; i++)
921 clippingRect.Merge(mBufferDamagedRects[i]);
926 // The buffer age is too old. Need full update.
927 clippingRect = surfaceRect;
931 if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
933 // clipping area too big or doesn't intersect surface rect
934 clippingRect = surfaceRect;
938 if(!clippingRect.IsEmpty())
940 std::vector<Rect<int>> damagedRegion;
943 damagedRegion.push_back(RecalculateRect[std::min(scene.GetCurrentSurfaceOrientation() / 90, 3)](clippingRect, scene.GetCurrentSurfaceRect()));
947 damagedRegion.push_back(clippingRect);
950 eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
955 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
957 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
960 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
962 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
964 mFullSwapNextFrame = false;
965 eglImpl.SwapBuffers(mEGLSurface);
969 mFullSwapNextFrame = false;
971 Rect<int32_t> surfaceRect;
972 Dali::Integration::Scene scene = mScene.GetHandle();
975 surfaceRect = scene.GetCurrentSurfaceRect();
978 if(!damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
980 // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
981 // For exceptional cases, swap full area.
982 eglImpl.SwapBuffers(mEGLSurface);
986 eglImpl.SwapBuffers(mEGLSurface, damagedRects);
991 } // namespace Adaptor
993 } // namespace Internal