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 );
111 Any WindowRenderSurface::GetNativeWindow()
113 return mWindowBase->GetNativeWindow();
116 int WindowRenderSurface::GetNativeWindowId()
118 return mWindowBase->GetNativeWindowId();
121 void WindowRenderSurface::Map()
126 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
128 mRenderNotification = renderNotification;
131 void WindowRenderSurface::SetTransparency( bool transparent )
133 mWindowBase->SetTransparency( transparent );
136 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
138 if( !mRotationTrigger )
140 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
143 mPositionSize.width = width;
144 mPositionSize.height = height;
146 mRotationAngle = angle;
147 mRotationFinished = false;
149 mWindowBase->SetWindowRotationAngle( mRotationAngle );
151 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
154 WindowBase* WindowRenderSurface::GetWindowBase()
156 return mWindowBase.get();
159 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
161 return mOutputTransformedSignal;
164 PositionSize WindowRenderSurface::GetPositionSize() const
166 return mPositionSize;
169 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
171 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
173 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
174 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
176 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
177 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
179 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
181 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
185 dpiHorizontal = mDpiHorizontal;
186 dpiVertical = mDpiVertical;
189 int WindowRenderSurface::GetOrientation() const
191 return mWindowBase->GetOrientation();
194 void WindowRenderSurface::InitializeGraphics()
196 mGraphics = &mAdaptor->GetGraphicsInterface();
198 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
200 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
201 mEGL = &eglGraphics->GetEglInterface();
203 if ( mEGLContext == NULL )
205 // Create the OpenGL context for this window
206 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
207 eglImpl.ChooseConfig(true, mColorDepth);
208 eglImpl.CreateWindowContext( mEGLContext );
210 // Create the OpenGL surface
215 void WindowRenderSurface::CreateSurface()
217 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
219 // Create the EGL window
220 EGLNativeWindowType window = mWindowBase->CreateEglWindow( mPositionSize.width, mPositionSize.height );
222 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
224 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
225 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
227 // Check rotation capability
228 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
230 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
231 mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
234 void WindowRenderSurface::DestroySurface()
236 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
238 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
241 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
243 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
245 eglImpl.DestroySurface( mEGLSurface );
246 mEGLSurface = nullptr;
248 // Destroy context also
249 eglImpl.DestroyContext( mEGLContext );
250 mEGLContext = nullptr;
252 mWindowBase->DestroyEglWindow();
256 bool WindowRenderSurface::ReplaceGraphicsSurface()
258 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
260 // Destroy the old one
261 mWindowBase->DestroyEglWindow();
264 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
266 width = mPositionSize.width;
267 height = mPositionSize.height;
271 width = mPositionSize.height;
272 height = mPositionSize.width;
275 // Create the EGL window
276 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
278 // Set screen rotation
279 mScreenRotationFinished = false;
281 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
283 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
284 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
287 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
289 bool needToMove = false;
290 bool needToResize = false;
293 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
294 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
300 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
301 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
310 mWindowBase->MoveResize( positionSize );
314 mWindowBase->Resize( positionSize );
317 mResizeFinished = false;
318 mPositionSize = positionSize;
324 mWindowBase->Move( positionSize );
326 mPositionSize = positionSize;
330 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
333 void WindowRenderSurface::StartRender()
337 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
339 Dali::Integration::Scene::FrameCallbackContainer callbacks;
341 Dali::Integration::Scene scene = mScene.GetHandle();
344 scene.GetFrameRenderedCallback( callbacks );
345 if( !callbacks.empty() )
347 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
348 if( frameRenderedSync != -1 )
350 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
352 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
354 if( !mFrameRenderedTrigger )
356 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
357 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
359 mFrameRenderedTrigger->Trigger();
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_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
378 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
380 if( !mFrameRenderedTrigger )
382 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
383 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
385 mFrameRenderedTrigger->Trigger();
389 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
397 MakeContextCurrent();
399 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
401 if( resizingSurface )
403 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
405 // Window rotate or screen rotate
406 if( !mRotationFinished || !mScreenRotationFinished )
408 mWindowBase->SetEglWindowRotation( totalAngle );
409 mWindowBase->SetEglWindowBufferTransform( totalAngle );
411 // Reset only screen rotation flag
412 mScreenRotationFinished = true;
414 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
417 // Only window rotate
418 if( !mRotationFinished )
420 mWindowBase->SetEglWindowTransform( mRotationAngle );
424 if ( !mResizeFinished )
426 Dali::PositionSize positionSize;
427 positionSize.x = mPositionSize.x;
428 positionSize.y = mPositionSize.y;
429 if( totalAngle == 0 || totalAngle == 180 )
431 positionSize.width = mPositionSize.width;
432 positionSize.height = mPositionSize.height;
436 positionSize.width = mPositionSize.height;
437 positionSize.height = mPositionSize.width;
439 mWindowBase->ResizeEglWindow( positionSize );
440 mResizeFinished = true;
442 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
447 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
448 eglImpl.SetFullSwapNextFrame();
454 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
455 eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
461 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
463 // Inform the gl implementation that rendering has finished before informing the surface
464 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
467 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
477 if( resizingSurface )
479 if( !mRotationFinished )
481 if( mThreadSynchronization )
483 // Enable PostRender flag
484 mThreadSynchronization->PostRenderStarted();
487 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
489 mRotationTrigger->Trigger();
491 if( mThreadSynchronization )
493 // Wait until the event-thread complete the rotation event processing
494 mThreadSynchronization->PostRenderWaitForCompletion();
500 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
501 eglImpl.SwapBuffers( mEGLSurface, damagedRects );
503 if( mRenderNotification )
505 mRenderNotification->Trigger();
510 void WindowRenderSurface::StopRender()
514 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
516 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
518 mThreadSynchronization = &threadSynchronization;
521 void WindowRenderSurface::ReleaseLock()
526 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
528 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
531 void WindowRenderSurface::MakeContextCurrent()
533 if ( mEGL != nullptr )
535 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
539 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
541 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
544 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
546 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
549 void WindowRenderSurface::OutputTransformed()
551 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
553 if( mScreenRotationAngle != screenRotationAngle )
555 mScreenRotationAngle = screenRotationAngle;
556 mScreenRotationFinished = false;
557 mResizeFinished = false;
559 mOutputTransformedSignal.Emit();
561 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: window = %d screen = %d\n", mRotationAngle, mScreenRotationAngle );
565 DALI_LOG_RELEASE_INFO( "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
569 void WindowRenderSurface::ProcessRotationRequest()
571 mRotationFinished = true;
573 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
575 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
577 if( mThreadSynchronization )
579 mThreadSynchronization->PostRenderComplete();
583 void WindowRenderSurface::ProcessFrameCallback()
585 for( auto&& iter : mFrameCallbackInfoContainer )
587 if( !iter->fileDescriptorMonitor )
589 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
590 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
592 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
597 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
599 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
601 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
602 close( fileDescriptor );
606 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
608 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
609 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
611 return callbackInfo->fileDescriptor == fileDescriptor;
613 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
615 // Call the connected callback
616 for( auto&& iter : ( *frameCallbackInfo )->callbacks )
618 CallbackBase::Execute( *( iter.first ), iter.second );
620 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
624 } // namespace Adaptor
626 } // namespace internal