Render to Frame Buffer Object.
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / render-task-processor.cpp
1 /*
2  * Copyright (c) 2017 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 unsigned int 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( unsigned int 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 unsigned int currentNumberOfInstructions = instructions.Count( updateBufferIndex );
256
257     if( renderTask.IsRenderRequired() )
258     {
259       for( size_t i = 0u, layerCount = sortedLayers.size(); i < layerCount; ++i )
260       {
261         sortedLayers[i]->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       for( unsigned int index = currentNumberOfInstructions, count = instructions.Count( updateBufferIndex ); index < count; ++index )
286       {
287         RenderInstruction& instruction = instructions.At( updateBufferIndex, index );
288         instruction.mIgnoreRenderToFbo = true;
289       }
290     }
291   }
292 }
293
294 } // Anonymous namespace.
295
296 RenderTaskProcessor::RenderTaskProcessor()
297 {
298 }
299
300 RenderTaskProcessor::~RenderTaskProcessor()
301 {
302 }
303
304 void RenderTaskProcessor::Process( BufferIndex updateBufferIndex,
305                                    RenderTaskList& renderTasks,
306                                    Layer& rootNode,
307                                    SortedLayerPointers& sortedLayers,
308                                    RenderInstructionContainer& instructions,
309                                    bool renderToFboEnabled,
310                                    bool isRenderingToFbo )
311 {
312   RenderTaskList::RenderTaskContainer& taskContainer = renderTasks.GetTasks();
313
314   if( taskContainer.IsEmpty() )
315   {
316     // Early-exit if there are no tasks to process
317     return;
318   }
319
320   // For each render-task:
321   //   1) Prepare the render-task
322   //   2) Clear the layer-stored lists of renderers (TODO check if the layer is not changed and don't clear in this case)
323   //   3) Traverse the scene-graph, filling the lists for the current render-task
324   //   4) Prepare render-instructions
325
326   DALI_LOG_INFO( gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Offscreens first\n" );
327
328   // First process off screen render tasks - we may need the results of these for the on screen renders
329
330   ProcessTasks( updateBufferIndex,
331                 taskContainer,
332                 rootNode,
333                 sortedLayers,
334                 instructions,
335                 mRenderInstructionProcessor,
336                 renderToFboEnabled,
337                 isRenderingToFbo,
338                 true );
339
340   DALI_LOG_INFO( gRenderTaskLogFilter, Debug::General, "RenderTaskProcessor::Process() Onscreen\n" );
341
342   // Now that the off screen renders are done we can process on screen render tasks.
343   // Reset the clipping Id for the OnScreen render tasks.
344
345   ProcessTasks( updateBufferIndex,
346                 taskContainer,
347                 rootNode,
348                 sortedLayers,
349                 instructions,
350                 mRenderInstructionProcessor,
351                 renderToFboEnabled,
352                 isRenderingToFbo,
353                 false );
354 }
355
356 } // SceneGraph
357
358 } // Internal
359
360 } // Dali