2 * Copyright (c) 2023 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/system/common/system-factory.h>
34 #include <dali/internal/window-system/common/window-base.h>
35 #include <dali/internal/window-system/common/window-factory.h>
36 #include <dali/internal/window-system/common/window-system.h>
46 const int MINIMUM_DIMENSION_CHANGE(1); ///< Minimum change for window to be considered to have moved
47 const float FULL_UPDATE_RATIO(0.8f); ///< Force full update when the dirty area is larget than this ratio
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
53 void InsertRects(WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const Rect<int>& damagedRects)
55 damagedRectsList.insert(damagedRectsList.begin(), damagedRects);
56 if(damagedRectsList.size() > 4) // past triple buffers + current
58 damagedRectsList.pop_back();
62 Rect<int32_t> RecalculateRect0(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
67 Rect<int32_t> RecalculateRect90(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
69 Rect<int32_t> newRect;
70 newRect.x = surfaceSize.height - (rect.y + rect.height);
72 newRect.width = rect.height;
73 newRect.height = rect.width;
77 Rect<int32_t> RecalculateRect180(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
79 Rect<int32_t> newRect;
80 newRect.x = surfaceSize.width - (rect.x + rect.width);
81 newRect.y = surfaceSize.height - (rect.y + rect.height);
82 newRect.width = rect.width;
83 newRect.height = rect.height;
87 Rect<int32_t> RecalculateRect270(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
89 Rect<int32_t> newRect;
91 newRect.y = surfaceSize.width - (rect.x + rect.width);
92 newRect.width = rect.height;
93 newRect.height = rect.width;
97 using RecalculateRectFunction = Rect<int32_t> (*)(Rect<int32_t>&, const Rect<int32_t>&);
99 RecalculateRectFunction RecalculateRect[4] = {RecalculateRect0, RecalculateRect90, RecalculateRect180, RecalculateRect270};
101 void MergeIntersectingRectsAndRotate(Rect<int>& mergingRect, std::vector<Rect<int>>& damagedRects, int orientation, const Rect<int32_t>& surfaceRect)
103 const int n = damagedRects.size();
104 for(int i = 0; i < n - 1; i++)
106 if(damagedRects[i].IsEmpty())
111 for(int j = i + 1; j < n; j++)
113 if(damagedRects[j].IsEmpty())
118 if(damagedRects[i].Intersects(damagedRects[j]))
120 damagedRects[i].Merge(damagedRects[j]);
121 damagedRects[j].width = 0;
122 damagedRects[j].height = 0;
128 for(int i = 0; i < n; i++)
130 if(!damagedRects[i].IsEmpty())
132 // Merge rects before rotate
133 if(mergingRect.IsEmpty())
135 mergingRect = damagedRects[i];
139 mergingRect.Merge(damagedRects[i]);
142 damagedRects[j++] = RecalculateRect[orientation](damagedRects[i], surfaceRect);
148 damagedRects.resize(j);
152 } // unnamed namespace
154 WindowRenderSurface::WindowRenderSurface(Dali::PositionSize positionSize, Any surface, bool isTransparent)
156 mDisplayConnection(nullptr),
157 mPositionSize(positionSize),
159 mThreadSynchronization(nullptr),
160 mRenderNotification(nullptr),
161 mPostRenderTrigger(),
162 mFrameRenderedTrigger(),
164 mEGLSurface(nullptr),
165 mEGLContext(nullptr),
166 mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
167 mOutputTransformedSignal(),
168 mWindowRotationFinishedSignal(),
169 mFrameCallbackInfoContainer(),
170 mBufferDamagedRects(),
172 mWindowRotationAngle(0),
173 mScreenRotationAngle(0),
177 mIsImeWindowSurface(false),
178 mNeedWindowRotationAcknowledgement(false),
179 mIsWindowOrientationChanging(false),
180 mIsFrontBufferRendering(false),
181 mIsFrontBufferRenderingChanged(false)
183 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n");
187 WindowRenderSurface::~WindowRenderSurface()
191 void WindowRenderSurface::Initialize(Any surface)
193 // If width or height are zero, go full screen.
194 if((mPositionSize.width == 0) || (mPositionSize.height == 0))
196 // Default window size == screen size
199 WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height);
202 // Create a window base
203 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
204 mWindowBase = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false));
207 mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed);
209 // Check screen rotation
210 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
211 if(screenRotationAngle != 0)
214 DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", screenRotationAngle);
218 Any WindowRenderSurface::GetNativeWindow()
220 return mWindowBase->GetNativeWindow();
223 int WindowRenderSurface::GetNativeWindowId()
225 return mWindowBase->GetNativeWindowId();
228 void WindowRenderSurface::Map()
233 void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
235 mRenderNotification = renderNotification;
238 void WindowRenderSurface::SetTransparency(bool transparent)
240 mWindowBase->SetTransparency(transparent);
243 void WindowRenderSurface::RequestRotation(int angle, PositionSize positionSize)
245 if(!mPostRenderTrigger)
247 mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
248 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
251 mPositionSize.x = positionSize.x;
252 mPositionSize.y = positionSize.y;
254 mWindowBase->SetWindowRotationAngle(angle);
256 DALI_LOG_RELEASE_INFO("start window rotation angle = %d screen rotation = %d\n", angle, mScreenRotationAngle);
259 WindowBase* WindowRenderSurface::GetWindowBase()
261 return mWindowBase.get();
264 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
266 return mOutputTransformedSignal;
269 WindowRenderSurface::RotationFinishedSignalType& WindowRenderSurface::RotationFinishedSignal()
271 return mWindowRotationFinishedSignal;
274 PositionSize WindowRenderSurface::GetPositionSize() const
276 return mPositionSize;
279 void WindowRenderSurface::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
281 if(mDpiHorizontal == 0 || mDpiVertical == 0)
283 const char* environmentDpiHorizontal = std::getenv(DALI_ENV_DPI_HORIZONTAL);
284 mDpiHorizontal = environmentDpiHorizontal ? std::atoi(environmentDpiHorizontal) : 0;
286 const char* environmentDpiVertical = std::getenv(DALI_ENV_DPI_VERTICAL);
287 mDpiVertical = environmentDpiVertical ? std::atoi(environmentDpiVertical) : 0;
289 if(mDpiHorizontal == 0 || mDpiVertical == 0)
291 mWindowBase->GetDpi(mDpiHorizontal, mDpiVertical);
295 dpiHorizontal = mDpiHorizontal;
296 dpiVertical = mDpiVertical;
299 int WindowRenderSurface::GetSurfaceOrientation() const
301 return mWindowBase->GetWindowRotationAngle();
304 int WindowRenderSurface::GetScreenOrientation() const
306 return mWindowBase->GetScreenRotationAngle();
309 void WindowRenderSurface::InitializeGraphics()
311 if(mEGLContext == NULL)
313 mGraphics = &mAdaptor->GetGraphicsInterface();
315 DALI_ASSERT_ALWAYS(mGraphics && "Graphics interface is not created");
317 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
318 mEGL = &eglGraphics->GetEglInterface();
320 // Create the OpenGL context for this window
321 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
322 eglImpl.ChooseConfig(true, mColorDepth);
323 eglImpl.CreateWindowContext(mEGLContext);
325 // Create the OpenGL surface
330 void WindowRenderSurface::CreateSurface()
332 DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
335 if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
337 width = mPositionSize.width;
338 height = mPositionSize.height;
342 width = mPositionSize.height;
343 height = mPositionSize.width;
346 // Create the EGL window
347 EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
349 if(mWindowBase->GetType() == WindowType::IME)
351 InitializeImeSurface();
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 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
414 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
415 return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext);
418 void WindowRenderSurface::UpdatePositionSize(Dali::PositionSize positionSize)
421 if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
422 (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
424 mPositionSize.x = positionSize.x;
425 mPositionSize.y = positionSize.y;
427 DALI_LOG_RELEASE_INFO("Update Position by server (%d, %d)\n", mPositionSize.x, mPositionSize.y);
431 void WindowRenderSurface::Move(Dali::PositionSize positionSize)
433 mPositionSize.x = positionSize.x;
434 mPositionSize.y = positionSize.y;
436 DALI_LOG_RELEASE_INFO("Update Position by client (%d, %d)\n", positionSize.x, positionSize.y);
438 mWindowBase->Move(positionSize);
441 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
443 mPositionSize.x = positionSize.x;
444 mPositionSize.y = positionSize.y;
446 DALI_LOG_RELEASE_INFO("Update Position by client (%d, %d)\n", positionSize.x, positionSize.y);
448 mWindowBase->MoveResize(positionSize);
451 void WindowRenderSurface::StartRender()
455 bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
457 InitializeGraphics();
459 Dali::Integration::Scene::FrameCallbackContainer callbacks;
461 Dali::Integration::Scene scene = mScene.GetHandle();
465 bool needFrameRenderedTrigger = false;
467 scene.GetFrameRenderedCallback(callbacks);
468 if(!callbacks.empty())
470 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
471 if(frameRenderedSync != -1)
473 Dali::Mutex::ScopedLock lock(mMutex);
475 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
477 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
479 needFrameRenderedTrigger = true;
483 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
490 scene.GetFramePresentedCallback(callbacks);
491 if(!callbacks.empty())
493 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
494 if(framePresentedSync != -1)
496 Dali::Mutex::ScopedLock lock(mMutex);
498 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
500 mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
502 needFrameRenderedTrigger = true;
506 DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
513 if(needFrameRenderedTrigger)
515 if(!mFrameRenderedTrigger)
517 mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
518 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
520 mFrameRenderedTrigger->Trigger();
525 * wl_egl_window_tizen_set_rotation(SetEglWindowRotation) -> PreRotation
526 * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
527 * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform) -> Window Rotation
528 * These function should be called before calling first drawing gl Function.
529 * Notice : PreRotation is not used in the latest tizen,
530 * because output transform event should be occured before egl window is not created.
532 if(scene && resizingSurface)
535 bool isScreenOrientationChanging = false;
537 if(mWindowRotationAngle != scene.GetCurrentSurfaceOrientation())
539 mWindowRotationAngle = scene.GetCurrentSurfaceOrientation();
540 mIsWindowOrientationChanging = true;
543 if(mScreenRotationAngle != scene.GetCurrentScreenOrientation())
545 mScreenRotationAngle = scene.GetCurrentScreenOrientation();
546 isScreenOrientationChanging = true;
548 totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
550 DALI_LOG_RELEASE_INFO("Window/Screen orientation ard changed, WinOrientation[%d],flag[%d], ScreenOrientation[%d],flag[%d], total[%d]\n", mWindowRotationAngle, mIsWindowOrientationChanging, mScreenRotationAngle, isScreenOrientationChanging, totalAngle);
552 Rect<int> surfaceSize = scene.GetCurrentSurfaceRect();
553 //update surface size
554 mPositionSize.width = surfaceSize.width;
555 mPositionSize.height = surfaceSize.height;
557 DALI_LOG_RELEASE_INFO("Window is resizing, (%d, %d), [%d x %d], IMEWindow [%d]\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height, mIsImeWindowSurface);
559 // Window rotate or screen rotate
560 if(mIsWindowOrientationChanging || isScreenOrientationChanging)
562 mWindowBase->SetEglWindowBufferTransform(totalAngle);
565 // Only window rotate
566 if(mIsWindowOrientationChanging)
568 mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
572 Dali::PositionSize positionSize;
574 // Some native resize API(wl_egl_window_resize) has the input parameters of x, y, width and height.
575 // So, position data should be set.
576 positionSize.x = mPositionSize.x;
577 positionSize.y = mPositionSize.y;
578 if(totalAngle == 0 || totalAngle == 180)
580 positionSize.width = mPositionSize.width;
581 positionSize.height = mPositionSize.height;
585 positionSize.width = mPositionSize.height;
586 positionSize.height = mPositionSize.width;
589 mWindowBase->ResizeEglWindow(positionSize);
591 SetFullSwapNextFrame();
594 // When mIsFrontBufferRendering is not equal to mWindowBase's
595 if(mIsFrontBufferRenderingChanged)
597 mIsFrontBufferRenderingChanged = false;
598 mWindowBase->SetEglWindowFrontBufferMode(mIsFrontBufferRendering);
599 SetFullSwapNextFrame();
602 SetBufferDamagedRects(damagedRects, clippingRect);
606 Rect<int> surfaceRect = scene.GetCurrentSurfaceRect();
607 if(clippingRect == surfaceRect)
609 int32_t totalAngle = scene.GetCurrentSurfaceOrientation() + scene.GetCurrentScreenOrientation();
610 if(totalAngle >= 360)
614 mDamagedRects.assign(1, RecalculateRect[std::min(totalAngle / 90, 3)](surfaceRect, surfaceRect));
618 // This is now done when the render pass for the render surface begins
619 // MakeContextCurrent();
624 void WindowRenderSurface::PostRender()
626 // Inform the gl implementation that rendering has finished before informing the surface
627 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
630 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
633 bool needWindowRotationCompleted = false;
635 if(mIsWindowOrientationChanging)
637 if(mNeedWindowRotationAcknowledgement)
639 Dali::Integration::Scene scene = mScene.GetHandle();
642 if(scene.IsRotationCompletedAcknowledgementSet())
644 needWindowRotationCompleted = true;
650 needWindowRotationCompleted = true;
654 if(needWindowRotationCompleted || mIsImeWindowSurface)
656 if(mThreadSynchronization)
658 // Enable PostRender flag
659 mThreadSynchronization->PostRenderStarted();
662 if(mIsWindowOrientationChanging || mIsImeWindowSurface)
664 mPostRenderTrigger->Trigger();
667 if(mThreadSynchronization)
669 // Wait until the event-thread complete the rotation event processing
670 mThreadSynchronization->PostRenderWaitForCompletion();
674 SwapBuffers(mDamagedRects);
676 if(mRenderNotification)
678 mRenderNotification->Trigger();
683 void WindowRenderSurface::StopRender()
687 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
689 DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
691 mThreadSynchronization = &threadSynchronization;
694 void WindowRenderSurface::ReleaseLock()
699 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
701 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
704 void WindowRenderSurface::MakeContextCurrent()
708 mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
712 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
714 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
717 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
719 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
722 void WindowRenderSurface::InitializeImeSurface()
724 if(!mIsImeWindowSurface)
726 mIsImeWindowSurface = true;
727 if(!mPostRenderTrigger)
729 mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
730 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
736 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
738 mNeedWindowRotationAcknowledgement = needAcknowledgement;
741 void WindowRenderSurface::OutputTransformed()
743 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
745 if(mScreenRotationAngle != screenRotationAngle)
747 mOutputTransformedSignal.Emit();
749 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d new screen angle = %d\n", mWindowRotationAngle, screenRotationAngle);
753 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
757 void WindowRenderSurface::ProcessPostRender()
759 if(mIsWindowOrientationChanging)
761 mWindowRotationFinishedSignal.Emit();
762 mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
763 mIsWindowOrientationChanging = false;
764 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mIsWindowOrientationChanging);
767 if(mIsImeWindowSurface)
769 mWindowBase->ImeWindowReadyToRender();
772 if(mThreadSynchronization)
774 mThreadSynchronization->PostRenderComplete();
778 void WindowRenderSurface::ProcessFrameCallback()
780 Dali::Mutex::ScopedLock lock(mMutex);
782 for(auto&& iter : mFrameCallbackInfoContainer)
784 if(!iter->fileDescriptorMonitor)
786 iter->fileDescriptorMonitor = Dali::Internal::Adaptor::GetSystemFactory()->CreateFileDescriptorMonitor(iter->fileDescriptor, MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched), FileDescriptorMonitor::FD_READABLE);
788 DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
793 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
795 DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
797 std::unique_ptr<FrameCallbackInfo> callbackInfo;
799 Dali::Mutex::ScopedLock lock(mMutex);
800 auto frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
801 return callbackInfo->fileDescriptor == fileDescriptor;
803 if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
805 callbackInfo = std::move(*frameCallbackInfo);
807 mFrameCallbackInfoContainer.erase(frameCallbackInfo);
811 // Call the connected callback
812 if(callbackInfo && (eventBitMask & FileDescriptorMonitor::FD_READABLE))
814 for(auto&& iter : (callbackInfo)->callbacks)
816 CallbackBase::Execute(*(iter.first), iter.second);
821 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
823 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
826 // If scene is not exist, just use stored mPositionSize.
827 Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
828 int32_t orientation = 0;
830 Dali::Integration::Scene scene = mScene.GetHandle();
833 surfaceRect = scene.GetCurrentSurfaceRect();
834 int32_t totalAngle = scene.GetCurrentSurfaceOrientation() + scene.GetCurrentScreenOrientation();
835 if(totalAngle >= 360)
839 orientation = std::min(totalAngle / 90, 3);
842 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
843 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
845 InsertRects(mBufferDamagedRects, surfaceRect);
846 clippingRect = surfaceRect;
850 if(damagedRects.empty())
852 // Empty damaged rect. We don't need rendering
853 clippingRect = Rect<int>();
854 // Clean up current damanged rects.
855 mDamagedRects.clear();
859 mGraphics->ActivateSurfaceContext(this);
861 EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
863 // Buffer age 0 means the back buffer in invalid and requires full swap
866 InsertRects(mBufferDamagedRects, surfaceRect);
867 clippingRect = surfaceRect;
871 mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
873 // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
874 // Could be optional and can be removed, needs to be checked with and without on platform
875 // And then, Make one clipping rect, and rotate rects by orientation.
876 MergeIntersectingRectsAndRotate(clippingRect, mDamagedRects, orientation, surfaceRect);
878 // We push current frame damaged rects here, zero index for current frame
879 InsertRects(mBufferDamagedRects, clippingRect);
881 // Merge damaged rects into clipping rect
882 if(bufferAge <= static_cast<EGLint>(mBufferDamagedRects.size()))
884 // clippingRect is already the current frame's damaged rect. Merge from the second
885 for(int i = 1; i < bufferAge; i++)
887 clippingRect.Merge(mBufferDamagedRects[i]);
892 // The buffer age is too old. Need full update.
893 clippingRect = surfaceRect;
897 if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
899 // clipping area too big or doesn't intersect surface rect
900 clippingRect = surfaceRect;
904 if(!clippingRect.IsEmpty())
906 std::vector<Rect<int>> damagedRegion;
909 damagedRegion.push_back(RecalculateRect[orientation](clippingRect, surfaceRect));
913 damagedRegion.push_back(clippingRect);
916 eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
921 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
923 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
926 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
928 if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
930 mFullSwapNextFrame = false;
931 eglImpl.SwapBuffers(mEGLSurface);
935 mFullSwapNextFrame = false;
937 Rect<int32_t> surfaceRect;
938 Dali::Integration::Scene scene = mScene.GetHandle();
941 surfaceRect = scene.GetCurrentSurfaceRect();
944 if(!damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
946 // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
947 // For exceptional cases, swap full area.
948 eglImpl.SwapBuffers(mEGLSurface);
952 eglImpl.SwapBuffers(mEGLSurface, damagedRects);
957 void WindowRenderSurface::SetFrontBufferRendering(bool enable)
959 if(mIsFrontBufferRendering != enable)
961 mIsFrontBufferRendering = enable;
962 mIsFrontBufferRenderingChanged = !mIsFrontBufferRenderingChanged;
966 } // namespace Adaptor
968 } // namespace Internal