Merge "Fix svace issues" into devel/master
[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       mDamagedRects.assign(1, RecalculateRect[std::min(scene.GetCurrentSurfaceOrientation() / 90, 3)](surfaceRect, surfaceRect));
584     }
585   }
586
587   // This is now done when the render pass for the render surface begins
588   //  MakeContextCurrent();
589
590   return true;
591 }
592
593 void WindowRenderSurface::PostRender()
594 {
595   // Inform the gl implementation that rendering has finished before informing the surface
596   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
597   if(eglGraphics)
598   {
599     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
600     mGLES.PostRender();
601
602     bool needWindowRotationCompleted = false;
603
604     if(mIsWindowOrientationChanging)
605     {
606       if(mNeedWindowRotationAcknowledgement)
607       {
608         Dali::Integration::Scene scene = mScene.GetHandle();
609         if(scene)
610         {
611           if(scene.IsRotationCompletedAcknowledgementSet())
612           {
613             needWindowRotationCompleted = true;
614           }
615         }
616       }
617       else
618       {
619         needWindowRotationCompleted = true;
620       }
621     }
622
623     if(needWindowRotationCompleted || mIsImeWindowSurface)
624     {
625       if(mThreadSynchronization)
626       {
627         // Enable PostRender flag
628         mThreadSynchronization->PostRenderStarted();
629       }
630
631       if(mIsWindowOrientationChanging || mIsImeWindowSurface)
632       {
633         mPostRenderTrigger->Trigger();
634       }
635
636       if(mThreadSynchronization)
637       {
638         // Wait until the event-thread complete the rotation event processing
639         mThreadSynchronization->PostRenderWaitForCompletion();
640       }
641     }
642
643     SwapBuffers(mDamagedRects);
644
645     if(mRenderNotification)
646     {
647       mRenderNotification->Trigger();
648     }
649   }
650 }
651
652 void WindowRenderSurface::StopRender()
653 {
654 }
655
656 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
657 {
658   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
659
660   mThreadSynchronization = &threadSynchronization;
661 }
662
663 void WindowRenderSurface::ReleaseLock()
664 {
665   // Nothing to do.
666 }
667
668 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
669 {
670   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
671 }
672
673 void WindowRenderSurface::MakeContextCurrent()
674 {
675   if(mEGL != nullptr)
676   {
677     mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
678   }
679 }
680
681 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
682 {
683   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
684 }
685
686 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
687 {
688   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
689 }
690
691 void WindowRenderSurface::InitializeImeSurface()
692 {
693   mIsImeWindowSurface = true;
694   if(!mPostRenderTrigger)
695   {
696     mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
697                                                                                                         TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
698   }
699 }
700
701 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
702 {
703   mNeedWindowRotationAcknowledgement = needAcknowledgement;
704 }
705
706 void WindowRenderSurface::OutputTransformed()
707 {
708   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
709
710   if(mScreenRotationAngle != screenRotationAngle)
711   {
712     mOutputTransformedSignal.Emit();
713
714     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d new screen angle = %d\n", mWindowRotationAngle, screenRotationAngle);
715   }
716   else
717   {
718     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
719   }
720 }
721
722 void WindowRenderSurface::ProcessPostRender()
723 {
724   if(mIsWindowOrientationChanging)
725   {
726     mWindowRotationFinishedSignal.Emit();
727     mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
728     mIsWindowOrientationChanging = false;
729     DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mIsWindowOrientationChanging);
730   }
731
732   if(mIsImeWindowSurface)
733   {
734     mWindowBase->ImeWindowReadyToRender();
735   }
736
737   if(mThreadSynchronization)
738   {
739     mThreadSynchronization->PostRenderComplete();
740   }
741 }
742
743 void WindowRenderSurface::ProcessFrameCallback()
744 {
745   Dali::Mutex::ScopedLock lock(mMutex);
746
747   for(auto&& iter : mFrameCallbackInfoContainer)
748   {
749     if(!iter->fileDescriptorMonitor)
750     {
751       iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
752                                                                                                      MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
753                                                                                                      FileDescriptorMonitor::FD_READABLE));
754
755       DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
756     }
757   }
758 }
759
760 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
761 {
762   if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
763   {
764     DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
765     close(fileDescriptor);
766     return;
767   }
768
769   DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
770
771   std::unique_ptr<FrameCallbackInfo> callbackInfo;
772   {
773     Dali::Mutex::ScopedLock lock(mMutex);
774     auto                    frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
775       return callbackInfo->fileDescriptor == fileDescriptor;
776     });
777     if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
778     {
779       callbackInfo = std::move(*frameCallbackInfo);
780
781       mFrameCallbackInfoContainer.erase(frameCallbackInfo);
782     }
783   }
784
785   // Call the connected callback
786   if(callbackInfo)
787   {
788     for(auto&& iter : (callbackInfo)->callbacks)
789     {
790       CallbackBase::Execute(*(iter.first), iter.second);
791     }
792   }
793 }
794
795 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
796 {
797   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
798   if(eglGraphics)
799   {
800     // If scene is not exist, just use stored mPositionSize.
801     Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
802     int32_t   orientation = 0;
803
804     Dali::Integration::Scene scene = mScene.GetHandle();
805     if(scene)
806     {
807       surfaceRect = scene.GetCurrentSurfaceRect();
808       orientation = std::min(scene.GetCurrentSurfaceOrientation() / 90, 3);
809     }
810
811     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
812     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
813     {
814       InsertRects(mBufferDamagedRects, surfaceRect);
815       clippingRect = surfaceRect;
816       return;
817     }
818
819     if(damagedRects.empty())
820     {
821       // Empty damaged rect. We don't need rendering
822       clippingRect = Rect<int>();
823       // Clean up current damanged rects.
824       mDamagedRects.clear();
825       return;
826     }
827
828     mGraphics->ActivateSurfaceContext(this);
829
830     EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
831
832     // Buffer age 0 means the back buffer in invalid and requires full swap
833     if(bufferAge == 0)
834     {
835       InsertRects(mBufferDamagedRects, surfaceRect);
836       clippingRect = surfaceRect;
837       return;
838     }
839
840     mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
841
842     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
843     // Could be optional and can be removed, needs to be checked with and without on platform
844     // And then, Make one clipping rect, and rotate rects by orientation.
845     MergeIntersectingRectsAndRotate(clippingRect, mDamagedRects, orientation, surfaceRect);
846
847     // We push current frame damaged rects here, zero index for current frame
848     InsertRects(mBufferDamagedRects, clippingRect);
849
850     // Merge damaged rects into clipping rect
851     if(bufferAge <= static_cast<EGLint>(mBufferDamagedRects.size()))
852     {
853       // clippingRect is already the current frame's damaged rect. Merge from the second
854       for(int i = 1; i < bufferAge; i++)
855       {
856         clippingRect.Merge(mBufferDamagedRects[i]);
857       }
858     }
859     else
860     {
861       // The buffer age is too old. Need full update.
862       clippingRect = surfaceRect;
863       return;
864     }
865
866     if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
867     {
868       // clipping area too big or doesn't intersect surface rect
869       clippingRect = surfaceRect;
870       return;
871     }
872
873     if(!clippingRect.IsEmpty())
874     {
875       std::vector<Rect<int>> damagedRegion;
876       if(scene)
877       {
878         damagedRegion.push_back(RecalculateRect[orientation](clippingRect, surfaceRect));
879       }
880       else
881       {
882         damagedRegion.push_back(clippingRect);
883       }
884
885       eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
886     }
887   }
888 }
889
890 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
891 {
892   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
893   if(eglGraphics)
894   {
895     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
896
897     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
898     {
899       mFullSwapNextFrame = false;
900       eglImpl.SwapBuffers(mEGLSurface);
901       return;
902     }
903
904     mFullSwapNextFrame = false;
905
906     Rect<int32_t>            surfaceRect;
907     Dali::Integration::Scene scene = mScene.GetHandle();
908     if(scene)
909     {
910       surfaceRect = scene.GetCurrentSurfaceRect();
911     }
912
913     if(!damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
914     {
915       // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
916       // For exceptional cases, swap full area.
917       eglImpl.SwapBuffers(mEGLSurface);
918     }
919     else
920     {
921       eglImpl.SwapBuffers(mEGLSurface, damagedRects);
922     }
923   }
924 }
925
926 } // namespace Adaptor
927
928 } // namespace Internal
929
930 } // namespace Dali