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