X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fwindow-system%2Fcommon%2Fwindow-render-surface.cpp;h=0d6dbdb3c4a1b9ebeb5017e95c13483f9ebfd03e;hb=738fd571c706537f8897163684fcb9d3fd9d535e;hp=e1a344f6c2bb36b301a51f7da64bc34005c2ce10;hpb=109a1e7447e6fd3ca65a7ac15037955f9f23ca0b;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 e1a344f..0d6dbdb 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) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -19,8 +19,8 @@ #include // EXTERNAL INCLUDES -#include #include +#include // INTERNAL INCLUDES #include @@ -29,10 +29,11 @@ #include #include #include +#include +#include #include #include #include -#include namespace Dali { @@ -40,81 +41,177 @@ namespace Internal { namespace Adaptor { - namespace { - -const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved +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 -} // unnamed namespace +void InsertRects(WindowRenderSurface::DamagedRectsContainer& damagedRectsList, const Rect& damagedRects) +{ + damagedRectsList.insert(damagedRectsList.begin(), damagedRects); + if(damagedRectsList.size() > 4) // past triple buffers + current + { + damagedRectsList.pop_back(); + } +} -WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent ) -: mEGL( nullptr ), - mDisplayConnection( nullptr ), - mPositionSize( positionSize ), - mWindowBase(), - mThreadSynchronization( NULL ), - mRenderNotification( NULL ), - mRotationTrigger( NULL ), - mGraphics( nullptr ), - mEGLSurface( nullptr ), - mEGLContext( nullptr ), - mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ), - mOutputTransformedSignal(), - mRotationAngle( 0 ), - mScreenRotationAngle( 0 ), - mOwnSurface( false ), - mRotationSupported( false ), - mRotationFinished( true ), - mScreenRotationFinished( true ), - mResizeFinished( true ), - mDpiHorizontal( 0 ), - mDpiVertical( 0 ) +Rect RecalculateRect0(Rect& rect, const Rect& surfaceSize) { - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" ); - Initialize( surface ); + return rect; } -WindowRenderSurface::~WindowRenderSurface() +Rect RecalculateRect90(Rect& rect, const Rect& surfaceSize) +{ + Rect newRect; + newRect.x = surfaceSize.height - (rect.y + rect.height); + newRect.y = rect.x; + newRect.width = rect.height; + newRect.height = rect.width; + return newRect; +} + +Rect RecalculateRect180(Rect& rect, const Rect& surfaceSize) +{ + Rect newRect; + newRect.x = surfaceSize.width - (rect.x + rect.width); + newRect.y = surfaceSize.height - (rect.y + rect.height); + newRect.width = rect.width; + newRect.height = rect.height; + return newRect; +} + +Rect RecalculateRect270(Rect& rect, const Rect& surfaceSize) { - if( mRotationTrigger ) + Rect newRect; + newRect.x = rect.y; + newRect.y = surfaceSize.width - (rect.x + rect.width); + newRect.width = rect.height; + newRect.height = rect.width; + return newRect; +} + +using RecalculateRectFunction = Rect (*)(Rect&, const Rect&); + +RecalculateRectFunction RecalculateRect[4] = {RecalculateRect0, RecalculateRect90, RecalculateRect180, RecalculateRect270}; + +void MergeIntersectingRectsAndRotate(Rect& mergingRect, std::vector>& damagedRects, int orientation, const Rect& surfaceRect) +{ + const int n = damagedRects.size(); + for(int i = 0; i < n - 1; i++) { - delete mRotationTrigger; + if(damagedRects[i].IsEmpty()) + { + continue; + } + + for(int j = i + 1; j < n; j++) + { + if(damagedRects[j].IsEmpty()) + { + continue; + } + + if(damagedRects[i].Intersects(damagedRects[j])) + { + damagedRects[i].Merge(damagedRects[j]); + damagedRects[j].width = 0; + damagedRects[j].height = 0; + } + } } - if ( mEGLSurface ) + int j = 0; + for(int i = 0; i < n; i++) { - DestroySurface(); + if(!damagedRects[i].IsEmpty()) + { + // Merge rects before rotate + if(mergingRect.IsEmpty()) + { + mergingRect = damagedRects[i]; + } + else + { + mergingRect.Merge(damagedRects[i]); + } + + damagedRects[j++] = RecalculateRect[orientation](damagedRects[i], surfaceRect); + } + } + + if(j != 0) + { + damagedRects.resize(j); } } -void WindowRenderSurface::Initialize( Any surface ) +} // unnamed namespace + +WindowRenderSurface::WindowRenderSurface(Dali::PositionSize positionSize, Any surface, bool isTransparent) +: mEGL(nullptr), + mDisplayConnection(nullptr), + mPositionSize(positionSize), + mWindowBase(), + mThreadSynchronization(nullptr), + mRenderNotification(nullptr), + mPostRenderTrigger(), + mFrameRenderedTrigger(), + mGraphics(nullptr), + mEGLSurface(nullptr), + mEGLContext(nullptr), + mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24), + mOutputTransformedSignal(), + mWindowRotationFinishedSignal(), + mFrameCallbackInfoContainer(), + mBufferDamagedRects(), + mMutex(), + mWindowRotationAngle(0), + mScreenRotationAngle(0), + mDpiHorizontal(0), + mDpiVertical(0), + mOwnSurface(false), + mIsImeWindowSurface(false), + mNeedWindowRotationAcknowledgement(false), + mIsWindowOrientationChanging(false), + mIsFrontBufferRendering(false), + mIsFrontBufferRenderingChanged(false) +{ + DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n"); + Initialize(surface); +} + +WindowRenderSurface::~WindowRenderSurface() +{ +} + +void WindowRenderSurface::Initialize(Any surface) { // If width or height are zero, go full screen. - if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) ) + if((mPositionSize.width == 0) || (mPositionSize.height == 0)) { // Default window size == screen size mPositionSize.x = 0; mPositionSize.y = 0; - WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height ); + WindowSystem::GetScreenSize(mPositionSize.width, mPositionSize.height); } // Create a window base auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory(); - mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) ); + mWindowBase = windowFactory->CreateWindowBase(mPositionSize, surface, (mColorDepth == COLOR_DEPTH_32 ? true : false)); // Connect signals - mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed ); + mWindowBase->OutputTransformedSignal().Connect(this, &WindowRenderSurface::OutputTransformed); // Check screen rotation - mScreenRotationAngle = mWindowBase->GetScreenRotationAngle(); - if( mScreenRotationAngle != 0 ) + int screenRotationAngle = mWindowBase->GetScreenRotationAngle(); + if(screenRotationAngle != 0) { - mScreenRotationFinished = false; + OutputTransformed(); + DALI_LOG_RELEASE_INFO("WindowRenderSurface::Initialize, screen rotation is enabled, screen rotation angle:[%d]\n", screenRotationAngle); } } @@ -133,38 +230,30 @@ void WindowRenderSurface::Map() mWindowBase->Show(); } -void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification ) +void WindowRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification) { mRenderNotification = renderNotification; } -void WindowRenderSurface::SetTransparency( bool transparent ) +void WindowRenderSurface::SetTransparency(bool transparent) { - mWindowBase->SetTransparency( transparent ); + mWindowBase->SetTransparency(transparent); } -void WindowRenderSurface::RequestRotation( int angle, int width, int height ) +void WindowRenderSurface::RequestRotation(int angle, PositionSize positionSize) { - if( !mRotationSupported ) - { - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" ); - return; - } - - if( !mRotationTrigger ) + if(!mPostRenderTrigger) { - mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER ); + mPostRenderTrigger = std::unique_ptr(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender), + TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER)); } - mPositionSize.width = width; - mPositionSize.height = height; + mPositionSize.x = positionSize.x; + mPositionSize.y = positionSize.y; - mRotationAngle = angle; - mRotationFinished = false; + mWindowBase->SetWindowRotationAngle(angle); - mWindowBase->SetWindowRotationAngle( mRotationAngle ); - - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle ); + DALI_LOG_RELEASE_INFO("start window rotation angle = %d screen rotation = %d\n", angle, mScreenRotationAngle); } WindowBase* WindowRenderSurface::GetWindowBase() @@ -177,46 +266,61 @@ WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal() return mOutputTransformedSignal; } +WindowRenderSurface::RotationFinishedSignalType& WindowRenderSurface::RotationFinishedSignal() +{ + return mWindowRotationFinishedSignal; +} + PositionSize WindowRenderSurface::GetPositionSize() const { return mPositionSize; } -void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) +void WindowRenderSurface::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical) { - if( mDpiHorizontal == 0 || mDpiVertical == 0 ) + if(mDpiHorizontal == 0 || mDpiVertical == 0) { - const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL ); - mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 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; + const char* environmentDpiVertical = std::getenv(DALI_ENV_DPI_VERTICAL); + mDpiVertical = environmentDpiVertical ? std::atoi(environmentDpiVertical) : 0; - if( mDpiHorizontal == 0 || mDpiVertical == 0 ) + if(mDpiHorizontal == 0 || mDpiVertical == 0) { - mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical ); + mWindowBase->GetDpi(mDpiHorizontal, mDpiVertical); } } dpiHorizontal = mDpiHorizontal; - dpiVertical = mDpiVertical; + dpiVertical = mDpiVertical; +} + +int WindowRenderSurface::GetSurfaceOrientation() const +{ + return mWindowBase->GetWindowRotationAngle(); +} + +int WindowRenderSurface::GetScreenOrientation() const +{ + return mWindowBase->GetScreenRotationAngle(); } void WindowRenderSurface::InitializeGraphics() { - mGraphics = &mAdaptor->GetGraphicsInterface(); + if(mEGLContext == NULL) + { + mGraphics = &mAdaptor->GetGraphicsInterface(); - DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" ); + DALI_ASSERT_ALWAYS(mGraphics && "Graphics interface is not created"); - auto eglGraphics = static_cast(mGraphics); - mEGL = &eglGraphics->GetEglInterface(); + auto eglGraphics = static_cast(mGraphics); + mEGL = &eglGraphics->GetEglInterface(); - if ( mEGLContext == NULL ) - { // Create the OpenGL context for this window Internal::Adaptor::EglImplementation& eglImpl = static_cast(*mEGL); eglImpl.ChooseConfig(true, mColorDepth); - eglImpl.CreateWindowContext( mEGLContext ); + eglImpl.CreateWindowContext(mEGLContext); // Create the OpenGL surface CreateSurface(); @@ -225,46 +329,59 @@ void WindowRenderSurface::InitializeGraphics() void WindowRenderSurface::CreateSurface() { - DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter ); + DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter); int width, height; - if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 ) + if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180) { - width = mPositionSize.width; + width = mPositionSize.width; height = mPositionSize.height; } else { - width = mPositionSize.height; + width = mPositionSize.height; height = mPositionSize.width; } // Create the EGL window - EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height ); + EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height); - auto eglGraphics = static_cast(mGraphics); - - Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); - mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth ); + if(mWindowBase->GetType() == WindowType::IME) + { + InitializeImeSurface(); + } - // Check rotation capability - mRotationSupported = mWindowBase->IsEglWindowRotationSupported(); + auto eglGraphics = static_cast(mGraphics); - 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 ); + Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); + mEGLSurface = eglImpl.CreateSurfaceWindow(window, mColorDepth); + + DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), EGLSurface (%p), w = %d h = %d angle = %d screen rotation = %d\n", + mWindowBase->GetNativeWindowId(), + mEGLSurface, + mPositionSize.width, + mPositionSize.height, + mWindowRotationAngle, + mScreenRotationAngle); } void WindowRenderSurface::DestroySurface() { - DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter ); + DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter); - auto eglGraphics = static_cast(mGraphics); - if( eglGraphics ) + auto eglGraphics = static_cast(mGraphics); + if(eglGraphics) { - DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() ); + DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId()); Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); - eglImpl.DestroySurface( mEGLSurface ); + + eglImpl.DestroySurface(mEGLSurface); + mEGLSurface = nullptr; + + // Destroy context also + eglImpl.DestroyContext(mEGLContext); + mEGLContext = nullptr; mWindowBase->DestroyEglWindow(); } @@ -272,174 +389,291 @@ void WindowRenderSurface::DestroySurface() bool WindowRenderSurface::ReplaceGraphicsSurface() { - DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter ); + DALI_LOG_TRACE_METHOD(gWindowRenderSurfaceLogFilter); // Destroy the old one mWindowBase->DestroyEglWindow(); int width, height; - if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 ) + if(mScreenRotationAngle == 0 || mScreenRotationAngle == 180) { - width = mPositionSize.width; + width = mPositionSize.width; height = mPositionSize.height; } else { - width = mPositionSize.height; + width = mPositionSize.height; height = mPositionSize.width; } // Create the EGL window - EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height ); + EGLNativeWindowType window = mWindowBase->CreateEglWindow(width, height); - // Set screen rotation - mScreenRotationFinished = false; - - auto eglGraphics = static_cast(mGraphics); + auto eglGraphics = static_cast(mGraphics); Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); - return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext ); + return eglImpl.ReplaceSurfaceWindow(window, mEGLSurface, mEGLContext); } -void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize ) +void WindowRenderSurface::UpdatePositionSize(Dali::PositionSize positionSize) { - bool needToMove = false; - bool needToResize = false; - // Check moving - if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) || - (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) ) + if((fabs(positionSize.x - mPositionSize.x) >= MINIMUM_DIMENSION_CHANGE) || + (fabs(positionSize.y - mPositionSize.y) >= MINIMUM_DIMENSION_CHANGE)) { - needToMove = true; - } + mPositionSize.x = positionSize.x; + mPositionSize.y = positionSize.y; - // Check resizing - if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) || - (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) ) - { - needToResize = true; + DALI_LOG_RELEASE_INFO("Update Position by server (%d, %d)\n", mPositionSize.x, mPositionSize.y); } +} + +void WindowRenderSurface::Move(Dali::PositionSize positionSize) +{ + mPositionSize.x = positionSize.x; + mPositionSize.y = positionSize.y; + + DALI_LOG_RELEASE_INFO("Update Position by client (%d, %d)\n", positionSize.x, positionSize.y); + + mWindowBase->Move(positionSize); +} + +void WindowRenderSurface::MoveResize(Dali::PositionSize positionSize) +{ + mPositionSize.x = positionSize.x; + mPositionSize.y = positionSize.y; + + DALI_LOG_RELEASE_INFO("Update Position by client (%d, %d)\n", positionSize.x, positionSize.y); + + mWindowBase->MoveResize(positionSize); +} + +void WindowRenderSurface::StartRender() +{ +} + +bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector>& damagedRects, Rect& clippingRect) +{ + InitializeGraphics(); + + Dali::Integration::Scene::FrameCallbackContainer callbacks; + + Dali::Integration::Scene scene = mScene.GetHandle(); - if( needToResize ) + if(scene) { - if( needToMove ) + bool needFrameRenderedTrigger = false; + + scene.GetFrameRenderedCallback(callbacks); + if(!callbacks.empty()) { - mWindowBase->MoveResize( positionSize ); + int frameRenderedSync = mWindowBase->CreateFrameRenderedSyncFence(); + if(frameRenderedSync != -1) + { + Dali::Mutex::ScopedLock lock(mMutex); + + DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence [%d]\n", frameRenderedSync); + + mFrameCallbackInfoContainer.push_back(std::unique_ptr(new FrameCallbackInfo(callbacks, frameRenderedSync))); + + needFrameRenderedTrigger = true; + } + else + { + DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFrameRenderedSyncFence is failed\n"); + } + + // Clear callbacks + callbacks.clear(); } - else + + scene.GetFramePresentedCallback(callbacks); + if(!callbacks.empty()) { - mWindowBase->Resize( positionSize ); + int framePresentedSync = mWindowBase->CreateFramePresentedSyncFence(); + if(framePresentedSync != -1) + { + Dali::Mutex::ScopedLock lock(mMutex); + + DALI_LOG_RELEASE_INFO("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence [%d]\n", framePresentedSync); + + mFrameCallbackInfoContainer.push_back(std::unique_ptr(new FrameCallbackInfo(callbacks, framePresentedSync))); + + needFrameRenderedTrigger = true; + } + else + { + DALI_LOG_ERROR("WindowRenderSurface::PreRender: CreateFramePresentedSyncFence is failed\n"); + } + + // Clear callbacks + callbacks.clear(); } - mResizeFinished = false; - mPositionSize = positionSize; + if(needFrameRenderedTrigger) + { + if(!mFrameRenderedTrigger) + { + mFrameRenderedTrigger = std::unique_ptr(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessFrameCallback), + TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER)); + } + mFrameRenderedTrigger->Trigger(); + } } - else + + /** + * wl_egl_window_tizen_set_rotation(SetEglWindowRotation) -> PreRotation + * wl_egl_window_tizen_set_buffer_transform(SetEglWindowBufferTransform) -> Screen Rotation + * wl_egl_window_tizen_set_window_transform(SetEglWindowTransform) -> Window Rotation + * These function should be called before calling first drawing gl Function. + * Notice : PreRotation is not used in the latest tizen, + * because output transform event should be occured before egl window is not created. + */ + if(scene && resizingSurface) { - if( needToMove ) + int totalAngle = 0; + bool isScreenOrientationChanging = false; + + if(mWindowRotationAngle != scene.GetCurrentSurfaceOrientation()) { - mWindowBase->Move( positionSize ); + mWindowRotationAngle = scene.GetCurrentSurfaceOrientation(); + mIsWindowOrientationChanging = true; + } - mPositionSize = positionSize; + if(mScreenRotationAngle != scene.GetCurrentScreenOrientation()) + { + mScreenRotationAngle = scene.GetCurrentScreenOrientation(); + isScreenOrientationChanging = true; } - } + totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360; - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height ); -} + DALI_LOG_RELEASE_INFO("Window/Screen orientation ard changed, WinOrientation[%d],flag[%d], ScreenOrientation[%d],flag[%d], total[%d]\n", mWindowRotationAngle, mIsWindowOrientationChanging, mScreenRotationAngle, isScreenOrientationChanging, totalAngle); -void WindowRenderSurface::StartRender() -{ -} + Rect surfaceSize = scene.GetCurrentSurfaceRect(); + //update surface size + mPositionSize.width = surfaceSize.width; + mPositionSize.height = surfaceSize.height; -bool WindowRenderSurface::PreRender( bool resizingSurface ) -{ - MakeContextCurrent(); + DALI_LOG_RELEASE_INFO("Window is resizing, (%d, %d), [%d x %d], IMEWindow [%d]\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height, mIsImeWindowSurface); - if( resizingSurface ) - { // Window rotate or screen rotate - if( !mRotationFinished || !mScreenRotationFinished ) + if(mIsWindowOrientationChanging || isScreenOrientationChanging) { - int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360; - - mWindowBase->SetEglWindowRotation( totalAngle ); - mWindowBase->SetEglWindowBufferTransform( totalAngle ); - - // Reset only screen rotation flag - mScreenRotationFinished = true; - - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle ); + mWindowBase->SetEglWindowBufferTransform(totalAngle); } // Only window rotate - if( !mRotationFinished ) + if(mIsWindowOrientationChanging) { - mWindowBase->SetEglWindowTransform( mRotationAngle ); + mWindowBase->SetEglWindowTransform(mWindowRotationAngle); } // Resize case - if( !mResizeFinished ) - { - mWindowBase->ResizeEglWindow( mPositionSize ); - mResizeFinished = true; + Dali::PositionSize positionSize; - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" ); + // Some native resize API(wl_egl_window_resize) has the input parameters of x, y, width and height. + // So, position data should be set. + positionSize.x = mPositionSize.x; + positionSize.y = mPositionSize.y; + if(totalAngle == 0 || totalAngle == 180) + { + positionSize.width = mPositionSize.width; + positionSize.height = mPositionSize.height; } + else + { + positionSize.width = mPositionSize.height; + positionSize.height = mPositionSize.width; + } + + mWindowBase->ResizeEglWindow(positionSize); + + SetFullSwapNextFrame(); } - auto eglGraphics = static_cast(mGraphics); - if ( eglGraphics ) + // When mIsFrontBufferRendering is not equal to mWindowBase's + if(mIsFrontBufferRenderingChanged) { - GlImplementation& mGLES = eglGraphics->GetGlesInterface(); - mGLES.PreRender(); + mIsFrontBufferRenderingChanged = false; + mWindowBase->SetEglWindowFrontBufferMode(mIsFrontBufferRendering); + SetFullSwapNextFrame(); + } + + SetBufferDamagedRects(damagedRects, clippingRect); + + if(scene) + { + Rect surfaceRect = scene.GetCurrentSurfaceRect(); + if(clippingRect == surfaceRect) + { + int32_t totalAngle = scene.GetCurrentSurfaceOrientation() + scene.GetCurrentScreenOrientation(); + if(totalAngle >= 360) + { + totalAngle -= 360; + } + mDamagedRects.assign(1, RecalculateRect[std::min(totalAngle / 90, 3)](surfaceRect, surfaceRect)); + } } + // This is now done when the render pass for the render surface begins + // MakeContextCurrent(); + return true; } -void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface ) +void WindowRenderSurface::PostRender() { // Inform the gl implementation that rendering has finished before informing the surface - auto eglGraphics = static_cast(mGraphics); - if ( eglGraphics ) + auto eglGraphics = static_cast(mGraphics); + if(eglGraphics) { GlImplementation& mGLES = eglGraphics->GetGlesInterface(); mGLES.PostRender(); - if( renderToFbo ) - { - mGLES.Flush(); - mGLES.Finish(); - } - else + bool needWindowRotationCompleted = false; + + if(mIsWindowOrientationChanging) { - if( resizingSurface ) + if(mNeedWindowRotationAcknowledgement) { - if( !mRotationFinished ) + Dali::Integration::Scene scene = mScene.GetHandle(); + if(scene) { - if( mThreadSynchronization ) + if(scene.IsRotationCompletedAcknowledgementSet()) { - // Enable PostRender flag - mThreadSynchronization->PostRenderStarted(); + needWindowRotationCompleted = true; } + } + } + else + { + needWindowRotationCompleted = true; + } + } - DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" ); + if(needWindowRotationCompleted || mIsImeWindowSurface) + { + if(mThreadSynchronization) + { + // Enable PostRender flag + mThreadSynchronization->PostRenderStarted(); + } - mRotationTrigger->Trigger(); + if(mIsWindowOrientationChanging || mIsImeWindowSurface) + { + mPostRenderTrigger->Trigger(); + } - if( mThreadSynchronization ) - { - // Wait until the event-thread complete the rotation event processing - mThreadSynchronization->PostRenderWaitForCompletion(); - } - } + if(mThreadSynchronization) + { + // Wait until the event-thread complete the rotation event processing + mThreadSynchronization->PostRenderWaitForCompletion(); } } - Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); - eglImpl.SwapBuffers( mEGLSurface ); + SwapBuffers(mDamagedRects); - if( mRenderNotification ) + if(mRenderNotification) { mRenderNotification->Trigger(); } @@ -450,9 +684,9 @@ void WindowRenderSurface::StopRender() { } -void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) +void WindowRenderSurface::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization) { - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" ); + DALI_LOG_INFO(gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n"); mThreadSynchronization = &threadSynchronization; } @@ -469,9 +703,9 @@ Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType() void WindowRenderSurface::MakeContextCurrent() { - if ( mEGL != nullptr ) + if(mEGL != nullptr) { - mEGL->MakeContextCurrent( mEGLSurface, mEGLContext ); + mEGL->MakeContextCurrent(mEGLSurface, mEGLContext); } } @@ -485,41 +719,252 @@ Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequire return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE; } +void WindowRenderSurface::InitializeImeSurface() +{ + if(!mIsImeWindowSurface) + { + mIsImeWindowSurface = true; + if(!mPostRenderTrigger) + { + mPostRenderTrigger = std::unique_ptr(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &WindowRenderSurface::ProcessPostRender), + TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER)); + + } + } +} + +void WindowRenderSurface::SetNeedsRotationCompletedAcknowledgement(bool needAcknowledgement) +{ + mNeedWindowRotationAcknowledgement = needAcknowledgement; +} + void WindowRenderSurface::OutputTransformed() { int screenRotationAngle = mWindowBase->GetScreenRotationAngle(); - if( mScreenRotationAngle != screenRotationAngle ) + if(mScreenRotationAngle != screenRotationAngle) { - mScreenRotationAngle = screenRotationAngle; - mScreenRotationFinished = false; - mOutputTransformedSignal.Emit(); - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle ); + DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: window = %d new screen angle = %d\n", mWindowRotationAngle, screenRotationAngle); } else { - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle ); + DALI_LOG_RELEASE_INFO("WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle); } } -void WindowRenderSurface::ProcessRotationRequest() +void WindowRenderSurface::ProcessPostRender() { - mRotationFinished = true; - - mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height ); + if(mIsWindowOrientationChanging) + { + mWindowRotationFinishedSignal.Emit(); + mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height); + mIsWindowOrientationChanging = false; + DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessPostRender: Rotation Done, flag = %d\n", mIsWindowOrientationChanging); + } - DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" ); + if(mIsImeWindowSurface) + { + mWindowBase->ImeWindowReadyToRender(); + } - if( mThreadSynchronization ) + if(mThreadSynchronization) { mThreadSynchronization->PostRenderComplete(); } } +void WindowRenderSurface::ProcessFrameCallback() +{ + Dali::Mutex::ScopedLock lock(mMutex); + + for(auto&& iter : mFrameCallbackInfoContainer) + { + if(!iter->fileDescriptorMonitor) + { + iter->fileDescriptorMonitor = Dali::Internal::Adaptor::GetSystemFactory()->CreateFileDescriptorMonitor(iter->fileDescriptor, MakeCallback(this, &WindowRenderSurface::OnFileDescriptorEventDispatched), FileDescriptorMonitor::FD_READABLE); + + DALI_LOG_RELEASE_INFO("WindowRenderSurface::ProcessFrameCallback: Add handler [%d]\n", iter->fileDescriptor); + } + } +} + +void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor::EventType eventBitMask, int fileDescriptor) +{ + DALI_LOG_RELEASE_INFO("WindowRenderSurface::OnFileDescriptorEventDispatched: Frame rendered [%d]\n", fileDescriptor); + + std::unique_ptr callbackInfo; + { + Dali::Mutex::ScopedLock lock(mMutex); + auto frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr& callbackInfo) { + return callbackInfo->fileDescriptor == fileDescriptor; + }); + if(frameCallbackInfo != mFrameCallbackInfoContainer.end()) + { + callbackInfo = std::move(*frameCallbackInfo); + + mFrameCallbackInfoContainer.erase(frameCallbackInfo); + } + } + + // Call the connected callback + if(callbackInfo && (eventBitMask & FileDescriptorMonitor::FD_READABLE)) + { + for(auto&& iter : (callbackInfo)->callbacks) + { + CallbackBase::Execute(*(iter.first), iter.second); + } + } +} + +void WindowRenderSurface::SetBufferDamagedRects(const std::vector>& damagedRects, Rect& clippingRect) +{ + auto eglGraphics = static_cast(mGraphics); + if(eglGraphics) + { + // If scene is not exist, just use stored mPositionSize. + Rect surfaceRect(0, 0, mPositionSize.width, mPositionSize.height); + int32_t orientation = 0; + + Dali::Integration::Scene scene = mScene.GetHandle(); + if(scene) + { + surfaceRect = scene.GetCurrentSurfaceRect(); + int32_t totalAngle = scene.GetCurrentSurfaceOrientation() + scene.GetCurrentScreenOrientation(); + if(totalAngle >= 360) + { + totalAngle -= 360; + } + orientation = std::min(totalAngle / 90, 3); + } + + Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); + if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame) + { + InsertRects(mBufferDamagedRects, surfaceRect); + clippingRect = surfaceRect; + return; + } + + if(damagedRects.empty()) + { + // Empty damaged rect. We don't need rendering + clippingRect = Rect(); + // Clean up current damanged rects. + mDamagedRects.clear(); + return; + } + + mGraphics->ActivateSurfaceContext(this); + + EGLint bufferAge = eglImpl.GetBufferAge(mEGLSurface); + + // Buffer age 0 means the back buffer in invalid and requires full swap + if(bufferAge == 0) + { + InsertRects(mBufferDamagedRects, surfaceRect); + clippingRect = surfaceRect; + return; + } + + mDamagedRects.assign(damagedRects.begin(), damagedRects.end()); + + // 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 + // And then, Make one clipping rect, and rotate rects by orientation. + MergeIntersectingRectsAndRotate(clippingRect, mDamagedRects, orientation, surfaceRect); + + // We push current frame damaged rects here, zero index for current frame + InsertRects(mBufferDamagedRects, clippingRect); + + // Merge damaged rects into clipping rect + if(bufferAge <= static_cast(mBufferDamagedRects.size())) + { + // clippingRect is already the current frame's damaged rect. Merge from the second + for(int i = 1; i < bufferAge; i++) + { + clippingRect.Merge(mBufferDamagedRects[i]); + } + } + else + { + // The buffer age is too old. Need full update. + clippingRect = surfaceRect; + return; + } + + if(!clippingRect.Intersect(surfaceRect) || clippingRect.Area() > surfaceRect.Area() * FULL_UPDATE_RATIO) + { + // clipping area too big or doesn't intersect surface rect + clippingRect = surfaceRect; + return; + } + + if(!clippingRect.IsEmpty()) + { + std::vector> damagedRegion; + if(scene) + { + damagedRegion.push_back(RecalculateRect[orientation](clippingRect, surfaceRect)); + } + else + { + damagedRegion.push_back(clippingRect); + } + + eglImpl.SetDamageRegion(mEGLSurface, damagedRegion); + } + } +} + +void WindowRenderSurface::SwapBuffers(const std::vector>& damagedRects) +{ + auto eglGraphics = static_cast(mGraphics); + if(eglGraphics) + { + Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation(); + + if(!eglImpl.IsPartialUpdateRequired() || mFullSwapNextFrame) + { + mFullSwapNextFrame = false; + eglImpl.SwapBuffers(mEGLSurface); + return; + } + + mFullSwapNextFrame = false; + + Rect surfaceRect; + Dali::Integration::Scene scene = mScene.GetHandle(); + if(scene) + { + surfaceRect = scene.GetCurrentSurfaceRect(); + } + + if(!damagedRects.size() || (damagedRects[0].Area() > surfaceRect.Area() * FULL_UPDATE_RATIO)) + { + // In normal cases, WindowRenderSurface::SwapBuffers() will not be called if mergedRects.size() is 0. + // For exceptional cases, swap full area. + eglImpl.SwapBuffers(mEGLSurface); + } + else + { + eglImpl.SwapBuffers(mEGLSurface, damagedRects); + } + } +} + +void WindowRenderSurface::SetFrontBufferRendering(bool enable) +{ + if(mIsFrontBufferRendering != enable) + { + mIsFrontBufferRendering = enable; + mIsFrontBufferRenderingChanged = !mIsFrontBufferRenderingChanged; + } +} + } // namespace Adaptor -} // namespace internal +} // namespace Internal } // namespace Dali