fix window resize and roation issue in GlWindow 70/256570/13
authorWonsik Jung <sidein@samsung.com>
Wed, 7 Apr 2021 08:31:00 +0000 (17:31 +0900)
committerWonsik Jung <sidein@samsung.com>
Thu, 6 May 2021 01:50:07 +0000 (10:50 +0900)
After render thread function was added to GlWindow,
GlWindow's resize and rotation don't work.
This patch is to fix them

Change-Id: I0708a3531309b5588a8b28a97315a0afa5bdb05a

dali/internal/window-system/common/gl-window-impl.cpp
dali/internal/window-system/common/gl-window-impl.h
dali/internal/window-system/common/gl-window-render-thread.cpp
dali/internal/window-system/common/gl-window-render-thread.h

index 89d4398..b491bc7 100644 (file)
@@ -74,8 +74,6 @@ GlWindow::GlWindow()
   mOpaqueState(false),
   mResizeEnabled(false),
   mVisible(false),
-  mIsRotated(false),
-  mIsWindowRotated(false),
   mIsTouched(false),
   mIsEGLInitialized(false),
   mDepth(false),
@@ -149,6 +147,7 @@ void GlWindow::Initialize(const PositionSize& positionSize, const std::string& n
   mWindowBase = windowFactory->CreateWindowBase(mPositionSize, surface, (mIsTransparent ? true : false));
   mWindowBase->IconifyChangedSignal().Connect(this, &GlWindow::OnIconifyChanged);
   mWindowBase->FocusChangedSignal().Connect(this, &GlWindow::OnFocusChanged);
+  mWindowBase->OutputTransformedSignal().Connect(this, &GlWindow::OnOutputTransformed);
 
   if(Dali::Adaptor::IsAvailable())
   {
@@ -385,11 +384,16 @@ void GlWindow::SetPositionSize(PositionSize positionSize)
   }
 
   // If window's size or position is changed, the signal will be emitted to user.
-  if((needToMove) || (needToResize))
+  if(needToMove || needToResize)
   {
     Uint16Pair     newSize(mPositionSize.width, mPositionSize.height);
     Dali::GlWindow handle(this);
     mResizeSignal.Emit(newSize);
+
+    if(mGlWindowRenderThread)
+    {
+      mGlWindowRenderThread->RequestWindowResize(mPositionSize.width, mPositionSize.height);
+    }
   }
 }
 
@@ -461,26 +465,12 @@ void GlWindow::OnFocusChanged(bool focusIn)
 
 void GlWindow::OnOutputTransformed()
 {
-  int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
-  if(screenRotationAngle != mScreenRotationAngle)
-  {
-    mScreenRotationAngle = screenRotationAngle;
-    mTotalRotationAngle  = (mWindowRotationAngle + mScreenRotationAngle) % 360;
-
-    if(mTotalRotationAngle == 90 || mTotalRotationAngle == 270)
-    {
-      mWindowWidth  = mPositionSize.height;
-      mWindowHeight = mPositionSize.width;
-    }
-    else
-    {
-      mWindowWidth  = mPositionSize.width;
-      mWindowHeight = mPositionSize.height;
-    }
+  int newScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
+  DALI_LOG_RELEASE_INFO("GlWindow::OnOutputTransformed(), screen rotation occurs, old[%d], new[%d\n", mScreenRotationAngle, newScreenRotationAngle);
 
-    // Emit Resize signal
-    Dali::GlWindow handle(this);
-    mResizeSignal.Emit(Dali::Uint16Pair(mWindowWidth, mWindowHeight));
+  if(newScreenRotationAngle != mScreenRotationAngle)
+  {
+    UpdateScreenRotation(newScreenRotationAngle);
   }
 }
 
@@ -537,13 +527,16 @@ void GlWindow::OnRotation(const RotationEvent& rotation)
     mWindowHeight = mPositionSize.height;
   }
 
-  mIsRotated       = true;
-  mIsWindowRotated = true;
   DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), OnRotation(): resize signal emit [%d x %d]\n", this, mNativeWindowId, mWindowWidth, mWindowHeight);
 
   // Emit Resize signal
   Dali::GlWindow handle(this);
   mResizeSignal.Emit(Dali::Uint16Pair(mWindowWidth, mWindowHeight));
+
+  if(mGlWindowRenderThread)
+  {
+    mGlWindowRenderThread->RequestWindowRotate(mWindowRotationAngle);
+  }
 }
 
 void GlWindow::RecalculateTouchPosition(Integration::Point& point)
@@ -823,6 +816,14 @@ void GlWindow::InitializeGraphics()
     mGlWindowRenderThread->SetOnDemandRenderMode(onDemand);
 
     mIsEGLInitialized = true;
+
+    // Check screen rotation
+    int newScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
+    DALI_LOG_RELEASE_INFO("GlWindow::InitializeGraphics(), GetScreenRotationAngle(): %d\n", mScreenRotationAngle);
+    if(newScreenRotationAngle != 0)
+    {
+      UpdateScreenRotation(newScreenRotationAngle);
+    }
   }
 }
 
@@ -830,6 +831,33 @@ void GlWindow::OnDamaged(const DamageArea& area)
 {
 }
 
+void GlWindow::UpdateScreenRotation(int newAngle)
+{
+  mScreenRotationAngle = newAngle;
+  mTotalRotationAngle  = (mWindowRotationAngle + mScreenRotationAngle) % 360;
+
+  if(mTotalRotationAngle == 90 || mTotalRotationAngle == 270)
+  {
+    mWindowWidth  = mPositionSize.height;
+    mWindowHeight = mPositionSize.width;
+  }
+  else
+  {
+    mWindowWidth  = mPositionSize.width;
+    mWindowHeight = mPositionSize.height;
+  }
+
+  // Emit Resize signal
+  Dali::GlWindow handle(this);
+  mResizeSignal.Emit(Dali::Uint16Pair(mWindowWidth, mWindowHeight));
+
+  if(mGlWindowRenderThread)
+  {
+    DALI_LOG_RELEASE_INFO("GlWindow::UpdateScreenRotation(), RequestScreenRotatem(), mScreenRotationAngle: %d\n", mScreenRotationAngle);
+    mGlWindowRenderThread->RequestScreenRotate(mScreenRotationAngle);
+  }
+}
+
 } // namespace Adaptor
 
 } // namespace Internal
index 4102736..954e297 100644 (file)
@@ -332,6 +332,13 @@ private: // From Dali::Internal::Adaptor::DamageObserver
    */
   void OnDamaged(const DamageArea& area);
 
+  /**
+   * @brief Updates screen rotation value and screen rotation works.
+   *
+   * @param[in] newAngle new screen rotation angle
+   */
+  void UpdateScreenRotation(int newAngle);
+
 public: // Signals
   /**
    * @copydoc Dali::GlWindow::FocusChangeSignal()
@@ -388,7 +395,6 @@ private:
   bool                                     mOpaqueState : 1;
   bool                                     mResizeEnabled : 1;
   bool                                     mVisible : 1;
-  bool                                     mIsRotated : 1;
   bool                                     mIsWindowRotated : 1;
   bool                                     mIsTouched : 1;
   bool                                     mIsEGLInitialized : 1;
index 55010ce..eacefaa 100644 (file)
  *
  */
 
+// EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/thread-settings.h>
 
+// INTERNAL INCLUDES
 #include <dali/internal/adaptor/common/adaptor-impl.h>
 #include <dali/internal/system/common/time-service.h>
 #include <dali/internal/window-system/common/gl-window-render-thread.h>
@@ -35,11 +37,13 @@ const unsigned int NANOSECONDS_PER_SECOND(1e+9);
 const float    DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f);
 const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND);
 
+const int MINIMUM_DIMENSION_CHANGE(1);
 } // namespace
 
 GlWindowRenderThread::GlWindowRenderThread(PositionSize positionSize, ColorDepth colorDepth)
 : mGraphics(nullptr),
   mWindowBase(nullptr),
+  mWindowRotationTrigger(),
   mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
   mPositionSize(positionSize),
   mColorDepth(colorDepth),
@@ -53,11 +57,14 @@ GlWindowRenderThread::GlWindowRenderThread(PositionSize positionSize, ColorDepth
   mIsEGLInitialize(false),
   mGLESVersion(30), //Default GLES version 30
   mMSAA(0),
+  mWindowRotationAngle(0),
+  mScreenRotationAngle(0),
   mRenderThreadWaitCondition(),
   mDestroyRenderThread(0),
   mPauseRenderThread(0),
   mRenderingMode(0),
-  mRequestRenderOnce(0)
+  mRequestRenderOnce(0),
+  mSurfaceStatus(0)
 {
   unsigned int refrashRate         = 1u;
   mDefaultFrameDurationNanoseconds = uint64_t(refrashRate) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
@@ -136,13 +143,83 @@ void GlWindowRenderThread::RenderOnce()
   mRenderThreadWaitCondition.Notify(lock);
 }
 
+void GlWindowRenderThread::RequestWindowResize(int width, int height)
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  // Check resizing
+  if((fabs(width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
+     (fabs(height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE))
+  {
+    mSurfaceStatus |= static_cast<unsigned int>(SurfaceStatus::RESIZED); // Set bit for window resized
+    mPositionSize.width  = width;
+    mPositionSize.height = height;
+
+    DALI_LOG_RELEASE_INFO("GlWindowRenderThread::RequestWindowResize(), width:%d, height:%d\n", width, height);
+    mRenderThreadWaitCondition.Notify(lock);
+  }
+}
+
+void GlWindowRenderThread::RequestWindowRotate(int windowAngle)
+{
+  if(!mWindowRotationTrigger)
+  {
+    mWindowRotationTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &GlWindowRenderThread::WindowRotationCompleted),
+                                                                                                            TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
+  }
+
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  if(mWindowRotationAngle != windowAngle)
+  {
+    mSurfaceStatus |= static_cast<unsigned int>(SurfaceStatus::WINDOW_ROTATED); // Set bit for window rotation
+    mWindowRotationAngle = windowAngle;
+    DALI_LOG_RELEASE_INFO("GlWindowRenderThread::RequestWindowRotate(): %d\n", windowAngle);
+    mRenderThreadWaitCondition.Notify(lock);
+  }
+}
+
+void GlWindowRenderThread::RequestScreenRotate(int screenAngle)
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  if(mScreenRotationAngle != screenAngle)
+  {
+    mSurfaceStatus |= static_cast<unsigned int>(SurfaceStatus::SCREEN_ROTATED); // Set bit for screen rotation
+    mScreenRotationAngle = screenAngle;
+    DALI_LOG_RELEASE_INFO("GlWindowRenderThread::RequestScreenRotate(): %d\n", screenAngle);
+    mRenderThreadWaitCondition.Notify(lock);
+  }
+}
+
+void GlWindowRenderThread::WindowRotationCompleted()
+{
+  mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
+
+  PostRenderFinish();
+}
+
+unsigned int GlWindowRenderThread::GetSurfaceStatus(int& windowRotationAngle, int& screenRotationAngle)
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+
+  // Get the surface status and reset that.
+  unsigned int status = mSurfaceStatus;
+  mSurfaceStatus       = static_cast<unsigned int>(SurfaceStatus::NO_CHANGED);
+
+  windowRotationAngle = mWindowRotationAngle;
+  screenRotationAngle = mScreenRotationAngle;
+
+  return status;
+}
+
 void GlWindowRenderThread::Run()
 {
   Dali::SetThreadName("GlWindowRenderThread");
   mLogFactory.InstallLogFunction();
 
-  int          renderFrameResult = 0;
-  EglGraphics* eglGraphics       = static_cast<EglGraphics*>(mGraphics);
+  int           renderFrameResult = 0;
+  unsigned int  isSurfaceChanged  = 0;
+  bool          isWindowResized = false, isWindowRotated = false, isScreenRotated = false;
+  int           windowRotationAngle = 0, screenRotationAngle = 0, totalAngle = 0;
+  EglGraphics*  eglGraphics = static_cast<EglGraphics*>(mGraphics);
 
   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
 
@@ -164,8 +241,58 @@ void GlWindowRenderThread::Run()
 
     if(mGLRenderFrameCallback)
     {
+      // PreRender
+      isSurfaceChanged = GetSurfaceStatus(windowRotationAngle, screenRotationAngle);
+      if(DALI_UNLIKELY(isSurfaceChanged))
+      {
+        isWindowResized = (isSurfaceChanged & static_cast<unsigned int>(SurfaceStatus::RESIZED)) ? true : false;
+        isWindowRotated = (isSurfaceChanged & static_cast<unsigned int>(SurfaceStatus::WINDOW_ROTATED)) ? true : false;
+        isScreenRotated = (isSurfaceChanged & static_cast<unsigned int>(SurfaceStatus::SCREEN_ROTATED)) ? true : false;
+        totalAngle      = (windowRotationAngle + screenRotationAngle) % 360;
+
+        if(isWindowRotated || isScreenRotated)
+        {
+          mWindowBase->SetEglWindowBufferTransform(totalAngle);
+          if(isWindowRotated)
+          {
+            mWindowBase->SetEglWindowTransform(windowRotationAngle);
+          }
+        }
+
+        if(isWindowResized)
+        {
+          Dali::PositionSize positionSize;
+          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);
+        }
+      }
+
+      // Render
       renderFrameResult = CallbackBase::ExecuteReturn<int>(*mGLRenderFrameCallback);
 
+      // PostRender
+      if(DALI_UNLIKELY(isWindowRotated))
+      {
+        PostRenderStart();
+
+        mWindowRotationTrigger->Trigger();
+
+        PostRenderWaitForFinished();
+        isWindowRotated = false;
+      }
+
+      // buffer commit
       if(renderFrameResult)
       {
         eglImpl.SwapBuffers(mEGLSurface);
@@ -253,7 +380,7 @@ void GlWindowRenderThread::InitializeGraphics(EglGraphics* eglGraphics)
 bool GlWindowRenderThread::RenderReady(uint64_t& timeToSleepUntil)
 {
   ConditionalWait::ScopedLock updateLock(mRenderThreadWaitCondition);
-  while((!mDestroyRenderThread && mRenderingMode && !mRequestRenderOnce) || mPauseRenderThread)
+  while((!mDestroyRenderThread && mRenderingMode && !mRequestRenderOnce && !mSurfaceStatus) || mPauseRenderThread)
   {
     timeToSleepUntil = 0;
     mRenderThreadWaitCondition.Wait(updateLock);
@@ -264,6 +391,28 @@ bool GlWindowRenderThread::RenderReady(uint64_t& timeToSleepUntil)
   return !mDestroyRenderThread;
 }
 
+void GlWindowRenderThread::PostRenderStart()
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  mPostRendering = false;
+}
+
+void GlWindowRenderThread::PostRenderFinish()
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  mPostRendering = true;
+  mRenderThreadWaitCondition.Notify(lock);
+}
+
+void GlWindowRenderThread::PostRenderWaitForFinished()
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  while(!mPostRendering && !mDestroyRenderThread)
+  {
+    mRenderThreadWaitCondition.Wait(lock);
+  }
+}
+
 } // namespace Adaptor
 
 } // namespace Internal
index 8111d69..8283c30 100644 (file)
@@ -29,6 +29,7 @@
 namespace Dali
 {
 class Adaptor;
+class TriggerEventInterface;
 
 namespace Internal
 {
@@ -61,6 +62,19 @@ class GlWindowRenderThread : public Dali::Thread
 {
 public:
   /**
+   * @brief Enumeration for GlWindow Surface status type
+   * It has the status as resized, window is rotated and screen is rotated.
+   *
+   */
+  enum class SurfaceStatus
+  {
+    NO_CHANGED     = 0x00, ///< no changed,
+    RESIZED        = 0x01, ///< When surface is resized,
+    WINDOW_ROTATED = 0x02, ///< When window is rotated,
+    SCREEN_ROTATED = 0x04  ///< When screen is rotated,
+  };
+
+  /**
    * Constructor
    *
    * @param[in] positionSize The position and size of the physical window
@@ -141,6 +155,28 @@ public:
    */
   void RenderOnce();
 
+  /**
+   * Requests the window resize to GlWindow's render thread.
+   *
+   * @param[in] width new width.
+   * @param[in] height new height.
+   */
+  void RequestWindowResize(int width, int height);
+
+  /**
+   * Requests the window rotation to GlWindow's render thread.
+   *
+   * @param[in] windowAngle the window rotation's angle as 0, 90, 180 and 270.
+   */
+  void RequestWindowRotate(int windowAngle);
+
+  /**
+   * Requests the screen rotation to GlWindow's render thread.
+   *
+   * @param[in] screenAngle the screen rotation's angle as 0, 90, 180 and 270.
+   */
+  void RequestScreenRotate(int screenAngle);
+
 protected:
   /**
    * The Render thread loop. This thread will be destroyed on exit from this function.
@@ -161,9 +197,53 @@ private:
    */
   bool RenderReady(uint64_t& timeToSleepUntil);
 
+  /**
+   * In the Tizen world, when GlWindow rotation is finished in client side,
+   * the completed message should be sent to display server.
+   * This function should be called in the event thread after buffer is committed.
+   */
+  void WindowRotationCompleted();
+
+  /**
+   * Gets window's current surface status
+   *
+   * @brief This function return window's current surface status.
+   * The status has the  the information of window resized, window rotated and screen rotated.
+   * After called, the status value is reset
+   *
+   * @[output] windowRotationAngle return current window rotation angle.
+   * @[output] screenRotationAngle return current screen rotation angle.
+   * @return the window's current surface status.
+   */
+  unsigned int GetSurfaceStatus(int& windowRotationAngle, int& screenRotationAngle);
+
+  /**
+   * Starts post rendering process
+   *
+   * @brief Starts post rendering process for window rotation
+   * It is to pause the render thread until maint thread finishes the window rotation work.
+   */
+  void PostRenderStart();
+
+  /**
+   * Finishs post rendering process
+   *
+   * @brief Finishes post rendering process for window rotation
+   * It set the resume flag for resume the render thread.
+   */
+  void PostRenderFinish();
+
+  /**
+   * Pauses the render thread unitil post rendering process
+   *
+   * @brief Pauses the render thread until main thread works window rotation.
+   */
+  void PostRenderWaitForFinished();
+
 private:
-  GraphicsInterface* mGraphics; ///< Graphics interface
-  WindowBase*        mWindowBase;
+  GraphicsInterface*                     mGraphics; ///< Graphics interface
+  WindowBase*                            mWindowBase;
+  std::unique_ptr<TriggerEventInterface> mWindowRotationTrigger;
 
   const Dali::LogFactoryInterface& mLogFactory;
 
@@ -181,13 +261,17 @@ private:
   bool                          mIsEGLInitialize : 1;
   int                           mGLESVersion;
   int                           mMSAA;
+  int                           mWindowRotationAngle; ///< The angle of window rotation angle
+  int                           mScreenRotationAngle; ///< The angle of screen rotation angle
 
   // To manage the render/main thread
-  ConditionalWait       mRenderThreadWaitCondition; ///< The wait condition for the update-render-thread.
-  volatile unsigned int mDestroyRenderThread;       ///< Stop render thread. It means this rendter thread will be destoried.
-  volatile unsigned int mPauseRenderThread;         ///< Sleep render thread by pause.
-  volatile unsigned int mRenderingMode;             ///< Rendering Mode, 0: continuous, 1:OnDemad
-  volatile unsigned int mRequestRenderOnce;         ///< Request rendering once
+  ConditionalWait                 mRenderThreadWaitCondition; ///< The wait condition for the update-render-thread.
+  volatile unsigned int           mDestroyRenderThread;       ///< Stop render thread. It means this rendter thread will be destoried.
+  volatile unsigned int           mPauseRenderThread;         ///< Sleep render thread by pause.
+  volatile unsigned int           mRenderingMode;             ///< Rendering Mode, 0: continuous, 1:OnDemad
+  volatile unsigned int           mRequestRenderOnce;         ///< Request rendering once
+  volatile unsigned int           mSurfaceStatus;             ///< When surface is changed as resized or rotated, this flag is set. 0: No changed, 1:resized, 2:window rotation, 4:screen rotation
+  volatile unsigned int           mPostRendering;             ///< Whether post-rendering is taking place (set by the event & render threads, read by the render-thread).
 
   uint64_t mDefaultFrameDurationNanoseconds; ///< Default duration of a frame (used for sleeping if not enough time elapsed). Not protected by lock, but written to rarely so not worth adding a lock when reading.