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