/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
-#include <dali/integration-api/trigger-event-factory-interface.h>
-#include <dali/integration-api/thread-synchronization-interface.h>
-#include <dali/internal/graphics/gles20/egl-implementation.h>
+#include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
#include <dali/internal/window-system/common/window-base.h>
#include <dali/internal/window-system/common/window-factory.h>
#include <dali/internal/window-system/common/window-system.h>
+#include <dali/internal/system/common/environment-variables.h>
namespace Dali
{
} // unnamed namespace
WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
-: mPositionSize( positionSize ),
+: mEGL( nullptr ),
+ mDisplayConnection( nullptr ),
+ mPositionSize( positionSize ),
mWindowBase(),
mThreadSynchronization( NULL ),
mRenderNotification( NULL ),
mRotationTrigger( NULL ),
+ mFrameRenderedTrigger(),
+ mGraphics( nullptr ),
+ mEGLSurface( nullptr ),
+ mEGLContext( nullptr ),
mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
mOutputTransformedSignal(),
+ mFrameCallbackInfoContainer(),
+ mMutex(),
mRotationAngle( 0 ),
mScreenRotationAngle( 0 ),
mOwnSurface( false ),
mRotationSupported( false ),
mRotationFinished( true ),
mScreenRotationFinished( true ),
- mResizeFinished( true )
+ mResizeFinished( true ),
+ mDpiHorizontal( 0 ),
+ mDpiVertical( 0 )
{
DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
Initialize( surface );
void WindowRenderSurface::Initialize( Any surface )
{
- // if width or height are zero, go full screen.
- if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
- {
- // Default window size == screen size
- mPositionSize.x = 0;
- mPositionSize.y = 0;
-
- WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
- }
+ // If width or height are zero, go full screen.
+ if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
+ {
+ // Default window size == screen size
+ mPositionSize.x = 0;
+ mPositionSize.y = 0;
+ WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
+ }
// Create a window base
auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
if( !mRotationTrigger )
{
- TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
- mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
+ mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
}
mPositionSize.width = width;
void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
{
- mWindowBase->GetDpi( dpiHorizontal, dpiVertical );
+ if( mDpiHorizontal == 0 || mDpiVertical == 0 )
+ {
+ const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
+ mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
+
+ const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
+ mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
+
+ if( mDpiHorizontal == 0 || mDpiVertical == 0 )
+ {
+ mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
+ }
+ }
+
+ dpiHorizontal = mDpiHorizontal;
+ dpiVertical = mDpiVertical;
}
-void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
+void WindowRenderSurface::InitializeGraphics()
{
- DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
+ mGraphics = &mAdaptor->GetGraphicsInterface();
+
+ DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
- Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
+ auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+ mEGL = &eglGraphics->GetEglInterface();
- eglImpl.ChooseConfig(true, mColorDepth);
+ if ( mEGLContext == NULL )
+ {
+ // Create the OpenGL context for this window
+ Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
+ eglImpl.ChooseConfig(true, mColorDepth);
+ eglImpl.CreateWindowContext( mEGLContext );
+
+ // Create the OpenGL surface
+ CreateSurface();
+ }
}
-void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
+void WindowRenderSurface::CreateSurface()
{
DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
height = mPositionSize.width;
}
- // create the EGL window
+ // Create the EGL window
EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
- Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
- eglImpl.CreateSurfaceWindow( window, mColorDepth );
+ auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
+ Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+ mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
// Check rotation capability
mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
- DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: w = %d h = %d angle = %d screen rotation = %d\n", mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
+ DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
+ mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
}
-void WindowRenderSurface::DestroyEglSurface( EglInterface& eglIf )
+void WindowRenderSurface::DestroySurface()
{
DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
- Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
- eglImpl.DestroySurface();
+ auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+ if( eglGraphics )
+ {
+ DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
+
+ Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
- mWindowBase->DestroyEglWindow();
+ eglImpl.DestroySurface( mEGLSurface );
+ mEGLSurface = nullptr;
+
+ // Destroy context also
+ eglImpl.DestroyContext( mEGLContext );
+ mEGLContext = nullptr;
+
+ mWindowBase->DestroyEglWindow();
+ }
}
-bool WindowRenderSurface::ReplaceEGLSurface( EglInterface& egl )
+bool WindowRenderSurface::ReplaceGraphicsSurface()
{
DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
height = mPositionSize.width;
}
- // create the EGL window
+ // Create the EGL window
EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
// Set screen rotation
mScreenRotationFinished = false;
- Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
- return eglImpl.ReplaceSurfaceWindow( window );
+ auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
+ Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+ return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
}
void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
bool needToMove = false;
bool needToResize = false;
- // check moving
+ // Check moving
if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
(fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
{
needToMove = true;
}
- // check resizing
+ // Check resizing
if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
(fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
{
DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
}
-void WindowRenderSurface::SetViewMode( ViewMode viewMode )
-{
- mWindowBase->SetViewMode( viewMode );
-}
-
void WindowRenderSurface::StartRender()
{
}
-bool WindowRenderSurface::PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, bool resizingSurface )
+bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
{
+ Dali::Integration::Scene::FrameCallbackContainer callbacks;
+
+ Dali::Integration::Scene scene = mScene.GetHandle();
+ if( scene )
+ {
+ bool needFrameRenderedTrigger = false;
+
+ scene.GetFrameRenderedCallback( callbacks );
+ if( !callbacks.empty() )
+ {
+ int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence();
+ if( frameRenderedSync != -1 )
+ {
+ Dali::Mutex::ScopedLock lock( mMutex );
+
+ DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync );
+
+ mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, frameRenderedSync ) ) );
+
+ needFrameRenderedTrigger = true;
+ }
+ else
+ {
+ DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n" );
+ }
+
+ // Clear callbacks
+ callbacks.clear();
+ }
+
+ scene.GetFramePresentedCallback( callbacks );
+ if( !callbacks.empty() )
+ {
+ int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence();
+ if( framePresentedSync != -1 )
+ {
+ Dali::Mutex::ScopedLock lock( mMutex );
+
+ DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync );
+
+ mFrameCallbackInfoContainer.push_back( std::unique_ptr< FrameCallbackInfo >( new FrameCallbackInfo( callbacks, framePresentedSync ) ) );
+
+ needFrameRenderedTrigger = true;
+ }
+ else
+ {
+ DALI_LOG_ERROR( "WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n" );
+ }
+
+ // Clear callbacks
+ callbacks.clear();
+ }
+
+ if( needFrameRenderedTrigger )
+ {
+ if( !mFrameRenderedTrigger )
+ {
+ mFrameRenderedTrigger = std::unique_ptr< TriggerEventInterface >( TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessFrameCallback ),
+ TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ) );
+ }
+ mFrameRenderedTrigger->Trigger();
+ }
+ }
+
+ MakeContextCurrent();
+
+ auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
if( resizingSurface )
{
-#ifdef OVER_TIZEN_VERSION_4
// Window rotate or screen rotate
if( !mRotationFinished || !mScreenRotationFinished )
{
{
mWindowBase->SetEglWindowTransform( mRotationAngle );
}
-#endif
// Resize case
if( !mResizeFinished )
DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
}
+
+ if (eglGraphics)
+ {
+ Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+ eglImpl.SetFullSwapNextFrame();
+ }
+ }
+
+ if (eglGraphics)
+ {
+ Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+ eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
}
return true;
}
-void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, Dali::DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
+void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
{
- if( resizingSurface )
+ // Inform the gl implementation that rendering has finished before informing the surface
+ auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+ if ( eglGraphics )
{
- if( !mRotationFinished )
- {
- DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
-
- mRotationTrigger->Trigger();
+ GlImplementation& mGLES = eglGraphics->GetGlesInterface();
+ mGLES.PostRender();
- if( mThreadSynchronization )
+ if( renderToFbo )
+ {
+ mGLES.Flush();
+ mGLES.Finish();
+ }
+ else
+ {
+ if( resizingSurface )
{
- // Wait until the event-thread complete the rotation event processing
- mThreadSynchronization->PostRenderWaitForCompletion();
+ if( !mRotationFinished )
+ {
+ if( mThreadSynchronization )
+ {
+ // Enable PostRender flag
+ mThreadSynchronization->PostRenderStarted();
+ }
+
+ DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
+
+ mRotationTrigger->Trigger();
+
+ if( mThreadSynchronization )
+ {
+ // Wait until the event-thread complete the rotation event processing
+ mThreadSynchronization->PostRenderWaitForCompletion();
+ }
+ }
}
}
- }
- Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
- eglImpl.SwapBuffers();
+ Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+ eglImpl.SwapBuffers( mEGLSurface, damagedRects );
- if( mRenderNotification )
- {
- mRenderNotification->Trigger();
+ if( mRenderNotification )
+ {
+ mRenderNotification->Trigger();
+ }
}
}
// Nothing to do.
}
-RenderSurface::Type WindowRenderSurface::GetSurfaceType()
+Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
+{
+ return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
+}
+
+void WindowRenderSurface::MakeContextCurrent()
+{
+ if ( mEGL != nullptr )
+ {
+ mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
+ }
+}
+
+Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
+{
+ return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
+}
+
+Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
{
- return RenderSurface::WINDOW_RENDER_SURFACE;
+ return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
}
void WindowRenderSurface::OutputTransformed()
}
}
+void WindowRenderSurface::ProcessFrameCallback()
+{
+ Dali::Mutex::ScopedLock lock( mMutex );
+
+ for( auto&& iter : mFrameCallbackInfoContainer )
+ {
+ if( !iter->fileDescriptorMonitor )
+ {
+ iter->fileDescriptorMonitor = std::unique_ptr< FileDescriptorMonitor >( new FileDescriptorMonitor( iter->fileDescriptor,
+ MakeCallback( this, &WindowRenderSurface::OnFileDescriptorEventDispatched ), FileDescriptorMonitor::FD_READABLE ) );
+
+ DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor );
+ }
+ }
+}
+
+void WindowRenderSurface::OnFileDescriptorEventDispatched( FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor )
+{
+ if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
+ {
+ DALI_LOG_ERROR( "WindowRenderSurface::OnFileDescriptorEventDispatched: file descriptor error [%d]\n", eventBitMask );
+ close( fileDescriptor );
+ return;
+ }
+
+ DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor );
+
+ std::unique_ptr< FrameCallbackInfo > callbackInfo;
+ {
+ Dali::Mutex::ScopedLock lock( mMutex );
+ auto frameCallbackInfo = std::find_if( mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(),
+ [fileDescriptor]( std::unique_ptr< FrameCallbackInfo >& callbackInfo )
+ {
+ return callbackInfo->fileDescriptor == fileDescriptor;
+ } );
+ if( frameCallbackInfo != mFrameCallbackInfoContainer.end() )
+ {
+ callbackInfo = std::move( *frameCallbackInfo );
+
+ mFrameCallbackInfoContainer.erase( frameCallbackInfo );
+ }
+ }
+
+ // Call the connected callback
+ if( callbackInfo )
+ {
+ for( auto&& iter : ( callbackInfo )->callbacks )
+ {
+ CallbackBase::Execute( *( iter.first ), iter.second );
+ }
+ }
+}
+
} // namespace Adaptor
} // namespace internal