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(),
71 mScreenRotationAngle( 0 ),
73 mRotationSupported( false ),
74 mRotationFinished( true ),
75 mScreenRotationFinished( true ),
76 mResizeFinished( true ),
80 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
81 Initialize( surface );
84 WindowRenderSurface::~WindowRenderSurface()
86 if( mRotationTrigger )
88 delete mRotationTrigger;
92 void WindowRenderSurface::Initialize( Any surface )
94 // If width or height are zero, go full screen.
95 if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
97 // Default window size == screen size
100 WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
103 // Create a window base
104 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
105 mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
108 mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
110 // Check screen rotation
111 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
112 if( mScreenRotationAngle != 0 )
114 mScreenRotationFinished = false;
115 mResizeFinished = false;
119 Any WindowRenderSurface::GetNativeWindow()
121 return mWindowBase->GetNativeWindow();
124 int WindowRenderSurface::GetNativeWindowId()
126 return mWindowBase->GetNativeWindowId();
129 void WindowRenderSurface::Map()
134 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
136 mRenderNotification = renderNotification;
139 void WindowRenderSurface::SetTransparency( bool transparent )
141 mWindowBase->SetTransparency( transparent );
144 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
146 if( !mRotationTrigger )
148 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
151 mPositionSize.width = width;
152 mPositionSize.height = height;
154 mRotationAngle = angle;
155 mRotationFinished = false;
157 mWindowBase->SetWindowRotationAngle( mRotationAngle );
159 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
162 WindowBase* WindowRenderSurface::GetWindowBase()
164 return mWindowBase.get();
167 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
169 return mOutputTransformedSignal;
172 PositionSize WindowRenderSurface::GetPositionSize() const
174 return mPositionSize;
177 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
179 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
181 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
182 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
184 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
185 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
187 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
189 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
193 dpiHorizontal = mDpiHorizontal;
194 dpiVertical = mDpiVertical;
197 int WindowRenderSurface::GetOrientation() const
199 return mWindowBase->GetOrientation();
202 void WindowRenderSurface::InitializeGraphics()
204 mGraphics = &mAdaptor->GetGraphicsInterface();
206 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
208 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
209 mEGL = &eglGraphics->GetEglInterface();
211 if ( mEGLContext == NULL )
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 );
218 // Create the OpenGL surface
223 void WindowRenderSurface::CreateSurface()
225 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
228 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
230 width = mPositionSize.width;
231 height = mPositionSize.height;
235 width = mPositionSize.height;
236 height = mPositionSize.width;
239 // Create the EGL window
240 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
242 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
244 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
245 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
247 // Check rotation capability
248 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
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 );
254 void WindowRenderSurface::DestroySurface()
256 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
258 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
261 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
263 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
265 eglImpl.DestroySurface( mEGLSurface );
266 mEGLSurface = nullptr;
268 // Destroy context also
269 eglImpl.DestroyContext( mEGLContext );
270 mEGLContext = nullptr;
272 mWindowBase->DestroyEglWindow();
276 bool WindowRenderSurface::ReplaceGraphicsSurface()
278 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
280 // Destroy the old one
281 mWindowBase->DestroyEglWindow();
284 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
286 width = mPositionSize.width;
287 height = mPositionSize.height;
291 width = mPositionSize.height;
292 height = mPositionSize.width;
295 // Create the EGL window
296 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
298 // Set screen rotation
299 mScreenRotationFinished = false;
301 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
303 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
304 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
307 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
309 bool needToMove = false;
310 bool needToResize = false;
313 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
314 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
320 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
321 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
330 mWindowBase->MoveResize( positionSize );
334 mWindowBase->Resize( positionSize );
337 mResizeFinished = false;
338 mPositionSize = positionSize;
344 mWindowBase->Move( positionSize );
346 mPositionSize = positionSize;
350 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
353 void WindowRenderSurface::StartRender()
357 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
359 Dali::Integration::Scene::FrameCallbackContainer callbacks;
361 Dali::Integration::Scene scene = mScene.GetHandle();
364 scene.GetFrameRenderedCallback( callbacks );
365 if( !callbacks.empty() )
367 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
368 if( frameRenderedSync != -1 )
370 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
372 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
374 if( !mFrameRenderedTrigger )
376 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
377 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
379 mFrameRenderedTrigger->Trigger();
383 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
390 scene.GetFramePresentedCallback( callbacks );
391 if( !callbacks.empty() )
393 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
394 if( framePresentedSync != -1 )
396 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
398 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
400 if( !mFrameRenderedTrigger )
402 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
403 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
405 mFrameRenderedTrigger->Trigger();
409 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
417 MakeContextCurrent();
419 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
421 if( resizingSurface )
423 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
425 // Window rotate or screen rotate
426 if( !mRotationFinished || !mScreenRotationFinished )
428 mWindowBase->SetEglWindowRotation( totalAngle );
429 mWindowBase->SetEglWindowBufferTransform( totalAngle );
431 // Reset only screen rotation flag
432 mScreenRotationFinished = true;
434 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
437 // Only window rotate
438 if( !mRotationFinished )
440 mWindowBase->SetEglWindowTransform( mRotationAngle );
444 if ( !mResizeFinished )
446 Dali::PositionSize positionSize;
447 positionSize.x = mPositionSize.x;
448 positionSize.y = mPositionSize.y;
449 if( totalAngle == 0 || totalAngle == 180 )
451 positionSize.width = mPositionSize.width;
452 positionSize.height = mPositionSize.height;
456 positionSize.width = mPositionSize.height;
457 positionSize.height = mPositionSize.width;
459 mWindowBase->ResizeEglWindow( positionSize );
460 mResizeFinished = true;
462 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
467 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
468 eglImpl.SetFullSwapNextFrame();
474 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
475 eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
481 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
483 // Inform the gl implementation that rendering has finished before informing the surface
484 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
487 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
497 if( resizingSurface )
499 if( !mRotationFinished )
501 if( mThreadSynchronization )
503 // Enable PostRender flag
504 mThreadSynchronization->PostRenderStarted();
507 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
509 mRotationTrigger->Trigger();
511 if( mThreadSynchronization )
513 // Wait until the event-thread complete the rotation event processing
514 mThreadSynchronization->PostRenderWaitForCompletion();
520 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
521 eglImpl.SwapBuffers( mEGLSurface, damagedRects );
523 if( mRenderNotification )
525 mRenderNotification->Trigger();
530 void WindowRenderSurface::StopRender()
534 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
536 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
538 mThreadSynchronization = &threadSynchronization;
541 void WindowRenderSurface::ReleaseLock()
546 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
548 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
551 void WindowRenderSurface::MakeContextCurrent()
553 if ( mEGL != nullptr )
555 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
559 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
561 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
564 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
566 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
569 void WindowRenderSurface::OutputTransformed()
571 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
573 if( mScreenRotationAngle != screenRotationAngle )
575 mScreenRotationAngle = screenRotationAngle;
576 mScreenRotationFinished = false;
577 mResizeFinished = false;
579 mOutputTransformedSignal.Emit();
581 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
585 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
589 void WindowRenderSurface::ProcessRotationRequest()
591 mRotationFinished = true;
593 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
595 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
597 if( mThreadSynchronization )
599 mThreadSynchronization->PostRenderComplete();
603 void WindowRenderSurface::ProcessFrameCallback()
605 for( auto&& iter : mFrameCallbackInfoContainer )
607 if( !iter->fileDescriptorMonitor )
609 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
610 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
612 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
617 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
619 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
621 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
622 close( fileDescriptor );
626 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
628 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
629 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
631 return callbackInfo->fileDescriptor == fileDescriptor;
633 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
635 // Call the connected callback
636 for( auto&& iter : ( *frameCallbackInfo )->callbacks )
638 CallbackBase::Execute( *( iter.first ), iter.second );
640 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
644 } // namespace Adaptor
646 } // namespace internal