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