Minor code cleans for render task
[platform/core/uifw/dali-core.git] / dali / internal / update / render-tasks / scene-graph-render-task.cpp
1 /*
2  * Copyright (c) 2023 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/internal/update/render-tasks/scene-graph-render-task.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/internal/render/common/render-instruction.h>
23 #include <dali/internal/render/common/render-tracker.h>
24 #include <dali/internal/update/controllers/render-message-dispatcher.h>
25 #include <dali/internal/update/nodes/node.h>
26 #include <dali/public-api/math/matrix.h>
27
28 #include <dali/internal/update/common/property-resetter.h>
29 #include <dali/internal/update/common/resetter-manager.h> ///< For AddInitializeResetter
30
31 #include <dali/internal/update/render-tasks/scene-graph-render-task-debug.h>
32
33 namespace Dali
34 {
35 namespace Internal
36 {
37 namespace SceneGraph
38 {
39 RenderTask* RenderTask::New()
40 {
41   return new RenderTask();
42 }
43
44 RenderTask::~RenderTask()
45 {
46   if(mSourceNode)
47   {
48     mSourceNode->RemoveObserver(*this);
49     if(mExclusive)
50     {
51       mSourceNode->SetExclusiveRenderTask(nullptr);
52     }
53   }
54   if(mCameraNode)
55   {
56     mCameraNode->RemoveObserver(*this);
57   }
58   if(mRenderSyncTracker)
59   {
60     mRenderMessageDispatcher->RemoveRenderTracker(*mRenderSyncTracker);
61   }
62 }
63
64 void RenderTask::Initialize(ResetterManager& resetterManager, RenderMessageDispatcher& renderMessageDispatcher)
65 {
66   mResetterManager         = &resetterManager;
67   mRenderMessageDispatcher = &renderMessageDispatcher;
68 }
69
70 void RenderTask::SetSourceNode(Node* node)
71 {
72   // Stop observing the old node (if we were)
73   if(mSourceNode)
74   {
75     mSourceNode->RemoveObserver(*this);
76     if(this == mSourceNode->GetExclusiveRenderTask())
77     {
78       mSourceNode->SetExclusiveRenderTask(nullptr);
79     }
80   }
81
82   mSourceNode = node;
83
84   if(mSourceNode)
85   {
86     mSourceNode->AddObserver(*this);
87     if(mExclusive)
88     {
89       mSourceNode->SetExclusiveRenderTask(this);
90     }
91   }
92   SetActiveStatus();
93 }
94
95 Node* RenderTask::GetSourceNode() const
96 {
97   return mSourceNode;
98 }
99
100 void RenderTask::SetViewportGuideNode(Node* node)
101 {
102   mViewportGuideNode = node;
103 }
104
105 Node* RenderTask::GetViewportGuideNode() const
106 {
107   return mViewportGuideNode;
108 }
109
110 void RenderTask::SetExclusive(bool exclusive)
111 {
112   mExclusive = exclusive;
113
114   if(mSourceNode)
115   {
116     if(mExclusive)
117     {
118       mSourceNode->SetExclusiveRenderTask(this);
119     }
120     else if(this == mSourceNode->GetExclusiveRenderTask())
121     {
122       mSourceNode->SetExclusiveRenderTask(nullptr);
123     }
124   }
125 }
126
127 bool RenderTask::IsExclusive() const
128 {
129   return mExclusive;
130 }
131
132 void RenderTask::SetCamera(Camera* cameraNode)
133 {
134   if(mCameraNode)
135   {
136     mCameraNode->RemoveObserver(*this);
137   }
138
139   mCameraNode = cameraNode;
140
141   if(mCameraNode)
142   {
143     mCameraNode->AddObserver(*this);
144   }
145   SetActiveStatus();
146 }
147
148 void RenderTask::SetFrameBuffer(Render::FrameBuffer* frameBuffer)
149 {
150   mFrameBuffer = frameBuffer;
151 }
152
153 Render::FrameBuffer* RenderTask::GetFrameBuffer()
154 {
155   return mFrameBuffer;
156 }
157
158 bool RenderTask::QueryViewport(BufferIndex bufferIndex, Viewport& viewport) const
159 {
160   if(!GetViewportEnabled(bufferIndex))
161   {
162     return false;
163   }
164
165   viewport.x      = static_cast<int>(mViewportPosition[bufferIndex].x);  // truncated
166   viewport.y      = static_cast<int>(mViewportPosition[bufferIndex].y);  // truncated
167   viewport.width  = static_cast<int>(mViewportSize[bufferIndex].width);  // truncated
168   viewport.height = static_cast<int>(mViewportSize[bufferIndex].height); // truncated
169
170   return true;
171 }
172
173 const Vector4& RenderTask::GetClearColor(BufferIndex bufferIndex) const
174 {
175   return mClearColor[bufferIndex];
176 }
177
178 void RenderTask::SetClearEnabled(bool enabled)
179 {
180   mClearEnabled = enabled;
181 }
182
183 bool RenderTask::GetClearEnabled() const
184 {
185   return mClearEnabled;
186 }
187
188 void RenderTask::SetCullMode(bool mode)
189 {
190   mCullMode = mode;
191 }
192
193 bool RenderTask::GetCullMode() const
194 {
195   return mCullMode;
196 }
197
198 void RenderTask::SetRefreshRate(uint32_t refreshRate)
199 {
200   DALI_LOG_TRACE_METHOD_FMT(gRenderTaskLogFilter, "this:%p RefreshRate:%d\n", this, refreshRate);
201
202   mRefreshRate = refreshRate;
203
204   if(mRefreshRate > 0)
205   {
206     mState = RENDER_CONTINUOUSLY;
207   }
208   else
209   {
210     mState           = RENDER_ONCE_WAITING_FOR_RESOURCES;
211     mWaitingToRender = true;
212     mNotifyTrigger   = false;
213   }
214
215   mFrameCounter = 0u;
216 }
217
218 uint32_t RenderTask::GetRefreshRate() const
219 {
220   return mRefreshRate;
221 }
222
223 bool RenderTask::ReadyToRender(BufferIndex updateBufferIndex)
224 {
225   return mActive;
226 }
227
228 bool RenderTask::IsRenderRequired()
229 {
230   bool required = false;
231
232   switch(mState)
233   {
234     case RENDER_CONTINUOUSLY:
235     {
236       required = (mFrameCounter == 0);
237       break;
238     }
239     case RENDER_ONCE_WAITING_FOR_RESOURCES:
240     {
241       required = true;
242       break;
243     }
244     default:
245     {
246       required = false;
247       break;
248     }
249   }
250
251   TASK_LOG_FMT(Debug::General, " State:%s = %s\n", STATE_STRING(mState), required ? "T" : "F");
252
253   return required;
254 }
255
256 // Called every frame regardless of whether render was required.
257 // If render was not required, ignore resourcesFinished.
258 void RenderTask::UpdateState()
259 {
260   TASK_LOG_FMT(Debug::General, "FC:%d State:%s RR:%d\n", mFrameCounter, STATE_STRING(mState), mRefreshRate);
261
262   switch(mState)
263   {
264     case RENDER_CONTINUOUSLY:
265     {
266       if(mRefreshRate != Dali::RenderTask::REFRESH_ALWAYS)
267       {
268         if(mFrameCounter == 0)
269         {
270           ++mFrameCounter; // Only start skipping frames when resources are loaded
271         }
272         else // Continue counting to skip frames
273         {
274           ++mFrameCounter;
275           if(mFrameCounter >= mRefreshRate)
276           {
277             mFrameCounter = 0;
278           }
279         }
280       }
281       // else do nothing
282     }
283     break;
284
285     case RENDER_ONCE_WAITING_FOR_RESOURCES:
286     {
287       mState = RENDERED_ONCE;
288     }
289     break;
290
291     case RENDERED_ONCE:
292     {
293       mWaitingToRender = true;
294       mNotifyTrigger   = false;
295       if(mFrameBuffer)
296       {
297         if(!mRenderSyncTracker || (mRenderSyncTracker && mRenderSyncTracker->IsSynced()))
298         {
299           mWaitingToRender = false;
300           mNotifyTrigger   = true;
301         }
302       }
303       else
304       {
305         mWaitingToRender = false;
306         mNotifyTrigger   = true;
307       }
308     }
309
310     break;
311
312     default:
313       break;
314   }
315
316   TASK_LOG_FMT(Debug::General, " EXIT FC:%d State:%s Notify:%s\n", mFrameCounter, STATE_STRING(mState), mNotifyTrigger ? "T" : "F");
317 }
318
319 bool RenderTask::IsWaitingToRender()
320 {
321   TASK_LOG_FMT(Debug::Verbose, " State:%s waiting:%s \n", STATE_STRING(mState), mWaitingToRender ? "T" : "F");
322   return mWaitingToRender;
323 }
324
325 bool RenderTask::HasRendered()
326 {
327   bool notify = false;
328   if(mNotifyTrigger == true)
329   {
330     ++mRenderedOnceCounter;
331     mState         = RENDERED_ONCE_AND_NOTIFIED;
332     mNotifyTrigger = false;
333     notify         = true;
334   }
335
336   TASK_LOG_FMT(Debug::Verbose, " State:%s hasRendered:%s \n", STATE_STRING(mState), notify ? "T" : "F");
337   return notify;
338 }
339
340 uint32_t RenderTask::GetRenderedOnceCounter() const
341 {
342   return mRenderedOnceCounter;
343 }
344
345 const Matrix& RenderTask::GetViewMatrix(BufferIndex bufferIndex) const
346 {
347   DALI_ASSERT_DEBUG(nullptr != mCameraNode);
348
349   return mCameraNode->GetViewMatrix(bufferIndex);
350 }
351
352 const SceneGraph::Camera& RenderTask::GetCamera() const
353 {
354   DALI_ASSERT_DEBUG(nullptr != mCameraNode);
355   return *mCameraNode;
356 }
357
358 const Matrix& RenderTask::GetProjectionMatrix(BufferIndex bufferIndex) const
359 {
360   DALI_ASSERT_DEBUG(nullptr != mCameraNode);
361
362   return mCameraNode->GetProjectionMatrix(bufferIndex);
363 }
364
365 RenderInstruction& RenderTask::PrepareRenderInstruction(BufferIndex updateBufferIndex)
366 {
367   DALI_ASSERT_DEBUG(nullptr != mCameraNode);
368
369   TASK_LOG(Debug::General);
370
371   Viewport viewport;
372   bool     viewportSet = QueryViewport(updateBufferIndex, viewport);
373
374   mRenderInstruction[updateBufferIndex].Reset(mCameraNode,
375                                               GetFrameBuffer(),
376                                               viewportSet ? &viewport : nullptr,
377                                               mClearEnabled ? &GetClearColor(updateBufferIndex) : nullptr);
378
379   if(mRequiresSync &&
380      mRefreshRate == Dali::RenderTask::REFRESH_ONCE)
381   {
382     // create tracker if one doesn't yet exist.
383     if(!mRenderSyncTracker)
384     {
385       mRenderSyncTracker = new Render::RenderTracker();
386       mRenderMessageDispatcher->AddRenderTracker(*mRenderSyncTracker);
387     }
388     mRenderInstruction[updateBufferIndex].mRenderTracker = mRenderSyncTracker;
389   }
390   else
391   {
392     // no sync needed, texture FBOs are "ready" the same frame they are rendered to
393     mRenderInstruction[updateBufferIndex].mRenderTracker = nullptr;
394   }
395
396   return mRenderInstruction[updateBufferIndex];
397 }
398
399 bool RenderTask::ViewMatrixUpdated()
400 {
401   bool retval = false;
402   if(mCameraNode)
403   {
404     retval = mCameraNode->ViewMatrixUpdated();
405   }
406   return retval;
407 }
408
409 void RenderTask::UpdateViewport(BufferIndex updateBufferIndex, Vector2 sceneSize, Vector3 cameraPosition)
410 {
411   if(GetViewportGuideNode() && GetViewportGuideNode()->ConnectedToScene())
412   {
413     Vector3 worldPosition = GetViewportGuideNode()->GetWorldPosition(updateBufferIndex);
414     worldPosition -= cameraPosition;
415
416     Vector3 nodeSize = GetViewportGuideNode()->GetSize(updateBufferIndex) * GetViewportGuideNode()->GetWorldScale(updateBufferIndex);
417     Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f); // World position origin is center of scene
418     Vector3 halfNodeSize(nodeSize * 0.5f);
419     Vector2 screenPosition(halfSceneSize.width + worldPosition.x - halfNodeSize.x,
420                            halfSceneSize.height + worldPosition.y - halfNodeSize.y);
421
422     /* This is an implicit constraint - the properties will be dirty until the node
423      * is removed. (RenderTask::Impl manages this)
424      */
425     mViewportPosition.Set(updateBufferIndex, screenPosition);
426     mViewportSize.Set(updateBufferIndex, Vector2(nodeSize));
427   }
428 }
429
430 const Vector2& RenderTask::GetViewportPosition(BufferIndex bufferIndex) const
431 {
432   return mViewportPosition[bufferIndex];
433 }
434
435 const Vector2& RenderTask::GetViewportSize(BufferIndex bufferIndex) const
436 {
437   return mViewportSize[bufferIndex];
438 }
439
440 bool RenderTask::GetViewportEnabled(BufferIndex bufferIndex) const
441 {
442   if(fabsf(mViewportPosition[bufferIndex].x) > Math::MACHINE_EPSILON_1 ||
443      fabsf(mViewportPosition[bufferIndex].y) > Math::MACHINE_EPSILON_1 ||
444      fabsf(mViewportSize[bufferIndex].width) > Math::MACHINE_EPSILON_1 ||
445      fabsf(mViewportSize[bufferIndex].height) > Math::MACHINE_EPSILON_1)
446   {
447     return true;
448   }
449
450   return false;
451 }
452
453 void RenderTask::SetSyncRequired(bool requiresSync)
454 {
455   mRequiresSync = requiresSync;
456 }
457
458 void RenderTask::PropertyOwnerConnected(PropertyOwner& owner)
459 {
460   // check if we've gone from inactive to active
461   SetActiveStatus();
462 }
463
464 void RenderTask::PropertyOwnerDisconnected(BufferIndex /*updateBufferIndex*/, PropertyOwner& owner)
465 {
466   mActive = false; // if either source or camera disconnected, we're no longer active
467 }
468
469 void RenderTask::PropertyOwnerDestroyed(PropertyOwner& owner)
470 {
471   if(static_cast<PropertyOwner*>(mSourceNode) == &owner)
472   {
473     mSourceNode = nullptr;
474   }
475   else if(static_cast<PropertyOwner*>(mCameraNode) == &owner)
476   {
477     mCameraNode = nullptr;
478   }
479
480   mActive = false; // if either source or camera destroyed, we're no longer active
481 }
482
483 void RenderTask::AddInitializeResetter(ResetterManager& manager) const
484 {
485   OwnerPointer<SceneGraph::PropertyResetterBase> resetterViewportPosition = SceneGraph::BakerResetter::New(*this, mViewportPosition, SceneGraph::BakerResetter::Lifetime::BAKE);
486   OwnerPointer<SceneGraph::PropertyResetterBase> resetterViewportSize     = SceneGraph::BakerResetter::New(*this, mViewportSize, SceneGraph::BakerResetter::Lifetime::BAKE);
487   OwnerPointer<SceneGraph::PropertyResetterBase> resetterClearColor       = SceneGraph::BakerResetter::New(*this, mClearColor, SceneGraph::BakerResetter::Lifetime::BAKE);
488   manager.AddPropertyResetter(resetterViewportPosition);
489   manager.AddPropertyResetter(resetterViewportSize);
490   manager.AddPropertyResetter(resetterClearColor);
491 }
492
493 RenderTask::RenderTask()
494 : mViewportPosition(Vector2::ZERO),
495   mViewportSize(Vector2::ZERO),
496   mClearColor(Dali::RenderTask::DEFAULT_CLEAR_COLOR),
497   mResetterManager(nullptr),
498   mRenderMessageDispatcher(nullptr),
499   mRenderSyncTracker(nullptr),
500   mSourceNode(nullptr),
501   mCameraNode(nullptr),
502   mViewportGuideNode(nullptr),
503   mFrameBuffer(nullptr),
504   mRefreshRate(Dali::RenderTask::DEFAULT_REFRESH_RATE),
505   mFrameCounter(0u),
506   mRenderedOnceCounter(0u),
507   mState((Dali::RenderTask::DEFAULT_REFRESH_RATE == Dali::RenderTask::REFRESH_ALWAYS)
508            ? RENDER_CONTINUOUSLY
509            : RENDER_ONCE_WAITING_FOR_RESOURCES),
510   mRequiresSync(false),
511   mActive(false),
512   mWaitingToRender(false),
513   mNotifyTrigger(false),
514   mExclusive(Dali::RenderTask::DEFAULT_EXCLUSIVE),
515   mClearEnabled(Dali::RenderTask::DEFAULT_CLEAR_ENABLED),
516   mCullMode(Dali::RenderTask::DEFAULT_CULL_MODE)
517 {
518 }
519
520 void RenderTask::SetActiveStatus()
521 {
522   bool oldActive = mActive;
523
524   // must have a source and camera both connected to scene
525   mActive = (mSourceNode && mSourceNode->ConnectedToScene() &&
526              mCameraNode && mCameraNode->ConnectedToScene());
527   TASK_LOG_FMT(Debug::General, " Source node(%x) active %d.  Frame counter: %d\n", mSourceNode, mSourceNode && mSourceNode->ConnectedToScene(), mFrameCounter);
528   TASK_LOG_FMT(Debug::General, " Camera node(%x) active %d\n", mCameraNode, mCameraNode && mCameraNode->ConnectedToScene());
529
530   if(!oldActive && mActive)
531   {
532     // Send resetter only if newly activated
533     AddInitializeResetter(*mResetterManager);
534   }
535 }
536
537 } // namespace SceneGraph
538
539 } // namespace Internal
540
541 } // namespace Dali