2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/devel-api/adaptor-framework/thread-settings.h>
22 #include <dali/internal/adaptor/common/adaptor-impl.h>
23 #include <dali/internal/system/common/time-service.h>
24 #include <dali/internal/window-system/common/gl-window-render-thread.h>
34 constexpr unsigned int NANOSECONDS_PER_SECOND(1e+9);
36 // The following values will get calculated at compile time
37 constexpr float DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f);
38 constexpr uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND);
39 constexpr uint64_t REFRESH_RATE(1u);
41 constexpr int MINIMUM_DIMENSION_CHANGE(1);
44 GlWindowRenderThread::GlWindowRenderThread(PositionSize positionSize, ColorDepth colorDepth)
47 mWindowRotationTrigger(),
48 mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
49 mPositionSize(positionSize),
50 mColorDepth(colorDepth),
52 mGLRenderFrameCallback(),
53 mGLTerminateCallback(),
58 mIsEGLInitialize(false),
59 mGLESVersion(30), //Default GLES version 30
61 mWindowRotationAngle(0),
62 mScreenRotationAngle(0),
63 mRenderThreadWaitCondition(),
64 mDestroyRenderThread(0),
65 mPauseRenderThread(0),
67 mRequestRenderOnce(0),
70 mDefaultFrameDurationNanoseconds(REFRESH_RATE * DEFAULT_FRAME_DURATION_IN_NANOSECONDS)
74 GlWindowRenderThread::~GlWindowRenderThread()
78 void GlWindowRenderThread::SetGraphicsInterface(GraphicsInterface* graphics)
83 void GlWindowRenderThread::SetWindowBase(WindowBase* windowBase)
85 mWindowBase = windowBase;
88 void GlWindowRenderThread::SetEglConfig(bool depth, bool stencil, int msaa, int version)
93 mGLESVersion = version;
96 void GlWindowRenderThread::Pause()
98 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
99 mPauseRenderThread = 1;
100 DALI_LOG_RELEASE_INFO("GlWindowRenderThread::Pause()\n");
103 void GlWindowRenderThread::Resume()
105 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
106 mPauseRenderThread = 0;
107 DALI_LOG_RELEASE_INFO("GlWindowRenderThread::Resume()\n");
108 mRenderThreadWaitCondition.Notify(lock);
111 void GlWindowRenderThread::Stop()
113 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
114 mDestroyRenderThread = 1;
115 DALI_LOG_RELEASE_INFO("GlWindowRenderThread::Stop()\n");
116 mRenderThreadWaitCondition.Notify(lock);
119 void GlWindowRenderThread::RegisterGlCallback(CallbackBase* initCallback,
120 CallbackBase* renderFrameCallback,
121 CallbackBase* terminateCallback)
123 mGLInitCallback = std::unique_ptr<CallbackBase>(initCallback);
124 mGLRenderFrameCallback = std::unique_ptr<CallbackBase>(renderFrameCallback);
125 mGLTerminateCallback = std::unique_ptr<CallbackBase>(terminateCallback);
128 void GlWindowRenderThread::SetOnDemandRenderMode(bool onDemand)
130 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
131 mRenderingMode = static_cast<unsigned int>(onDemand);
132 DALI_LOG_RELEASE_INFO("GlWindowRenderThread::SetOnDemandRenderMode(): mRenderingMode: %d\n", mRenderingMode);
135 mRenderThreadWaitCondition.Notify(lock);
139 void GlWindowRenderThread::RenderOnce()
141 // Most of all, this function is called in event thread
142 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
143 mRequestRenderOnce = 1;
144 mRenderThreadWaitCondition.Notify(lock);
147 void GlWindowRenderThread::RequestWindowResize(int width, int height)
149 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
151 if((fabs(width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
152 (fabs(height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE))
154 mSurfaceStatus |= static_cast<unsigned int>(SurfaceStatus::RESIZED); // Set bit for window resized
155 mPositionSize.width = width;
156 mPositionSize.height = height;
158 DALI_LOG_RELEASE_INFO("GlWindowRenderThread::RequestWindowResize(), width:%d, height:%d\n", width, height);
159 mRenderThreadWaitCondition.Notify(lock);
163 void GlWindowRenderThread::RequestWindowRotate(int windowAngle)
165 if(!mWindowRotationTrigger)
167 mWindowRotationTrigger = std::unique_ptr<TriggerEventInterface>(TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &GlWindowRenderThread::WindowRotationCompleted),
168 TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER));
171 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
172 if(mWindowRotationAngle != windowAngle)
174 mSurfaceStatus |= static_cast<unsigned int>(SurfaceStatus::WINDOW_ROTATED); // Set bit for window rotation
175 mWindowRotationAngle = windowAngle;
176 DALI_LOG_RELEASE_INFO("GlWindowRenderThread::RequestWindowRotate(): %d\n", windowAngle);
177 mRenderThreadWaitCondition.Notify(lock);
181 void GlWindowRenderThread::RequestScreenRotate(int screenAngle)
183 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
184 if(mScreenRotationAngle != screenAngle)
186 mSurfaceStatus |= static_cast<unsigned int>(SurfaceStatus::SCREEN_ROTATED); // Set bit for screen rotation
187 mScreenRotationAngle = screenAngle;
188 DALI_LOG_RELEASE_INFO("GlWindowRenderThread::RequestScreenRotate(): %d\n", screenAngle);
189 mRenderThreadWaitCondition.Notify(lock);
193 void GlWindowRenderThread::WindowRotationCompleted()
195 mWindowBase->WindowRotationCompleted(mWindowRotationAngle, mPositionSize.width, mPositionSize.height);
200 unsigned int GlWindowRenderThread::GetSurfaceStatus(int& windowRotationAngle, int& screenRotationAngle)
202 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
204 // Get the surface status and reset that.
205 unsigned int status = mSurfaceStatus;
206 mSurfaceStatus = static_cast<unsigned int>(SurfaceStatus::NO_CHANGED);
208 windowRotationAngle = mWindowRotationAngle;
209 screenRotationAngle = mScreenRotationAngle;
214 void GlWindowRenderThread::Run()
216 Dali::SetThreadName("GlWindowRenderThread");
217 mLogFactory.InstallLogFunction();
219 int renderFrameResult = 0;
220 unsigned int isSurfaceChanged = 0;
221 bool isWindowResized = false, isWindowRotated = false, isScreenRotated = false;
222 int windowRotationAngle = 0, screenRotationAngle = 0, totalAngle = 0;
223 EglGraphics* eglGraphics = static_cast<EglGraphics*>(mGraphics);
225 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
227 InitializeGraphics(eglGraphics);
229 eglImpl.MakeContextCurrent(mEGLSurface, mEGLContext);
233 CallbackBase::Execute(*mGLInitCallback);
236 uint64_t timeToSleepUntil = 0;
238 while(RenderReady(timeToSleepUntil))
240 uint64_t currentFrameStartTime = 0;
241 TimeService::GetNanoseconds(currentFrameStartTime);
243 if(mGLRenderFrameCallback)
246 isSurfaceChanged = GetSurfaceStatus(windowRotationAngle, screenRotationAngle);
247 if(DALI_UNLIKELY(isSurfaceChanged))
249 isWindowResized = (isSurfaceChanged & static_cast<unsigned int>(SurfaceStatus::RESIZED)) ? true : false;
250 isWindowRotated = (isSurfaceChanged & static_cast<unsigned int>(SurfaceStatus::WINDOW_ROTATED)) ? true : false;
251 isScreenRotated = (isSurfaceChanged & static_cast<unsigned int>(SurfaceStatus::SCREEN_ROTATED)) ? true : false;
252 totalAngle = (windowRotationAngle + screenRotationAngle) % 360;
254 if(isWindowRotated || isScreenRotated)
256 mWindowBase->SetEglWindowBufferTransform(totalAngle);
259 mWindowBase->SetEglWindowTransform(windowRotationAngle);
265 Dali::PositionSize positionSize;
266 positionSize.x = mPositionSize.x;
267 positionSize.y = mPositionSize.y;
268 if(totalAngle == 0 || totalAngle == 180)
270 positionSize.width = mPositionSize.width;
271 positionSize.height = mPositionSize.height;
275 positionSize.width = mPositionSize.height;
276 positionSize.height = mPositionSize.width;
278 mWindowBase->ResizeEglWindow(positionSize);
283 renderFrameResult = CallbackBase::ExecuteReturn<int>(*mGLRenderFrameCallback);
286 if(DALI_UNLIKELY(isWindowRotated))
290 mWindowRotationTrigger->Trigger();
292 PostRenderWaitForFinished();
293 isWindowRotated = false;
297 if(renderFrameResult)
299 eglImpl.SwapBuffers(mEGLSurface);
302 renderFrameResult = 0;
304 if(timeToSleepUntil == 0)
306 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
310 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
311 uint64_t currentFrameEndTime = 0;
312 TimeService::GetNanoseconds(currentFrameEndTime);
313 while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
315 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
319 TimeService::SleepUntil(timeToSleepUntil);
322 if(mGLTerminateCallback)
324 CallbackBase::Execute(*mGLTerminateCallback);
329 EglGraphics* eglGraphics = static_cast<EglGraphics*>(mGraphics);
330 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
334 eglImpl.DestroySurface(mEGLSurface);
335 mEGLSurface = nullptr;
340 eglImpl.DestroyContext(mEGLContext);
341 mEGLContext = nullptr;
344 eglImpl.TerminateGles();
348 void GlWindowRenderThread::InitializeGraphics(EglGraphics* eglGraphics)
350 mIsEGLInitialize = true;
352 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
353 eglImpl.SetGlesVersion(mGLESVersion);
355 if(eglImpl.ChooseConfig(true, mColorDepth) == false)
357 if(mGLESVersion == 30)
359 DALI_LOG_RELEASE_INFO("InitializeGraphics: Fail to choose config with GLES30, retry with GLES20\n");
360 eglImpl.SetGlesVersion(20);
362 if(eglImpl.ChooseConfig(true, mColorDepth) == false)
364 DALI_LOG_ERROR("InitializeGraphics: Fail to choose config with GLES20");
370 DALI_LOG_ERROR("InitializeGraphics: Fail to choose config with GLES20");
374 eglImpl.CreateWindowContext(mEGLContext);
376 // Create the EGL window
377 EGLNativeWindowType window = mWindowBase->CreateEglWindow(mPositionSize.width, mPositionSize.height);
378 mEGLSurface = eglImpl.CreateSurfaceWindow(window, mColorDepth);
381 bool GlWindowRenderThread::RenderReady(uint64_t& timeToSleepUntil)
383 ConditionalWait::ScopedLock updateLock(mRenderThreadWaitCondition);
384 while((!mDestroyRenderThread && mRenderingMode && !mRequestRenderOnce && !mSurfaceStatus) || mPauseRenderThread)
386 timeToSleepUntil = 0;
387 mRenderThreadWaitCondition.Wait(updateLock);
390 mRequestRenderOnce = 0;
391 // Keep the update-render thread alive if this thread is NOT to be destroyed
392 return !mDestroyRenderThread;
395 void GlWindowRenderThread::PostRenderStart()
397 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
398 mPostRendering = false;
401 void GlWindowRenderThread::PostRenderFinish()
403 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
404 mPostRendering = true;
405 mRenderThreadWaitCondition.Notify(lock);
408 void GlWindowRenderThread::PostRenderWaitForFinished()
410 ConditionalWait::ScopedLock lock(mRenderThreadWaitCondition);
411 while(!mPostRendering && !mDestroyRenderThread)
413 mRenderThreadWaitCondition.Wait(lock);
417 } // namespace Adaptor
419 } // namespace Internal