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 ),
78 mDefaultScreenRotationAvailable( false ),
82 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
83 Initialize( surface );
86 WindowRenderSurface::~WindowRenderSurface()
88 if( mRotationTrigger )
90 delete mRotationTrigger;
94 void WindowRenderSurface::Initialize( Any surface )
96 // If width or height are zero, go full screen.
97 if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
99 // Default window size == screen size
102 WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
105 // Create a window base
106 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
107 mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
110 mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
112 // Check screen rotation
113 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
114 if( mScreenRotationAngle != 0 )
116 mScreenRotationFinished = false;
117 mResizeFinished = false;
118 mDefaultScreenRotationAvailable = true;
119 DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", mScreenRotationAngle );
123 Any WindowRenderSurface::GetNativeWindow()
125 return mWindowBase->GetNativeWindow();
128 int WindowRenderSurface::GetNativeWindowId()
130 return mWindowBase->GetNativeWindowId();
133 void WindowRenderSurface::Map()
138 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
140 mRenderNotification = renderNotification;
143 void WindowRenderSurface::SetTransparency( bool transparent )
145 mWindowBase->SetTransparency( transparent );
148 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
150 if( !mRotationTrigger )
152 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
155 mPositionSize.width = width;
156 mPositionSize.height = height;
158 mRotationAngle = angle;
159 mRotationFinished = false;
161 mWindowBase->SetWindowRotationAngle( mRotationAngle );
163 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
166 WindowBase* WindowRenderSurface::GetWindowBase()
168 return mWindowBase.get();
171 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
173 return mOutputTransformedSignal;
176 PositionSize WindowRenderSurface::GetPositionSize() const
178 return mPositionSize;
181 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
183 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
185 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
186 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
188 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
189 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
191 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
193 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
197 dpiHorizontal = mDpiHorizontal;
198 dpiVertical = mDpiVertical;
201 int WindowRenderSurface::GetOrientation() const
203 return mWindowBase->GetOrientation();
206 void WindowRenderSurface::InitializeGraphics()
208 mGraphics = &mAdaptor->GetGraphicsInterface();
210 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
212 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
213 mEGL = &eglGraphics->GetEglInterface();
215 if ( mEGLContext == NULL )
217 // Create the OpenGL context for this window
218 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
219 eglImpl.ChooseConfig(true, mColorDepth);
220 eglImpl.CreateWindowContext( mEGLContext );
222 // Create the OpenGL surface
227 void WindowRenderSurface::CreateSurface()
229 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
232 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
234 width = mPositionSize.width;
235 height = mPositionSize.height;
239 width = mPositionSize.height;
240 height = mPositionSize.width;
243 // Create the EGL window
244 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
246 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
248 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
249 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
251 // Check rotation capability
252 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
254 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
255 mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
258 void WindowRenderSurface::DestroySurface()
260 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
262 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
265 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
267 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
269 eglImpl.DestroySurface( mEGLSurface );
270 mEGLSurface = nullptr;
272 // Destroy context also
273 eglImpl.DestroyContext( mEGLContext );
274 mEGLContext = nullptr;
276 mWindowBase->DestroyEglWindow();
280 bool WindowRenderSurface::ReplaceGraphicsSurface()
282 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
284 // Destroy the old one
285 mWindowBase->DestroyEglWindow();
288 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
290 width = mPositionSize.width;
291 height = mPositionSize.height;
295 width = mPositionSize.height;
296 height = mPositionSize.width;
299 // Create the EGL window
300 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
302 // Set screen rotation
303 mScreenRotationFinished = false;
305 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
307 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
308 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
311 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
313 bool needToMove = false;
314 bool needToResize = false;
317 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
318 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
324 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
325 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
334 mWindowBase->MoveResize( positionSize );
338 mWindowBase->Resize( positionSize );
341 mResizeFinished = false;
342 mPositionSize = positionSize;
348 mWindowBase->Move( positionSize );
350 mPositionSize = positionSize;
354 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
357 void WindowRenderSurface::StartRender()
361 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
363 Dali::Integration::Scene::FrameCallbackContainer callbacks;
365 Dali::Integration::Scene scene = mScene.GetHandle();
368 bool needFrameRenderedTrigger = false;
370 scene.GetFrameRenderedCallback( callbacks );
371 if( !callbacks.empty() )
373 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
374 if( frameRenderedSync != -1 )
376 Dali::Mutex::ScopedLock lock( mMutex );
378 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
380 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
382 needFrameRenderedTrigger = true;
386 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
393 scene.GetFramePresentedCallback( callbacks );
394 if( !callbacks.empty() )
396 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
397 if( framePresentedSync != -1 )
399 Dali::Mutex::ScopedLock lock( mMutex );
401 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
403 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
405 needFrameRenderedTrigger = true;
409 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
416 if( needFrameRenderedTrigger )
418 if( !mFrameRenderedTrigger )
420 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
421 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
423 mFrameRenderedTrigger->Trigger();
427 MakeContextCurrent();
429 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
431 if( resizingSurface || mDefaultScreenRotationAvailable )
433 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
435 // Window rotate or screen rotate
436 if( !mRotationFinished || !mScreenRotationFinished )
438 mWindowBase->SetEglWindowRotation( totalAngle );
439 mWindowBase->SetEglWindowBufferTransform( totalAngle );
441 // Reset only screen rotation flag
442 mScreenRotationFinished = true;
444 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
447 // Only window rotate
448 if( !mRotationFinished )
450 mWindowBase->SetEglWindowTransform( mRotationAngle );
454 if ( !mResizeFinished )
456 Dali::PositionSize positionSize;
457 positionSize.x = mPositionSize.x;
458 positionSize.y = mPositionSize.y;
459 if( totalAngle == 0 || totalAngle == 180 )
461 positionSize.width = mPositionSize.width;
462 positionSize.height = mPositionSize.height;
466 positionSize.width = mPositionSize.height;
467 positionSize.height = mPositionSize.width;
469 mWindowBase->ResizeEglWindow( positionSize );
470 mResizeFinished = true;
472 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::PreRender: Set resize\n" );
477 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
478 eglImpl.SetFullSwapNextFrame();
480 mDefaultScreenRotationAvailable = false;
485 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
486 eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
492 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
494 // Inform the gl implementation that rendering has finished before informing the surface
495 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
498 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
508 if( resizingSurface )
510 if( !mRotationFinished )
512 if( mThreadSynchronization )
514 // Enable PostRender flag
515 mThreadSynchronization->PostRenderStarted();
518 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
520 mRotationTrigger->Trigger();
522 if( mThreadSynchronization )
524 // Wait until the event-thread complete the rotation event processing
525 mThreadSynchronization->PostRenderWaitForCompletion();
531 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
532 eglImpl.SwapBuffers( mEGLSurface, damagedRects );
534 if( mRenderNotification )
536 mRenderNotification->Trigger();
541 void WindowRenderSurface::StopRender()
545 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
547 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
549 mThreadSynchronization = &threadSynchronization;
552 void WindowRenderSurface::ReleaseLock()
557 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
559 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
562 void WindowRenderSurface::MakeContextCurrent()
564 if ( mEGL != nullptr )
566 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
570 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
572 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
575 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
577 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
580 void WindowRenderSurface::OutputTransformed()
582 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
584 if( mScreenRotationAngle != screenRotationAngle )
586 mScreenRotationAngle = screenRotationAngle;
587 mScreenRotationFinished = false;
588 mResizeFinished = false;
590 mOutputTransformedSignal.Emit();
592 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
596 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
600 void WindowRenderSurface::ProcessRotationRequest()
602 mRotationFinished = true;
604 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
606 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
608 if( mThreadSynchronization )
610 mThreadSynchronization->PostRenderComplete();
614 void WindowRenderSurface::ProcessFrameCallback()
616 Dali::Mutex::ScopedLock lock( mMutex );
618 for( auto&& iter : mFrameCallbackInfoContainer )
620 if( !iter->fileDescriptorMonitor )
622 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
623 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
625 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
630 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
632 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
634 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
635 close( fileDescriptor );
639 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
641 std::unique_ptr< FrameCallbackInfo > callbackInfo;
643 Dali::Mutex::ScopedLock lock( mMutex );
644 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
645 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
647 return callbackInfo->fileDescriptor == fileDescriptor;
649 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
651 callbackInfo = std::move( *frameCallbackInfo );
653 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
657 // Call the connected callback
660 for( auto&& iter : ( callbackInfo )->callbacks )
662 CallbackBase::Execute( *( iter.first ), iter.second );
667 } // namespace Adaptor
669 } // namespace internal