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