2ec42bfe99da271689dc7e3ea5ea9296c6f46511
[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   mMutex(),
71   mRotationAngle( 0 ),
72   mScreenRotationAngle( 0 ),
73   mOwnSurface( false ),
74   mRotationSupported( false ),
75   mRotationFinished( true ),
76   mScreenRotationFinished( true ),
77   mResizeFinished( true ),
78   mDpiHorizontal( 0 ),
79   mDpiVertical( 0 )
80 {
81   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
82   Initialize( surface );
83 }
84
85 WindowRenderSurface::~WindowRenderSurface()
86 {
87   if( mRotationTrigger )
88   {
89     delete mRotationTrigger;
90   }
91 }
92
93 void WindowRenderSurface::Initialize( Any surface )
94 {
95   // If width or height are zero, go full screen.
96   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
97   {
98     // Default window size == screen size
99     mPositionSize.x = 0;
100     mPositionSize.y = 0;
101     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
102   }
103
104   // Create a window base
105   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
106   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
107
108   // Connect signals
109   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
110 }
111
112 Any WindowRenderSurface::GetNativeWindow()
113 {
114   return mWindowBase->GetNativeWindow();
115 }
116
117 int WindowRenderSurface::GetNativeWindowId()
118 {
119   return mWindowBase->GetNativeWindowId();
120 }
121
122 void WindowRenderSurface::Map()
123 {
124   mWindowBase->Show();
125 }
126
127 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
128 {
129   mRenderNotification = renderNotification;
130 }
131
132 void WindowRenderSurface::SetTransparency( bool transparent )
133 {
134   mWindowBase->SetTransparency( transparent );
135 }
136
137 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
138 {
139   if( !mRotationTrigger )
140   {
141     mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
142   }
143
144   mPositionSize.width = width;
145   mPositionSize.height = height;
146
147   mRotationAngle = angle;
148   mRotationFinished = false;
149
150   mWindowBase->SetWindowRotationAngle( mRotationAngle );
151
152   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
153 }
154
155 WindowBase* WindowRenderSurface::GetWindowBase()
156 {
157   return mWindowBase.get();
158 }
159
160 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
161 {
162   return mOutputTransformedSignal;
163 }
164
165 PositionSize WindowRenderSurface::GetPositionSize() const
166 {
167   return mPositionSize;
168 }
169
170 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
171 {
172   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
173   {
174     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
175     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
176
177     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
178     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
179
180     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
181     {
182       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
183     }
184   }
185
186   dpiHorizontal = mDpiHorizontal;
187   dpiVertical = mDpiVertical;
188 }
189
190 int WindowRenderSurface::GetOrientation() const
191 {
192   return mWindowBase->GetOrientation();
193 }
194
195 void WindowRenderSurface::InitializeGraphics()
196 {
197   mGraphics = &mAdaptor->GetGraphicsInterface();
198
199   DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
200
201   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
202   mEGL = &eglGraphics->GetEglInterface();
203
204   if ( mEGLContext == NULL )
205   {
206     // Create the OpenGL context for this window
207     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
208     eglImpl.ChooseConfig(true, mColorDepth);
209     eglImpl.CreateWindowContext( mEGLContext );
210
211     // Create the OpenGL surface
212     CreateSurface();
213   }
214 }
215
216 void WindowRenderSurface::CreateSurface()
217 {
218   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
219
220   // Create the EGL window
221   EGLNativeWindowType window = mWindowBase->CreateEglWindow( mPositionSize.width, mPositionSize.height );
222
223   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
224
225   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
226   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
227
228   // Check rotation capability
229   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
230
231   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
232       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
233 }
234
235 void WindowRenderSurface::DestroySurface()
236 {
237   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
238
239   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
240   if( eglGraphics )
241   {
242     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
243
244     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
245
246     eglImpl.DestroySurface( mEGLSurface );
247     mEGLSurface = nullptr;
248
249     // Destroy context also
250     eglImpl.DestroyContext( mEGLContext );
251     mEGLContext = nullptr;
252
253     mWindowBase->DestroyEglWindow();
254   }
255 }
256
257 bool WindowRenderSurface::ReplaceGraphicsSurface()
258 {
259   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
260
261   // Destroy the old one
262   mWindowBase->DestroyEglWindow();
263
264   int width, height;
265   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
266   {
267     width = mPositionSize.width;
268     height = mPositionSize.height;
269   }
270   else
271   {
272     width = mPositionSize.height;
273     height = mPositionSize.width;
274   }
275
276   // Create the EGL window
277   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
278
279   // Set screen rotation
280   mScreenRotationFinished = false;
281
282   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
283
284   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
285   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
286 }
287
288 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
289 {
290   bool needToMove = false;
291   bool needToResize = false;
292
293   // Check moving
294   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
295       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
296   {
297     needToMove = true;
298   }
299
300   // Check resizing
301   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
302       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
303   {
304     needToResize = true;
305   }
306
307   if( needToResize )
308   {
309     if( needToMove )
310     {
311       mWindowBase->MoveResize( positionSize );
312     }
313     else
314     {
315       mWindowBase->Resize( positionSize );
316     }
317
318     mResizeFinished = false;
319     mPositionSize = positionSize;
320   }
321   else
322   {
323     if( needToMove )
324     {
325       mWindowBase->Move( positionSize );
326
327       mPositionSize = positionSize;
328     }
329   }
330
331   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
332 }
333
334 void WindowRenderSurface::StartRender()
335 {
336 }
337
338 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
339 {
340   Dali::Integration::Scene::FrameCallbackContainer callbacks;
341
342   Dali::Integration::Scene scene = mScene.GetHandle();
343   if( scene )
344   {
345     bool needFrameRenderedTrigger = false;
346
347     scene.GetFrameRenderedCallback( callbacks );
348     if( !callbacks.empty() )
349     {
350       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
351       if( frameRenderedSync != -1 )
352       {
353         Dali::Mutex::ScopedLock lock( mMutex );
354
355         DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
356
357         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
358
359         needFrameRenderedTrigger = true;
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::Mutex::ScopedLock lock( mMutex );
377
378         DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
379
380         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
381
382         needFrameRenderedTrigger = true;
383       }
384       else
385       {
386         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
387       }
388
389       // Clear callbacks
390       callbacks.clear();
391     }
392
393     if( needFrameRenderedTrigger )
394     {
395       if( !mFrameRenderedTrigger )
396       {
397         mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
398                                                                                                                    TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
399       }
400       mFrameRenderedTrigger->Trigger();
401     }
402   }
403
404   MakeContextCurrent();
405
406   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
407
408   if( resizingSurface )
409   {
410     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
411
412     // Window rotate or screen rotate
413     if( !mRotationFinished || !mScreenRotationFinished )
414     {
415       mWindowBase->SetEglWindowRotation( totalAngle );
416       mWindowBase->SetEglWindowBufferTransform( totalAngle );
417
418       // Reset only screen rotation flag
419       mScreenRotationFinished = true;
420
421       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
422     }
423
424     // Only window rotate
425     if( !mRotationFinished )
426     {
427       mWindowBase->SetEglWindowTransform( mRotationAngle );
428     }
429
430     // Resize case
431     if ( !mResizeFinished )
432     {
433       Dali::PositionSize positionSize;
434       positionSize.x = mPositionSize.x;
435       positionSize.y = mPositionSize.y;
436       if( totalAngle == 0 || totalAngle == 180 )
437       {
438         positionSize.width = mPositionSize.width;
439         positionSize.height = mPositionSize.height;
440       }
441       else
442       {
443         positionSize.width = mPositionSize.height;
444         positionSize.height = mPositionSize.width;
445       }
446       mWindowBase->ResizeEglWindow( positionSize );
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     mResizeFinished = false;
565
566     mOutputTransformedSignal.Emit();
567
568     DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
569   }
570   else
571   {
572     DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
573   }
574 }
575
576 void WindowRenderSurface::ProcessRotationRequest()
577 {
578   mRotationFinished = true;
579
580   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
581
582   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
583
584   if( mThreadSynchronization )
585   {
586     mThreadSynchronization->PostRenderComplete();
587   }
588 }
589
590 void WindowRenderSurface::ProcessFrameCallback()
591 {
592   Dali::Mutex::ScopedLock lock( mMutex );
593
594   for( auto&& iter : mFrameCallbackInfoContainer )
595   {
596     if( !iter->fileDescriptorMonitor )
597     {
598       iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
599                                                                              MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
600
601       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
602     }
603   }
604 }
605
606 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
607 {
608   if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
609   {
610     DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
611     close( fileDescriptor );
612     return;
613   }
614
615   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
616
617   std::unique_ptr< FrameCallbackInfo > callbackInfo;
618   {
619     Dali::Mutex::ScopedLock lock( mMutex );
620     auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
621                                       [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
622                                       {
623                                         return callbackInfo->fileDescriptor == fileDescriptor;
624                                       } );
625     if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
626     {
627       callbackInfo = std::move( *frameCallbackInfo );
628
629       mFrameCallbackInfoContainer.erase( frameCallbackInfo );
630     }
631   }
632
633   // Call the connected callback
634   if( callbackInfo )
635   {
636     for( auto&& iter : ( callbackInfo )->callbacks )
637     {
638       CallbackBase::Execute( *( iter.first ), iter.second );
639     }
640   }
641 }
642
643 } // namespace Adaptor
644
645 } // namespace internal
646
647 } // namespace Dali