Merge changes I8783ad29,I2c860a84 into 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/render-tasks/scene-graph-render-task-debug.h>
29
30 namespace Dali
31 {
32 namespace Internal
33 {
34 namespace SceneGraph
35 {
36 RenderTask* RenderTask::New()
37 {
38   return new RenderTask();
39 }
40
41 RenderTask::~RenderTask()
42 {
43   if(mSourceNode)
44   {
45     mSourceNode->RemoveObserver(*this);
46     if(mExclusive)
47     {
48       mSourceNode->SetExclusiveRenderTask(nullptr);
49     }
50   }
51   if(mCameraNode)
52   {
53     mCameraNode->RemoveObserver(*this);
54   }
55   if(mRenderSyncTracker)
56   {
57     mRenderMessageDispatcher->RemoveRenderTracker(*mRenderSyncTracker);
58   }
59 }
60
61 void RenderTask::Initialize(RenderMessageDispatcher& renderMessageDispatcher)
62 {
63   mRenderMessageDispatcher = &renderMessageDispatcher;
64 }
65
66 void RenderTask::SetSourceNode(Node* node)
67 {
68   // Stop observing the old node (if we were)
69   if(mSourceNode)
70   {
71     mSourceNode->RemoveObserver(*this);
72     if(this == mSourceNode->GetExclusiveRenderTask())
73     {
74       mSourceNode->SetExclusiveRenderTask(nullptr);
75     }
76   }
77
78   mSourceNode = node;
79
80   if(mSourceNode)
81   {
82     mSourceNode->AddObserver(*this);
83     if(mExclusive)
84     {
85       mSourceNode->SetExclusiveRenderTask(this);
86     }
87   }
88   SetActiveStatus();
89 }
90
91 Node* RenderTask::GetSourceNode() const
92 {
93   return mSourceNode;
94 }
95
96 void RenderTask::SetViewportGuideNode(Node* node)
97 {
98   mViewportGuideNode = node;
99 }
100
101 Node* RenderTask::GetViewportGuideNode() const
102 {
103   return mViewportGuideNode;
104 }
105
106 void RenderTask::SetExclusive(bool exclusive)
107 {
108   mExclusive = exclusive;
109
110   if(mSourceNode)
111   {
112     if(mExclusive)
113     {
114       mSourceNode->SetExclusiveRenderTask(this);
115     }
116     else if(this == mSourceNode->GetExclusiveRenderTask())
117     {
118       mSourceNode->SetExclusiveRenderTask(nullptr);
119     }
120   }
121 }
122
123 bool RenderTask::IsExclusive() const
124 {
125   return mExclusive;
126 }
127
128 void RenderTask::SetCamera(Node* cameraNode, Camera* camera)
129 {
130   if(mCameraNode)
131   {
132     mCameraNode->RemoveObserver(*this);
133   }
134
135   mCameraNode = cameraNode;
136   mCamera     = camera;
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 != mCamera);
345
346   return mCamera->GetViewMatrix(bufferIndex);
347 }
348
349 const SceneGraph::Camera& RenderTask::GetCamera() const
350 {
351   DALI_ASSERT_DEBUG(nullptr != mCamera);
352   return *mCamera;
353 }
354
355 const Matrix& RenderTask::GetProjectionMatrix(BufferIndex bufferIndex) const
356 {
357   DALI_ASSERT_DEBUG(nullptr != mCamera);
358
359   return mCamera->GetProjectionMatrix(bufferIndex);
360 }
361
362 RenderInstruction& RenderTask::PrepareRenderInstruction(BufferIndex updateBufferIndex)
363 {
364   DALI_ASSERT_DEBUG(nullptr != mCamera);
365
366   TASK_LOG(Debug::General);
367
368   Viewport viewport;
369   bool     viewportSet = QueryViewport(updateBufferIndex, viewport);
370
371   mRenderInstruction[updateBufferIndex].Reset(mCamera,
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   return mRenderInstruction[updateBufferIndex];
394 }
395
396 bool RenderTask::ViewMatrixUpdated()
397 {
398   bool retval = false;
399   if(mCamera)
400   {
401     retval = mCamera->ViewMatrixUpdated();
402   }
403   return retval;
404 }
405
406 void RenderTask::UpdateViewport(BufferIndex updateBufferIndex, Vector2 sceneSize, Vector3 cameraPosition)
407 {
408   if(GetViewportGuideNode() && GetViewportGuideNode()->ConnectedToScene())
409   {
410     Vector3 worldPosition = GetViewportGuideNode()->GetWorldPosition(updateBufferIndex);
411     worldPosition -= cameraPosition;
412
413     Vector3 nodeSize = GetViewportGuideNode()->GetSize(updateBufferIndex) * GetViewportGuideNode()->GetWorldScale(updateBufferIndex);
414     Vector2 halfSceneSize(sceneSize.width * 0.5f, sceneSize.height * 0.5f); // World position origin is center of scene
415     Vector3 halfNodeSize(nodeSize * 0.5f);
416     Vector2 screenPosition(halfSceneSize.width + worldPosition.x - halfNodeSize.x,
417                            halfSceneSize.height + worldPosition.y - halfNodeSize.y);
418
419     /* This is an implicit constraint - the properties will be dirty until the node
420      * is removed. (RenderTask::Impl manages this)
421      */
422     mViewportPosition.Set(updateBufferIndex, screenPosition);
423     mViewportSize.Set(updateBufferIndex, Vector2(nodeSize));
424   }
425 }
426
427 const Vector2& RenderTask::GetViewportPosition(BufferIndex bufferIndex) const
428 {
429   return mViewportPosition[bufferIndex];
430 }
431
432 const Vector2& RenderTask::GetViewportSize(BufferIndex bufferIndex) const
433 {
434   return mViewportSize[bufferIndex];
435 }
436
437 bool RenderTask::GetViewportEnabled(BufferIndex bufferIndex) const
438 {
439   if(fabsf(mViewportPosition[bufferIndex].x) > Math::MACHINE_EPSILON_1 ||
440      fabsf(mViewportPosition[bufferIndex].y) > Math::MACHINE_EPSILON_1 ||
441      fabsf(mViewportSize[bufferIndex].width) > Math::MACHINE_EPSILON_1 ||
442      fabsf(mViewportSize[bufferIndex].height) > Math::MACHINE_EPSILON_1)
443   {
444     return true;
445   }
446
447   return false;
448 }
449
450 void RenderTask::SetSyncRequired(bool requiresSync)
451 {
452   mRequiresSync = requiresSync;
453 }
454
455 void RenderTask::PropertyOwnerConnected(PropertyOwner& owner)
456 {
457   // check if we've gone from inactive to active
458   SetActiveStatus();
459 }
460
461 void RenderTask::PropertyOwnerDisconnected(BufferIndex /*updateBufferIndex*/, PropertyOwner& owner)
462 {
463   mActive = false; // if either source or camera disconnected, we're no longer active
464 }
465
466 void RenderTask::PropertyOwnerDestroyed(PropertyOwner& owner)
467 {
468   if(static_cast<PropertyOwner*>(mSourceNode) == &owner)
469   {
470     mSourceNode = nullptr;
471   }
472   else if(static_cast<PropertyOwner*>(mCameraNode) == &owner)
473   {
474     mCameraNode = nullptr;
475   }
476 }
477
478 RenderTask::RenderTask()
479 : mViewportPosition(Vector2::ZERO),
480   mViewportSize(Vector2::ZERO),
481   mClearColor(Dali::RenderTask::DEFAULT_CLEAR_COLOR),
482   mRenderMessageDispatcher(nullptr),
483   mRenderSyncTracker(nullptr),
484   mSourceNode(nullptr),
485   mCameraNode(nullptr),
486   mViewportGuideNode(nullptr),
487   mCamera(nullptr),
488   mFrameBuffer(nullptr),
489   mRefreshRate(Dali::RenderTask::DEFAULT_REFRESH_RATE),
490   mFrameCounter(0u),
491   mRenderedOnceCounter(0u),
492   mState((Dali::RenderTask::DEFAULT_REFRESH_RATE == Dali::RenderTask::REFRESH_ALWAYS)
493            ? RENDER_CONTINUOUSLY
494            : RENDER_ONCE_WAITING_FOR_RESOURCES),
495   mRequiresSync(false),
496   mActive(false),
497   mWaitingToRender(false),
498   mNotifyTrigger(false),
499   mExclusive(Dali::RenderTask::DEFAULT_EXCLUSIVE),
500   mClearEnabled(Dali::RenderTask::DEFAULT_CLEAR_ENABLED),
501   mCullMode(Dali::RenderTask::DEFAULT_CULL_MODE)
502 {
503 }
504
505 void RenderTask::SetActiveStatus()
506 {
507   // must have a source and camera both connected to scene
508   mActive = (mSourceNode && mSourceNode->ConnectedToScene() &&
509              mCameraNode && mCameraNode->ConnectedToScene() && mCamera);
510   TASK_LOG_FMT(Debug::General, " Source node(%x) active %d.  Frame counter: %d\n", mSourceNode, mSourceNode && mSourceNode->ConnectedToScene(), mFrameCounter);
511   TASK_LOG_FMT(Debug::General, " Camera node(%x) active %d\n", mCameraNode, mCameraNode && mCameraNode->ConnectedToScene());
512 }
513
514 } // namespace SceneGraph
515
516 } // namespace Internal
517
518 } // namespace Dali