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