Add the render threading for GlWindow.
The user callback works on the separated render thread.
Change-Id: Ic2470a1fc70f02fa0d1819e8bb36c6e62325022c
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();
};
/**
+ * @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
*/
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
/**
: mWindowBase(),
mGraphics(),
mDisplayConnection(nullptr),
+ mGlWindowRenderThread(nullptr),
mEventHandler(nullptr),
- mPositionSize(),
- mColorDepth(COLOR_DEPTH_24),
mIsTransparent(false),
mIsFocusAcceptable(false),
mIconified(false),
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),
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()
{
}
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();
}
}
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()
mEventHandler->Resume();
}
+ if(mGlWindowRenderThread)
+ {
+ mGlWindowRenderThread->Resume();
+ }
+
DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), Show(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible);
}
mEventHandler->Pause();
}
+ if(mGlWindowRenderThread)
+ {
+ mGlWindowRenderThread->Pause();
+ }
+
DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), Hide(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible);
}
mEventHandler->Pause();
}
+ if(mGlWindowRenderThread)
+ {
+ mGlWindowRenderThread->Pause();
+ }
+
DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), Iconified: visible = %d\n", this, mNativeWindowId, mVisible);
}
else
mEventHandler->Resume();
}
+ if(mGlWindowRenderThread)
+ {
+ mGlWindowRenderThread->Resume();
+ }
+
DALI_LOG_RELEASE_INFO("Window (%p), WinId (%d), Deiconified: visible = %d\n", this, mNativeWindowId, mVisible);
}
}
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);
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;
}
}
#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
{
*/
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
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();
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;
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;
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
${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