[Tizen] Fix screen rotation bug when application is initialized
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / common / window-render-surface.cpp
1 /*
2  * Copyright (c) 2020 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/gl-abstraction.h>
23 #include <dali/integration-api/debug.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/window-system/common/window-base.h>
33 #include <dali/internal/window-system/common/window-factory.h>
34 #include <dali/internal/window-system/common/window-system.h>
35 #include <dali/internal/system/common/environment-variables.h>
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace Adaptor
42 {
43
44 namespace
45 {
46
47 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
48
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
51 #endif
52
53 } // unnamed namespace
54
55 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
56 : mEGL( nullptr ),
57   mDisplayConnection( nullptr ),
58   mPositionSize( positionSize ),
59   mWindowBase(),
60   mThreadSynchronization( NULL ),
61   mRenderNotification( NULL ),
62   mRotationTrigger( NULL ),
63   mFrameRenderedTrigger(),
64   mGraphics( nullptr ),
65   mEGLSurface( nullptr ),
66   mEGLContext( nullptr ),
67   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
68   mOutputTransformedSignal(),
69   mFrameCallbackInfoContainer(),
70   mRotationAngle( 0 ),
71   mScreenRotationAngle( 0 ),
72   mOwnSurface( false ),
73   mRotationSupported( false ),
74   mRotationFinished( true ),
75   mScreenRotationFinished( true ),
76   mResizeFinished( true ),
77   mDpiHorizontal( 0 ),
78   mDpiVertical( 0 )
79 {
80   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
81   Initialize( surface );
82 }
83
84 WindowRenderSurface::~WindowRenderSurface()
85 {
86   if( mRotationTrigger )
87   {
88     delete mRotationTrigger;
89   }
90 }
91
92 void WindowRenderSurface::Initialize( Any surface )
93 {
94   // If width or height are zero, go full screen.
95   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
96   {
97     // Default window size == screen size
98     mPositionSize.x = 0;
99     mPositionSize.y = 0;
100     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
101   }
102
103   // Create a window base
104   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
105   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
106
107   // Connect signals
108   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
109 }
110
111 Any WindowRenderSurface::GetNativeWindow()
112 {
113   return mWindowBase->GetNativeWindow();
114 }
115
116 int WindowRenderSurface::GetNativeWindowId()
117 {
118   return mWindowBase->GetNativeWindowId();
119 }
120
121 void WindowRenderSurface::Map()
122 {
123   mWindowBase->Show();
124 }
125
126 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
127 {
128   mRenderNotification = renderNotification;
129 }
130
131 void WindowRenderSurface::SetTransparency( bool transparent )
132 {
133   mWindowBase->SetTransparency( transparent );
134 }
135
136 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
137 {
138   if( !mRotationTrigger )
139   {
140     mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
141   }
142
143   mPositionSize.width = width;
144   mPositionSize.height = height;
145
146   mRotationAngle = angle;
147   mRotationFinished = false;
148
149   mWindowBase->SetWindowRotationAngle( mRotationAngle );
150
151   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
152 }
153
154 WindowBase* WindowRenderSurface::GetWindowBase()
155 {
156   return mWindowBase.get();
157 }
158
159 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
160 {
161   return mOutputTransformedSignal;
162 }
163
164 PositionSize WindowRenderSurface::GetPositionSize() const
165 {
166   return mPositionSize;
167 }
168
169 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
170 {
171   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
172   {
173     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
174     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
175
176     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
177     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
178
179     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
180     {
181       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
182     }
183   }
184
185   dpiHorizontal = mDpiHorizontal;
186   dpiVertical = mDpiVertical;
187 }
188
189 int WindowRenderSurface::GetOrientation() const
190 {
191   return mWindowBase->GetOrientation();
192 }
193
194 void WindowRenderSurface::InitializeGraphics()
195 {
196   mGraphics = &mAdaptor->GetGraphicsInterface();
197
198   DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
199
200   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
201   mEGL = &eglGraphics->GetEglInterface();
202
203   if ( mEGLContext == NULL )
204   {
205     // Create the OpenGL context for this window
206     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
207     eglImpl.ChooseConfig(true, mColorDepth);
208     eglImpl.CreateWindowContext( mEGLContext );
209
210     // Create the OpenGL surface
211     CreateSurface();
212   }
213 }
214
215 void WindowRenderSurface::CreateSurface()
216 {
217   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
218
219   // Create the EGL window
220   EGLNativeWindowType window = mWindowBase->CreateEglWindow( mPositionSize.width, mPositionSize.height );
221
222   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
223
224   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
225   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
226
227   // Check rotation capability
228   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
229
230   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
231       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
232 }
233
234 void WindowRenderSurface::DestroySurface()
235 {
236   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
237
238   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
239   if( eglGraphics )
240   {
241     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
242
243     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
244
245     eglImpl.DestroySurface( mEGLSurface );
246     mEGLSurface = nullptr;
247
248     // Destroy context also
249     eglImpl.DestroyContext( mEGLContext );
250     mEGLContext = nullptr;
251
252     mWindowBase->DestroyEglWindow();
253   }
254 }
255
256 bool WindowRenderSurface::ReplaceGraphicsSurface()
257 {
258   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
259
260   // Destroy the old one
261   mWindowBase->DestroyEglWindow();
262
263   int width, height;
264   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
265   {
266     width = mPositionSize.width;
267     height = mPositionSize.height;
268   }
269   else
270   {
271     width = mPositionSize.height;
272     height = mPositionSize.width;
273   }
274
275   // Create the EGL window
276   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
277
278   // Set screen rotation
279   mScreenRotationFinished = false;
280
281   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
282
283   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
284   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
285 }
286
287 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
288 {
289   bool needToMove = false;
290   bool needToResize = false;
291
292   // Check moving
293   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
294       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
295   {
296     needToMove = true;
297   }
298
299   // Check resizing
300   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
301       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
302   {
303     needToResize = true;
304   }
305
306   if( needToResize )
307   {
308     if( needToMove )
309     {
310       mWindowBase->MoveResize( positionSize );
311     }
312     else
313     {
314       mWindowBase->Resize( positionSize );
315     }
316
317     mResizeFinished = false;
318     mPositionSize = positionSize;
319   }
320   else
321   {
322     if( needToMove )
323     {
324       mWindowBase->Move( positionSize );
325
326       mPositionSize = positionSize;
327     }
328   }
329
330   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
331 }
332
333 void WindowRenderSurface::StartRender()
334 {
335 }
336
337 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
338 {
339   Dali::Integration::Scene::FrameCallbackContainer callbacks;
340
341   Dali::Integration::Scene scene = mScene.GetHandle();
342   if( scene )
343   {
344     scene.GetFrameRenderedCallback( callbacks );
345     if( !callbacks.empty() )
346     {
347       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
348       if( frameRenderedSync != -1 )
349       {
350         DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
351
352         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
353
354         if( !mFrameRenderedTrigger )
355         {
356           mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
357                                                                                                                      TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
358         }
359         mFrameRenderedTrigger->Trigger();
360       }
361       else
362       {
363         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
364       }
365
366       // Clear callbacks
367       callbacks.clear();
368     }
369
370     scene.GetFramePresentedCallback( callbacks );
371     if( !callbacks.empty() )
372     {
373       int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
374       if( framePresentedSync != -1 )
375       {
376         DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
377
378         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
379
380         if( !mFrameRenderedTrigger )
381         {
382           mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
383                                                                                                                      TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
384         }
385         mFrameRenderedTrigger->Trigger();
386       }
387       else
388       {
389         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
390       }
391
392       // Clear callbacks
393       callbacks.clear();
394     }
395   }
396
397   MakeContextCurrent();
398
399   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
400
401   if( resizingSurface )
402   {
403     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
404
405     // Window rotate or screen rotate
406     if( !mRotationFinished || !mScreenRotationFinished )
407     {
408       mWindowBase->SetEglWindowRotation( totalAngle );
409       mWindowBase->SetEglWindowBufferTransform( totalAngle );
410
411       // Reset only screen rotation flag
412       mScreenRotationFinished = true;
413
414       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
415     }
416
417     // Only window rotate
418     if( !mRotationFinished )
419     {
420       mWindowBase->SetEglWindowTransform( mRotationAngle );
421     }
422
423     // Resize case
424     if ( !mResizeFinished )
425     {
426       Dali::PositionSize positionSize;
427       positionSize.x = mPositionSize.x;
428       positionSize.y = mPositionSize.y;
429       if( totalAngle == 0 || totalAngle == 180 )
430       {
431         positionSize.width = mPositionSize.width;
432         positionSize.height = mPositionSize.height;
433       }
434       else
435       {
436         positionSize.width = mPositionSize.height;
437         positionSize.height = mPositionSize.width;
438       }
439       mWindowBase->ResizeEglWindow( positionSize );
440       mResizeFinished = true;
441
442       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
443     }
444
445     if (eglGraphics)
446     {
447       Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
448       eglImpl.SetFullSwapNextFrame();
449     }
450   }
451
452   if (eglGraphics)
453   {
454     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
455     eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
456   }
457
458   return true;
459 }
460
461 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
462 {
463   // Inform the gl implementation that rendering has finished before informing the surface
464   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
465   if ( eglGraphics )
466   {
467     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
468     mGLES.PostRender();
469
470     if( renderToFbo )
471     {
472       mGLES.Flush();
473       mGLES.Finish();
474     }
475     else
476     {
477       if( resizingSurface )
478       {
479         if( !mRotationFinished )
480         {
481           if( mThreadSynchronization )
482           {
483             // Enable PostRender flag
484             mThreadSynchronization->PostRenderStarted();
485           }
486
487           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
488
489           mRotationTrigger->Trigger();
490
491           if( mThreadSynchronization )
492           {
493             // Wait until the event-thread complete the rotation event processing
494             mThreadSynchronization->PostRenderWaitForCompletion();
495           }
496         }
497       }
498     }
499
500     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
501     eglImpl.SwapBuffers( mEGLSurface, damagedRects );
502
503     if( mRenderNotification )
504     {
505       mRenderNotification->Trigger();
506     }
507   }
508 }
509
510 void WindowRenderSurface::StopRender()
511 {
512 }
513
514 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
515 {
516   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
517
518   mThreadSynchronization = &threadSynchronization;
519 }
520
521 void WindowRenderSurface::ReleaseLock()
522 {
523   // Nothing to do.
524 }
525
526 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
527 {
528   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
529 }
530
531 void WindowRenderSurface::MakeContextCurrent()
532 {
533   if ( mEGL != nullptr )
534   {
535     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
536   }
537 }
538
539 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
540 {
541   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
542 }
543
544 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
545 {
546   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
547 }
548
549 void WindowRenderSurface::OutputTransformed()
550 {
551   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
552
553   if( mScreenRotationAngle != screenRotationAngle )
554   {
555     mScreenRotationAngle = screenRotationAngle;
556     mScreenRotationFinished = false;
557     mResizeFinished = false;
558
559     mOutputTransformedSignal.Emit();
560
561     DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
562   }
563   else
564   {
565     DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
566   }
567 }
568
569 void WindowRenderSurface::ProcessRotationRequest()
570 {
571   mRotationFinished = true;
572
573   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
574
575   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
576
577   if( mThreadSynchronization )
578   {
579     mThreadSynchronization->PostRenderComplete();
580   }
581 }
582
583 void WindowRenderSurface::ProcessFrameCallback()
584 {
585   for( auto&& iter : mFrameCallbackInfoContainer )
586   {
587     if( !iter->fileDescriptorMonitor )
588     {
589       iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
590                                                                              MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
591
592       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
593     }
594   }
595 }
596
597 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
598 {
599   if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
600   {
601     DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
602     close( fileDescriptor );
603     return;
604   }
605
606   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
607
608   auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
609                                     [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
610                                     {
611                                       return callbackInfo->fileDescriptor == fileDescriptor;
612                                     } );
613   if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
614   {
615     // Call the connected callback
616     for( auto&& iter : ( *frameCallbackInfo )->callbacks )
617     {
618       CallbackBase::Execute( *( iter.first ), iter.second );
619     }
620     mFrameCallbackInfoContainer.erase( frameCallbackInfo );
621   }
622 }
623
624 } // namespace Adaptor
625
626 } // namespace internal
627
628 } // namespace Dali