[dali_2.3.48] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / render-task-processor.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/manager/render-task-processor.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/internal/render/common/render-instruction-container.h>
24 #include <dali/internal/render/common/render-instruction.h>
25 #include <dali/internal/render/common/render-item.h>
26 #include <dali/internal/render/common/render-tracker.h>
27 #include <dali/internal/render/renderers/render-renderer.h>
28 #include <dali/internal/update/manager/sorted-layers.h>
29 #include <dali/internal/update/nodes/scene-graph-layer.h>
30 #include <dali/internal/update/render-tasks/scene-graph-render-task-list.h>
31 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
32
33 #if defined(DEBUG_ENABLED)
34 extern Debug::Filter* gRenderTaskLogFilter;
35 #endif
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace SceneGraph
42 {
43 namespace // Unnamed namespace
44 {
45 // Return false if the node or it's parents are exclusive to another render-task.
46 bool CheckExclusivity(const Node& node, const RenderTask& task)
47 {
48   if(node.IsExclusiveRenderTask(&task))
49   {
50     return true;
51   }
52
53   const Node* parent = node.GetParent();
54   if(parent)
55   {
56     return CheckExclusivity(*parent, task);
57   }
58
59   // No exclusive flags set.
60   return true;
61 }
62
63 Layer* FindLayer(Node& node)
64 {
65   Node*  currentNode(&node);
66   Layer* layer(nullptr);
67   while(currentNode)
68   {
69     if((layer = currentNode->GetLayer()) != nullptr)
70     {
71       return layer;
72     }
73
74     currentNode = currentNode->GetParent();
75   }
76
77   return nullptr;
78 }
79
80 /**
81  * Rebuild the Layer::colorRenderables and overlayRenderables members,
82  * including only renderers which are included in the current render-task.
83  *
84  * @param[in]  updateBufferIndex The current update buffer index.
85  * @param[in]  node The current node of the scene-graph.
86  * @param[in]  parentVisibilityChanged The parent node's visibility might be changed at current frame. (Due to visibility property, or ancient's clipping mode change)
87  * @param[in]  currentLayer The current layer containing lists of opaque/transparent renderables.
88  * @param[in]  renderTask The current render-task.
89  * @param[in]  inheritedDrawMode The draw mode of the parent
90  * @param[in]  parentDepthIndex The inherited parent node depth index
91  * @param[in]  currentClippingId The current Clipping Id
92  *               Note: ClippingId is passed by reference, so it is permanently modified when traversing back up the tree for uniqueness.
93  * @param[in]  clippingDepth The current stencil clipping depth
94  * @param[in]  clippingDepth The current scissor clipping depth
95  * @param[out] clippingUsed  Gets set to true if any clipping nodes have been found
96  * @param[out] keepRendering Gets set to true if rendering should be kept.
97  */
98 void AddRenderablesForTask(BufferIndex updateBufferIndex,
99                            Node&       node,
100                            bool        parentVisibilityChanged,
101                            Layer&      currentLayer,
102                            RenderTask& renderTask,
103                            int         inheritedDrawMode,
104                            uint32_t&   currentClippingId,
105                            uint32_t    clippingDepth,
106                            uint32_t    scissorDepth,
107                            bool&       clippingUsed,
108                            bool&       keepRendering)
109 {
110   // Short-circuit for invisible nodes
111   if(!node.IsVisible(updateBufferIndex))
112   {
113     node.GetPartialRenderingData().mVisible = false;
114     return;
115   }
116
117   // If the node was not previously visible
118   if(!node.GetPartialRenderingData().mVisible)
119   {
120     node.GetPartialRenderingData().mVisible = true;
121     parentVisibilityChanged                 = true;
122   }
123
124   // If the node's clipping mode is changed, we need to mark all descendent nodes as updated
125   if(node.IsClippingModeChanged())
126   {
127     parentVisibilityChanged = true;
128   }
129
130   if(parentVisibilityChanged)
131   {
132     node.SetUpdated(true);
133   }
134
135   // Check whether node is exclusive to a different render-task
136   if(node.GetExclusiveRenderTaskCount() && !node.IsExclusiveRenderTask(&renderTask))
137   {
138     return;
139   }
140
141   // Assume all children go to this layer (if this node is a layer).
142   Layer* layer = node.GetLayer();
143   if(layer)
144   {
145     // Layers do not inherit the DrawMode from their parents
146     inheritedDrawMode = node.GetDrawMode();
147   }
148   else
149   {
150     // This node is not a layer.
151     layer = &currentLayer;
152     inheritedDrawMode |= node.GetDrawMode();
153   }
154
155   DALI_ASSERT_DEBUG(NULL != layer);
156
157   const uint32_t count = node.GetRendererCount();
158
159   // Update the clipping Id and depth for this node (if clipping is enabled).
160   const Dali::ClippingMode::Type clippingMode = node.GetClippingMode();
161   if(DALI_UNLIKELY(clippingMode != ClippingMode::DISABLED))
162   {
163     if(DALI_LIKELY(clippingMode == ClippingMode::CLIP_TO_BOUNDING_BOX))
164     {
165       ++scissorDepth; // This only modifies the local value (which is passed in when the method recurses).
166       // If we do not have any renderers, create one to house the scissor operation.
167       if(count == 0u)
168       {
169         RenderableContainer& target = (inheritedDrawMode == DrawMode::NORMAL) ? layer->colorRenderables : layer->overlayRenderables;
170         target.PushBack(Renderable(&node, RendererKey{}));
171       }
172     }
173     else
174     {
175       // We only need clipping Id for stencil clips. This means we can deliberately avoid modifying it for bounding box clips,
176       // thus allowing bounding box clipping to still detect clip depth changes without turning on the stencil buffer for non-clipped nodes.
177       ++currentClippingId; // This modifies the reference passed in as well as the local value, causing the value to be global to the recursion.
178       ++clippingDepth;     // This only modifies the local value (which is passed in when the method recurses).
179     }
180     clippingUsed = true;
181   }
182   // Set the information in the node.
183   node.SetClippingInformation(currentClippingId, clippingDepth, scissorDepth);
184
185   RenderableContainer& target = DALI_LIKELY(inheritedDrawMode == DrawMode::NORMAL) ? layer->colorRenderables : layer->overlayRenderables;
186   for(uint32_t i = 0; i < count; ++i)
187   {
188     SceneGraph::RendererKey rendererKey = node.GetRendererAt(i);
189
190     target.PushBack(Renderable(&node, rendererKey));
191     keepRendering = keepRendering || (rendererKey->GetRenderingBehavior() == DevelRenderer::Rendering::CONTINUOUSLY);
192   }
193
194   if(DALI_UNLIKELY(node == renderTask.GetStopperNode() && count == 0u))
195   {
196     // Forcibly add renderables if stopper node don't have renderer.
197     target.PushBack(Renderable(&node, RendererKey{}));
198   }
199
200   // Recurse children.
201   NodeContainer& children = node.GetChildren();
202   const NodeIter endIter  = children.End();
203   for(NodeIter iter = children.Begin(); iter != endIter; ++iter)
204   {
205     Node& child = **iter;
206     AddRenderablesForTask(updateBufferIndex, child, parentVisibilityChanged, *layer, renderTask, inheritedDrawMode, currentClippingId, clippingDepth, scissorDepth, clippingUsed, keepRendering);
207   }
208 }
209
210 /**
211  * Process the list of render-tasks; the output is a series of render instructions.
212  * @note When ProcessRenderTasks is called, the layers should already the transparent/opaque renderers which are ready to render.
213  * If there is only one default render-task, then no further processing is required.
214  * @param[in]  updateBufferIndex          The current update buffer index.
215  * @param[in]  taskContainer              The container of render-tasks.
216  * @param[in]  sortedLayers               The layers containing lists of opaque / transparent renderables.
217  * @param[out] instructions               The instructions for rendering the next frame.
218  * @param[in]  renderInstructionProcessor An instance of the RenderInstructionProcessor used to sort and handle the renderers for each layer.
219  * @param[out] keepRendering              Gets set to true if rendering should be kept.
220  * @param[in]  renderToFboEnabled         Whether rendering into the Frame Buffer Object is enabled (used to measure FPS above 60)
221  * @param[in]  isRenderingToFbo           Whether this frame is being rendered into the Frame Buffer Object (used to measure FPS above 60)
222  * @param[in]  processOffscreen           Whether the offscreen render tasks are the ones processed. Otherwise it processes the onscreen tasks.
223  */
224 void ProcessTasks(BufferIndex                          updateBufferIndex,
225                   RenderTaskList::RenderTaskContainer& taskContainer,
226                   SortedLayerPointers&                 sortedLayers,
227                   RenderInstructionContainer&          instructions,
228                   RenderInstructionProcessor&          renderInstructionProcessor,
229                   bool&                                keepRendering,
230                   bool                                 renderToFboEnabled,
231                   bool                                 isRenderingToFbo,
232                   bool                                 processOffscreen)
233 {
234   uint32_t clippingId       = 0u;
235   bool     hasClippingNodes = false;
236
237   bool isFirstRenderTask = true;
238
239   // Retrieve size of Scene and default camera position to update viewport of each RenderTask if the RenderTask uses ViewportGuideNode.
240   RenderTaskList::RenderTaskContainer::Iterator iter                  = taskContainer.Begin();
241   RenderTask&                                   defaultRenderTask     = **iter;
242   const Camera&                                 defaultCamera         = defaultRenderTask.GetCamera();
243   auto                                          defaultRootNode       = defaultRenderTask.GetSourceNode();
244   Vector3                                       defaultCameraPosition = Vector3::ZERO;
245   Vector2                                       sceneSize             = Vector2::ZERO;
246   if(defaultRootNode)
247   {
248     defaultCameraPosition = defaultCamera.GetWorldPosition(updateBufferIndex);
249     sceneSize             = Vector2(defaultRootNode->GetSize(updateBufferIndex) * defaultRootNode->GetWorldScale(updateBufferIndex));
250   }
251
252   for(RenderTaskList::RenderTaskContainer::Iterator iter = taskContainer.Begin(), endIter = taskContainer.End(); endIter != iter; ++iter)
253   {
254     RenderTask& renderTask = **iter;
255
256     const bool hasFrameBuffer      = nullptr != renderTask.GetFrameBuffer();
257     const bool isDefaultRenderTask = isFirstRenderTask;
258     isFirstRenderTask              = false;
259
260     if((!renderToFboEnabled && ((!processOffscreen && hasFrameBuffer) ||
261                                 (processOffscreen && !hasFrameBuffer))) ||
262        (renderToFboEnabled && ((processOffscreen && !hasFrameBuffer) ||
263                                (isDefaultRenderTask && processOffscreen) ||
264                                (!isDefaultRenderTask && !processOffscreen && hasFrameBuffer))) ||
265        !renderTask.ReadyToRender(updateBufferIndex))
266     {
267       // Skip to next task.
268       continue;
269     }
270
271     Node* sourceNode = renderTask.GetSourceNode();
272     DALI_ASSERT_DEBUG(NULL != sourceNode); // Otherwise Prepare() should return false
273
274     // Check that the source node is not exclusive to another task.
275     if(!CheckExclusivity(*sourceNode, renderTask))
276     {
277       continue;
278     }
279
280     Layer* layer = FindLayer(*sourceNode);
281     if(!layer)
282     {
283       // Skip to next task as no layer.
284       continue;
285     }
286
287     renderTask.UpdateViewport(updateBufferIndex, sceneSize, defaultCameraPosition);
288
289     const uint32_t currentNumberOfInstructions = instructions.Count(updateBufferIndex);
290
291     if(renderTask.IsRenderRequired())
292     {
293       for(auto&& sortedLayer : sortedLayers)
294       {
295         sortedLayer->ClearRenderables();
296       }
297
298       AddRenderablesForTask(updateBufferIndex,
299                             *sourceNode,
300                             false,
301                             *layer,
302                             renderTask,
303                             sourceNode->GetDrawMode(),
304                             clippingId,
305                             0u,
306                             0u,
307                             hasClippingNodes,
308                             keepRendering);
309
310       renderInstructionProcessor.Prepare(updateBufferIndex,
311                                          sortedLayers,
312                                          renderTask,
313                                          renderTask.GetCullMode(),
314                                          hasClippingNodes,
315                                          instructions);
316     }
317
318     if(!processOffscreen && isDefaultRenderTask && renderToFboEnabled && !isRenderingToFbo && hasFrameBuffer)
319     {
320       // Traverse the instructions of the default render task and mark them to be rendered into the frame buffer.
321       const uint32_t count = instructions.Count(updateBufferIndex);
322       for(uint32_t index = currentNumberOfInstructions; index < count; ++index)
323       {
324         RenderInstruction& instruction = instructions.At(updateBufferIndex, index);
325         instruction.mIgnoreRenderToFbo = true;
326       }
327     }
328   }
329 }
330
331 } // Anonymous namespace.
332
333 RenderTaskProcessor::RenderTaskProcessor() = default;
334
335 RenderTaskProcessor::~RenderTaskProcessor() = default;
336
337 bool RenderTaskProcessor::Process(BufferIndex                 updateBufferIndex,
338                                   RenderTaskList&             renderTasks,
339                                   SortedLayerPointers&        sortedLayers,
340                                   RenderInstructionContainer& instructions,
341                                   bool                        renderToFboEnabled,
342                                   bool                        isRenderingToFbo)
343 {
344   RenderTaskList::RenderTaskContainer& taskContainer = renderTasks.GetTasks();
345   bool                                 keepRendering = false;
346
347   if(taskContainer.IsEmpty())
348   {
349     // Early-exit if there are no tasks to process
350     return keepRendering;
351   }
352
353   // For each render-task:
354   //   1) Prepare the render-task
355   //   2) Clear the layer-stored lists of renderers (TODO check if the layer is not changed and don't clear in this case)
356   //   3) Traverse the scene-graph, filling the lists for the current render-task
357   //   4) Prepare render-instructions
358
359   DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Offscreens first\n");
360
361   // First process off screen render tasks - we may need the results of these for the on screen renders
362
363   ProcessTasks(updateBufferIndex,
364                taskContainer,
365                sortedLayers,
366                instructions,
367                mRenderInstructionProcessor,
368                keepRendering,
369                renderToFboEnabled,
370                isRenderingToFbo,
371                true);
372
373   DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Onscreen\n");
374
375   // Now that the off screen renders are done we can process on screen render tasks.
376   // Reset the clipping Id for the OnScreen render tasks.
377
378   ProcessTasks(updateBufferIndex,
379                taskContainer,
380                sortedLayers,
381                instructions,
382                mRenderInstructionProcessor,
383                keepRendering,
384                renderToFboEnabled,
385                isRenderingToFbo,
386                false);
387
388   return keepRendering;
389 }
390
391 } // namespace SceneGraph
392
393 } // namespace Internal
394
395 } // namespace Dali