2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
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>
28 #include <dali/internal/update/common/property-resetter.h>
29 #include <dali/internal/update/common/resetter-manager.h> ///< For AddInitializeResetter
31 #include <dali/internal/update/render-tasks/scene-graph-render-task-debug.h>
39 RenderTask* RenderTask::New()
41 return new RenderTask();
44 RenderTask::~RenderTask()
48 mSourceNode->RemoveObserver(*this);
51 mSourceNode->SetExclusiveRenderTask(nullptr);
56 mCameraNode->RemoveObserver(*this);
58 if(mRenderSyncTracker)
60 mRenderMessageDispatcher->RemoveRenderTracker(*mRenderSyncTracker);
64 void RenderTask::Initialize(ResetterManager& resetterManager, RenderMessageDispatcher& renderMessageDispatcher)
66 mResetterManager = &resetterManager;
67 mRenderMessageDispatcher = &renderMessageDispatcher;
70 void RenderTask::SetSourceNode(Node* node)
72 // Stop observing the old node (if we were)
75 mSourceNode->RemoveObserver(*this);
76 if(this == mSourceNode->GetExclusiveRenderTask())
78 mSourceNode->SetExclusiveRenderTask(nullptr);
86 mSourceNode->AddObserver(*this);
89 mSourceNode->SetExclusiveRenderTask(this);
95 Node* RenderTask::GetSourceNode() const
100 void RenderTask::SetViewportGuideNode(Node* node)
102 mViewportGuideNode = node;
105 Node* RenderTask::GetViewportGuideNode() const
107 return mViewportGuideNode;
110 void RenderTask::SetExclusive(bool exclusive)
112 mExclusive = exclusive;
118 mSourceNode->SetExclusiveRenderTask(this);
120 else if(this == mSourceNode->GetExclusiveRenderTask())
122 mSourceNode->SetExclusiveRenderTask(nullptr);
127 bool RenderTask::IsExclusive() const
132 void RenderTask::SetCamera(Camera* cameraNode)
136 mCameraNode->RemoveObserver(*this);
139 mCameraNode = cameraNode;
143 mCameraNode->AddObserver(*this);
148 void RenderTask::SetFrameBuffer(Render::FrameBuffer* frameBuffer)
150 mFrameBuffer = frameBuffer;
153 Render::FrameBuffer* RenderTask::GetFrameBuffer()
158 bool RenderTask::QueryViewport(BufferIndex bufferIndex, Viewport& viewport) const
160 if(!GetViewportEnabled(bufferIndex))
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
173 const Vector4& RenderTask::GetClearColor(BufferIndex bufferIndex) const
175 return mClearColor[bufferIndex];
178 void RenderTask::SetClearEnabled(bool enabled)
180 mClearEnabled = enabled;
183 bool RenderTask::GetClearEnabled() const
185 return mClearEnabled;
188 void RenderTask::SetCullMode(bool mode)
193 bool RenderTask::GetCullMode() const
198 void RenderTask::SetRefreshRate(uint32_t refreshRate)
200 DALI_LOG_TRACE_METHOD_FMT(gRenderTaskLogFilter, "this:%p RefreshRate:%d\n", this, refreshRate);
202 mRefreshRate = refreshRate;
206 mState = RENDER_CONTINUOUSLY;
210 mState = RENDER_ONCE_WAITING_FOR_RESOURCES;
211 mWaitingToRender = true;
212 mNotifyTrigger = false;
218 uint32_t RenderTask::GetRefreshRate() const
223 bool RenderTask::ReadyToRender(BufferIndex updateBufferIndex)
228 bool RenderTask::IsRenderRequired()
230 bool required = false;
234 case RENDER_CONTINUOUSLY:
236 required = (mFrameCounter == 0);
239 case RENDER_ONCE_WAITING_FOR_RESOURCES:
251 TASK_LOG_FMT(Debug::General, " State:%s = %s\n", STATE_STRING(mState), required ? "T" : "F");
256 // Called every frame regardless of whether render was required.
257 // If render was not required, ignore resourcesFinished.
258 void RenderTask::UpdateState()
260 TASK_LOG_FMT(Debug::General, "FC:%d State:%s RR:%d\n", mFrameCounter, STATE_STRING(mState), mRefreshRate);
264 case RENDER_CONTINUOUSLY:
266 if(mRefreshRate != Dali::RenderTask::REFRESH_ALWAYS)
268 if(mFrameCounter == 0)
270 ++mFrameCounter; // Only start skipping frames when resources are loaded
272 else // Continue counting to skip frames
275 if(mFrameCounter >= mRefreshRate)
285 case RENDER_ONCE_WAITING_FOR_RESOURCES:
287 mState = RENDERED_ONCE;
293 mWaitingToRender = true;
294 mNotifyTrigger = false;
297 if(!mRenderSyncTracker || (mRenderSyncTracker && mRenderSyncTracker->IsSynced()))
299 mWaitingToRender = false;
300 mNotifyTrigger = true;
305 mWaitingToRender = false;
306 mNotifyTrigger = true;
316 TASK_LOG_FMT(Debug::General, " EXIT FC:%d State:%s Notify:%s\n", mFrameCounter, STATE_STRING(mState), mNotifyTrigger ? "T" : "F");
319 bool RenderTask::IsWaitingToRender()
321 TASK_LOG_FMT(Debug::Verbose, " State:%s waiting:%s \n", STATE_STRING(mState), mWaitingToRender ? "T" : "F");
322 return mWaitingToRender;
325 bool RenderTask::HasRendered()
328 if(mNotifyTrigger == true)
330 ++mRenderedOnceCounter;
331 mState = RENDERED_ONCE_AND_NOTIFIED;
332 mNotifyTrigger = false;
336 TASK_LOG_FMT(Debug::Verbose, " State:%s hasRendered:%s \n", STATE_STRING(mState), notify ? "T" : "F");
340 uint32_t RenderTask::GetRenderedOnceCounter() const
342 return mRenderedOnceCounter;
345 const Matrix& RenderTask::GetViewMatrix(BufferIndex bufferIndex) const
347 DALI_ASSERT_DEBUG(nullptr != mCameraNode);
349 return mCameraNode->GetViewMatrix(bufferIndex);
352 const SceneGraph::Camera& RenderTask::GetCamera() const
354 DALI_ASSERT_DEBUG(nullptr != mCameraNode);
358 const Matrix& RenderTask::GetProjectionMatrix(BufferIndex bufferIndex) const
360 DALI_ASSERT_DEBUG(nullptr != mCameraNode);
362 return mCameraNode->GetProjectionMatrix(bufferIndex);
365 RenderInstruction& RenderTask::PrepareRenderInstruction(BufferIndex updateBufferIndex)
367 DALI_ASSERT_DEBUG(nullptr != mCameraNode);
369 TASK_LOG(Debug::General);
372 bool viewportSet = QueryViewport(updateBufferIndex, viewport);
374 mRenderInstruction[updateBufferIndex].Reset(mCameraNode,
376 viewportSet ? &viewport : nullptr,
377 mClearEnabled ? &GetClearColor(updateBufferIndex) : nullptr);
380 mRefreshRate == Dali::RenderTask::REFRESH_ONCE)
382 // create tracker if one doesn't yet exist.
383 if(!mRenderSyncTracker)
385 mRenderSyncTracker = new Render::RenderTracker();
386 mRenderMessageDispatcher->AddRenderTracker(*mRenderSyncTracker);
388 mRenderInstruction[updateBufferIndex].mRenderTracker = mRenderSyncTracker;
392 // no sync needed, texture FBOs are "ready" the same frame they are rendered to
393 mRenderInstruction[updateBufferIndex].mRenderTracker = nullptr;
396 return mRenderInstruction[updateBufferIndex];
399 bool RenderTask::ViewMatrixUpdated()
404 retval = mCameraNode->ViewMatrixUpdated();
409 void RenderTask::UpdateViewport(BufferIndex updateBufferIndex, Vector2 sceneSize, Vector3 cameraPosition)
411 if(GetViewportGuideNode() && GetViewportGuideNode()->ConnectedToScene())
413 Vector3 worldPosition = GetViewportGuideNode()->GetWorldPosition(updateBufferIndex);
414 worldPosition -= cameraPosition;
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);
422 /* This is an implicit constraint - the properties will be dirty until the node
423 * is removed. (RenderTask::Impl manages this)
425 mViewportPosition.Set(updateBufferIndex, screenPosition);
426 mViewportSize.Set(updateBufferIndex, Vector2(nodeSize));
430 const Vector2& RenderTask::GetViewportPosition(BufferIndex bufferIndex) const
432 return mViewportPosition[bufferIndex];
435 const Vector2& RenderTask::GetViewportSize(BufferIndex bufferIndex) const
437 return mViewportSize[bufferIndex];
440 bool RenderTask::GetViewportEnabled(BufferIndex bufferIndex) const
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)
453 void RenderTask::SetSyncRequired(bool requiresSync)
455 mRequiresSync = requiresSync;
458 void RenderTask::PropertyOwnerConnected(PropertyOwner& owner)
460 // check if we've gone from inactive to active
464 void RenderTask::PropertyOwnerDisconnected(BufferIndex /*updateBufferIndex*/, PropertyOwner& owner)
466 mActive = false; // if either source or camera disconnected, we're no longer active
469 void RenderTask::PropertyOwnerDestroyed(PropertyOwner& owner)
471 if(static_cast<PropertyOwner*>(mSourceNode) == &owner)
473 mSourceNode = nullptr;
475 else if(static_cast<PropertyOwner*>(mCameraNode) == &owner)
477 mCameraNode = nullptr;
480 mActive = false; // if either source or camera destroyed, we're no longer active
483 void RenderTask::AddInitializeResetter(ResetterManager& manager) const
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);
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),
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),
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)
520 void RenderTask::SetActiveStatus()
522 bool oldActive = mActive;
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());
530 if(!oldActive && mActive)
532 // Send resetter only if newly activated
533 AddInitializeResetter(*mResetterManager);
537 } // namespace SceneGraph
539 } // namespace Internal