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->RemoveExclusiveRenderTask(this);
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 mSourceNode->RemoveExclusiveRenderTask(this);
83 mSourceNode->AddObserver(*this);
86 mSourceNode->AddExclusiveRenderTask(this);
92 Node* RenderTask::GetSourceNode() const
97 void RenderTask::SetViewportGuideNode(Node* node)
99 mViewportGuideNode = node;
102 Node* RenderTask::GetViewportGuideNode() const
104 return mViewportGuideNode;
107 void RenderTask::SetExclusive(bool exclusive)
109 mExclusive = exclusive;
115 mSourceNode->AddExclusiveRenderTask(this);
119 mSourceNode->RemoveExclusiveRenderTask(this);
124 bool RenderTask::IsExclusive() const
129 void RenderTask::SetCamera(Camera* cameraNode)
133 mCameraNode->RemoveObserver(*this);
136 mCameraNode = cameraNode;
140 mCameraNode->AddObserver(*this);
145 void RenderTask::SetFrameBuffer(Render::FrameBuffer* frameBuffer)
147 mFrameBuffer = frameBuffer;
150 Render::FrameBuffer* RenderTask::GetFrameBuffer()
155 bool RenderTask::QueryViewport(BufferIndex bufferIndex, Viewport& viewport) const
157 if(!GetViewportEnabled(bufferIndex))
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
170 const Vector4& RenderTask::GetClearColor(BufferIndex bufferIndex) const
172 return mClearColor[bufferIndex];
175 void RenderTask::SetClearEnabled(bool enabled)
177 mClearEnabled = enabled;
180 bool RenderTask::GetClearEnabled() const
182 return mClearEnabled;
185 void RenderTask::SetCullMode(bool mode)
190 bool RenderTask::GetCullMode() const
195 void RenderTask::SetRefreshRate(uint32_t refreshRate)
197 DALI_LOG_TRACE_METHOD_FMT(gRenderTaskLogFilter, "this:%p RefreshRate:%d\n", this, refreshRate);
199 mRefreshRate = refreshRate;
203 mState = RENDER_CONTINUOUSLY;
207 mState = RENDER_ONCE_WAITING_FOR_RESOURCES;
208 mWaitingToRender = true;
209 mNotifyTrigger = false;
215 uint32_t RenderTask::GetRefreshRate() const
220 bool RenderTask::ReadyToRender(BufferIndex updateBufferIndex)
225 bool RenderTask::IsRenderRequired()
227 bool required = false;
231 case RENDER_CONTINUOUSLY:
233 required = (mFrameCounter == 0);
236 case RENDER_ONCE_WAITING_FOR_RESOURCES:
248 TASK_LOG_FMT(Debug::General, " State:%s = %s\n", STATE_STRING(mState), required ? "T" : "F");
253 // Called every frame regardless of whether render was required.
254 // If render was not required, ignore resourcesFinished.
255 void RenderTask::UpdateState()
257 TASK_LOG_FMT(Debug::General, "FC:%d State:%s RR:%d\n", mFrameCounter, STATE_STRING(mState), mRefreshRate);
261 case RENDER_CONTINUOUSLY:
263 if(mRefreshRate != Dali::RenderTask::REFRESH_ALWAYS)
265 if(mFrameCounter == 0)
267 ++mFrameCounter; // Only start skipping frames when resources are loaded
269 else // Continue counting to skip frames
272 if(mFrameCounter >= mRefreshRate)
282 case RENDER_ONCE_WAITING_FOR_RESOURCES:
284 mState = RENDERED_ONCE;
290 mWaitingToRender = true;
291 mNotifyTrigger = false;
294 if(!mRenderSyncTracker || (mRenderSyncTracker && mRenderSyncTracker->IsSynced()))
296 mWaitingToRender = false;
297 mNotifyTrigger = true;
302 mWaitingToRender = false;
303 mNotifyTrigger = true;
313 TASK_LOG_FMT(Debug::General, " EXIT FC:%d State:%s Notify:%s\n", mFrameCounter, STATE_STRING(mState), mNotifyTrigger ? "T" : "F");
316 bool RenderTask::IsWaitingToRender()
318 TASK_LOG_FMT(Debug::Verbose, " State:%s waiting:%s \n", STATE_STRING(mState), mWaitingToRender ? "T" : "F");
319 return mWaitingToRender;
322 bool RenderTask::HasRendered()
325 if(mNotifyTrigger == true)
327 ++mRenderedOnceCounter;
328 mState = RENDERED_ONCE_AND_NOTIFIED;
329 mNotifyTrigger = false;
333 TASK_LOG_FMT(Debug::Verbose, " State:%s hasRendered:%s \n", STATE_STRING(mState), notify ? "T" : "F");
337 uint32_t RenderTask::GetRenderedOnceCounter() const
339 return mRenderedOnceCounter;
342 const Matrix& RenderTask::GetViewMatrix(BufferIndex bufferIndex) const
344 DALI_ASSERT_DEBUG(nullptr != mCameraNode);
346 return mCameraNode->GetViewMatrix(bufferIndex);
349 const SceneGraph::Camera& RenderTask::GetCamera() const
351 DALI_ASSERT_DEBUG(nullptr != mCameraNode);
355 const Matrix& RenderTask::GetProjectionMatrix(BufferIndex bufferIndex) const
357 DALI_ASSERT_DEBUG(nullptr != mCameraNode);
359 return mCameraNode->GetProjectionMatrix(bufferIndex);
362 RenderInstruction& RenderTask::PrepareRenderInstruction(BufferIndex updateBufferIndex)
364 DALI_ASSERT_DEBUG(nullptr != mCameraNode);
366 TASK_LOG(Debug::General);
369 bool viewportSet = QueryViewport(updateBufferIndex, viewport);
371 mRenderInstruction[updateBufferIndex].Reset(mCameraNode,
373 viewportSet ? &viewport : nullptr,
374 mClearEnabled ? &GetClearColor(updateBufferIndex) : nullptr);
377 mRefreshRate == Dali::RenderTask::REFRESH_ONCE)
379 // create tracker if one doesn't yet exist.
380 if(!mRenderSyncTracker)
382 mRenderSyncTracker = new Render::RenderTracker();
383 mRenderMessageDispatcher->AddRenderTracker(*mRenderSyncTracker);
385 mRenderInstruction[updateBufferIndex].mRenderTracker = mRenderSyncTracker;
389 // no sync needed, texture FBOs are "ready" the same frame they are rendered to
390 mRenderInstruction[updateBufferIndex].mRenderTracker = nullptr;
393 mRenderInstruction[updateBufferIndex].mRenderPassTag = mRenderPassTag;
394 return mRenderInstruction[updateBufferIndex];
397 bool RenderTask::ViewMatrixUpdated()
402 retval = mCameraNode->ViewMatrixUpdated();
407 void RenderTask::UpdateViewport(BufferIndex updateBufferIndex, Vector2 sceneSize, Vector3 cameraPosition)
409 if(GetViewportGuideNode() && GetViewportGuideNode()->ConnectedToScene())
411 Vector3 worldPosition = GetViewportGuideNode()->GetWorldPosition(updateBufferIndex);
412 worldPosition -= cameraPosition;
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);
420 /* This is an implicit constraint - the properties will be dirty until the node
421 * is removed. (RenderTask::Impl manages this)
423 mViewportPosition.Set(updateBufferIndex, screenPosition);
424 mViewportSize.Set(updateBufferIndex, Vector2(nodeSize));
428 const Vector2& RenderTask::GetViewportPosition(BufferIndex bufferIndex) const
430 return mViewportPosition[bufferIndex];
433 const Vector2& RenderTask::GetViewportSize(BufferIndex bufferIndex) const
435 return mViewportSize[bufferIndex];
438 bool RenderTask::GetViewportEnabled(BufferIndex bufferIndex) const
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)
451 void RenderTask::SetSyncRequired(bool requiresSync)
453 mRequiresSync = requiresSync;
456 void RenderTask::SetRenderPassTag(uint32_t renderPassTag)
458 mRenderPassTag = renderPassTag;
461 void RenderTask::PropertyOwnerConnected(PropertyOwner& owner)
463 // check if we've gone from inactive to active
467 void RenderTask::PropertyOwnerDisconnected(BufferIndex /*updateBufferIndex*/, PropertyOwner& owner)
469 mActive = false; // if either source or camera disconnected, we're no longer active
472 void RenderTask::PropertyOwnerDestroyed(PropertyOwner& owner)
474 if(static_cast<PropertyOwner*>(mSourceNode) == &owner)
476 mSourceNode = nullptr;
478 else if(static_cast<PropertyOwner*>(mCameraNode) == &owner)
480 mCameraNode = nullptr;
483 mActive = false; // if either source or camera destroyed, we're no longer active
486 void RenderTask::AddInitializeResetter(ResetterManager& manager) const
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);
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),
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),
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)
523 void RenderTask::SetActiveStatus()
525 bool oldActive = mActive;
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());
533 if(!oldActive && mActive)
535 // Send resetter only if newly activated
536 AddInitializeResetter(*mResetterManager);
540 } // namespace SceneGraph
542 } // namespace Internal