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;
118 Any WindowRenderSurface::GetNativeWindow()
120 return mWindowBase->GetNativeWindow();
123 int WindowRenderSurface::GetNativeWindowId()
125 return mWindowBase->GetNativeWindowId();
128 void WindowRenderSurface::Map()
133 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
135 mRenderNotification = renderNotification;
138 void WindowRenderSurface::SetTransparency( bool transparent )
140 mWindowBase->SetTransparency( transparent );
143 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
145 if( !mRotationSupported )
147 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
151 if( !mRotationTrigger )
153 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
156 mPositionSize.width = width;
157 mPositionSize.height = height;
159 mRotationAngle = angle;
160 mRotationFinished = false;
162 mWindowBase->SetWindowRotationAngle( mRotationAngle );
164 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
167 WindowBase* WindowRenderSurface::GetWindowBase()
169 return mWindowBase.get();
172 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
174 return mOutputTransformedSignal;
177 PositionSize WindowRenderSurface::GetPositionSize() const
179 return mPositionSize;
182 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
184 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
186 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
187 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
189 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
190 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
192 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
194 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
198 dpiHorizontal = mDpiHorizontal;
199 dpiVertical = mDpiVertical;
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 // Window rotate or screen rotate
424 if( !mRotationFinished || !mScreenRotationFinished )
426 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
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 mWindowBase->ResizeEglWindow( mPositionSize );
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;
565 mOutputTransformedSignal.Emit();
567 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
571 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
575 void WindowRenderSurface::ProcessRotationRequest()
577 mRotationFinished = true;
579 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
581 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
583 if( mThreadSynchronization )
585 mThreadSynchronization->PostRenderComplete();
589 void WindowRenderSurface::ProcessFrameCallback()
591 for( auto&& iter : mFrameCallbackInfoContainer )
593 if( !iter->fileDescriptorMonitor )
595 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
596 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
598 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
603 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
605 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
607 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
608 close( fileDescriptor );
612 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
614 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
615 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
617 return callbackInfo->fileDescriptor == fileDescriptor;
619 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
621 // Call the connected callback
622 for( auto&& iter : ( *frameCallbackInfo )->callbacks )
624 CallbackBase::Execute( *( iter.first ), iter.second );
626 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
630 } // namespace Adaptor
632 } // namespace internal