X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fwindow-system%2Fcommon%2Fwindow-render-surface.cpp;h=021843e2f5179915c6e4fcae2357da6e6f293f7c;hb=1d0d7873858fd2010b71e5db8f03654fb307370f;hp=f1e4cb71a18e36f3d3c3f2c79ae539fa334d8326;hpb=a6c2b112773d20254ec7c99ef279d1b21d89a3ca;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/window-system/common/window-render-surface.cpp b/dali/internal/window-system/common/window-render-surface.cpp index f1e4cb7..021843e 100644 --- a/dali/internal/window-system/common/window-render-surface.cpp +++ b/dali/internal/window-system/common/window-render-surface.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 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. @@ -23,18 +23,17 @@ #include // INTERNAL INCLUDES -#include -#include -#include +#include +#include #include #include +#include +#include #include #include #include -#include #include - namespace Dali { namespace Internal @@ -46,11 +45,42 @@ namespace { const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved +const float FULL_UPDATE_RATIO( 0.8f ); ///< Force full update when the dirty area is larget than this ratio #if defined(DEBUG_ENABLED) Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE"); #endif +void MergeRects( Rect< int >& mergingRect, const std::vector< Rect< int > >& rects ) +{ + uint32_t i = 0; + if( mergingRect.IsEmpty() ) + { + for( ; i < rects.size(); i++ ) + { + if( !rects[i].IsEmpty() ) + { + mergingRect = rects[i]; + break; + } + } + } + + for( ; i < rects.size(); i++ ) + { + mergingRect.Merge( rects[i] ); + } +} + +void InsertRects( WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const std::vector< Rect< int > >& damagedRects ) +{ + damagedRectsList.push_front( damagedRects ); + if( damagedRectsList.size() > 4 ) // past triple buffers + current + { + damagedRectsList.pop_back(); + } +} + } // unnamed namespace WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent ) @@ -61,20 +91,24 @@ WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any s mThreadSynchronization( NULL ), mRenderNotification( NULL ), mRotationTrigger( NULL ), + mFrameRenderedTrigger(), mGraphics( nullptr ), mEGLSurface( nullptr ), mEGLContext( nullptr ), mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ), mOutputTransformedSignal(), + mFrameCallbackInfoContainer(), + mBufferDamagedRects(), + mMutex(), mRotationAngle( 0 ), mScreenRotationAngle( 0 ), + mDpiHorizontal( 0 ), + mDpiVertical( 0 ), mOwnSurface( false ), mRotationSupported( false ), mRotationFinished( true ), mScreenRotationFinished( true ), - mResizeFinished( true ), - mDpiHorizontal( 0 ), - mDpiVertical( 0 ) + mResizeFinished( true ) { DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" ); Initialize( surface ); @@ -86,11 +120,6 @@ WindowRenderSurface::~WindowRenderSurface() { delete mRotationTrigger; } - - if ( mEGLSurface ) - { - DestroySurface(); - } } void WindowRenderSurface::Initialize( Any surface ) @@ -101,7 +130,6 @@ void WindowRenderSurface::Initialize( Any surface ) // Default window size == screen size mPositionSize.x = 0; mPositionSize.y = 0; - WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height ); } @@ -155,8 +183,7 @@ void WindowRenderSurface::RequestRotation( int angle, int width, int height ) 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; @@ -207,9 +234,10 @@ void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpi void WindowRenderSurface::InitializeGraphics() { - mGraphics = &mAdaptor->GetGraphicsInterface(); + DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" ); + auto eglGraphics = static_cast(mGraphics); mEGL = &eglGraphics->GetEglInterface(); @@ -252,8 +280,8 @@ void WindowRenderSurface::CreateSurface() // Check rotation capability mRotationSupported = mWindowBase->IsEglWindowRotationSupported(); - DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: 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::DestroySurface() @@ -261,11 +289,21 @@ void WindowRenderSurface::DestroySurface() DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter ); auto eglGraphics = static_cast(mGraphics); + if( eglGraphics ) + { + DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() ); - Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); - eglImpl.DestroySurface( mEGLSurface ); + 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::ReplaceGraphicsSurface() @@ -349,8 +387,72 @@ void WindowRenderSurface::StartRender() { } -bool WindowRenderSurface::PreRender( bool resizingSurface ) +bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector>& damagedRects, Rect& 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(); if( resizingSurface ) @@ -383,19 +485,16 @@ bool WindowRenderSurface::PreRender( bool resizingSurface ) DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" ); } - } - auto eglGraphics = static_cast(mGraphics); - if ( eglGraphics ) - { - GlImplementation& mGLES = eglGraphics->GetGlesInterface(); - mGLES.PreRender(); + SetFullSwapNextFrame(); } + SetBufferDamagedRects( damagedRects, clippingRect ); + return true; } -void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface ) +void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector>& damagedRects ) { // Inform the gl implementation that rendering has finished before informing the surface auto eglGraphics = static_cast(mGraphics); @@ -415,7 +514,13 @@ void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, b { if( !mRotationFinished ) { - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" ); + if( mThreadSynchronization ) + { + // Enable PostRender flag + mThreadSynchronization->PostRenderStarted(); + } + + DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" ); mRotationTrigger->Trigger(); @@ -428,8 +533,7 @@ void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, b } } - Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); - eglImpl.SwapBuffers( mEGLSurface ); + SwapBuffers( damagedRects ); if( mRenderNotification ) { @@ -454,9 +558,9 @@ void WindowRenderSurface::ReleaseLock() // Nothing to do. } -Integration::RenderSurface::Type WindowRenderSurface::GetSurfaceType() +Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType() { - return RenderSurface::WINDOW_RENDER_SURFACE; + return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE; } void WindowRenderSurface::MakeContextCurrent() @@ -510,6 +614,185 @@ void WindowRenderSurface::ProcessRotationRequest() } } +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 ); + } + } +} + +void WindowRenderSurface::SetBufferDamagedRects( const std::vector< Rect< int > >& damagedRects, Rect< int >& clippingRect ) +{ + auto eglGraphics = static_cast< EglGraphics* >( mGraphics ); + if ( eglGraphics ) + { + Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); + if( !eglImpl.IsPartialUpdateRequired() ) + { + return; + } + + Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height ); + + if( mFullSwapNextFrame ) + { + InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) ); + clippingRect = Rect< int >(); + return; + } + + EGLint bufferAge = eglImpl.GetBufferAge( mEGLSurface ); + + // Buffer age 0 means the back buffer in invalid and requires full swap + if( !damagedRects.size() || bufferAge == 0 ) + { + InsertRects( mBufferDamagedRects, std::vector< Rect< int > >( 1, surfaceRect ) ); + clippingRect = Rect< int >(); + return; + } + + // We push current frame damaged rects here, zero index for current frame + InsertRects( mBufferDamagedRects, damagedRects ); + + // Merge damaged rects into clipping rect + auto bufferDamagedRects = mBufferDamagedRects.begin(); + while( bufferAge-- >= 0 && bufferDamagedRects != mBufferDamagedRects.end() ) + { + const std::vector< Rect< int > >& rects = *bufferDamagedRects++; + MergeRects( clippingRect, rects ); + } + + if( !clippingRect.Intersect( surfaceRect ) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) + { + // clipping area too big or doesn't intersect surface rect + clippingRect = Rect< int >(); + return; + } + + std::vector< Rect< int > > damagedRegion; + damagedRegion.push_back( clippingRect ); + + eglImpl.SetDamageRegion( mEGLSurface, damagedRegion ); + } +} + +void WindowRenderSurface::SwapBuffers( const std::vector>& damagedRects ) +{ + auto eglGraphics = static_cast< EglGraphics* >( mGraphics ); + if( eglGraphics ) + { + Rect< int > surfaceRect( 0, 0, mPositionSize.width, mPositionSize.height ); + + Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); + + if( !eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame || !damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) ) + { + mFullSwapNextFrame = false; + eglImpl.SwapBuffers( mEGLSurface ); + return; + } + + mFullSwapNextFrame = false; + + std::vector< Rect< int > > mergedRects = damagedRects; + + // Merge intersecting rects, form an array of non intersecting rects to help driver a bit + // Could be optional and can be removed, needs to be checked with and without on platform + const int n = mergedRects.size(); + for( int i = 0; i < n - 1; i++ ) + { + if( mergedRects[i].IsEmpty() ) + { + continue; + } + + for( int j = i + 1; j < n; j++ ) + { + if( mergedRects[j].IsEmpty() ) + { + continue; + } + + if( mergedRects[i].Intersects( mergedRects[j] ) ) + { + mergedRects[i].Merge( mergedRects[j] ); + mergedRects[j].width = 0; + mergedRects[j].height = 0; + } + } + } + + int j = 0; + for( int i = 0; i < n; i++ ) + { + if( !mergedRects[i].IsEmpty() ) + { + mergedRects[j++] = mergedRects[i]; + } + } + + if( j != 0 ) + { + mergedRects.resize( j ); + } + + if( !mergedRects.size() || ( mergedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO ) ) + { + eglImpl.SwapBuffers( mEGLSurface ); + } + else + { + eglImpl.SwapBuffers( mEGLSurface, mergedRects ); + } + } +} + } // namespace Adaptor } // namespace internal