e4bc5b6b56fa3fba06a1041c1377b2a6f96315b1
[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   mPostRenderTrigger(),
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   mIsImeWindowSurface(false),
150   mNeedWindowRotationAcknowledgement(false)
151 {
152   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n");
153   Initialize(surface);
154 }
155
156 WindowRenderSurface::~WindowRenderSurface()
157 {
158 }
159
160 void WindowRenderSurface::Initialize(Any surface)
161 {
162   // If width or height are zero, go full screen.
163   if((mPositionSize.width == 0) || (mPositionSize.height == 0))
164   {
165     // Default window size == screen size
166     mPositionSize.x = 0;
167     mPositionSize.y = 0;
168     WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height);
169   }
170
171   // Create a window base
172   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
173   mWindowBase        = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false));
174
175   // Connect signals
176   mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed);
177
178   // Check screen rotation
179   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
180   if(mScreenRotationAngle != 0)
181   {
182     mScreenRotationFinished         = false;
183     mResizeFinished                 = false;
184     mDefaultScreenRotationAvailable = true;
185     DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle);
186   }
187 }
188
189 Any WindowRenderSurface::GetNativeWindow()
190 {
191   return mWindowBase->GetNativeWindow();
192 }
193
194 int WindowRenderSurface::GetNativeWindowId()
195 {
196   return mWindowBase->GetNativeWindowId();
197 }
198
199 void WindowRenderSurface::Map()
200 {
201   mWindowBase->Show();
202 }
203
204 void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
205 {
206   mRenderNotification = renderNotification;
207 }
208
209 void WindowRenderSurface::SetTransparency(bool transparent)
210 {
211   mWindowBase->SetTransparency(transparent);
212 }
213
214 void WindowRenderSurface::RequestRotation(int angle, int width, int height)
215 {
216   if(!mPostRenderTrigger)
217   {
218     mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
219                                                                                                       TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
220   }
221
222   mPositionSize.width  = width;
223   mPositionSize.height = height;
224
225   mWindowRotationAngle    = angle;
226   mWindowRotationFinished = false;
227   mResizeFinished         = false;
228
229   mWindowBase->SetWindowRotationAngle(mWindowRotationAngle);
230
231   DALI_LOG_RELEASE_INFO("angle = %d screen rotation = %d, flag = %d\n", mWindowRotationAngle, mScreenRotationAngle, mWindowRotationFinished);
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   if(mEGLContext == NULL)
277   {
278     mGraphics = &mAdaptor->GetGraphicsInterface();
279
280     DALI_ASSERT_ALWAYS(mGraphics && "Graphics interface is not created");
281
282     auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
283     mEGL             = &eglGraphics->GetEglInterface();
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   InitializeGraphics();
433
434   mDamagedRects.assign(damagedRects.begin(), damagedRects.end());
435
436   Dali::Integration::Scene::FrameCallbackContainer callbacks;
437
438   Dali::Integration::Scene scene = mScene.GetHandle();
439   if(scene)
440   {
441     bool needFrameRenderedTrigger = false;
442
443     scene.GetFrameRenderedCallback(callbacks);
444     if(!callbacks.empty())
445     {
446       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
447       if(frameRenderedSync != -1)
448       {
449         Dali::Mutex::ScopedLock lock(mMutex);
450
451         DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync);
452
453         mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, frameRenderedSync)));
454
455         needFrameRenderedTrigger = true;
456       }
457       else
458       {
459         DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n");
460       }
461
462       // Clear callbacks
463       callbacks.clear();
464     }
465
466     scene.GetFramePresentedCallback(callbacks);
467     if(!callbacks.empty())
468     {
469       int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
470       if(framePresentedSync != -1)
471       {
472         Dali::Mutex::ScopedLock lock(mMutex);
473
474         DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync);
475
476         mFrameCallbackInfoContainer.push_back(std::unique_ptr<FrameCallbackInfo>(new FrameCallbackInfo(callbacks, framePresentedSync)));
477
478         needFrameRenderedTrigger = true;
479       }
480       else
481       {
482         DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n");
483       }
484
485       // Clear callbacks
486       callbacks.clear();
487     }
488
489     if(needFrameRenderedTrigger)
490     {
491       if(!mFrameRenderedTrigger)
492       {
493         mFrameRenderedTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback),
494                                                                                                                TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
495       }
496       mFrameRenderedTrigger->Trigger();
497     }
498   }
499
500   /**
501     * wl_egl_window_tizen_set_rotation(SetEglWindowRotation)                -> PreRotation
502     * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation
503     * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform)       -> Window Rotation
504     * These function should be called before calling first drawing gl Function.
505     * Notice : PreRotation is not used in the latest tizen,
506     *          because output transform event should be occured before egl window is not created.
507     */
508
509   if(mIsResizing || mDefaultScreenRotationAvailable)
510   {
511     int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
512
513     // Window rotate or screen rotate
514     if(!mWindowRotationFinished || !mScreenRotationFinished)
515     {
516       mWindowBase->SetEglWindowBufferTransform(totalAngle);
517
518       // Reset only screen rotation flag
519       mScreenRotationFinished = true;
520
521       DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mWindowRotationAngle, mScreenRotationAngle);
522     }
523
524     // Only window rotate
525     if(!mWindowRotationFinished)
526     {
527       mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
528     }
529
530     // Resize case
531     if(!mResizeFinished)
532     {
533       Dali::PositionSize positionSize;
534       positionSize.x = mPositionSize.x;
535       positionSize.y = mPositionSize.y;
536       if(totalAngle == 0 || totalAngle == 180)
537       {
538         positionSize.width  = mPositionSize.width;
539         positionSize.height = mPositionSize.height;
540       }
541       else
542       {
543         positionSize.width  = mPositionSize.height;
544         positionSize.height = mPositionSize.width;
545       }
546       mWindowBase->ResizeEglWindow(positionSize);
547       mResizeFinished = true;
548
549       DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: Set resize, x: %d, y: %d, w: %d, h:%d\n", positionSize.x, positionSize.y, positionSize.width, positionSize.height);
550     }
551
552     SetFullSwapNextFrame();
553     mDefaultScreenRotationAvailable = false;
554   }
555
556   SetBufferDamagedRects(mDamagedRects, clippingRect);
557
558   if(scene)
559   {
560     Rect<int> surfaceRect = scene.GetCurrentSurfaceRect();
561     if(clippingRect == surfaceRect)
562     {
563       mDamagedRects.assign(1, surfaceRect);
564     }
565     else if(mDamagedRects.empty() && !clippingRect.IsEmpty())
566     {
567       // We will render clippingRect area but mDamagedRects is empty.
568       // So make mDamagedRects same with clippingRect to swap buffers.
569       mDamagedRects.assign(1, clippingRect);
570     }
571   }
572
573   // This is now done when the render pass for the render surface begins
574   //  MakeContextCurrent();
575
576   return true;
577 }
578
579 void WindowRenderSurface::PostRender()
580 {
581   // Inform the gl implementation that rendering has finished before informing the surface
582   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
583   if(eglGraphics)
584   {
585     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
586     mGLES.PostRender();
587
588     bool needWindowRotationCompleted = false;
589
590     if(!mWindowRotationFinished)
591     {
592       if(mNeedWindowRotationAcknowledgement)
593       {
594         Dali::Integration::Scene scene = mScene.GetHandle();
595         if(scene)
596         {
597           if(scene.IsRotationCompletedAcknowledgementSet())
598           {
599             needWindowRotationCompleted = true;
600           }
601         }
602       }
603       else
604       {
605         if(mIsResizing)
606         {
607           needWindowRotationCompleted = true;
608         }
609       }
610     }
611
612     if(needWindowRotationCompleted || mIsImeWindowSurface)
613     {
614       if(mThreadSynchronization)
615       {
616         // Enable PostRender flag
617         mThreadSynchronization->PostRenderStarted();
618       }
619
620       if(!mWindowRotationFinished || mIsImeWindowSurface)
621       {
622         mPostRenderTrigger->Trigger();
623       }
624
625       if(mThreadSynchronization)
626       {
627         // Wait until the event-thread complete the rotation event processing
628         mThreadSynchronization->PostRenderWaitForCompletion();
629       }
630     }
631
632     SwapBuffers(mDamagedRects);
633
634     if(mRenderNotification)
635     {
636       mRenderNotification->Trigger();
637     }
638   }
639 }
640
641 void WindowRenderSurface::StopRender()
642 {
643 }
644
645 void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
646 {
647   DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n");
648
649   mThreadSynchronization = &threadSynchronization;
650 }
651
652 void WindowRenderSurface::ReleaseLock()
653 {
654   // Nothing to do.
655 }
656
657 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
658 {
659   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
660 }
661
662 void WindowRenderSurface::MakeContextCurrent()
663 {
664   if(mEGL != nullptr)
665   {
666     mEGL->MakeContextCurrent(mEGLSurface, mEGLContext);
667   }
668 }
669
670 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
671 {
672   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
673 }
674
675 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
676 {
677   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
678 }
679
680 void WindowRenderSurface::InitializeImeSurface()
681 {
682   mIsImeWindowSurface = true;
683   if(!mPostRenderTrigger)
684   {
685     mPostRenderTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender),
686                                                                                                         TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
687   }
688 }
689
690 void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement)
691 {
692   mNeedWindowRotationAcknowledgement = needAcknowledgement;
693 }
694
695 void WindowRenderSurface::OutputTransformed()
696 {
697   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
698
699   if(mScreenRotationAngle != screenRotationAngle)
700   {
701     mScreenRotationAngle    = screenRotationAngle;
702     mScreenRotationFinished = false;
703     mResizeFinished         = false;
704
705     mOutputTransformedSignal.Emit();
706
707     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mWindowRotationAngle, mScreenRotationAngle);
708   }
709   else
710   {
711     DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle);
712   }
713 }
714
715 bool WindowRenderSurface::IsWindowRotating() const
716 {
717   return !(mWindowRotationFinished);
718 }
719
720 void WindowRenderSurface::ProcessPostRender()
721 {
722   if(!mWindowRotationFinished)
723   {
724     mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
725     mWindowRotationFinished = true;
726     DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mWindowRotationFinished);
727   }
728
729   if(mIsImeWindowSurface)
730   {
731     mWindowBase->ImeWindowReadyToRender();
732   }
733
734   if(mThreadSynchronization)
735   {
736     mThreadSynchronization->PostRenderComplete();
737   }
738 }
739
740 void WindowRenderSurface::ProcessFrameCallback()
741 {
742   Dali::Mutex::ScopedLock lock(mMutex);
743
744   for(auto&& iter : mFrameCallbackInfoContainer)
745   {
746     if(!iter->fileDescriptorMonitor)
747     {
748       iter->fileDescriptorMonitor = std::unique_ptr<FileDescriptorMonitor>(new FileDescriptorMonitor(iter->fileDescriptor,
749                                                                                                      MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched),
750                                                                                                      FileDescriptorMonitor::FD_READABLE));
751
752       DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor);
753     }
754   }
755 }
756
757 void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor)
758 {
759   if(!(eventBitMask & FileDescriptorMonitor::FD_READABLE))
760   {
761     DALI_LOG_ERROR("WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask);
762     close(fileDescriptor);
763     return;
764   }
765
766   DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor);
767
768   std::unique_ptr<FrameCallbackInfo> callbackInfo;
769   {
770     Dali::Mutex::ScopedLock lock(mMutex);
771     auto                    frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
772       return callbackInfo->fileDescriptor == fileDescriptor;
773     });
774     if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
775     {
776       callbackInfo = std::move(*frameCallbackInfo);
777
778       mFrameCallbackInfoContainer.erase(frameCallbackInfo);
779     }
780   }
781
782   // Call the connected callback
783   if(callbackInfo)
784   {
785     for(auto&& iter : (callbackInfo)->callbacks)
786     {
787       CallbackBase::Execute(*(iter.first), iter.second);
788     }
789   }
790 }
791
792 void WindowRenderSurface::SetBufferDamagedRects(const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect)
793 {
794   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
795   if(eglGraphics)
796   {
797     // If scene is not exist, just use stored mPositionSize.
798     Rect<int> surfaceRect(0, 0, mPositionSize.width, mPositionSize.height);
799
800     Dali::Integration::Scene scene = mScene.GetHandle();
801     if(scene)
802     {
803       surfaceRect = scene.GetCurrentSurfaceRect();
804     }
805
806     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
807     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame)
808     {
809       InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
810       clippingRect = surfaceRect;
811       return;
812     }
813
814     mGraphics->ActivateSurfaceContext(this);
815
816     EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface);
817
818     // Buffer age 0 means the back buffer in invalid and requires full swap
819     if(bufferAge == 0)
820     {
821       InsertRects(mBufferDamagedRects, std::vector<Rect<int>>(1, surfaceRect));
822       clippingRect = surfaceRect;
823       return;
824     }
825
826     // We push current frame damaged rects here, zero index for current frame
827     InsertRects(mBufferDamagedRects, damagedRects);
828
829     // Merge damaged rects into clipping rect
830     auto bufferDamagedRects = mBufferDamagedRects.begin();
831     while(bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end())
832     {
833       const std::vector<Rect<int>>& rects = *bufferDamagedRects++;
834       MergeRects(clippingRect, rects);
835     }
836
837     if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)
838     {
839       // clipping area too big or doesn't intersect surface rect
840       clippingRect = surfaceRect;
841       return;
842     }
843
844     if(!clippingRect.IsEmpty())
845     {
846       std::vector<Rect<int>> damagedRegion;
847       if(scene)
848       {
849         damagedRegion.push_back(RecalculateRect[std::min(scene.GetCurrentSurfaceOrientation() / 90, 3)](clippingRect, scene.GetCurrentSurfaceRect()));
850       }
851       else
852       {
853         damagedRegion.push_back(clippingRect);
854       }
855
856       eglImpl.SetDamageRegion(mEGLSurface, damagedRegion);
857     }
858   }
859 }
860
861 void WindowRenderSurface::SwapBuffers(const std::vector<Rect<int>>& damagedRects)
862 {
863   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
864   if(eglGraphics)
865   {
866     Rect<int32_t> surfaceRect;
867     int32_t       orientation = 0;
868
869     Dali::Integration::Scene scene = mScene.GetHandle();
870     if(scene)
871     {
872       surfaceRect = scene.GetCurrentSurfaceRect();
873       orientation = std::min(scene.GetCurrentSurfaceOrientation() / 90, 3);
874     }
875
876     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
877
878     if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || (damagedRects.size() != 0 && damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
879     {
880       mFullSwapNextFrame = false;
881       eglImpl.SwapBuffers(mEGLSurface);
882       return;
883     }
884
885     mFullSwapNextFrame = false;
886
887     std::vector<Rect<int>> mergedRects = damagedRects;
888
889     // Merge intersecting rects, form an array of non intersecting rects to help driver a bit
890     // Could be optional and can be removed, needs to be checked with and without on platform
891     const int n = mergedRects.size();
892     for(int i = 0; i < n - 1; i++)
893     {
894       if(mergedRects[i].IsEmpty())
895       {
896         continue;
897       }
898
899       for(int j = i + 1; j < n; j++)
900       {
901         if(mergedRects[j].IsEmpty())
902         {
903           continue;
904         }
905
906         if(mergedRects[i].Intersects(mergedRects[j]))
907         {
908           mergedRects[i].Merge(mergedRects[j]);
909           mergedRects[j].width  = 0;
910           mergedRects[j].height = 0;
911         }
912       }
913     }
914
915     int j = 0;
916     for(int i = 0; i < n; i++)
917     {
918       if(!mergedRects[i].IsEmpty())
919       {
920         mergedRects[j++] = RecalculateRect[orientation](mergedRects[i], surfaceRect);
921       }
922     }
923
924     if(j != 0)
925     {
926       mergedRects.resize(j);
927     }
928
929     if(!mergedRects.size() || (mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO))
930     {
931       // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0.
932       // For exceptional cases, swap full area.
933       eglImpl.SwapBuffers(mEGLSurface);
934     }
935     else
936     {
937       eglImpl.SwapBuffers(mEGLSurface, mergedRects);
938     }
939   }
940 }
941
942 } // namespace Adaptor
943
944 } // namespace Internal
945
946 } // namespace Dali