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