mOpaqueState(false),
mResizeEnabled(false),
mVisible(false),
- mIsRotated(false),
- mIsWindowRotated(false),
mIsTouched(false),
mIsEGLInitialized(false),
mDepth(false),
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())
{
}
// 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);
+ }
}
}
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);
}
}
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)
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);
+ }
}
}
{
}
+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
*/
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()
bool mOpaqueState : 1;
bool mResizeEnabled : 1;
bool mVisible : 1;
- bool mIsRotated : 1;
bool mIsWindowRotated : 1;
bool mIsTouched : 1;
bool mIsEGLInitialized : 1;
*
*/
+// 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>
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),
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;
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();
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);
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);
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
namespace Dali
{
class Adaptor;
+class TriggerEventInterface;
namespace Internal
{
{
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
*/
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.
*/
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;
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.