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