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