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;
363 mScene->GetFrameRenderedCallback( callbacks );
364 if( !callbacks.empty() )
366 int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
367 if( frameRenderedSync != -1 )
369 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
371 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
373 if( !mFrameRenderedTrigger )
375 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
376 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
378 mFrameRenderedTrigger->Trigger();
382 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
389 mScene->GetFramePresentedCallback( callbacks );
390 if( !callbacks.empty() )
392 int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
393 if( framePresentedSync != -1 )
395 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
397 mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
399 if( !mFrameRenderedTrigger )
401 mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
402 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
404 mFrameRenderedTrigger->Trigger();
408 DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
416 MakeContextCurrent();
418 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
420 if( resizingSurface )
422 // Window rotate or screen rotate
423 if( !mRotationFinished || !mScreenRotationFinished )
425 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
427 mWindowBase->SetEglWindowRotation( totalAngle );
428 mWindowBase->SetEglWindowBufferTransform( totalAngle );
430 // Reset only screen rotation flag
431 mScreenRotationFinished = true;
433 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
436 // Only window rotate
437 if( !mRotationFinished )
439 mWindowBase->SetEglWindowTransform( mRotationAngle );
443 if( !mResizeFinished )
445 mWindowBase->ResizeEglWindow( mPositionSize );
446 mResizeFinished = true;
448 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
453 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
454 eglImpl.SetFullSwapNextFrame();
460 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
461 eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
467 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
469 // Inform the gl implementation that rendering has finished before informing the surface
470 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
473 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
483 if( resizingSurface )
485 if( !mRotationFinished )
487 if( mThreadSynchronization )
489 // Enable PostRender flag
490 mThreadSynchronization->PostRenderStarted();
493 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
495 mRotationTrigger->Trigger();
497 if( mThreadSynchronization )
499 // Wait until the event-thread complete the rotation event processing
500 mThreadSynchronization->PostRenderWaitForCompletion();
506 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
507 eglImpl.SwapBuffers( mEGLSurface, damagedRects );
509 if( mRenderNotification )
511 mRenderNotification->Trigger();
516 void WindowRenderSurface::StopRender()
520 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
522 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
524 mThreadSynchronization = &threadSynchronization;
527 void WindowRenderSurface::ReleaseLock()
532 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
534 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
537 void WindowRenderSurface::MakeContextCurrent()
539 if ( mEGL != nullptr )
541 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
545 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
547 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
550 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
552 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
555 void WindowRenderSurface::OutputTransformed()
557 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
559 if( mScreenRotationAngle != screenRotationAngle )
561 mScreenRotationAngle = screenRotationAngle;
562 mScreenRotationFinished = false;
564 mOutputTransformedSignal.Emit();
566 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
570 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
574 void WindowRenderSurface::ProcessRotationRequest()
576 mRotationFinished = true;
578 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
580 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
582 if( mThreadSynchronization )
584 mThreadSynchronization->PostRenderComplete();
588 void WindowRenderSurface::ProcessFrameCallback()
590 for( auto&& iter : mFrameCallbackInfoContainer )
592 if( !iter->fileDescriptorMonitor )
594 iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
595 MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
597 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
602 void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
604 if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
606 DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
607 close( fileDescriptor );
611 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
613 auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
614 [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
616 return callbackInfo->fileDescriptor == fileDescriptor;
618 if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
620 // Call the connected callback
621 for( auto&& iter : ( *frameCallbackInfo )->callbacks )
623 CallbackBase::Execute( *( iter.first ), iter.second );
625 mFrameCallbackInfoContainer.erase( frameCallbackInfo );
629 } // namespace Adaptor
631 } // namespace internal