Merge "Add comment in the capture.h" into devel/master
[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   if( mScene )
362   {
363     mScene->GetFrameRenderedCallback( callbacks );
364     if( !callbacks.empty() )
365     {
366       int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
367       if( frameRenderedSync != -1 )
368       {
369         DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
370
371         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
372
373         if( !mFrameRenderedTrigger )
374         {
375           mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
376                                                                                                                      TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
377         }
378         mFrameRenderedTrigger->Trigger();
379       }
380       else
381       {
382         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
383       }
384
385       // Clear callbacks
386       callbacks.clear();
387     }
388
389     mScene->GetFramePresentedCallback( callbacks );
390     if( !callbacks.empty() )
391     {
392       int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
393       if( framePresentedSync != -1 )
394       {
395         DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
396
397         mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
398
399         if( !mFrameRenderedTrigger )
400         {
401           mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
402                                                                                                                      TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
403         }
404         mFrameRenderedTrigger->Trigger();
405       }
406       else
407       {
408         DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
409       }
410
411       // Clear callbacks
412       callbacks.clear();
413     }
414   }
415
416   MakeContextCurrent();
417
418   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
419
420   if( resizingSurface )
421   {
422     // Window rotate or screen rotate
423     if( !mRotationFinished || !mScreenRotationFinished )
424     {
425       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
426
427       mWindowBase->SetEglWindowRotation( totalAngle );
428       mWindowBase->SetEglWindowBufferTransform( totalAngle );
429
430       // Reset only screen rotation flag
431       mScreenRotationFinished = true;
432
433       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
434     }
435
436     // Only window rotate
437     if( !mRotationFinished )
438     {
439       mWindowBase->SetEglWindowTransform( mRotationAngle );
440     }
441
442     // Resize case
443     if( !mResizeFinished )
444     {
445       mWindowBase->ResizeEglWindow( mPositionSize );
446       mResizeFinished = true;
447
448       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
449     }
450
451     if (eglGraphics)
452     {
453       Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
454       eglImpl.SetFullSwapNextFrame();
455     }
456   }
457
458   if (eglGraphics)
459   {
460     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
461     eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
462   }
463
464   return true;
465 }
466
467 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
468 {
469   // Inform the gl implementation that rendering has finished before informing the surface
470   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
471   if ( eglGraphics )
472   {
473     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
474     mGLES.PostRender();
475
476     if( renderToFbo )
477     {
478       mGLES.Flush();
479       mGLES.Finish();
480     }
481     else
482     {
483       if( resizingSurface )
484       {
485         if( !mRotationFinished )
486         {
487           if( mThreadSynchronization )
488           {
489             // Enable PostRender flag
490             mThreadSynchronization->PostRenderStarted();
491           }
492
493           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
494
495           mRotationTrigger->Trigger();
496
497           if( mThreadSynchronization )
498           {
499             // Wait until the event-thread complete the rotation event processing
500             mThreadSynchronization->PostRenderWaitForCompletion();
501           }
502         }
503       }
504     }
505
506     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
507     eglImpl.SwapBuffers( mEGLSurface, damagedRects );
508
509     if( mRenderNotification )
510     {
511       mRenderNotification->Trigger();
512     }
513   }
514 }
515
516 void WindowRenderSurface::StopRender()
517 {
518 }
519
520 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
521 {
522   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
523
524   mThreadSynchronization = &threadSynchronization;
525 }
526
527 void WindowRenderSurface::ReleaseLock()
528 {
529   // Nothing to do.
530 }
531
532 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
533 {
534   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
535 }
536
537 void WindowRenderSurface::MakeContextCurrent()
538 {
539   if ( mEGL != nullptr )
540   {
541     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
542   }
543 }
544
545 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
546 {
547   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
548 }
549
550 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
551 {
552   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
553 }
554
555 void WindowRenderSurface::OutputTransformed()
556 {
557   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
558
559   if( mScreenRotationAngle != screenRotationAngle )
560   {
561     mScreenRotationAngle = screenRotationAngle;
562     mScreenRotationFinished = false;
563
564     mOutputTransformedSignal.Emit();
565
566     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
567   }
568   else
569   {
570     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
571   }
572 }
573
574 void WindowRenderSurface::ProcessRotationRequest()
575 {
576   mRotationFinished = true;
577
578   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
579
580   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
581
582   if( mThreadSynchronization )
583   {
584     mThreadSynchronization->PostRenderComplete();
585   }
586 }
587
588 void WindowRenderSurface::ProcessFrameCallback()
589 {
590   for( auto&& iter : mFrameCallbackInfoContainer )
591   {
592     if( !iter->fileDescriptorMonitor )
593     {
594       iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
595                                                                              MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
596
597       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
598     }
599   }
600 }
601
602 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
603 {
604   if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
605   {
606     DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
607     close( fileDescriptor );
608     return;
609   }
610
611   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
612
613   auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
614                                     [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
615                                     {
616                                       return callbackInfo->fileDescriptor == fileDescriptor;
617                                     } );
618   if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
619   {
620     // Call the connected callback
621     for( auto&& iter : ( *frameCallbackInfo )->callbacks )
622     {
623       CallbackBase::Execute( *( iter.first ), iter.second );
624     }
625     mFrameCallbackInfoContainer.erase( frameCallbackInfo );
626   }
627 }
628
629 } // namespace Adaptor
630
631 } // namespace internal
632
633 } // namespace Dali