Add render threading for GlWindow 86/247686/18
authorWonsik Jung <sidein@samsung.com>
Fri, 13 Nov 2020 09:48:27 +0000 (18:48 +0900)
committerWonsik Jung <sidein@samsung.com>
Fri, 22 Jan 2021 09:18:03 +0000 (18:18 +0900)
Add the render threading for GlWindow.
The user callback works on the separated render thread.

Change-Id: Ic2470a1fc70f02fa0d1819e8bb36c6e62325022c

dali/devel-api/adaptor-framework/gl-window.cpp
dali/devel-api/adaptor-framework/gl-window.h
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 [new file with mode: 0644]
dali/internal/window-system/common/gl-window-render-thread.h [new file with mode: 0644]
dali/internal/window-system/file.list

index 7eccfec..bd85059 100644 (file)
@@ -185,6 +185,16 @@ void GlWindow::RenderOnce()
   GetImplementation(*this).RenderOnce();
 }
 
+void GlWindow::SetRenderingMode( RenderingMode mode )
+{
+  GetImplementation(*this).SetRenderingMode( mode );
+}
+
+GlWindow::RenderingMode GlWindow::GetRenderingMode() const
+{
+  return GetImplementation(*this).GetRenderingMode();
+}
+
 GlWindow::FocusChangeSignalType& GlWindow::FocusChangeSignal()
 {
   return GetImplementation(*this).FocusChangeSignal();
index 986c3ff..ccd51fa 100644 (file)
@@ -90,6 +90,20 @@ public:
   };
 
   /**
+   * @brief Enumeration for rendering mode
+   *
+   * This Enumeration is used to choose the rendering mode.
+   * It has two options.
+   * One of them is continuous mode. It is rendered continuously.
+   * The other is on demand mode. It is rendered by application.
+   */
+  enum class RenderingMode
+  {
+    CONTINUOUS,                  ///< continuous mode
+    ON_DEMAND                    ///< on demand by application
+  };
+
+  /**
    * @brief Creates an initialized handle to a new GlWindow.
    *
    * @return A new GlWindow
@@ -362,6 +376,26 @@ public:
    */
   void RenderOnce();
 
+  /**
+   * @brief Sets rendering mode.
+   *
+   * @param[in] mode the rendering mode for GlWindow
+   *
+   * @note The default Rendering mode is continuous.
+   * If OnDemand mode is set, it is rendered by RenderOnce()
+   */
+  void SetRenderingMode( RenderingMode mode );
+
+  /**
+   * @brief Gets rendering mode.
+   *
+   * @return current rendering mode in this GlWindow
+   *
+   * @note The default Rendering mode is continuous.
+   * If OnDemand mode is set, it is rendered by RenderOnce()
+   */
+  RenderingMode GetRenderingMode() const;
+
 public: // Signals
 
   /**
index 520082b..89d4398 100644 (file)
@@ -66,9 +66,8 @@ GlWindow::GlWindow()
 : mWindowBase(),
   mGraphics(),
   mDisplayConnection(nullptr),
+  mGlWindowRenderThread(nullptr),
   mEventHandler(nullptr),
-  mPositionSize(),
-  mColorDepth(COLOR_DEPTH_24),
   mIsTransparent(false),
   mIsFocusAcceptable(false),
   mIconified(false),
@@ -78,7 +77,13 @@ GlWindow::GlWindow()
   mIsRotated(false),
   mIsWindowRotated(false),
   mIsTouched(false),
+  mIsEGLInitialized(false),
+  mDepth(false),
+  mStencil(false),
+  mPositionSize(),
   mAvailableAngles(),
+  mColorDepth(COLOR_DEPTH_24),
+  mRenderingMode(Dali::GlWindow::RenderingMode::CONTINUOUS),
   mPreferredAngle(0),
   mTotalRotationAngle(0),
   mWindowRotationAngle(0),
@@ -87,23 +92,12 @@ GlWindow::GlWindow()
   mWindowWidth(0),
   mWindowHeight(0),
   mNativeWindowId(-1),
+  mMSAA(0),
   mKeyEventSignal(),
   mTouchedSignal(),
   mFocusChangeSignal(),
   mResizeSignal(),
-  mVisibilityChangedSignal(),
-  mGLInitCallback(),
-  mGLRenderFrameCallback(),
-  mGLTerminateCallback(),
-  mGLRenderCallback(nullptr),
-  mEGLSurface(nullptr),
-  mEGLContext(nullptr),
-  mGLESVersion(Dali::GlWindow::GlesVersion::VERSION_3_0),
-  mInitCallback(false),
-  mDepth(false),
-  mStencil(false),
-  mIsEGLInitialize(false),
-  mMSAA(0)
+  mVisibilityChangedSignal()
 {
 }
 
@@ -114,31 +108,14 @@ GlWindow::~GlWindow()
     mEventHandler->RemoveObserver(*this);
   }
 
-  if(mGLTerminateCallback)
+  if(mGlWindowRenderThread)
   {
-    CallbackBase::Execute(*mGLTerminateCallback);
+    mGlWindowRenderThread->Stop();
+    mGlWindowRenderThread->Join();
   }
 
-  if(mIsEGLInitialize)
+  if(mIsEGLInitialized)
   {
-    GraphicsInterface*                    graphics    = mGraphics.get();
-    EglGraphics*                          eglGraphics = static_cast<EglGraphics*>(graphics);
-    Internal::Adaptor::EglImplementation& eglImpl     = eglGraphics->GetEglImplementation();
-
-    if(mEGLSurface)
-    {
-      eglImpl.DestroySurface(mEGLSurface);
-      mEGLSurface = nullptr;
-    }
-
-    if(mEGLContext)
-    {
-      eglImpl.DestroyContext(mEGLContext);
-      mEGLContext = nullptr;
-    }
-
-    eglImpl.TerminateGles();
-
     mGraphics->Destroy();
   }
 }
@@ -217,12 +194,24 @@ void GlWindow::SetClass(const std::string& name, const std::string className)
 void GlWindow::SetEglConfig(bool depth, bool stencil, int msaa, Dali::GlWindow::GlesVersion version)
 {
   // Init Graphics
-  mDepth       = depth;
-  mStencil     = stencil;
-  mMSAA        = msaa;
-  mGLESVersion = version;
+  mDepth   = depth;
+  mStencil = stencil;
+  mMSAA    = msaa;
 
   InitializeGraphics();
+
+  int rVersion = 30;
+
+  if(version == Dali::GlWindow::GlesVersion::VERSION_2_0)
+  {
+    rVersion = 20;
+  }
+  else if(version == Dali::GlWindow::GlesVersion::VERSION_3_0)
+  {
+    rVersion = 30;
+  }
+
+  mGlWindowRenderThread->SetEglConfig(depth, stencil, msaa, rVersion);
 }
 
 void GlWindow::Raise()
@@ -260,6 +249,11 @@ void GlWindow::Show()
     mEventHandler->Resume();
   }
 
+  if(mGlWindowRenderThread)
+  {
+    mGlWindowRenderThread->Resume();
+  }
+
   DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), Show(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible);
 }
 
@@ -280,6 +274,11 @@ void GlWindow::Hide()
     mEventHandler->Pause();
   }
 
+  if(mGlWindowRenderThread)
+  {
+    mGlWindowRenderThread->Pause();
+  }
+
   DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), Hide(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible);
 }
 
@@ -423,6 +422,11 @@ void GlWindow::OnIconifyChanged(bool iconified)
       mEventHandler->Pause();
     }
 
+    if(mGlWindowRenderThread)
+    {
+      mGlWindowRenderThread->Pause();
+    }
+
     DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), Iconified: visible = %d\n", this, mNativeWindowId, mVisible);
   }
   else
@@ -440,6 +444,11 @@ void GlWindow::OnIconifyChanged(bool iconified)
       mEventHandler->Resume();
     }
 
+    if(mGlWindowRenderThread)
+    {
+      mGlWindowRenderThread->Resume();
+    }
+
     DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), Deiconified: visible = %d\n", this, mNativeWindowId, mVisible);
   }
 }
@@ -745,87 +754,44 @@ void GlWindow::SetChild(Dali::Window& child)
 
 void GlWindow::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
 {
-  if(mIsEGLInitialize == false)
+  if(mIsEGLInitialized == false)
   {
     InitializeGraphics();
   }
-  mGLInitCallback        = std::unique_ptr<CallbackBase>(initCallback);
-  mGLRenderFrameCallback = std::unique_ptr<CallbackBase>(renderFrameCallback);
-  mGLTerminateCallback   = std::unique_ptr<CallbackBase>(terminateCallback);
-
-  mInitCallback = false;
-
-  if(!mGLRenderCallback)
-  {
-    mGLRenderCallback = MakeCallback(this, &GlWindow::RunCallback);
-
-    if(Dali::Adaptor::IsAvailable())
-    {
-      Dali::Adaptor::Get().AddIdle(mGLRenderCallback, true);
-    }
-    else
-    {
-      DALI_LOG_RELEASE_INFO("RegisterGlCallback: Adaptor is not avaiable\n");
-    }
-  }
+  mGlWindowRenderThread->RegisterGlCallback(initCallback, renderFrameCallback, terminateCallback);
+  mGlWindowRenderThread->Start();
 }
 
-bool GlWindow::RunCallback()
+void GlWindow::RenderOnce()
 {
-  GraphicsInterface*                    graphics    = mGraphics.get();
-  EglGraphics*                          eglGraphics = static_cast<EglGraphics*>(graphics);
-  Internal::Adaptor::EglImplementation& eglImpl     = eglGraphics->GetEglImplementation();
-
-  eglImpl.MakeContextCurrent(mEGLSurface, mEGLContext);
-
-  int renderFrameResult = 0;
-
-  if(mIsRotated)
+  if(mGlWindowRenderThread)
   {
-    mWindowBase->SetEglWindowBufferTransform(mTotalRotationAngle);
-    if(mIsWindowRotated)
-    {
-      mWindowBase->SetEglWindowTransform(mWindowRotationAngle);
-    }
-    mIsRotated = false;
+    mGlWindowRenderThread->RenderOnce();
   }
+}
 
-  if(!mInitCallback)
+void GlWindow::SetRenderingMode(Dali::GlWindow::RenderingMode mode)
+{
+  mRenderingMode = mode;
+  if(mGlWindowRenderThread)
   {
-    if(mGLInitCallback)
+    bool onDemand = false;
+    if(mRenderingMode == Dali::GlWindow::RenderingMode::ON_DEMAND)
     {
-      CallbackBase::Execute(*mGLInitCallback);
+      onDemand = true;
     }
-    mInitCallback = true;
-  }
-
-  if(mGLRenderFrameCallback)
-  {
-    renderFrameResult = CallbackBase::ExecuteReturn<int>(*mGLRenderFrameCallback);
-  }
-
-  if(mIsWindowRotated)
-  {
-    mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
-    mIsWindowRotated = false;
+    mGlWindowRenderThread->SetOnDemandRenderMode(onDemand);
   }
-
-  if(renderFrameResult)
-  {
-    eglImpl.SwapBuffers(mEGLSurface);
-  }
-
-  return true;
 }
 
-void GlWindow::RenderOnce()
+Dali::GlWindow::RenderingMode GlWindow::GetRenderingMode() const
 {
-  RunCallback();
+  return mRenderingMode;
 }
 
 void GlWindow::InitializeGraphics()
 {
-  if(!mIsEGLInitialize)
+  if(!mIsEGLInitialized)
   {
     // Init Graphics
     std::unique_ptr<GraphicsFactory> graphicsFactoryPtr = Utils::MakeUnique<GraphicsFactory>(mEnvironmentOptions);
@@ -839,42 +805,24 @@ void GlWindow::InitializeGraphics()
     mDisplayConnection = std::unique_ptr<Dali::DisplayConnection>(Dali::DisplayConnection::New(*graphics, Dali::RenderSurfaceInterface::Type::WINDOW_RENDER_SURFACE));
     mDisplayConnection->Initialize();
 
-    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
-    if(mGLESVersion == Dali::GlWindow::GlesVersion::VERSION_2_0)
+    // Create Render Thread
+    mGlWindowRenderThread = std::unique_ptr<Dali::Internal::Adaptor::GlWindowRenderThread>(new GlWindowRenderThread(mPositionSize, mColorDepth));
+    if(!mGlWindowRenderThread)
     {
-      eglImpl.SetGlesVersion(20);
-    }
-    else if(mGLESVersion == Dali::GlWindow::GlesVersion::VERSION_3_0)
-    {
-      eglImpl.SetGlesVersion(30);
+      DALI_LOG_ERROR("Fail to create GlWindow Render Thread!!!!\n");
+      return;
     }
 
-    if(eglImpl.ChooseConfig(true, mColorDepth) == false)
+    mGlWindowRenderThread->SetGraphicsInterface(graphics);
+    mGlWindowRenderThread->SetWindowBase(mWindowBase.get());
+    bool onDemand = false;
+    if(mRenderingMode == Dali::GlWindow::RenderingMode::ON_DEMAND)
     {
-      if(mGLESVersion == Dali::GlWindow::GlesVersion::VERSION_3_0)
-      {
-        DALI_LOG_RELEASE_INFO("InitializeGraphics: Fail to choose config with GLES30, retry with GLES20\n");
-        eglImpl.SetGlesVersion(20);
-        mGLESVersion = Dali::GlWindow::GlesVersion::VERSION_2_0;
-        if(eglImpl.ChooseConfig(true, mColorDepth) == false)
-        {
-          DALI_LOG_ERROR("InitializeGraphics: Fail to choose config with GLES20");
-          return;
-        }
-      }
-      else
-      {
-        DALI_LOG_ERROR("InitializeGraphics: Fail to choose config with GLES20");
-        return;
-      }
+      onDemand = true;
     }
-    eglImpl.CreateWindowContext(mEGLContext);
-
-    // Create the EGL window
-    EGLNativeWindowType window = mWindowBase->CreateEglWindow(mPositionSize.width, mPositionSize.height);
-    mEGLSurface                = eglImpl.CreateSurfaceWindow(window, mColorDepth);
+    mGlWindowRenderThread->SetOnDemandRenderMode(onDemand);
 
-    mIsEGLInitialize = true;
+    mIsEGLInitialized = true;
   }
 }
 
index a5f5fb0..4102736 100644 (file)
@@ -28,7 +28,7 @@
 #include <dali/internal/adaptor/common/adaptor-impl.h>
 #include <dali/internal/graphics/gles/egl-graphics.h>
 #include <dali/internal/window-system/common/event-handler.h>
-#include <dali/public-api/adaptor-framework/key-grab.h>
+#include <dali/internal/window-system/common/gl-window-render-thread.h>
 
 namespace Dali
 {
@@ -182,6 +182,16 @@ public:
    */
   void RenderOnce();
 
+  /**
+   * @copydoc Dali::GlWindow::SetRenderingMode()
+   */
+  void SetRenderingMode(Dali::GlWindow::RenderingMode mode);
+
+  /**
+   * @copydoc Dali::GlWindow::GetRenderingMode()
+   */
+  Dali::GlWindow::RenderingMode GetRenderingMode() const;
+
 public: // For implementation
   /**
    * @brief Sets child window with Dali::Window
@@ -273,13 +283,6 @@ private:
   WindowOrientation ConvertToOrientation(int angle) const;
 
   /**
-   * @brief Run Ui GL callback function.
-   *
-   * @return true is the callback function works continuos.
-   */
-  bool RunCallback();
-
-  /**
    * @brief Initialize and create EGL resource
    */
   void InitializeGraphics();
@@ -372,14 +375,13 @@ public: // Signals
 
 private:
   std::unique_ptr<WindowBase>              mWindowBase;
-  std::unique_ptr<GraphicsInterface>       mGraphics; ///< Graphics interface
-  std::unique_ptr<Dali::DisplayConnection> mDisplayConnection;
+  std::unique_ptr<GraphicsInterface>       mGraphics;             ///< Graphics interface
+  std::unique_ptr<Dali::DisplayConnection> mDisplayConnection;    ///< The native display connection
+  std::unique_ptr<GlWindowRenderThread>    mGlWindowRenderThread; ///< The render thread
+  EventHandlerPtr                          mEventHandler;         ///< The window events handler
+  Dali::Window                             mChildWindow;          ///< The default child UI Window
   std::string                              mName;
   std::string                              mClassName;
-  EventHandlerPtr                          mEventHandler; ///< The window events handler
-  PositionSize                             mPositionSize;
-  ColorDepth                               mColorDepth;
-  Dali::Window                             mChildWindow;
   bool                                     mIsTransparent : 1;
   bool                                     mIsFocusAcceptable : 1;
   bool                                     mIconified : 1;
@@ -389,16 +391,25 @@ private:
   bool                                     mIsRotated : 1;
   bool                                     mIsWindowRotated : 1;
   bool                                     mIsTouched : 1;
+  bool                                     mIsEGLInitialized : 1;
+  bool                                     mDepth : 1;
+  bool                                     mStencil : 1;
 
-  std::vector<int> mAvailableAngles;
-  int              mPreferredAngle;
-  int              mTotalRotationAngle;  ///< The angle of window + screen rotation angle % 360
-  int              mWindowRotationAngle; ///< The angle of window rotation angle
-  int              mScreenRotationAngle; ///< The angle of screen rotation angle
-  int              mOrientationMode;     ///< 0: Default portrati, 1:Default landscape
-  int              mWindowWidth;         ///< The width of the window
-  int              mWindowHeight;        ///< The height of the window
-  int              mNativeWindowId;      ///< The Native Window Id
+  PositionSize                  mPositionSize; ///< The window position and size
+  EnvironmentOptions            mEnvironmentOptions;
+  std::vector<int>              mAvailableAngles; ///< The list of available angle
+  ColorDepth                    mColorDepth;      ///< The color depth of window
+  Dali::GlWindow::RenderingMode mRenderingMode;   ///< The rendering mode
+
+  int mPreferredAngle;      ///< The angle of preferred angle
+  int mTotalRotationAngle;  ///< The angle of window + screen rotation angle % 360
+  int mWindowRotationAngle; ///< The angle of window rotation angle
+  int mScreenRotationAngle; ///< The angle of screen rotation angle
+  int mOrientationMode;     ///< 0: Default portrati, 1:Default landscape
+  int mWindowWidth;         ///< The width of the window
+  int mWindowHeight;        ///< The height of the window
+  int mNativeWindowId;      ///< The Native Window Id
+  int mMSAA;                ///< The multisample anti-aliasing for EGL Configuration
 
   // Signals
   KeyEventSignalType          mKeyEventSignal;
@@ -406,21 +417,6 @@ private:
   FocusChangeSignalType       mFocusChangeSignal;
   ResizeSignalType            mResizeSignal;
   VisibilityChangedSignalType mVisibilityChangedSignal;
-
-  // EGL, GL Resource
-  EnvironmentOptions            mEnvironmentOptions;
-  std::unique_ptr<CallbackBase> mGLInitCallback;
-  std::unique_ptr<CallbackBase> mGLRenderFrameCallback;
-  std::unique_ptr<CallbackBase> mGLTerminateCallback;
-  CallbackBase*                 mGLRenderCallback;
-  EGLSurface                    mEGLSurface;
-  EGLContext                    mEGLContext;
-  Dali::GlWindow::GlesVersion   mGLESVersion;
-  bool                          mInitCallback : 1;
-  bool                          mDepth : 1;
-  bool                          mStencil : 1;
-  bool                          mIsEGLInitialize : 1;
-  int                           mMSAA;
 };
 
 } // namespace Adaptor
diff --git a/dali/internal/window-system/common/gl-window-render-thread.cpp b/dali/internal/window-system/common/gl-window-render-thread.cpp
new file mode 100644 (file)
index 0000000..783ff36
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+
+#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>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+namespace
+{
+const unsigned int NANOSECONDS_PER_SECOND(1e+9);
+
+// The following values will get calculated at compile time
+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);
+
+} // namespace
+
+GlWindowRenderThread::GlWindowRenderThread(PositionSize positionSize, ColorDepth colorDepth)
+: mGraphics(nullptr),
+  mWindowBase(nullptr),
+  mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
+  mPositionSize(positionSize),
+  mColorDepth(colorDepth),
+  mGLInitCallback(),
+  mGLRenderFrameCallback(),
+  mGLTerminateCallback(),
+  mEGLSurface(nullptr),
+  mEGLContext(nullptr),
+  mDepth(false),
+  mStencil(false),
+  mIsEGLInitialize(false),
+  mGLESVersion(30), //Default GLES version 30
+  mMSAA(0),
+  mRenderThreadWaitCondition(),
+  mDestroyRenderThread(0),
+  mPauseRenderThread(0),
+  mRenderingMode(0),
+  mRequestRenderOnce(0)
+{
+  unsigned int refrashRate         = 1u;
+  mDefaultFrameDurationNanoseconds = uint64_t(refrashRate) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
+}
+
+GlWindowRenderThread::~GlWindowRenderThread()
+{
+}
+
+void GlWindowRenderThread::SetGraphicsInterface(GraphicsInterface* graphics)
+{
+  mGraphics = graphics;
+}
+
+void GlWindowRenderThread::SetWindowBase(WindowBase* windowBase)
+{
+  mWindowBase = windowBase;
+}
+
+void GlWindowRenderThread::SetEglConfig(bool depth, bool stencil, int msaa, int version)
+{
+  mDepth       = depth;
+  mStencil     = stencil;
+  mMSAA        = msaa;
+  mGLESVersion = version;
+}
+
+void GlWindowRenderThread::Pause()
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  mPauseRenderThread = 1;
+  DALI_LOG_RELEASE_INFO("GlWindowRenderThread::Pause()\n");
+}
+
+void GlWindowRenderThread::Resume()
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  mPauseRenderThread = 0;
+  DALI_LOG_RELEASE_INFO("GlWindowRenderThread::Resume()\n");
+  mRenderThreadWaitCondition.Notify(lock);
+}
+
+void GlWindowRenderThread::Stop()
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  mDestroyRenderThread = 1;
+  DALI_LOG_RELEASE_INFO("GlWindowRenderThread::Stop()\n");
+  mRenderThreadWaitCondition.Notify(lock);
+}
+
+void GlWindowRenderThread::RegisterGlCallback(CallbackBase* initCallback,
+                                              CallbackBase* renderFrameCallback,
+                                              CallbackBase* terminateCallback)
+{
+  mGLInitCallback        = std::unique_ptr<CallbackBase>(initCallback);
+  mGLRenderFrameCallback = std::unique_ptr<CallbackBase>(renderFrameCallback);
+  mGLTerminateCallback   = std::unique_ptr<CallbackBase>(terminateCallback);
+}
+
+void GlWindowRenderThread::SetOnDemandRenderMode(bool onDemand)
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  mRenderingMode = static_cast<unsigned int>(onDemand);
+  DALI_LOG_RELEASE_INFO("GlWindowRenderThread::SetOnDemandRenderMode(): mRenderingMode: %d\n", mRenderingMode);
+  if(!onDemand)
+  {
+    mRenderThreadWaitCondition.Notify(lock);
+  }
+}
+
+void GlWindowRenderThread::RenderOnce()
+{
+  ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
+  mRequestRenderOnce = 1;
+  mRenderThreadWaitCondition.Notify(lock);
+}
+
+void GlWindowRenderThread::Run()
+{
+  Dali::SetThreadName("GlWindowRenderThread");
+  mLogFactory.InstallLogFunction();
+
+  int          renderFrameResult = 0;
+  EglGraphics* eglGraphics       = static_cast<EglGraphics*>(mGraphics);
+
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  InitializeGraphics(eglGraphics);
+
+  eglImpl.MakeContextCurrent(mEGLSurface, mEGLContext);
+
+  if(mGLInitCallback)
+  {
+    CallbackBase::Execute(*mGLInitCallback);
+  }
+
+  uint64_t timeToSleepUntil = 0;
+
+  while(RenderReady(timeToSleepUntil))
+  {
+    uint64_t currentFrameStartTime = 0;
+    TimeService::GetNanoseconds(currentFrameStartTime);
+
+    if(mGLRenderFrameCallback)
+    {
+      renderFrameResult = CallbackBase::ExecuteReturn<int>(*mGLRenderFrameCallback);
+
+      if(renderFrameResult)
+      {
+        eglImpl.SwapBuffers(mEGLSurface);
+      }
+    }
+    renderFrameResult = 0;
+
+    if(timeToSleepUntil == 0)
+    {
+      timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
+    }
+    else
+    {
+      timeToSleepUntil += mDefaultFrameDurationNanoseconds;
+      uint64_t currentFrameEndTime = 0;
+      TimeService::GetNanoseconds(currentFrameEndTime);
+      while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
+      {
+        timeToSleepUntil += mDefaultFrameDurationNanoseconds;
+      }
+    }
+
+    TimeService::SleepUntil(timeToSleepUntil);
+
+    if(mRequestRenderOnce)
+    {
+      mRequestRenderOnce = 0;
+    }
+  }
+
+  if(mGLTerminateCallback)
+  {
+    CallbackBase::Execute(*mGLTerminateCallback);
+  }
+
+  if(mIsEGLInitialize)
+  {
+    EglGraphics*                          eglGraphics = static_cast<EglGraphics*>(mGraphics);
+    Internal::Adaptor::EglImplementation& eglImpl     = eglGraphics->GetEglImplementation();
+
+    if(mEGLSurface)
+    {
+      eglImpl.DestroySurface(mEGLSurface);
+      mEGLSurface = nullptr;
+    }
+
+    if(mEGLContext)
+    {
+      eglImpl.DestroyContext(mEGLContext);
+      mEGLContext = nullptr;
+    }
+
+    eglImpl.TerminateGles();
+  }
+}
+
+void GlWindowRenderThread::InitializeGraphics(EglGraphics* eglGraphics)
+{
+  mIsEGLInitialize = true;
+
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+  eglImpl.SetGlesVersion(mGLESVersion);
+
+  if(eglImpl.ChooseConfig(true, mColorDepth) == false)
+  {
+    if(mGLESVersion == 30)
+    {
+      DALI_LOG_RELEASE_INFO("InitializeGraphics: Fail to choose config with GLES30, retry with GLES20\n");
+      eglImpl.SetGlesVersion(20);
+      mGLESVersion = 20;
+      if(eglImpl.ChooseConfig(true, mColorDepth) == false)
+      {
+        DALI_LOG_ERROR("InitializeGraphics: Fail to choose config with GLES20");
+        return;
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR("InitializeGraphics: Fail to choose config with GLES20");
+      return;
+    }
+  }
+  eglImpl.CreateWindowContext(mEGLContext);
+
+  // Create the EGL window
+  EGLNativeWindowType window = mWindowBase->CreateEglWindow(mPositionSize.width, mPositionSize.height);
+  mEGLSurface                = eglImpl.CreateSurfaceWindow(window, mColorDepth);
+}
+
+bool GlWindowRenderThread::RenderReady(uint64_t& timeToSleepUntil)
+{
+  ConditionalWait::ScopedLock updateLock(mRenderThreadWaitCondition);
+  while((!mDestroyRenderThread && mRenderingMode && !mRequestRenderOnce) || mPauseRenderThread)
+  {
+    timeToSleepUntil = 0;
+    mRenderThreadWaitCondition.Wait(updateLock);
+  }
+
+  // Keep the update-render thread alive if this thread is NOT to be destroyed
+  return !mDestroyRenderThread;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/common/gl-window-render-thread.h b/dali/internal/window-system/common/gl-window-render-thread.h
new file mode 100644 (file)
index 0000000..8111d69
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_GL_WINDOW_RENDER_THREAD_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_GL_WINDOW_RENDER_THREAD_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/thread.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/window-system/common/window-base.h>
+
+namespace Dali
+{
+class Adaptor;
+
+namespace Internal
+{
+namespace Adaptor
+{
+class WindowBase;
+class GlWindow;
+
+/**
+ * @brief It is for render thread for GlWindow.
+ * User callbacks works in the thread.
+ *
+ * Key Points:
+ *  1. Two Threads:
+ *    a. Main/Event Thread.
+ *    b. Render Thread.
+ *  2. There is NO VSync thread:
+ *    a. We calculate the difference between these two times and if:
+ *      i.  The difference is less than the default frame time, we sleep.
+ *      ii. If it’s more or the same, we continue.
+ *  3. Support Rendering mode
+ *    a. CONTINUOUS mode
+ *      i. The rendering loop works continuously.
+ *    b. ON_DEMAND mode
+ *      i. The rendering works by user's request.
+ *      ii. User's request is the renderOnce()'s function calling.
+ */
+
+class GlWindowRenderThread : public Dali::Thread
+{
+public:
+  /**
+   * Constructor
+   *
+   * @param[in] positionSize The position and size of the physical window
+   * @param[in] depth color depth of the physical window
+   */
+  GlWindowRenderThread(PositionSize positionSize, ColorDepth colorDepth);
+
+  /**
+   * destructor.
+   */
+  virtual ~GlWindowRenderThread();
+
+  /**
+   * Sets the GraphicsInterface instance.
+   * This graphics instance is used to create and initialize graphics resource
+   *
+   * @param[in]  graphics           The graphice instance
+   */
+  void SetGraphicsInterface(GraphicsInterface* graphics);
+
+  /**
+   * Sets the WindowBase instance
+   * This WindowBase instance is used to call wl egl window APIs.
+   *
+   * @param[in]  windowBase           The WindowBase instance
+   */
+  void SetWindowBase(WindowBase* windowBase);
+
+  /**
+   * @brief Sets egl configuration for GlWindow
+   *
+   * @param[in] depth the flag of depth buffer. If true is set, 24bit depth buffer is enabled.
+   * @param[in] stencil the flag of stencil. it true is set, 8bit stencil buffer is enabled.
+   * @param[in] msaa the bit of msaa.
+   * @param[in] version the GLES version.
+   *
+   */
+  void SetEglConfig(bool depth, bool stencil, int msaa, int version);
+
+  /**
+   * Pauses the Render Thread.
+   * It is called when GlWindow is iconified or hidden.
+   *
+   * This will lock the mutex in mRenderThreadWaitCondition.
+   */
+  void Pause();
+
+  /**
+   * Resumes the Render Thread.
+   * It is called when GlWindow is de-iconified or shown.
+   *
+   * This will lock the mutex in mRenderThreadWaitCondition.
+   */
+  void Resume();
+
+  /**
+   * Stops the Render Thread.
+   * This will lock the mutex in mRenderThreadWaitCondition.
+   *
+   * @note Should only be called in Stop as calling this will kill the render thread.
+   */
+  void Stop();
+
+  /**
+   * @copydoc Dali::GlWindow::RegisterGlCallback()
+   */
+  void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback);
+
+  /**
+   * Enable OnDemand Rendering Mode
+   *
+   * @param[in] onDemand the flag of OnDemand Rendering Mode. If the flag is true, rendering mode is OnDemand, otherwise the flag is false, rendering mode is continuous mode.
+   */
+  void SetOnDemandRenderMode(bool onDemand);
+
+  /**
+   * @copydoc Dali::GlWindow::RenderOnce()
+   */
+  void RenderOnce();
+
+protected:
+  /**
+   * The Render thread loop. This thread will be destroyed on exit from this function.
+   */
+  virtual void Run();
+
+private:
+  /**
+   * @brief Initialize and create EGL resource
+   */
+  void InitializeGraphics(EglGraphics* eglGraphics);
+
+  /**
+   * Called by the Render Thread which ensures a wait if required.
+   *
+   * @param[out] timeToSleepUntil  The time remaining in nanoseconds to keep the thread sleeping before resuming.
+   * @return false, if the thread should stop.
+   */
+  bool RenderReady(uint64_t& timeToSleepUntil);
+
+private:
+  GraphicsInterface* mGraphics; ///< Graphics interface
+  WindowBase*        mWindowBase;
+
+  const Dali::LogFactoryInterface& mLogFactory;
+
+  PositionSize mPositionSize; ///< Position
+  ColorDepth   mColorDepth;
+
+  // EGL, GL Resource
+  std::unique_ptr<CallbackBase> mGLInitCallback;
+  std::unique_ptr<CallbackBase> mGLRenderFrameCallback;
+  std::unique_ptr<CallbackBase> mGLTerminateCallback;
+  EGLSurface                    mEGLSurface;
+  EGLContext                    mEGLContext;
+  bool                          mDepth : 1;
+  bool                          mStencil : 1;
+  bool                          mIsEGLInitialize : 1;
+  int                           mGLESVersion;
+  int                           mMSAA;
+
+  // 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
+
+  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.
+
+}; // GlWindowRenderThread
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif
index 4f7b234..101958f 100644 (file)
@@ -9,6 +9,7 @@ SET( adaptor_window_system_common_src_files
     ${adaptor_window_system_dir}/common/window-impl.cpp
     ${adaptor_window_system_dir}/common/window-render-surface.cpp
     ${adaptor_window_system_dir}/common/gl-window-impl.cpp
+    ${adaptor_window_system_dir}/common/gl-window-render-thread.cpp
 )
 
 # module: window-system, backend: tizen-wayland