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