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 );
111 // Check screen rotation
112 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
113 if( mScreenRotationAngle != 0 )
115 mScreenRotationFinished = 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( !mRotationSupported )
148 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
152 if( !mRotationTrigger )
154 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
157 mPositionSize.width = width;
158 mPositionSize.height = height;
160 mRotationAngle = angle;
161 mRotationFinished = false;
163 mWindowBase->SetWindowRotationAngle( mRotationAngle );
165 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
168 WindowBase* WindowRenderSurface::GetWindowBase()
170 return mWindowBase.get();
173 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
175 return mOutputTransformedSignal;
178 PositionSize WindowRenderSurface::GetPositionSize() const
180 return mPositionSize;
183 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
185 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
187 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
188 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
190 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
191 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
193 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
195 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
199 dpiHorizontal = mDpiHorizontal;
200 dpiVertical = mDpiVertical;
203 void WindowRenderSurface::InitializeGraphics()
205 mGraphics = &mAdaptor->GetGraphicsInterface();
207 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
209 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
210 mEGL = &eglGraphics->GetEglInterface();
212 if ( mEGLContext == NULL )
214 // Create the OpenGL context for this window
215 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
216 eglImpl.ChooseConfig(true, mColorDepth);
217 eglImpl.CreateWindowContext( mEGLContext );
219 // Create the OpenGL surface
224 void WindowRenderSurface::CreateSurface()
226 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
229 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
231 width = mPositionSize.width;
232 height = mPositionSize.height;
236 width = mPositionSize.height;
237 height = mPositionSize.width;
240 // Create the EGL window
241 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
243 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
245 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
246 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
248 // Check rotation capability
249 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
251 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
252 mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
255 void WindowRenderSurface::DestroySurface()
257 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
259 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
262 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
264 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
266 eglImpl.DestroySurface( mEGLSurface );
267 mEGLSurface = nullptr;
269 // Destroy context also
270 eglImpl.DestroyContext( mEGLContext );
271 mEGLContext = nullptr;
273 mWindowBase->DestroyEglWindow();
277 bool WindowRenderSurface::ReplaceGraphicsSurface()
279 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
281 // Destroy the old one
282 mWindowBase->DestroyEglWindow();
285 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
287 width = mPositionSize.width;
288 height = mPositionSize.height;
292 width = mPositionSize.height;
293 height = mPositionSize.width;
296 // Create the EGL window
297 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
299 // Set screen rotation
300 mScreenRotationFinished = false;
302 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
304 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
305 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
308 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
310 bool needToMove = false;
311 bool needToResize = false;
314 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
315 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
321 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
322 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
331 mWindowBase->MoveResize( positionSize );
335 mWindowBase->Resize( positionSize );
338 mResizeFinished = false;
339 mPositionSize = positionSize;
345 mWindowBase->Move( positionSize );
347 mPositionSize = positionSize;
351 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
354 void WindowRenderSurface::StartRender()
358 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
360 Dali::Integration::Scene::FrameCallbackContainer callbacks;
362 Dali::Integration::Scene scene = mScene.GetHandle();
365 bool needFrameRenderedTrigger = false;
367 scene.GetFrameRenderedCallback( callbacks );
368 if( !callbacks.empty() )
370 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
371 if( frameRenderedSync != -1 )
373 Dali::Mutex::ScopedLock lock( mMutex );
375 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
377 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
379 needFrameRenderedTrigger = true;
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::Mutex::ScopedLock lock( mMutex );
398 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
400 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
402 needFrameRenderedTrigger = true;
406 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
413 if( needFrameRenderedTrigger )
415 if( !mFrameRenderedTrigger )
417 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
418 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
420 mFrameRenderedTrigger->Trigger();
424 MakeContextCurrent();
426 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
428 if( resizingSurface )
430 // Window rotate or screen rotate
431 if( !mRotationFinished || !mScreenRotationFinished )
433 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
435 mWindowBase->SetEglWindowRotation( totalAngle );
436 mWindowBase->SetEglWindowBufferTransform( totalAngle );
438 // Reset only screen rotation flag
439 mScreenRotationFinished = true;
441 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
444 // Only window rotate
445 if( !mRotationFinished )
447 mWindowBase->SetEglWindowTransform( mRotationAngle );
451 if( !mResizeFinished )
453 mWindowBase->ResizeEglWindow( mPositionSize );
454 mResizeFinished = true;
456 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
461 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
462 eglImpl.SetFullSwapNextFrame();
468 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
469 eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
475 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
477 // Inform the gl implementation that rendering has finished before informing the surface
478 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
481 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
491 if( resizingSurface )
493 if( !mRotationFinished )
495 if( mThreadSynchronization )
497 // Enable PostRender flag
498 mThreadSynchronization->PostRenderStarted();
501 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
503 mRotationTrigger->Trigger();
505 if( mThreadSynchronization )
507 // Wait until the event-thread complete the rotation event processing
508 mThreadSynchronization->PostRenderWaitForCompletion();
514 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
515 eglImpl.SwapBuffers( mEGLSurface, damagedRects );
517 if( mRenderNotification )
519 mRenderNotification->Trigger();
524 void WindowRenderSurface::StopRender()
528 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
530 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
532 mThreadSynchronization = &threadSynchronization;
535 void WindowRenderSurface::ReleaseLock()
540 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
542 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
545 void WindowRenderSurface::MakeContextCurrent()
547 if ( mEGL != nullptr )
549 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
553 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
555 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
558 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
560 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
563 void WindowRenderSurface::OutputTransformed()
565 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
567 if( mScreenRotationAngle != screenRotationAngle )
569 mScreenRotationAngle = screenRotationAngle;
570 mScreenRotationFinished = false;
572 mOutputTransformedSignal.Emit();
574 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
578 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
582 void WindowRenderSurface::ProcessRotationRequest()
584 mRotationFinished = true;
586 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
588 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
590 if( mThreadSynchronization )
592 mThreadSynchronization->PostRenderComplete();
596 void WindowRenderSurface::ProcessFrameCallback()
598 Dali::Mutex::ScopedLock lock( mMutex );
600 for( auto&& iter : mFrameCallbackInfoContainer )
602 if( !iter->fileDescriptorMonitor )
604 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
605 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
607 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
612 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
614 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
616 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
617 close( fileDescriptor );
621 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
623 std::unique_ptr< FrameCallbackInfo > callbackInfo;
625 Dali::Mutex::ScopedLock lock( mMutex );
626 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
627 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
629 return callbackInfo->fileDescriptor == fileDescriptor;
631 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
633 callbackInfo = std::move( *frameCallbackInfo );
635 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
639 // Call the connected callback
642 for( auto&& iter : ( callbackInfo )->callbacks )
644 CallbackBase::Execute( *( iter.first ), iter.second );
649 } // namespace Adaptor
651 } // namespace internal