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