Revert "[Tizen] Do not call SetBufferDamagedRects if the damaged rect is empty"
[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     else if(mDamagedRects.empty() && !clippingRect.IsEmpty())
640     {
641       // We will render clippingRect area but mDamagedRects is empty.
642       // So make mDamagedRects same with clippingRect to swap buffers.
643       mDamagedRects.assign(1, clippingRect);
644     }
645   }
646
647   // This is now done when the render pass for the render surface begins
648   //  MakeContextCurrent();
649
650   return true;
651 }
652
653 void WindowRenderSurface::PostRender()
654 {
655   // Inform the gl implementation that rendering has finished before informing the surface
656   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
657   if(eglGraphics)
658   {
659     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
660     mGLES.PostRender();
661
662     bool needWindowRotationCompleted = false;
663
664     if(!mWindowRotationFinished)
665     {
666       if(mNeedWindowRotationAcknowledgement)
667       {
668         Dali::Integration::Scene scene = mScene.GetHandle();
669         if(scene)
670         {
671           if(scene.IsRotationCompletedAcknowledgementSet())
672           {
673             needWindowRotationCompleted = true;
674           }
675         }
676       }
677       else
678       {
679         if(mIsResizing)
680         {
681           needWindowRotationCompleted = true;
682         }
683       }
684     }
685
686     if(needWindowRotationCompleted || mIsImeWindowSurface)
687     {
688       if(mThreadSynchronization)
689       {
690         // Enable PostRender flag
691         mThreadSynchronization->PostRenderStarted();
692       }
693
694       if(!mWindowRotationFinished || mIsImeWindowSurface)
695       {
696         mPostRenderTrigger->Trigger();
697       }
698
699       if(mThreadSynchronization)
700       {
701         // Wait until the event-thread complete the rotation event processing
702         mThreadSynchronization->PostRenderWaitForCompletion();
703       }
704     }
705
706     SwapBuffers(mDamagedRects);
707
708     if(mRenderNotification)
709     {
710       mRenderNotification->Trigger();
711     }
712   }
713 }
714
715 void WindowRenderSurface::StopRender()
716 {
717 }
718
719 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
720 {
721   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
722
723   mThreadSynchronization = &threadSynchronization;
724 }
725
726 void WindowRenderSurface::ReleaseLock()
727 {
728   // Nothing to do.
729 }
730
731 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
732 {
733   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
734 }
735
736 void WindowRenderSurface::MakeContextCurrent()
737 {
738   if(mEGL != nullptr)
739   {
740     mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
741   }
742 }
743
744 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
745 {
746   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
747 }
748
749 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
750 {
751   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
752 }
753
754 void WindowRenderSurface::InitializeImeSurface()
755 {
756   mIsImeWindowSurface = true;
757   if(!mPostRenderTrigger)
758   {
759     mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
760                                                                                                         TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
761   }
762 }
763
764 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
765 {
766   mNeedWindowRotationAcknowledgement = needAcknowledgement;
767 }
768
769 void WindowRenderSurface::OutputTransformed()
770 {
771   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
772
773   if(mScreenRotationAngle != screenRotationAngle)
774   {
775     mScreenRotationAngle    = screenRotationAngle;
776     mScreenRotationFinished = false;
777     mResizeFinished         = false;
778
779     mOutputTransformedSignal.Emit();
780
781     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
782   }
783   else
784   {
785     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
786   }
787 }
788
789 bool WindowRenderSurface::IsWindowRotating() const
790 {
791   return !(mWindowRotationFinished);
792 }
793
794 void WindowRenderSurface::ProcessPostRender()
795 {
796   if(!mWindowRotationFinished)
797   {
798     mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
799     mWindowRotationFinished = true;
800     DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mWindowRotationFinished);
801   }
802
803   if(mIsImeWindowSurface)
804   {
805     mWindowBase->ImeWindowReadyToRender();
806   }
807
808   if(mThreadSynchronization)
809   {
810     mThreadSynchronization->PostRenderComplete();
811   }
812 }
813
814 void WindowRenderSurface::ProcessFrameCallback()
815 {
816   Dali::Mutex::ScopedLock lock(mMutex);
817
818   for(auto&& iter : mFrameCallbackInfoContainer)
819   {
820     if(!iter->fileDescriptorMonitor)
821     {
822       iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
823                                                                                                      MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
824                                                                                                      FileDescriptorMonitor::FD_READABLE));
825
826       DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
827     }
828   }
829 }
830
831 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
832 {
833   if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
834   {
835     DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
836     close(fileDescriptor);
837     return;
838   }
839
840   DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
841
842   std::unique_ptr<FrameCallbackInfo> callbackInfo;
843   {
844     Dali::Mutex::ScopedLock lock(mMutex);
845     auto                    frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
846       return callbackInfo->fileDescriptor == fileDescriptor;
847     });
848     if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
849     {
850       callbackInfo = std::move(*frameCallbackInfo);
851
852       mFrameCallbackInfoContainer.erase(frameCallbackInfo);
853     }
854   }
855
856   // Call the connected callback
857   if(callbackInfo)
858   {
859     for(auto&& iter : (callbackInfo)->callbacks)
860     {
861       CallbackBase::Execute(*(iter.first), iter.second);
862     }
863   }
864 }
865
866 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
867 {
868   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
869   if(eglGraphics)
870   {
871     // If scene is not exist, just use stored mPositionSize.
872     Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
873     int32_t   orientation = 0;
874
875     Dali::Integration::Scene scene = mScene.GetHandle();
876     if(scene)
877     {
878       surfaceRect = scene.GetCurrentSurfaceRect();
879       orientation = std::min(scene.GetCurrentSurfaceOrientation() / 90, 3);
880     }
881
882     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
883     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
884     {
885       InsertRects(mBufferDamagedRects, surfaceRect);
886       clippingRect = surfaceRect;
887       return;
888     }
889
890     mGraphics->ActivateSurfaceContext(this);
891
892     EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
893
894     // Buffer age 0 means the back buffer in invalid and requires full swap
895     if(bufferAge == 0)
896     {
897       InsertRects(mBufferDamagedRects, surfaceRect);
898       clippingRect = surfaceRect;
899       return;
900     }
901
902     mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
903
904     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
905     // Could be optional and can be removed, needs to be checked with and without on platform
906     MergeIntersectingRects(mDamagedRects, orientation, surfaceRect);
907
908     // Make one clipping rect
909     MergeRects(clippingRect, mDamagedRects);
910
911     // We push current frame damaged rects here, zero index for current frame
912     InsertRects(mBufferDamagedRects, clippingRect);
913
914     // Merge damaged rects into clipping rect
915     if(bufferAge <= static_cast<EGLint>(mBufferDamagedRects.size()))
916     {
917       // clippingRect is already the current frame's damaged rect. Merge from the second
918       for(int i = 1; i < bufferAge; i++)
919       {
920         clippingRect.Merge(mBufferDamagedRects[i]);
921       }
922     }
923     else
924     {
925       // The buffer age is too old. Need full update.
926       clippingRect = surfaceRect;
927       return;
928     }
929
930     if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
931     {
932       // clipping area too big or doesn't intersect surface rect
933       clippingRect = surfaceRect;
934       return;
935     }
936
937     if(!clippingRect.IsEmpty())
938     {
939       std::vector<Rect<int>> damagedRegion;
940       if(scene)
941       {
942         damagedRegion.push_back(RecalculateRect[std::min(scene.GetCurrentSurfaceOrientation() / 90, 3)](clippingRect, scene.GetCurrentSurfaceRect()));
943       }
944       else
945       {
946         damagedRegion.push_back(clippingRect);
947       }
948
949       eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
950     }
951   }
952 }
953
954 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
955 {
956   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
957   if(eglGraphics)
958   {
959     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
960
961     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
962     {
963       mFullSwapNextFrame = false;
964       eglImpl.SwapBuffers(mEGLSurface);
965       return;
966     }
967
968     mFullSwapNextFrame = false;
969
970     Rect<int32_t>            surfaceRect;
971     Dali::Integration::Scene scene = mScene.GetHandle();
972     if(scene)
973     {
974       surfaceRect = scene.GetCurrentSurfaceRect();
975     }
976
977     if(!damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
978     {
979       // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
980       // For exceptional cases, swap full area.
981       eglImpl.SwapBuffers(mEGLSurface);
982     }
983     else
984     {
985       eglImpl.SwapBuffers(mEGLSurface, damagedRects);
986     }
987   }
988 }
989
990 } // namespace Adaptor
991
992 } // namespace Internal
993
994 } // namespace Dali