Merge "dali-adaptor: Multi-Window DnD Feature Implementation" into devel/master
[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_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mWindowRotationAngle, mScreenRotationAngle);
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), EGLSurface (%p), w = %d h = %d angle = %d screen rotation = %d\n",
320                         mWindowBase->GetNativeWindowId(),
321                         mEGLSurface,
322                         mPositionSize.width,
323                         mPositionSize.height,
324                         mWindowRotationAngle,
325                         mScreenRotationAngle);
326 }
327
328 void WindowRenderSurface::DestroySurface()
329 {
330   DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
331
332   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
333   if(eglGraphics)
334   {
335     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId());
336
337     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
338
339     eglImpl.DestroySurface(mEGLSurface);
340     mEGLSurface = nullptr;
341
342     // Destroy context also
343     eglImpl.DestroyContext(mEGLContext);
344     mEGLContext = nullptr;
345
346     mWindowBase->DestroyEglWindow();
347   }
348 }
349
350 bool WindowRenderSurface::ReplaceGraphicsSurface()
351 {
352   DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter);
353
354   // Destroy the old one
355   mWindowBase->DestroyEglWindow();
356
357   int width, height;
358   if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180)
359   {
360     width  = mPositionSize.width;
361     height = mPositionSize.height;
362   }
363   else
364   {
365     width  = mPositionSize.height;
366     height = mPositionSize.width;
367   }
368
369   // Create the EGL window
370   EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height);
371
372   // Set screen rotation
373   mScreenRotationFinished = false;
374
375   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
376
377   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
378   return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext);
379 }
380
381 void WindowRenderSurface::UpdatePositionSize(Dali::PositionSize positionSize)
382 {
383   bool needToMove   = false;
384   bool needToResize = false;
385
386   // Check moving
387   if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
388      (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
389   {
390     needToMove = true;
391   }
392
393   // Check resizing
394   if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
395      (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
396   {
397     needToResize = true;
398   }
399
400   if(needToResize)
401   {
402     mResizeFinished = false;
403     mPositionSize   = positionSize;
404   }
405   else
406   {
407     if(needToMove)
408     {
409       mPositionSize = positionSize;
410     }
411   }
412
413   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
414 }
415
416 void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize)
417 {
418   bool needToMove   = false;
419   bool needToResize = false;
420
421   // Check moving
422   if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) ||
423      (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE))
424   {
425     needToMove = true;
426   }
427
428   // Check resizing
429   if((fabs(positionSize.width - mPositionSize.width) >= MINIMUM_DIMENSION_CHANGE) ||
430      (fabs(positionSize.height - mPositionSize.height) >= MINIMUM_DIMENSION_CHANGE))
431   {
432     needToResize = true;
433   }
434
435   if(needToResize)
436   {
437     if(needToMove)
438     {
439       mWindowBase->MoveResize(positionSize);
440     }
441     else
442     {
443       mWindowBase->Resize(positionSize);
444     }
445
446     mResizeFinished = false;
447     mPositionSize   = positionSize;
448   }
449   else
450   {
451     if(needToMove)
452     {
453       mWindowBase->Move(positionSize);
454
455       mPositionSize = positionSize;
456     }
457   }
458
459   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height);
460 }
461
462 void WindowRenderSurface::StartRender()
463 {
464 }
465
466 bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
467 {
468   InitializeGraphics();
469
470   mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
471
472   Dali::Integration::Scene::FrameCallbackContainer callbacks;
473
474   Dali::Integration::Scene scene = mScene.GetHandle();
475   if(scene)
476   {
477     bool needFrameRenderedTrigger = false;
478
479     scene.GetFrameRenderedCallback(callbacks);
480     if(!callbacks.empty())
481     {
482       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
483       if(frameRenderedSync != -1)
484       {
485         Dali::Mutex::ScopedLock lock(mMutex);
486
487         DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
488
489         mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
490
491         needFrameRenderedTrigger = true;
492       }
493       else
494       {
495         DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
496       }
497
498       // Clear callbacks
499       callbacks.clear();
500     }
501
502     scene.GetFramePresentedCallback(callbacks);
503     if(!callbacks.empty())
504     {
505       int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
506       if(framePresentedSync != -1)
507       {
508         Dali::Mutex::ScopedLock lock(mMutex);
509
510         DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
511
512         mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
513
514         needFrameRenderedTrigger = true;
515       }
516       else
517       {
518         DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
519       }
520
521       // Clear callbacks
522       callbacks.clear();
523     }
524
525     if(needFrameRenderedTrigger)
526     {
527       if(!mFrameRenderedTrigger)
528       {
529         mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
530                                                                                                                TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
531       }
532       mFrameRenderedTrigger->Trigger();
533     }
534   }
535
536   /**
537     * wl_egl_window_tizen_set_rotation(SetEglWindowRotation)                -> PreRotation
538     * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
539     * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform)       -> Window Rotation
540     * These function should be called before calling first drawing gl Function.
541     * Notice : PreRotation is not used in the latest tizen,
542     *          because output transform event should be occured before egl window is not created.
543     */
544
545   if(mIsResizing || mDefaultScreenRotationAvailable)
546   {
547     int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
548
549     // Window rotate or screen rotate
550     if(!mWindowRotationFinished || !mScreenRotationFinished)
551     {
552       mWindowBase->SetEglWindowBufferTransform(totalAngle);
553
554       // Reset only screen rotation flag
555       mScreenRotationFinished = true;
556
557       DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
558     }
559
560     // Only window rotate
561     if(!mWindowRotationFinished)
562     {
563       mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
564     }
565
566     // Resize case
567     if(!mResizeFinished)
568     {
569       Dali::PositionSize positionSize;
570       positionSize.x = mPositionSize.x;
571       positionSize.y = mPositionSize.y;
572       if(totalAngle == 0 || totalAngle == 180)
573       {
574         positionSize.width  = mPositionSize.width;
575         positionSize.height = mPositionSize.height;
576       }
577       else
578       {
579         positionSize.width  = mPositionSize.height;
580         positionSize.height = mPositionSize.width;
581       }
582       mWindowBase->ResizeEglWindow(positionSize);
583       mResizeFinished = true;
584
585       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);
586     }
587
588     SetFullSwapNextFrame();
589     mDefaultScreenRotationAvailable = false;
590   }
591
592   SetBufferDamagedRects(mDamagedRects, clippingRect);
593
594   if(scene)
595   {
596     Rect<int> surfaceRect = scene.GetCurrentSurfaceRect();
597     if(clippingRect == surfaceRect)
598     {
599       mDamagedRects.assign(1, surfaceRect);
600     }
601     else if(mDamagedRects.empty() && !clippingRect.IsEmpty())
602     {
603       // We will render clippingRect area but mDamagedRects is empty.
604       // So make mDamagedRects same with clippingRect to swap buffers.
605       mDamagedRects.assign(1, clippingRect);
606     }
607   }
608
609   // This is now done when the render pass for the render surface begins
610   //  MakeContextCurrent();
611
612   return true;
613 }
614
615 void WindowRenderSurface::PostRender()
616 {
617   // Inform the gl implementation that rendering has finished before informing the surface
618   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
619   if(eglGraphics)
620   {
621     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
622     mGLES.PostRender();
623
624     bool needWindowRotationCompleted = false;
625
626     if(!mWindowRotationFinished)
627     {
628       if(mNeedWindowRotationAcknowledgement)
629       {
630         Dali::Integration::Scene scene = mScene.GetHandle();
631         if(scene)
632         {
633           if(scene.IsRotationCompletedAcknowledgementSet())
634           {
635             needWindowRotationCompleted = true;
636           }
637         }
638       }
639       else
640       {
641         if(mIsResizing)
642         {
643           needWindowRotationCompleted = true;
644         }
645       }
646     }
647
648     if(needWindowRotationCompleted || mIsImeWindowSurface)
649     {
650       if(mThreadSynchronization)
651       {
652         // Enable PostRender flag
653         mThreadSynchronization->PostRenderStarted();
654       }
655
656       if(!mWindowRotationFinished || mIsImeWindowSurface)
657       {
658         mPostRenderTrigger->Trigger();
659       }
660
661       if(mThreadSynchronization)
662       {
663         // Wait until the event-thread complete the rotation event processing
664         mThreadSynchronization->PostRenderWaitForCompletion();
665       }
666     }
667
668     SwapBuffers(mDamagedRects);
669
670     if(mRenderNotification)
671     {
672       mRenderNotification->Trigger();
673     }
674   }
675 }
676
677 void WindowRenderSurface::StopRender()
678 {
679 }
680
681 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
682 {
683   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
684
685   mThreadSynchronization = &threadSynchronization;
686 }
687
688 void WindowRenderSurface::ReleaseLock()
689 {
690   // Nothing to do.
691 }
692
693 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
694 {
695   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
696 }
697
698 void WindowRenderSurface::MakeContextCurrent()
699 {
700   if(mEGL != nullptr)
701   {
702     mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
703   }
704 }
705
706 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
707 {
708   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
709 }
710
711 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
712 {
713   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
714 }
715
716 void WindowRenderSurface::InitializeImeSurface()
717 {
718   mIsImeWindowSurface = true;
719   if(!mPostRenderTrigger)
720   {
721     mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
722                                                                                                         TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
723   }
724 }
725
726 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
727 {
728   mNeedWindowRotationAcknowledgement = needAcknowledgement;
729 }
730
731 void WindowRenderSurface::OutputTransformed()
732 {
733   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
734
735   if(mScreenRotationAngle != screenRotationAngle)
736   {
737     mScreenRotationAngle    = screenRotationAngle;
738     mScreenRotationFinished = false;
739     mResizeFinished         = false;
740
741     mOutputTransformedSignal.Emit();
742
743     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
744   }
745   else
746   {
747     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
748   }
749 }
750
751 void WindowRenderSurface::ProcessPostRender()
752 {
753   if(!mWindowRotationFinished)
754   {
755     mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
756     DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done\n");
757     mWindowRotationFinished = true;
758   }
759
760   if(mIsImeWindowSurface)
761   {
762     mWindowBase->ImeWindowReadyToRender();
763   }
764
765   if(mThreadSynchronization)
766   {
767     mThreadSynchronization->PostRenderComplete();
768   }
769 }
770
771 void WindowRenderSurface::ProcessFrameCallback()
772 {
773   Dali::Mutex::ScopedLock lock(mMutex);
774
775   for(auto&& iter : mFrameCallbackInfoContainer)
776   {
777     if(!iter->fileDescriptorMonitor)
778     {
779       iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
780                                                                                                      MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
781                                                                                                      FileDescriptorMonitor::FD_READABLE));
782
783       DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
784     }
785   }
786 }
787
788 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
789 {
790   if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
791   {
792     DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
793     close(fileDescriptor);
794     return;
795   }
796
797   DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
798
799   std::unique_ptr<FrameCallbackInfo> callbackInfo;
800   {
801     Dali::Mutex::ScopedLock lock(mMutex);
802     auto                    frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
803       return callbackInfo->fileDescriptor == fileDescriptor;
804     });
805     if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
806     {
807       callbackInfo = std::move(*frameCallbackInfo);
808
809       mFrameCallbackInfoContainer.erase(frameCallbackInfo);
810     }
811   }
812
813   // Call the connected callback
814   if(callbackInfo)
815   {
816     for(auto&& iter : (callbackInfo)->callbacks)
817     {
818       CallbackBase::Execute(*(iter.first), iter.second);
819     }
820   }
821 }
822
823 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
824 {
825   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
826   if(eglGraphics)
827   {
828     // If scene is not exist, just use stored mPositionSize.
829     Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
830
831     Dali::Integration::Scene scene = mScene.GetHandle();
832     if(scene)
833     {
834       surfaceRect = scene.GetCurrentSurfaceRect();
835     }
836
837     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
838     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
839     {
840       InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
841       clippingRect = surfaceRect;
842       return;
843     }
844
845     mGraphics->ActivateSurfaceContext(this);
846
847     EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
848
849     // Buffer age 0 means the back buffer in invalid and requires full swap
850     if(bufferAge == 0)
851     {
852       InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
853       clippingRect = surfaceRect;
854       return;
855     }
856
857     // We push current frame damaged rects here, zero index for current frame
858     InsertRects(mBufferDamagedRects, damagedRects);
859
860     // Merge damaged rects into clipping rect
861     auto bufferDamagedRects = mBufferDamagedRects.begin();
862     while(bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
863     {
864       const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
865       MergeRects(clippingRect, rects);
866     }
867
868     if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
869     {
870       // clipping area too big or doesn't intersect surface rect
871       clippingRect = surfaceRect;
872       return;
873     }
874
875     if(!clippingRect.IsEmpty())
876     {
877       std::vector<Rect<int>> damagedRegion;
878       if(scene)
879       {
880         damagedRegion.push_back(RecalculateRect[std::min(scene.GetCurrentSurfaceOrientation() / 90, 3)](clippingRect, scene.GetCurrentSurfaceRect()));
881       }
882       else
883       {
884         damagedRegion.push_back(clippingRect);
885       }
886
887       eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
888     }
889   }
890 }
891
892 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
893 {
894   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
895   if(eglGraphics)
896   {
897     Rect<int32_t> surfaceRect;
898     int32_t       orientation = 0;
899
900     Dali::Integration::Scene scene = mScene.GetHandle();
901     if(scene)
902     {
903       surfaceRect = scene.GetCurrentSurfaceRect();
904       orientation = std::min(scene.GetCurrentSurfaceOrientation() / 90, 3);
905     }
906
907     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
908
909     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || (damagedRects.size() != 0 && damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
910     {
911       mFullSwapNextFrame = false;
912       eglImpl.SwapBuffers(mEGLSurface);
913       return;
914     }
915
916     mFullSwapNextFrame = false;
917
918     std::vector<Rect<int>> mergedRects = damagedRects;
919
920     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
921     // Could be optional and can be removed, needs to be checked with and without on platform
922     const int n = mergedRects.size();
923     for(int i = 0; i < n - 1; i++)
924     {
925       if(mergedRects[i].IsEmpty())
926       {
927         continue;
928       }
929
930       for(int j = i + 1; j < n; j++)
931       {
932         if(mergedRects[j].IsEmpty())
933         {
934           continue;
935         }
936
937         if(mergedRects[i].Intersects(mergedRects[j]))
938         {
939           mergedRects[i].Merge(mergedRects[j]);
940           mergedRects[j].width  = 0;
941           mergedRects[j].height = 0;
942         }
943       }
944     }
945
946     int j = 0;
947     for(int i = 0; i < n; i++)
948     {
949       if(!mergedRects[i].IsEmpty())
950       {
951         mergedRects[j++] = RecalculateRect[orientation](mergedRects[i], surfaceRect);
952       }
953     }
954
955     if(j != 0)
956     {
957       mergedRects.resize(j);
958     }
959
960     if(!mergedRects.size() || (mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
961     {
962       // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
963       // For exceptional cases, swap full area.
964       eglImpl.SwapBuffers(mEGLSurface);
965     }
966     else
967     {
968       eglImpl.SwapBuffers(mEGLSurface, mergedRects);
969     }
970   }
971 }
972
973 } // namespace Adaptor
974
975 } // namespace Internal
976
977 } // namespace Dali