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