2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/window-system/common/window-render-surface.h>
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/debug.h>
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>
47 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
53 } // unnamed namespace
55 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
57 mDisplayConnection( nullptr ),
58 mPositionSize( positionSize ),
60 mThreadSynchronization( NULL ),
61 mRenderNotification( NULL ),
62 mRotationTrigger( NULL ),
63 mFrameRenderedTrigger(),
65 mEGLSurface( nullptr ),
66 mEGLContext( nullptr ),
67 mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
68 mOutputTransformedSignal(),
69 mFrameCallbackInfoContainer(),
72 mScreenRotationAngle( 0 ),
74 mRotationSupported( false ),
75 mRotationFinished( true ),
76 mScreenRotationFinished( true ),
77 mResizeFinished( true ),
81 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
82 Initialize( surface );
85 WindowRenderSurface::~WindowRenderSurface()
87 if( mRotationTrigger )
89 delete mRotationTrigger;
93 void WindowRenderSurface::Initialize( Any surface )
95 // If width or height are zero, go full screen.
96 if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
98 // Default window size == screen size
101 WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
104 // Create a window base
105 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
106 mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
109 mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
112 Any WindowRenderSurface::GetNativeWindow()
114 return mWindowBase->GetNativeWindow();
117 int WindowRenderSurface::GetNativeWindowId()
119 return mWindowBase->GetNativeWindowId();
122 void WindowRenderSurface::Map()
127 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
129 mRenderNotification = renderNotification;
132 void WindowRenderSurface::SetTransparency( bool transparent )
134 mWindowBase->SetTransparency( transparent );
137 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
139 if( !mRotationTrigger )
141 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
144 mPositionSize.width = width;
145 mPositionSize.height = height;
147 mRotationAngle = angle;
148 mRotationFinished = false;
150 mWindowBase->SetWindowRotationAngle( mRotationAngle );
152 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
155 WindowBase* WindowRenderSurface::GetWindowBase()
157 return mWindowBase.get();
160 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
162 return mOutputTransformedSignal;
165 PositionSize WindowRenderSurface::GetPositionSize() const
167 return mPositionSize;
170 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
172 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
174 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
175 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
177 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
178 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
180 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
182 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
186 dpiHorizontal = mDpiHorizontal;
187 dpiVertical = mDpiVertical;
190 int WindowRenderSurface::GetOrientation() const
192 return mWindowBase->GetOrientation();
195 void WindowRenderSurface::InitializeGraphics()
197 mGraphics = &mAdaptor->GetGraphicsInterface();
199 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
201 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
202 mEGL = &eglGraphics->GetEglInterface();
204 if ( mEGLContext == NULL )
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 );
211 // Create the OpenGL surface
216 void WindowRenderSurface::CreateSurface()
218 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
220 // Create the EGL window
221 EGLNativeWindowType window = mWindowBase->CreateEglWindow( mPositionSize.width, mPositionSize.height );
223 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
225 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
226 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
228 // Check rotation capability
229 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
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 );
235 void WindowRenderSurface::DestroySurface()
237 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
239 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
242 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
244 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
246 eglImpl.DestroySurface( mEGLSurface );
247 mEGLSurface = nullptr;
249 // Destroy context also
250 eglImpl.DestroyContext( mEGLContext );
251 mEGLContext = nullptr;
253 mWindowBase->DestroyEglWindow();
257 bool WindowRenderSurface::ReplaceGraphicsSurface()
259 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
261 // Destroy the old one
262 mWindowBase->DestroyEglWindow();
265 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
267 width = mPositionSize.width;
268 height = mPositionSize.height;
272 width = mPositionSize.height;
273 height = mPositionSize.width;
276 // Create the EGL window
277 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
279 // Set screen rotation
280 mScreenRotationFinished = false;
282 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
284 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
285 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
288 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
290 bool needToMove = false;
291 bool needToResize = false;
294 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
295 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
301 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
302 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
311 mWindowBase->MoveResize( positionSize );
315 mWindowBase->Resize( positionSize );
318 mResizeFinished = false;
319 mPositionSize = positionSize;
325 mWindowBase->Move( positionSize );
327 mPositionSize = positionSize;
331 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
334 void WindowRenderSurface::StartRender()
338 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
340 Dali::Integration::Scene::FrameCallbackContainer callbacks;
342 Dali::Integration::Scene scene = mScene.GetHandle();
345 bool needFrameRenderedTrigger = false;
347 scene.GetFrameRenderedCallback( callbacks );
348 if( !callbacks.empty() )
350 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
351 if( frameRenderedSync != -1 )
353 Dali::Mutex::ScopedLock lock( mMutex );
355 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
357 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
359 needFrameRenderedTrigger = true;
363 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
370 scene.GetFramePresentedCallback( callbacks );
371 if( !callbacks.empty() )
373 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
374 if( framePresentedSync != -1 )
376 Dali::Mutex::ScopedLock lock( mMutex );
378 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
380 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
382 needFrameRenderedTrigger = true;
386 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
393 if( needFrameRenderedTrigger )
395 if( !mFrameRenderedTrigger )
397 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
398 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
400 mFrameRenderedTrigger->Trigger();
404 MakeContextCurrent();
406 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
408 if( resizingSurface )
410 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
412 // Window rotate or screen rotate
413 if( !mRotationFinished || !mScreenRotationFinished )
415 mWindowBase->SetEglWindowRotation( totalAngle );
416 mWindowBase->SetEglWindowBufferTransform( totalAngle );
418 // Reset only screen rotation flag
419 mScreenRotationFinished = true;
421 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
424 // Only window rotate
425 if( !mRotationFinished )
427 mWindowBase->SetEglWindowTransform( mRotationAngle );
431 if ( !mResizeFinished )
433 Dali::PositionSize positionSize;
434 positionSize.x = mPositionSize.x;
435 positionSize.y = mPositionSize.y;
436 if( totalAngle == 0 || totalAngle == 180 )
438 positionSize.width = mPositionSize.width;
439 positionSize.height = mPositionSize.height;
443 positionSize.width = mPositionSize.height;
444 positionSize.height = mPositionSize.width;
446 mWindowBase->ResizeEglWindow( positionSize );
447 mResizeFinished = true;
449 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
454 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
455 eglImpl.SetFullSwapNextFrame();
461 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
462 eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
468 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
470 // Inform the gl implementation that rendering has finished before informing the surface
471 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
474 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
484 if( resizingSurface )
486 if( !mRotationFinished )
488 if( mThreadSynchronization )
490 // Enable PostRender flag
491 mThreadSynchronization->PostRenderStarted();
494 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
496 mRotationTrigger->Trigger();
498 if( mThreadSynchronization )
500 // Wait until the event-thread complete the rotation event processing
501 mThreadSynchronization->PostRenderWaitForCompletion();
507 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
508 eglImpl.SwapBuffers( mEGLSurface, damagedRects );
510 if( mRenderNotification )
512 mRenderNotification->Trigger();
517 void WindowRenderSurface::StopRender()
521 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
523 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
525 mThreadSynchronization = &threadSynchronization;
528 void WindowRenderSurface::ReleaseLock()
533 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
535 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
538 void WindowRenderSurface::MakeContextCurrent()
540 if ( mEGL != nullptr )
542 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
546 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
548 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
551 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
553 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
556 void WindowRenderSurface::OutputTransformed()
558 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
560 if( mScreenRotationAngle != screenRotationAngle )
562 mScreenRotationAngle = screenRotationAngle;
563 mScreenRotationFinished = false;
564 mResizeFinished = false;
566 mOutputTransformedSignal.Emit();
568 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
572 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
576 void WindowRenderSurface::ProcessRotationRequest()
578 mRotationFinished = true;
580 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
582 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
584 if( mThreadSynchronization )
586 mThreadSynchronization->PostRenderComplete();
590 void WindowRenderSurface::ProcessFrameCallback()
592 Dali::Mutex::ScopedLock lock( mMutex );
594 for( auto&& iter : mFrameCallbackInfoContainer )
596 if( !iter->fileDescriptorMonitor )
598 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
599 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
601 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
606 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
608 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
610 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
611 close( fileDescriptor );
615 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
617 std::unique_ptr< FrameCallbackInfo > callbackInfo;
619 Dali::Mutex::ScopedLock lock( mMutex );
620 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
621 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
623 return callbackInfo->fileDescriptor == fileDescriptor;
625 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
627 callbackInfo = std::move( *frameCallbackInfo );
629 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
633 // Call the connected callback
636 for( auto&& iter : ( callbackInfo )->callbacks )
638 CallbackBase::Execute( *( iter.first ), iter.second );
643 } // namespace Adaptor
645 } // namespace internal