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