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