2 * Copyright (c) 2023 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-toolkit/internal/controls/gl-view/gl-view-render-thread.h>
22 #include <dali/devel-api/adaptor-framework/thread-settings.h>
23 #include <dali/integration-api/adaptor-framework/adaptor.h>
24 #include <dali/integration-api/debug.h>
36 constexpr unsigned int NANOSECONDS_PER_SECOND(1e+9);
38 // The following values will get calculated at compile time
39 constexpr float DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f);
40 constexpr uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND);
44 GlViewRenderThread::GlViewRenderThread(Dali::NativeImageSourceQueuePtr queue)
45 : mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
46 mTraceFactory(Dali::Adaptor::Get().GetTraceFactory()),
48 mNativeImageSurface(),
49 mNativeImageQueue(queue),
51 mGlInitCallback(nullptr),
52 mGlRenderFrameCallback(nullptr),
53 mGlTerminateCallback(nullptr),
54 mResizeCallback(nullptr),
58 mGraphicsApiVersion(20),
63 mIsRenderRequested(0),
66 mDefaultFrameDurationNanoseconds(DEFAULT_FRAME_DURATION_IN_NANOSECONDS)
68 mNativeImageSurface = Dali::NativeImageSurface::New(mNativeImageQueue);
70 if(!mNativeImageSurface)
72 DALI_LOG_ERROR("Creating NativeImageSurface Failed, Could not start GlView Render Thread");
76 void GlViewRenderThread::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
78 if(!mGlInitCallback && !mGlRenderFrameCallback && !mGlTerminateCallback)
80 mGlInitCallback = std::unique_ptr<CallbackBase>(initCallback);
81 mGlRenderFrameCallback = std::unique_ptr<CallbackBase>(renderFrameCallback);
82 mGlTerminateCallback = std::unique_ptr<CallbackBase>(terminateCallback);
86 void GlViewRenderThread::SetResizeCallback(CallbackBase* resizeCallback)
90 mResizeCallback = std::unique_ptr<CallbackBase>(resizeCallback);
94 bool GlViewRenderThread::SetGraphicsConfig(bool depth, bool stencil, int msaa, int version)
99 mGraphicsApiVersion = version;
101 if(mNativeImageSurface)
103 return mNativeImageSurface->SetGraphicsConfig(mDepth, mStencil, mMSAA, mGraphicsApiVersion);
109 void GlViewRenderThread::SetOnDemandRenderMode(bool onDemand)
111 ConditionalWait::ScopedLock lock(mConditionalWait);
112 mRenderingMode = static_cast<unsigned int>(onDemand);
113 DALI_LOG_RELEASE_INFO("GlViewRenderThread::SetOnDemandRenderMode(): mRenderingMode: %d\n", mRenderingMode);
114 if(!onDemand && !mIsThreadPaused)
116 mConditionalWait.Notify(lock);
120 void GlViewRenderThread::SetSurfaceSize(Dali::Vector2 size)
122 //GlViewRenderThread::Run was already blocked in Internal::GlView::OnSizeSet
124 mIsSurfaceResized = 1;
127 void GlViewRenderThread::RenderOnce()
129 //Notify GLRender thread.
130 Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
131 mIsRenderRequested = 1;
132 mConditionalWait.Notify(lock);
135 void GlViewRenderThread::GetNanoSeconds(uint64_t& timeInNanoseconds)
137 // Get the time of a monotonic clock since its epoch.
138 auto epoch = std::chrono::steady_clock::now().time_since_epoch();
139 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
140 timeInNanoseconds = static_cast<uint64_t>(duration.count());
143 void GlViewRenderThread::SleepUntil(uint64_t timeInNanoseconds)
145 using Clock = std::chrono::steady_clock;
146 using TimePoint = std::chrono::time_point<Clock>;
148 const Clock::duration duration = std::chrono::nanoseconds(timeInNanoseconds);
149 const TimePoint timePoint(duration);
151 std::this_thread::sleep_until(timePoint);
154 void GlViewRenderThread::Run()
156 Dali::SetThreadName("GlViewRenderer");
157 mLogFactory.InstallLogFunction();
158 mTraceFactory.InstallTraceFunction();
160 int renderFrameResult = 0;
162 if(!mNativeImageSurface)
164 DALI_LOG_ERROR("NativeImageSurface is null, Could not start GlView Render Thread");
169 mNativeImageSurface->InitializeGraphics();
172 mNativeImageSurface->PreRender();
175 CallbackBase::Execute(*mGlInitCallback);
178 uint64_t timeToSleepUntil = 0;
180 while(RenderReady(timeToSleepUntil))
182 uint64_t currentFrameStartTime = 0;
183 GetNanoSeconds(currentFrameStartTime);
186 mNativeImageSurface->PreRender();
187 if(mIsSurfaceResized)
191 CallbackBase::Execute(*mResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
193 mIsSurfaceResized = 0;
196 if(mNativeImageSurface->CanRender())
198 if(mGlRenderFrameCallback)
200 renderFrameResult = CallbackBase::ExecuteReturn<int>(*mGlRenderFrameCallback);
201 if(renderFrameResult)
203 mNativeImageSurface->PostRender();
210 if(timeToSleepUntil == 0)
212 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
216 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
217 uint64_t currentFrameEndTime = 0;
218 GetNanoSeconds(currentFrameEndTime);
219 while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
221 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
225 SleepUntil(timeToSleepUntil);
228 if(mGlTerminateCallback)
230 CallbackBase::Execute(*mGlTerminateCallback);
233 mNativeImageSurface->TerminateGraphics();
238 void GlViewRenderThread::Stop()
240 // Set to come out Render Thread out of waiting condition.
241 Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
242 mIsThreadStopped = 1;
244 mConditionalWait.Notify(lock);
247 void GlViewRenderThread::Pause()
249 //Notify GLRender thread, If actor visibility is change
250 Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
252 mConditionalWait.Notify(lock);
255 void GlViewRenderThread::Resume()
257 Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
258 if(!mIsThreadStarted)
261 mIsThreadStarted = 1;
264 mConditionalWait.Notify(lock);
267 bool GlViewRenderThread::RenderReady(uint64_t& timeToSleepUntil)
269 ConditionalWait::ScopedLock lock(mConditionalWait);
270 while((!mIsThreadStopped && mRenderingMode && !mIsRenderRequested) || mIsThreadPaused)
272 timeToSleepUntil = 0;
273 mConditionalWait.Wait(lock);
276 mIsRenderRequested = 0;
277 // Keep the update-render thread alive if this thread is NOT to be destroyed
278 return !mIsThreadStopped;
281 void GlViewRenderThread::AcquireSurface()
283 mSurfaceSemaphore.Acquire();
286 void GlViewRenderThread::ReleaseSurface()
288 mSurfaceSemaphore.Release(1);
291 GlViewRenderThread::~GlViewRenderThread()
295 } // namespace Internal
296 } // namespace Toolkit