[Tizen] Add to get the status whether window is rotating or not
[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 Rect<int32_t> RecalculateRect0(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
83 {
84   return rect;
85 }
86
87 Rect<int32_t> RecalculateRect90(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
88 {
89   Rect<int32_t> newRect;
90   newRect.x      = surfaceSize.height - (rect.y + rect.height);
91   newRect.y      = rect.x;
92   newRect.width  = rect.height;
93   newRect.height = rect.width;
94   return newRect;
95 }
96
97 Rect<int32_t> RecalculateRect180(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
98 {
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;
104   return newRect;
105 }
106
107 Rect<int32_t> RecalculateRect270(Rect<int32_t>& rect, const Rect<int32_t>& surfaceSize)
108 {
109   Rect<int32_t> newRect;
110   newRect.x      = rect.y;
111   newRect.y      = surfaceSize.width - (rect.x + rect.width);
112   newRect.width  = rect.height;
113   newRect.height = rect.width;
114   return newRect;
115 }
116
117 using RecalculateRectFunction = Rect<int32_t> (*)(Rect<int32_t>&, const Rect<int32_t>&);
118
119 RecalculateRectFunction RecalculateRect[4] = {RecalculateRect0, RecalculateRect90, RecalculateRect180, RecalculateRect270};
120
121 } // unnamed namespace
122
123 WindowRenderSurface::WindowRenderSurface(Dali::PositionSize positionSize, Any surface, bool isTransparent)
124 : mEGL(nullptr),
125   mDisplayConnection(nullptr),
126   mPositionSize(positionSize),
127   mWindowBase(),
128   mThreadSynchronization(nullptr),
129   mRenderNotification(nullptr),
130   mPostRenderTrigger(),
131   mFrameRenderedTrigger(),
132   mGraphics(nullptr),
133   mEGLSurface(nullptr),
134   mEGLContext(nullptr),
135   mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
136   mOutputTransformedSignal(),
137   mFrameCallbackInfoContainer(),
138   mBufferDamagedRects(),
139   mMutex(),
140   mWindowRotationAngle(0),
141   mScreenRotationAngle(0),
142   mDpiHorizontal(0),
143   mDpiVertical(0),
144   mOwnSurface(false),
145   mWindowRotationFinished(true),
146   mScreenRotationFinished(true),
147   mResizeFinished(true),
148   mDefaultScreenRotationAvailable(false),
149   mIsImeWindowSurface(false),
150   mNeedWindowRotationAcknowledgement(false)
151 {
152   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n");
153   Initialize(surface);
154 }
155
156 WindowRenderSurface::~WindowRenderSurface()
157 {
158 }
159
160 void WindowRenderSurface::Initialize(Any surface)
161 {
162   // If width or height are zero, go full screen.
163   if((mPositionSize.width == 0) || (mPositionSize.height == 0))
164   {
165     // Default window size == screen size
166     mPositionSize.x = 0;
167     mPositionSize.y = 0;
168     WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height);
169   }
170
171   // Create a window base
172   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
173   mWindowBase        = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false));
174
175   // Connect signals
176   mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed);
177
178   // Check screen rotation
179   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
180   if(mScreenRotationAngle != 0)
181   {
182     mScreenRotationFinished         = false;
183     mResizeFinished                 = false;
184     mDefaultScreenRotationAvailable = true;
185     DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle);
186   }
187 }
188
189 Any WindowRenderSurface::GetNativeWindow()
190 {
191   return mWindowBase->GetNativeWindow();
192 }
193
194 int WindowRenderSurface::GetNativeWindowId()
195 {
196   return mWindowBase->GetNativeWindowId();
197 }
198
199 void WindowRenderSurface::Map()
200 {
201   mWindowBase->Show();
202 }
203
204 void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
205 {
206   mRenderNotification = renderNotification;
207 }
208
209 void WindowRenderSurface::SetTransparency(bool transparent)
210 {
211   mWindowBase->SetTransparency(transparent);
212 }
213
214 void WindowRenderSurface::RequestRotation(int angle, PositionSize positionSize)
215 {
216   if(!mPostRenderTrigger)
217   {
218     mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
219                                                                                                       TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
220   }
221
222   mPositionSize = positionSize;
223
224   mWindowRotationAngle    = angle;
225   mWindowRotationFinished = false;
226   mResizeFinished         = false;
227
228   mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
229
230   DALI_LOG_RELEASE_INFO("angle = %d screen rotation = %d, flag = %d\n", mWindowRotationAngle, mScreenRotationAngle, mWindowRotationFinished);
231 }
232
233 WindowBase* WindowRenderSurface::GetWindowBase()
234 {
235   return mWindowBase.get();
236 }
237
238 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
239 {
240   return mOutputTransformedSignal;
241 }
242
243 PositionSize WindowRenderSurface::GetPositionSize() const
244 {
245   return mPositionSize;
246 }
247
248 void WindowRenderSurface::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
249 {
250   if(mDpiHorizontal == 0 || mDpiVertical == 0)
251   {
252     const char* environmentDpiHorizontal = std::getenv(DALI_ENV_DPI_HORIZONTAL);
253     mDpiHorizontal                       = environmentDpiHorizontal ? std::atoi(environmentDpiHorizontal) : 0;
254
255     const char* environmentDpiVertical = std::getenv(DALI_ENV_DPI_VERTICAL);
256     mDpiVertical                       = environmentDpiVertical ? std::atoi(environmentDpiVertical) : 0;
257
258     if(mDpiHorizontal == 0 || mDpiVertical == 0)
259     {
260       mWindowBase->GetDpi(mDpiHorizontal, mDpiVertical);
261     }
262   }
263
264   dpiHorizontal = mDpiHorizontal;
265   dpiVertical   = mDpiVertical;
266 }
267
268 int WindowRenderSurface::GetOrientation() const
269 {
270   return mWindowBase->GetOrientation();
271 }
272
273 void WindowRenderSurface::InitializeGraphics()
274 {
275   if(mEGLContext == NULL)
276   {
277     mGraphics = &mAdaptor->GetGraphicsInterface();
278
279     DALI_ASSERT_ALWAYS(mGraphics && "Graphics interface is not created");
280
281     auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
282     mEGL             = &eglGraphics->GetEglInterface();
283
284     // Create the OpenGL context for this window
285     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
286     eglImpl.ChooseConfig(true, mColorDepth);
287     eglImpl.CreateWindowContext(mEGLContext);
288
289     // Create the OpenGL surface
290     CreateSurface();
291   }
292 }
293
294 void WindowRenderSurface::CreateSurface()
295 {
296   DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
297
298   int width, height;
299   if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
300   {
301     width  = mPositionSize.width;
302     height = mPositionSize.height;
303   }
304   else
305   {
306     width  = mPositionSize.height;
307     height = mPositionSize.width;
308   }
309
310   // Create the EGL window
311   EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
312
313   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
314
315   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
316   mEGLSurface                                   = eglImpl.CreateSurfaceWindow(window, mColorDepth);
317
318   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), EGLSurface (%p), w = %d h = %d angle = %d screen rotation = %d\n",
319                         mWindowBase->GetNativeWindowId(),
320                         mEGLSurface,
321                         mPositionSize.width,
322                         mPositionSize.height,
323                         mWindowRotationAngle,
324                         mScreenRotationAngle);
325 }
326
327 void WindowRenderSurface::DestroySurface()
328 {
329   DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
330
331   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
332   if(eglGraphics)
333   {
334     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId());
335
336     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
337
338     eglImpl.DestroySurface(mEGLSurface);
339     mEGLSurface = nullptr;
340
341     // Destroy context also
342     eglImpl.DestroyContext(mEGLContext);
343     mEGLContext = nullptr;
344
345     mWindowBase->DestroyEglWindow();
346   }
347 }
348
349 bool WindowRenderSurface::ReplaceGraphicsSurface()
350 {
351   DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
352
353   // Destroy the old one
354   mWindowBase->DestroyEglWindow();
355
356   int width, height;
357   if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
358   {
359     width  = mPositionSize.width;
360     height = mPositionSize.height;
361   }
362   else
363   {
364     width  = mPositionSize.height;
365     height = mPositionSize.width;
366   }
367
368   // Create the EGL window
369   EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
370
371   // Set screen rotation
372   mScreenRotationFinished = false;
373
374   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
375
376   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
377   return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext);
378 }
379
380 void WindowRenderSurface::UpdatePositionSize(Dali::PositionSize positionSize)
381 {
382   bool needToMove   = false;
383   bool needToResize = false;
384
385   // Check moving
386   if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
387      (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
388   {
389     needToMove = true;
390   }
391
392   // Check resizing
393   if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
394      (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
395   {
396     needToResize = true;
397   }
398
399   if(needToResize)
400   {
401     mResizeFinished = false;
402     mPositionSize   = positionSize;
403   }
404   else
405   {
406     if(needToMove)
407     {
408       mPositionSize = positionSize;
409     }
410   }
411
412   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
413 }
414
415 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
416 {
417   bool needToMove   = false;
418   bool needToResize = false;
419
420   // Check moving
421   if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
422      (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
423   {
424     needToMove = true;
425   }
426
427   // Check resizing
428   if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
429      (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
430   {
431     needToResize = true;
432   }
433
434   if(needToResize)
435   {
436     if(needToMove)
437     {
438       mWindowBase->MoveResize(positionSize);
439     }
440     else
441     {
442       mWindowBase->Resize(positionSize);
443     }
444
445     mResizeFinished = false;
446     mPositionSize   = positionSize;
447   }
448   else
449   {
450     if(needToMove)
451     {
452       mWindowBase->Move(positionSize);
453
454       mPositionSize = positionSize;
455     }
456   }
457
458   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
459 }
460
461 void WindowRenderSurface::StartRender()
462 {
463 }
464
465 bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
466 {
467   InitializeGraphics();
468
469   mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
470
471   Dali::Integration::Scene::FrameCallbackContainer callbacks;
472
473   Dali::Integration::Scene scene = mScene.GetHandle();
474   if(scene)
475   {
476     bool needFrameRenderedTrigger = false;
477
478     scene.GetFrameRenderedCallback(callbacks);
479     if(!callbacks.empty())
480     {
481       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
482       if(frameRenderedSync != -1)
483       {
484         Dali::Mutex::ScopedLock lock(mMutex);
485
486         DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
487
488         mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
489
490         needFrameRenderedTrigger = true;
491       }
492       else
493       {
494         DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
495       }
496
497       // Clear callbacks
498       callbacks.clear();
499     }
500
501     scene.GetFramePresentedCallback(callbacks);
502     if(!callbacks.empty())
503     {
504       int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
505       if(framePresentedSync != -1)
506       {
507         Dali::Mutex::ScopedLock lock(mMutex);
508
509         DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
510
511         mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
512
513         needFrameRenderedTrigger = true;
514       }
515       else
516       {
517         DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
518       }
519
520       // Clear callbacks
521       callbacks.clear();
522     }
523
524     if(needFrameRenderedTrigger)
525     {
526       if(!mFrameRenderedTrigger)
527       {
528         mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
529                                                                                                                TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
530       }
531       mFrameRenderedTrigger->Trigger();
532     }
533   }
534
535   /**
536     * wl_egl_window_tizen_set_rotation(SetEglWindowRotation)                -> PreRotation
537     * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
538     * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform)       -> Window Rotation
539     * These function should be called before calling first drawing gl Function.
540     * Notice : PreRotation is not used in the latest tizen,
541     *          because output transform event should be occured before egl window is not created.
542     */
543
544   if(mIsResizing || mDefaultScreenRotationAvailable)
545   {
546     int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
547
548     // Window rotate or screen rotate
549     if(!mWindowRotationFinished || !mScreenRotationFinished)
550     {
551       mWindowBase->SetEglWindowBufferTransform(totalAngle);
552
553       // Reset only screen rotation flag
554       mScreenRotationFinished = true;
555
556       DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
557     }
558
559     // Only window rotate
560     if(!mWindowRotationFinished)
561     {
562       mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
563     }
564
565     // Resize case
566     if(!mResizeFinished)
567     {
568       Dali::PositionSize positionSize;
569       positionSize.x = mPositionSize.x;
570       positionSize.y = mPositionSize.y;
571       if(totalAngle == 0 || totalAngle == 180)
572       {
573         positionSize.width  = mPositionSize.width;
574         positionSize.height = mPositionSize.height;
575       }
576       else
577       {
578         positionSize.width  = mPositionSize.height;
579         positionSize.height = mPositionSize.width;
580       }
581       mWindowBase->ResizeEglWindow(positionSize);
582       mResizeFinished = true;
583
584       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);
585     }
586
587     SetFullSwapNextFrame();
588     mDefaultScreenRotationAvailable = false;
589   }
590
591   SetBufferDamagedRects(mDamagedRects, clippingRect);
592
593   if(scene)
594   {
595     Rect<int> surfaceRect = scene.GetCurrentSurfaceRect();
596     if(clippingRect == surfaceRect)
597     {
598       mDamagedRects.assign(1, surfaceRect);
599     }
600     else if(mDamagedRects.empty() && !clippingRect.IsEmpty())
601     {
602       // We will render clippingRect area but mDamagedRects is empty.
603       // So make mDamagedRects same with clippingRect to swap buffers.
604       mDamagedRects.assign(1, clippingRect);
605     }
606   }
607
608   // This is now done when the render pass for the render surface begins
609   //  MakeContextCurrent();
610
611   return true;
612 }
613
614 void WindowRenderSurface::PostRender()
615 {
616   // Inform the gl implementation that rendering has finished before informing the surface
617   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
618   if(eglGraphics)
619   {
620     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
621     mGLES.PostRender();
622
623     bool needWindowRotationCompleted = false;
624
625     if(!mWindowRotationFinished)
626     {
627       if(mNeedWindowRotationAcknowledgement)
628       {
629         Dali::Integration::Scene scene = mScene.GetHandle();
630         if(scene)
631         {
632           if(scene.IsRotationCompletedAcknowledgementSet())
633           {
634             needWindowRotationCompleted = true;
635           }
636         }
637       }
638       else
639       {
640         if(mIsResizing)
641         {
642           needWindowRotationCompleted = true;
643         }
644       }
645     }
646
647     if(needWindowRotationCompleted || mIsImeWindowSurface)
648     {
649       if(mThreadSynchronization)
650       {
651         // Enable PostRender flag
652         mThreadSynchronization->PostRenderStarted();
653       }
654
655       if(!mWindowRotationFinished || mIsImeWindowSurface)
656       {
657         mPostRenderTrigger->Trigger();
658       }
659
660       if(mThreadSynchronization)
661       {
662         // Wait until the event-thread complete the rotation event processing
663         mThreadSynchronization->PostRenderWaitForCompletion();
664       }
665     }
666
667     SwapBuffers(mDamagedRects);
668
669     if(mRenderNotification)
670     {
671       mRenderNotification->Trigger();
672     }
673   }
674 }
675
676 void WindowRenderSurface::StopRender()
677 {
678 }
679
680 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
681 {
682   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
683
684   mThreadSynchronization = &threadSynchronization;
685 }
686
687 void WindowRenderSurface::ReleaseLock()
688 {
689   // Nothing to do.
690 }
691
692 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
693 {
694   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
695 }
696
697 void WindowRenderSurface::MakeContextCurrent()
698 {
699   if(mEGL != nullptr)
700   {
701     mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
702   }
703 }
704
705 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
706 {
707   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
708 }
709
710 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
711 {
712   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
713 }
714
715 void WindowRenderSurface::InitializeImeSurface()
716 {
717   mIsImeWindowSurface = true;
718   if(!mPostRenderTrigger)
719   {
720     mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
721                                                                                                         TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
722   }
723 }
724
725 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
726 {
727   mNeedWindowRotationAcknowledgement = needAcknowledgement;
728 }
729
730 void WindowRenderSurface::OutputTransformed()
731 {
732   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
733
734   if(mScreenRotationAngle != screenRotationAngle)
735   {
736     mScreenRotationAngle    = screenRotationAngle;
737     mScreenRotationFinished = false;
738     mResizeFinished         = false;
739
740     mOutputTransformedSignal.Emit();
741
742     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
743   }
744   else
745   {
746     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
747   }
748 }
749
750 bool WindowRenderSurface::IsWindowRotating() const
751 {
752   return !(mWindowRotationFinished);
753 }
754
755 void WindowRenderSurface::ProcessPostRender()
756 {
757   if(!mWindowRotationFinished)
758   {
759     mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
760     mWindowRotationFinished = true;
761     DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mWindowRotationFinished);
762   }
763
764   if(mIsImeWindowSurface)
765   {
766     mWindowBase->ImeWindowReadyToRender();
767   }
768
769   if(mThreadSynchronization)
770   {
771     mThreadSynchronization->PostRenderComplete();
772   }
773 }
774
775 void WindowRenderSurface::ProcessFrameCallback()
776 {
777   Dali::Mutex::ScopedLock lock(mMutex);
778
779   for(auto&& iter : mFrameCallbackInfoContainer)
780   {
781     if(!iter->fileDescriptorMonitor)
782     {
783       iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
784                                                                                                      MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
785                                                                                                      FileDescriptorMonitor::FD_READABLE));
786
787       DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
788     }
789   }
790 }
791
792 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
793 {
794   if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
795   {
796     DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
797     close(fileDescriptor);
798     return;
799   }
800
801   DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
802
803   std::unique_ptr<FrameCallbackInfo> callbackInfo;
804   {
805     Dali::Mutex::ScopedLock lock(mMutex);
806     auto                    frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
807       return callbackInfo->fileDescriptor == fileDescriptor;
808     });
809     if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
810     {
811       callbackInfo = std::move(*frameCallbackInfo);
812
813       mFrameCallbackInfoContainer.erase(frameCallbackInfo);
814     }
815   }
816
817   // Call the connected callback
818   if(callbackInfo)
819   {
820     for(auto&& iter : (callbackInfo)->callbacks)
821     {
822       CallbackBase::Execute(*(iter.first), iter.second);
823     }
824   }
825 }
826
827 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
828 {
829   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
830   if(eglGraphics)
831   {
832     // If scene is not exist, just use stored mPositionSize.
833     Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
834
835     Dali::Integration::Scene scene = mScene.GetHandle();
836     if(scene)
837     {
838       surfaceRect = scene.GetCurrentSurfaceRect();
839     }
840
841     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
842     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
843     {
844       InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
845       clippingRect = surfaceRect;
846       return;
847     }
848
849     mGraphics->ActivateSurfaceContext(this);
850
851     EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
852
853     // Buffer age 0 means the back buffer in invalid and requires full swap
854     if(bufferAge == 0)
855     {
856       InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
857       clippingRect = surfaceRect;
858       return;
859     }
860
861     // We push current frame damaged rects here, zero index for current frame
862     InsertRects(mBufferDamagedRects, damagedRects);
863
864     // Merge damaged rects into clipping rect
865     auto bufferDamagedRects = mBufferDamagedRects.begin();
866     while(bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
867     {
868       const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
869       MergeRects(clippingRect, rects);
870     }
871
872     if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
873     {
874       // clipping area too big or doesn't intersect surface rect
875       clippingRect = surfaceRect;
876       return;
877     }
878
879     if(!clippingRect.IsEmpty())
880     {
881       std::vector<Rect<int>> damagedRegion;
882       if(scene)
883       {
884         damagedRegion.push_back(RecalculateRect[std::min(scene.GetCurrentSurfaceOrientation() / 90, 3)](clippingRect, scene.GetCurrentSurfaceRect()));
885       }
886       else
887       {
888         damagedRegion.push_back(clippingRect);
889       }
890
891       eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
892     }
893   }
894 }
895
896 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
897 {
898   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
899   if(eglGraphics)
900   {
901     Rect<int32_t> surfaceRect;
902     int32_t       orientation = 0;
903
904     Dali::Integration::Scene scene = mScene.GetHandle();
905     if(scene)
906     {
907       surfaceRect = scene.GetCurrentSurfaceRect();
908       orientation = std::min(scene.GetCurrentSurfaceOrientation() / 90, 3);
909     }
910
911     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
912
913     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || (damagedRects.size() != 0 && damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
914     {
915       mFullSwapNextFrame = false;
916       eglImpl.SwapBuffers(mEGLSurface);
917       return;
918     }
919
920     mFullSwapNextFrame = false;
921
922     std::vector<Rect<int>> mergedRects = damagedRects;
923
924     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
925     // Could be optional and can be removed, needs to be checked with and without on platform
926     const int n = mergedRects.size();
927     for(int i = 0; i < n - 1; i++)
928     {
929       if(mergedRects[i].IsEmpty())
930       {
931         continue;
932       }
933
934       for(int j = i + 1; j < n; j++)
935       {
936         if(mergedRects[j].IsEmpty())
937         {
938           continue;
939         }
940
941         if(mergedRects[i].Intersects(mergedRects[j]))
942         {
943           mergedRects[i].Merge(mergedRects[j]);
944           mergedRects[j].width  = 0;
945           mergedRects[j].height = 0;
946         }
947       }
948     }
949
950     int j = 0;
951     for(int i = 0; i < n; i++)
952     {
953       if(!mergedRects[i].IsEmpty())
954       {
955         mergedRects[j++] = RecalculateRect[orientation](mergedRects[i], surfaceRect);
956       }
957     }
958
959     if(j != 0)
960     {
961       mergedRects.resize(j);
962     }
963
964     if(!mergedRects.size() || (mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
965     {
966       // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
967       // For exceptional cases, swap full area.
968       eglImpl.SwapBuffers(mEGLSurface);
969     }
970     else
971     {
972       eglImpl.SwapBuffers(mEGLSurface, mergedRects);
973     }
974   }
975 }
976
977 } // namespace Adaptor
978
979 } // namespace Internal
980
981 } // namespace Dali