Merge "Change RegisterGlCallback function name of GlView" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / gl-view / gl-view-render-thread.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h>
20
21 //EXTERNAL INCLUDES
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>
25 #include <chrono>
26 #include <thread>
27
28 namespace Dali
29 {
30 namespace Toolkit
31 {
32 namespace Internal
33 {
34 namespace
35 {
36 constexpr unsigned int NANOSECONDS_PER_SECOND(1e+9);
37
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);
41
42 } // namespace
43
44 GlViewRenderThread::GlViewRenderThread(Dali::NativeImageSourceQueuePtr queue)
45 : mLogFactory(Dali::Adaptor::Get().GetLogFactory()),
46   mSurfaceSize(1, 1),
47   mNativeImageSurface(),
48   mNativeImageQueue(queue),
49   mSurfaceSemaphore(1),
50   mGlInitCallback(nullptr),
51   mGlRenderFrameCallback(nullptr),
52   mGlTerminateCallback(nullptr),
53   mResizeCallback(nullptr),
54   mDepth(false),
55   mStencil(false),
56   mMSAA(0),
57   mGraphicsApiVersion(20),
58   mConditionalWait(),
59   mIsThreadStarted(0),
60   mIsThreadStopped(0),
61   mIsThreadPaused(0),
62   mIsRenderRequested(0),
63   mRenderingMode(0),
64   mIsSurfaceResized(0),
65   mDefaultFrameDurationNanoseconds(DEFAULT_FRAME_DURATION_IN_NANOSECONDS)
66 {
67   mNativeImageSurface = Dali::NativeImageSurface::New(mNativeImageQueue);
68
69   if(!mNativeImageSurface)
70   {
71     DALI_LOG_ERROR("Creating NativeImageSurface Failed, Could not start GlView Render Thread");
72   }
73 }
74
75 void GlViewRenderThread::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
76 {
77   if(!mGlInitCallback && !mGlRenderFrameCallback && !mGlTerminateCallback)
78   {
79     mGlInitCallback        = std::unique_ptr<CallbackBase>(initCallback);
80     mGlRenderFrameCallback = std::unique_ptr<CallbackBase>(renderFrameCallback);
81     mGlTerminateCallback   = std::unique_ptr<CallbackBase>(terminateCallback);
82   }
83 }
84
85 void GlViewRenderThread::SetResizeCallback(CallbackBase* resizeCallback)
86 {
87   if(!mResizeCallback)
88   {
89     mResizeCallback = std::unique_ptr<CallbackBase>(resizeCallback);
90   }
91 }
92
93 bool GlViewRenderThread::SetGraphicsConfig(bool depth, bool stencil, int msaa, int version)
94 {
95   mDepth              = depth;
96   mStencil            = stencil;
97   mMSAA               = msaa;
98   mGraphicsApiVersion = version;
99
100   if(mNativeImageSurface)
101   {
102     return mNativeImageSurface->SetGraphicsConfig(mDepth, mStencil, mMSAA, mGraphicsApiVersion);
103   }
104
105   return false;
106 }
107
108 void GlViewRenderThread::SetOnDemandRenderMode(bool onDemand)
109 {
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)
114   {
115     mConditionalWait.Notify(lock);
116   }
117 }
118
119 void GlViewRenderThread::SetSurfaceSize(Dali::Vector2 size)
120 {
121   //GlViewRenderThread::Run was already blocked in Internal::GlView::OnSizeSet
122   mSurfaceSize      = size;
123   mIsSurfaceResized = 1;
124 }
125
126 void GlViewRenderThread::RenderOnce()
127 {
128   //Notify GLRender thread.
129   Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
130   mIsRenderRequested = 1;
131   mConditionalWait.Notify(lock);
132 }
133
134 void GlViewRenderThread::GetNanoSeconds(uint64_t& timeInNanoseconds)
135 {
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());
140 }
141
142 void GlViewRenderThread::SleepUntil(uint64_t timeInNanoseconds)
143 {
144   using Clock     = std::chrono::steady_clock;
145   using TimePoint = std::chrono::time_point<Clock>;
146
147   const Clock::duration duration = std::chrono::nanoseconds(timeInNanoseconds);
148   const TimePoint       timePoint(duration);
149
150   std::this_thread::sleep_until(timePoint);
151 }
152
153 void GlViewRenderThread::Run()
154 {
155   Dali::SetThreadName("GlViewRenderer");
156   mLogFactory.InstallLogFunction();
157
158   int renderFrameResult = 0;
159
160   if(!mNativeImageSurface)
161   {
162     DALI_LOG_ERROR("NativeImageSurface is null, Could not start GlView Render Thread");
163     return;
164   }
165
166   AcquireSurface();
167   mNativeImageSurface->InitializeGraphics();
168   ReleaseSurface();
169
170   mNativeImageSurface->PreRender();
171   if(mGlInitCallback)
172   {
173     CallbackBase::Execute(*mGlInitCallback);
174   }
175
176   uint64_t timeToSleepUntil = 0;
177
178   while(RenderReady(timeToSleepUntil))
179   {
180     uint64_t currentFrameStartTime = 0;
181     GetNanoSeconds(currentFrameStartTime);
182
183     AcquireSurface();
184     mNativeImageSurface->PreRender();
185     if(mIsSurfaceResized)
186     {
187       if(mResizeCallback)
188       {
189         CallbackBase::Execute(*mResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
190       }
191       mIsSurfaceResized = 0;
192     }
193
194     if(mNativeImageSurface->CanRender())
195     {
196       if(mGlRenderFrameCallback)
197       {
198         renderFrameResult = CallbackBase::ExecuteReturn<int>(*mGlRenderFrameCallback);
199         if(renderFrameResult)
200         {
201           mNativeImageSurface->PostRender();
202         }
203       }
204     }
205
206     ReleaseSurface();
207
208     if(timeToSleepUntil == 0)
209     {
210       timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds;
211     }
212     else
213     {
214       timeToSleepUntil += mDefaultFrameDurationNanoseconds;
215       uint64_t currentFrameEndTime = 0;
216       GetNanoSeconds(currentFrameEndTime);
217       while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds)
218       {
219         timeToSleepUntil += mDefaultFrameDurationNanoseconds;
220       }
221     }
222
223     SleepUntil(timeToSleepUntil);
224   }
225
226   if(mGlTerminateCallback)
227   {
228     CallbackBase::Execute(*mGlTerminateCallback);
229   }
230
231   mNativeImageSurface->TerminateGraphics();
232
233   return;
234 }
235
236 void GlViewRenderThread::Stop()
237 {
238   // Set to come out Render Thread out of waiting condition.
239   Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
240   mIsThreadStopped = 1;
241   mIsThreadPaused  = 0;
242   mConditionalWait.Notify(lock);
243 }
244
245 void GlViewRenderThread::Pause()
246 {
247   //Notify GLRender thread, If actor visibility is change
248   Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
249   mIsThreadPaused = 1;
250   mConditionalWait.Notify(lock);
251 }
252
253 void GlViewRenderThread::Resume()
254 {
255   Dali::ConditionalWait::ScopedLock lock(mConditionalWait);
256   if(!mIsThreadStarted)
257   {
258     Start();
259     mIsThreadStarted = 1;
260   }
261   mIsThreadPaused = 0;
262   mConditionalWait.Notify(lock);
263 }
264
265 bool GlViewRenderThread::RenderReady(uint64_t& timeToSleepUntil)
266 {
267   ConditionalWait::ScopedLock lock(mConditionalWait);
268   while((!mIsThreadStopped && mRenderingMode && !mIsRenderRequested) || mIsThreadPaused)
269   {
270     timeToSleepUntil = 0;
271     mConditionalWait.Wait(lock);
272   }
273
274   mIsRenderRequested = 0;
275   // Keep the update-render thread alive if this thread is NOT to be destroyed
276   return !mIsThreadStopped;
277 }
278
279 void GlViewRenderThread::AcquireSurface()
280 {
281   mSurfaceSemaphore.Acquire();
282 }
283
284 void GlViewRenderThread::ReleaseSurface()
285 {
286   mSurfaceSemaphore.Release(1);
287 }
288
289 GlViewRenderThread::~GlViewRenderThread()
290 {
291 }
292
293 } // namespace Internal
294 } // namespace Toolkit
295 } // namespace Dali