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-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()),
47 mNativeImageSurface(),
48 mNativeImageQueue(queue),
50 mGlInitCallback(nullptr),
51 mGlRenderFrameCallback(nullptr),
52 mGlTerminateCallback(nullptr),
53 mResizeCallback(nullptr),
57 mGraphicsApiVersion(20),
62 mIsRenderRequested(0),
65 mDefaultFrameDurationNanoseconds(DEFAULT_FRAME_DURATION_IN_NANOSECONDS)
67 mNativeImageSurface = Dali::NativeImageSurface::New(mNativeImageQueue);
69 if(!mNativeImageSurface)
71 DALI_LOG_ERROR("Creating NativeImageSurface Failed, Could not start GlView Render Thread");
75 void GlViewRenderThread::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
77 if(!mGlInitCallback && !mGlRenderFrameCallback && !mGlTerminateCallback)
79 mGlInitCallback = std::unique_ptr<CallbackBase>(initCallback);
80 mGlRenderFrameCallback = std::unique_ptr<CallbackBase>(renderFrameCallback);
81 mGlTerminateCallback = std::unique_ptr<CallbackBase>(terminateCallback);
85 void GlViewRenderThread::SetResizeCallback(CallbackBase* resizeCallback)
89 mResizeCallback = std::unique_ptr<CallbackBase>(resizeCallback);
93 bool GlViewRenderThread::SetGraphicsConfig(bool depth, bool stencil, int msaa, int version)
98 mGraphicsApiVersion = version;
100 if(mNativeImageSurface)
102 return mNativeImageSurface->SetGraphicsConfig(mDepth, mStencil, mMSAA, mGraphicsApiVersion);
108 void GlViewRenderThread::SetOnDemandRenderMode(bool onDemand)
110 ConditionalWait::ScopedLock lock(mConditionalWait);
111 mRenderingMode = static_cast<unsigned int>(onDemand);
112 DALI_LOG_RELEASE_INFO("GlViewRenderThread::SetOnDemandRenderMode(): mRenderingMode: %d\n", mRenderingMode);
113 if(!onDemand && !mIsThreadPaused)
115 mConditionalWait.Notify(lock);
119 void GlViewRenderThread::SetSurfaceSize(Dali::Vector2 size)
121 //GlViewRenderThread::Run was already blocked in Internal::GlView::OnSizeSet
123 mIsSurfaceResized = 1;
126 void GlViewRenderThread::RenderOnce()
128 //Notify GLRender thread.
129 Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
130 mIsRenderRequested = 1;
131 mConditionalWait.Notify(lock);
134 void GlViewRenderThread::GetNanoSeconds(uint64_t& timeInNanoseconds)
136 // Get the time of a monotonic clock since its epoch.
137 auto epoch = std::chrono::steady_clock::now().time_since_epoch();
138 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
139 timeInNanoseconds = static_cast<uint64_t>(duration.count());
142 void GlViewRenderThread::SleepUntil(uint64_t timeInNanoseconds)
144 using Clock = std::chrono::steady_clock;
145 using TimePoint = std::chrono::time_point<Clock>;
147 const Clock::duration duration = std::chrono::nanoseconds(timeInNanoseconds);
148 const TimePoint timePoint(duration);
150 std::this_thread::sleep_until(timePoint);
153 void GlViewRenderThread::Run()
155 Dali::SetThreadName("GlViewRenderer");
156 mLogFactory.InstallLogFunction();
158 int renderFrameResult = 0;
160 if(!mNativeImageSurface)
162 DALI_LOG_ERROR("NativeImageSurface is null, Could not start GlView Render Thread");
167 mNativeImageSurface->InitializeGraphics();
170 mNativeImageSurface->PreRender();
173 CallbackBase::Execute(*mGlInitCallback);
176 uint64_t timeToSleepUntil = 0;
178 while(RenderReady(timeToSleepUntil))
180 uint64_t currentFrameStartTime = 0;
181 GetNanoSeconds(currentFrameStartTime);
184 mNativeImageSurface->PreRender();
185 if(mIsSurfaceResized)
189 CallbackBase::Execute(*mResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
191 mIsSurfaceResized = 0;
194 if(mNativeImageSurface->CanRender())
196 if(mGlRenderFrameCallback)
198 renderFrameResult = CallbackBase::ExecuteReturn<int>(*mGlRenderFrameCallback);
199 if(renderFrameResult)
201 mNativeImageSurface->PostRender();
208 if(timeToSleepUntil == 0)
210 timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
214 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
215 uint64_t currentFrameEndTime = 0;
216 GetNanoSeconds(currentFrameEndTime);
217 while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
219 timeToSleepUntil += mDefaultFrameDurationNanoseconds;
223 SleepUntil(timeToSleepUntil);
226 if(mGlTerminateCallback)
228 CallbackBase::Execute(*mGlTerminateCallback);
231 mNativeImageSurface->TerminateGraphics();
236 void GlViewRenderThread::Stop()
238 // Set to come out Render Thread out of waiting condition.
239 Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
240 mIsThreadStopped = 1;
242 mConditionalWait.Notify(lock);
245 void GlViewRenderThread::Pause()
247 //Notify GLRender thread, If actor visibility is change
248 Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
250 mConditionalWait.Notify(lock);
253 void GlViewRenderThread::Resume()
255 Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
256 if(!mIsThreadStarted)
259 mIsThreadStarted = 1;
262 mConditionalWait.Notify(lock);
265 bool GlViewRenderThread::RenderReady(uint64_t& timeToSleepUntil)
267 ConditionalWait::ScopedLock lock(mConditionalWait);
268 while((!mIsThreadStopped && mRenderingMode && !mIsRenderRequested) || mIsThreadPaused)
270 timeToSleepUntil = 0;
271 mConditionalWait.Wait(lock);
274 mIsRenderRequested = 0;
275 // Keep the update-render thread alive if this thread is NOT to be destroyed
276 return !mIsThreadStopped;
279 void GlViewRenderThread::AcquireSurface()
281 mSurfaceSemaphore.Acquire();
284 void GlViewRenderThread::ReleaseSurface()
286 mSurfaceSemaphore.Release(1);
289 GlViewRenderThread::~GlViewRenderThread()
293 } // namespace Internal
294 } // namespace Toolkit