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