Merge "Modify window configure notification event callback" into devel/master
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / common / window-render-surface.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/window-system/common/window-render-surface.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/gl-abstraction.h>
24
25 // INTERNAL INCLUDES
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>
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace Adaptor
42 {
43 namespace
44 {
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
47
48 #if defined(DEBUG_ENABLED)
49 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
50 #endif
51
52 void MergeRects(Rect<int>& mergingRect, const std::vector<Rect<int>>& rects)
53 {
54   uint32_t i = 0;
55   if(mergingRect.IsEmpty())
56   {
57     for(; i < rects.size(); i++)
58     {
59       if(!rects[i].IsEmpty())
60       {
61         mergingRect = rects[i];
62         break;
63       }
64     }
65   }
66
67   for(; i < rects.size(); i++)
68   {
69     mergingRect.Merge(rects[i]);
70   }
71 }
72
73 void InsertRects(WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const std::vector<Rect<int>>& damagedRects)
74 {
75   damagedRectsList.push_front(damagedRects);
76   if(damagedRectsList.size() > 4) // past triple buffers + current
77   {
78     damagedRectsList.pop_back();
79   }
80 }
81
82 } // unnamed namespace
83
84 WindowRenderSurface::WindowRenderSurface(Dali::PositionSize positionSize, Any surface, bool isTransparent)
85 : mEGL(nullptr),
86   mDisplayConnection(nullptr),
87   mPositionSize(positionSize),
88   mWindowBase(),
89   mThreadSynchronization(nullptr),
90   mRenderNotification(nullptr),
91   mRotationTrigger(nullptr),
92   mFrameRenderedTrigger(),
93   mGraphics(nullptr),
94   mEGLSurface(nullptr),
95   mEGLContext(nullptr),
96   mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
97   mOutputTransformedSignal(),
98   mFrameCallbackInfoContainer(),
99   mBufferDamagedRects(),
100   mMutex(),
101   mWindowRotationAngle(0),
102   mScreenRotationAngle(0),
103   mDpiHorizontal(0),
104   mDpiVertical(0),
105   mOwnSurface(false),
106   mWindowRotationFinished(true),
107   mScreenRotationFinished(true),
108   mResizeFinished(true),
109   mDefaultScreenRotationAvailable(false)
110 {
111   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n");
112   Initialize(surface);
113 }
114
115 WindowRenderSurface::~WindowRenderSurface()
116 {
117   if(mRotationTrigger)
118   {
119     delete mRotationTrigger;
120   }
121 }
122
123 void WindowRenderSurface::Initialize(Any surface)
124 {
125   // If width or height are zero, go full screen.
126   if((mPositionSize.width == 0) || (mPositionSize.height == 0))
127   {
128     // Default window size == screen size
129     mPositionSize.x = 0;
130     mPositionSize.y = 0;
131     WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height);
132   }
133
134   // Create a window base
135   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
136   mWindowBase        = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false));
137
138   // Connect signals
139   mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed);
140
141   // Check screen rotation
142   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
143   if(mScreenRotationAngle != 0)
144   {
145     mScreenRotationFinished         = false;
146     mResizeFinished                 = false;
147     mDefaultScreenRotationAvailable = true;
148     DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle);
149   }
150 }
151
152 Any WindowRenderSurface::GetNativeWindow()
153 {
154   return mWindowBase->GetNativeWindow();
155 }
156
157 int WindowRenderSurface::GetNativeWindowId()
158 {
159   return mWindowBase->GetNativeWindowId();
160 }
161
162 void WindowRenderSurface::Map()
163 {
164   mWindowBase->Show();
165 }
166
167 void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
168 {
169   mRenderNotification = renderNotification;
170 }
171
172 void WindowRenderSurface::SetTransparency(bool transparent)
173 {
174   mWindowBase->SetTransparency(transparent);
175 }
176
177 void WindowRenderSurface::RequestRotation(int angle, int width, int height)
178 {
179   if(!mRotationTrigger)
180   {
181     mRotationTrigger = TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessRotationRequest), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
182   }
183
184   mPositionSize.width  = width;
185   mPositionSize.height = height;
186
187   mWindowRotationAngle    = angle;
188   mWindowRotationFinished = false;
189
190   mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
191
192   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mWindowRotationAngle, mScreenRotationAngle);
193 }
194
195 WindowBase* WindowRenderSurface::GetWindowBase()
196 {
197   return mWindowBase.get();
198 }
199
200 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
201 {
202   return mOutputTransformedSignal;
203 }
204
205 PositionSize WindowRenderSurface::GetPositionSize() const
206 {
207   return mPositionSize;
208 }
209
210 void WindowRenderSurface::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
211 {
212   if(mDpiHorizontal == 0 || mDpiVertical == 0)
213   {
214     const char* environmentDpiHorizontal = std::getenv(DALI_ENV_DPI_HORIZONTAL);
215     mDpiHorizontal                       = environmentDpiHorizontal ? std::atoi(environmentDpiHorizontal) : 0;
216
217     const char* environmentDpiVertical = std::getenv(DALI_ENV_DPI_VERTICAL);
218     mDpiVertical                       = environmentDpiVertical ? std::atoi(environmentDpiVertical) : 0;
219
220     if(mDpiHorizontal == 0 || mDpiVertical == 0)
221     {
222       mWindowBase->GetDpi(mDpiHorizontal, mDpiVertical);
223     }
224   }
225
226   dpiHorizontal = mDpiHorizontal;
227   dpiVertical   = mDpiVertical;
228 }
229
230 int WindowRenderSurface::GetOrientation() const
231 {
232   return mWindowBase->GetOrientation();
233 }
234
235 void WindowRenderSurface::InitializeGraphics()
236 {
237   mGraphics = &mAdaptor->GetGraphicsInterface();
238
239   DALI_ASSERT_ALWAYS(mGraphics && "Graphics interface is not created");
240
241   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
242   mEGL             = &eglGraphics->GetEglInterface();
243
244   if(mEGLContext == NULL)
245   {
246     // Create the OpenGL context for this window
247     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
248     eglImpl.ChooseConfig(true, mColorDepth);
249     eglImpl.CreateWindowContext(mEGLContext);
250
251     // Create the OpenGL surface
252     CreateSurface();
253   }
254 }
255
256 void WindowRenderSurface::CreateSurface()
257 {
258   DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
259
260   int width, height;
261   if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
262   {
263     width  = mPositionSize.width;
264     height = mPositionSize.height;
265   }
266   else
267   {
268     width  = mPositionSize.height;
269     height = mPositionSize.width;
270   }
271
272   // Create the EGL window
273   EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
274
275   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
276
277   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
278   mEGLSurface                                   = eglImpl.CreateSurfaceWindow(window, mColorDepth);
279
280   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
281                         mWindowBase->GetNativeWindowId(),
282                         mPositionSize.width,
283                         mPositionSize.height,
284                         mWindowRotationAngle,
285                         mScreenRotationAngle);
286 }
287
288 void WindowRenderSurface::DestroySurface()
289 {
290   DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
291
292   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
293   if(eglGraphics)
294   {
295     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId());
296
297     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
298
299     eglImpl.DestroySurface(mEGLSurface);
300     mEGLSurface = nullptr;
301
302     // Destroy context also
303     eglImpl.DestroyContext(mEGLContext);
304     mEGLContext = nullptr;
305
306     mWindowBase->DestroyEglWindow();
307   }
308 }
309
310 bool WindowRenderSurface::ReplaceGraphicsSurface()
311 {
312   DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
313
314   // Destroy the old one
315   mWindowBase->DestroyEglWindow();
316
317   int width, height;
318   if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
319   {
320     width  = mPositionSize.width;
321     height = mPositionSize.height;
322   }
323   else
324   {
325     width  = mPositionSize.height;
326     height = mPositionSize.width;
327   }
328
329   // Create the EGL window
330   EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
331
332   // Set screen rotation
333   mScreenRotationFinished = false;
334
335   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
336
337   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
338   return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext);
339 }
340
341 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
342 {
343   bool needToMove   = false;
344   bool needToResize = false;
345
346   // Check moving
347   if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
348      (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
349   {
350     needToMove = true;
351   }
352
353   // Check resizing
354   if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
355      (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
356   {
357     needToResize = true;
358   }
359
360   if(needToResize)
361   {
362     if(needToMove)
363     {
364       mWindowBase->MoveResize(positionSize);
365     }
366     else
367     {
368       mWindowBase->Resize(positionSize);
369     }
370
371     mResizeFinished = false;
372     mPositionSize   = positionSize;
373   }
374   else
375   {
376     if(needToMove)
377     {
378       mWindowBase->Move(positionSize);
379
380       mPositionSize = positionSize;
381     }
382   }
383
384   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
385 }
386
387 void WindowRenderSurface::StartRender()
388 {
389 }
390
391 bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
392 {
393   Dali::Integration::Scene::FrameCallbackContainer callbacks;
394
395   Dali::Integration::Scene scene = mScene.GetHandle();
396   if(scene)
397   {
398     bool needFrameRenderedTrigger = false;
399
400     scene.GetFrameRenderedCallback(callbacks);
401     if(!callbacks.empty())
402     {
403       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
404       if(frameRenderedSync != -1)
405       {
406         Dali::Mutex::ScopedLock lock(mMutex);
407
408         DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
409
410         mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
411
412         needFrameRenderedTrigger = true;
413       }
414       else
415       {
416         DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
417       }
418
419       // Clear callbacks
420       callbacks.clear();
421     }
422
423     scene.GetFramePresentedCallback(callbacks);
424     if(!callbacks.empty())
425     {
426       int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
427       if(framePresentedSync != -1)
428       {
429         Dali::Mutex::ScopedLock lock(mMutex);
430
431         DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
432
433         mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
434
435         needFrameRenderedTrigger = true;
436       }
437       else
438       {
439         DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
440       }
441
442       // Clear callbacks
443       callbacks.clear();
444     }
445
446     if(needFrameRenderedTrigger)
447     {
448       if(!mFrameRenderedTrigger)
449       {
450         mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
451                                                                                                                TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
452       }
453       mFrameRenderedTrigger->Trigger();
454     }
455   }
456
457   MakeContextCurrent();
458
459   /**
460     * wl_egl_window_tizen_set_rotation(SetEglWindowRotation)                -> PreRotation
461     * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
462     * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform)       -> Window Rotation
463     * These function should be called before calling first drawing gl Function.
464     * Notice : PreRotation is not used in the latest tizen,
465     *          because output transform event should be occured before egl window is not created.
466     */
467
468   if(resizingSurface || mDefaultScreenRotationAvailable)
469   {
470     int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
471
472     // Window rotate or screen rotate
473     if(!mWindowRotationFinished || !mScreenRotationFinished)
474     {
475       mWindowBase->SetEglWindowBufferTransform(totalAngle);
476
477       // Reset only screen rotation flag
478       mScreenRotationFinished = true;
479
480       DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
481     }
482
483     // Only window rotate
484     if(!mWindowRotationFinished)
485     {
486       mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
487     }
488
489     // Resize case
490     if(!mResizeFinished)
491     {
492       Dali::PositionSize positionSize;
493       positionSize.x = mPositionSize.x;
494       positionSize.y = mPositionSize.y;
495       if(totalAngle == 0 || totalAngle == 180)
496       {
497         positionSize.width  = mPositionSize.width;
498         positionSize.height = mPositionSize.height;
499       }
500       else
501       {
502         positionSize.width  = mPositionSize.height;
503         positionSize.height = mPositionSize.width;
504       }
505       mWindowBase->ResizeEglWindow(positionSize);
506       mResizeFinished = true;
507
508       DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set resize\n");
509     }
510
511     SetFullSwapNextFrame();
512     mDefaultScreenRotationAvailable = false;
513   }
514
515   SetBufferDamagedRects(damagedRects, clippingRect);
516
517   return true;
518 }
519
520 void WindowRenderSurface::PostRender(bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects)
521 {
522   // Inform the gl implementation that rendering has finished before informing the surface
523   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
524   if(eglGraphics)
525   {
526     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
527     mGLES.PostRender();
528
529     if(renderToFbo)
530     {
531       mGLES.Flush();
532       mGLES.Finish();
533     }
534     else
535     {
536       if(resizingSurface)
537       {
538         if(!mWindowRotationFinished)
539         {
540           if(mThreadSynchronization)
541           {
542             // Enable PostRender flag
543             mThreadSynchronization->PostRenderStarted();
544           }
545
546           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n");
547
548           mRotationTrigger->Trigger();
549
550           if(mThreadSynchronization)
551           {
552             // Wait until the event-thread complete the rotation event processing
553             mThreadSynchronization->PostRenderWaitForCompletion();
554           }
555         }
556       }
557     }
558
559     SwapBuffers(damagedRects);
560
561     if(mRenderNotification)
562     {
563       mRenderNotification->Trigger();
564     }
565   }
566 }
567
568 void WindowRenderSurface::StopRender()
569 {
570 }
571
572 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
573 {
574   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
575
576   mThreadSynchronization = &threadSynchronization;
577 }
578
579 void WindowRenderSurface::ReleaseLock()
580 {
581   // Nothing to do.
582 }
583
584 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
585 {
586   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
587 }
588
589 void WindowRenderSurface::MakeContextCurrent()
590 {
591   if(mEGL != nullptr)
592   {
593     mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
594   }
595 }
596
597 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
598 {
599   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
600 }
601
602 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
603 {
604   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
605 }
606
607 void WindowRenderSurface::OutputTransformed()
608 {
609   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
610
611   if(mScreenRotationAngle != screenRotationAngle)
612   {
613     mScreenRotationAngle    = screenRotationAngle;
614     mScreenRotationFinished = false;
615     mResizeFinished         = false;
616
617     mOutputTransformedSignal.Emit();
618
619     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
620   }
621   else
622   {
623     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
624   }
625 }
626
627 void WindowRenderSurface::ProcessRotationRequest()
628 {
629   mWindowRotationFinished = true;
630
631   mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
632
633   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n");
634
635   if(mThreadSynchronization)
636   {
637     mThreadSynchronization->PostRenderComplete();
638   }
639 }
640
641 void WindowRenderSurface::ProcessFrameCallback()
642 {
643   Dali::Mutex::ScopedLock lock(mMutex);
644
645   for(auto&& iter : mFrameCallbackInfoContainer)
646   {
647     if(!iter->fileDescriptorMonitor)
648     {
649       iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
650                                                                                                      MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
651                                                                                                      FileDescriptorMonitor::FD_READABLE));
652
653       DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
654     }
655   }
656 }
657
658 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
659 {
660   if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
661   {
662     DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
663     close(fileDescriptor);
664     return;
665   }
666
667   DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
668
669   std::unique_ptr<FrameCallbackInfo> callbackInfo;
670   {
671     Dali::Mutex::ScopedLock lock(mMutex);
672     auto                    frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
673       return callbackInfo->fileDescriptor == fileDescriptor;
674     });
675     if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
676     {
677       callbackInfo = std::move(*frameCallbackInfo);
678
679       mFrameCallbackInfoContainer.erase(frameCallbackInfo);
680     }
681   }
682
683   // Call the connected callback
684   if(callbackInfo)
685   {
686     for(auto&& iter : (callbackInfo)->callbacks)
687     {
688       CallbackBase::Execute(*(iter.first), iter.second);
689     }
690   }
691 }
692
693 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
694 {
695   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
696   if(eglGraphics)
697   {
698     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
699     if(!eglImpl.IsPartialUpdateRequired())
700     {
701       return;
702     }
703
704     Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
705
706     if(mFullSwapNextFrame)
707     {
708       InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
709       clippingRect = Rect<int>();
710       return;
711     }
712
713     EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
714
715     // Buffer age 0 means the back buffer in invalid and requires full swap
716     if(!damagedRects.size() || bufferAge == 0)
717     {
718       InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
719       clippingRect = Rect<int>();
720       return;
721     }
722
723     // We push current frame damaged rects here, zero index for current frame
724     InsertRects(mBufferDamagedRects, damagedRects);
725
726     // Merge damaged rects into clipping rect
727     auto bufferDamagedRects = mBufferDamagedRects.begin();
728     while(bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
729     {
730       const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
731       MergeRects(clippingRect, rects);
732     }
733
734     if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
735     {
736       // clipping area too big or doesn't intersect surface rect
737       clippingRect = Rect<int>();
738       return;
739     }
740
741     std::vector<Rect<int>> damagedRegion;
742     damagedRegion.push_back(clippingRect);
743
744     eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
745   }
746 }
747
748 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
749 {
750   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
751   if(eglGraphics)
752   {
753     Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
754
755     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
756
757     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
758     {
759       mFullSwapNextFrame = false;
760       eglImpl.SwapBuffers(mEGLSurface);
761       return;
762     }
763
764     mFullSwapNextFrame = false;
765
766     std::vector<Rect<int>> mergedRects = damagedRects;
767
768     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
769     // Could be optional and can be removed, needs to be checked with and without on platform
770     const int n = mergedRects.size();
771     for(int i = 0; i < n - 1; i++)
772     {
773       if(mergedRects[i].IsEmpty())
774       {
775         continue;
776       }
777
778       for(int j = i + 1; j < n; j++)
779       {
780         if(mergedRects[j].IsEmpty())
781         {
782           continue;
783         }
784
785         if(mergedRects[i].Intersects(mergedRects[j]))
786         {
787           mergedRects[i].Merge(mergedRects[j]);
788           mergedRects[j].width  = 0;
789           mergedRects[j].height = 0;
790         }
791       }
792     }
793
794     int j = 0;
795     for(int i = 0; i < n; i++)
796     {
797       if(!mergedRects[i].IsEmpty())
798       {
799         mergedRects[j++] = mergedRects[i];
800       }
801     }
802
803     if(j != 0)
804     {
805       mergedRects.resize(j);
806     }
807
808     if(!mergedRects.size() || (mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
809     {
810       eglImpl.SwapBuffers(mEGLSurface);
811     }
812     else
813     {
814       eglImpl.SwapBuffers(mEGLSurface, mergedRects);
815     }
816   }
817 }
818
819 } // namespace Adaptor
820
821 } // namespace Internal
822
823 } // namespace Dali