Merge "fix property buffer gl initialization" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / prepare-render-instructions.cpp
1 /*
2  * Copyright (c) 2015 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/prepare-render-instructions.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/shader-effects/shader-effect.h>
23 #include <dali/public-api/actors/layer.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/internal/event/actors/layer-impl.h> // for the default sorting function
26 #include <dali/internal/update/node-attachments/scene-graph-renderable-attachment.h>
27 #include <dali/internal/update/nodes/scene-graph-layer.h>
28 #include <dali/internal/update/manager/sorted-layers.h>
29 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
30 #include <dali/internal/update/rendering/scene-graph-material.h>
31 #include <dali/internal/update/rendering/scene-graph-geometry.h>
32 #include <dali/internal/update/resources/resource-manager-declarations.h>
33 #include <dali/internal/render/common/render-item.h>
34 #include <dali/internal/render/common/render-tracker.h>
35 #include <dali/internal/render/common/render-instruction.h>
36 #include <dali/internal/render/common/render-instruction-container.h>
37 #include <dali/internal/render/shaders/scene-graph-shader.h>
38 #include <dali/internal/render/renderers/render-renderer.h>
39
40 namespace
41 {
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gRenderListLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_LISTS");
44 #endif
45 }
46
47 namespace Dali
48 {
49
50 namespace Internal
51 {
52
53 namespace SceneGraph
54 {
55
56 /**
57  * Add a renderer to the list
58  * @param updateBufferIndex to read the model matrix from
59  * @param renderList to add the item to
60  * @param renderable attachment
61  * @param viewMatrix used to calculate modelview matrix for the item
62  * @param cameraAttachment The camera used to render
63  * @param isLayer3d Whether we are processing a 3D layer or not
64  */
65 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
66                                      RenderList& renderList,
67                                      RenderableAttachment& renderable,
68                                      const Matrix& viewMatrix,
69                                      SceneGraph::CameraAttachment& cameraAttachment,
70                                      bool isLayer3d )
71 {
72   const Node& parentNode = renderable.GetParent();
73   const Matrix& worldMatrix = parentNode.GetWorldMatrix( updateBufferIndex );
74
75   // Get the next free RenderItem and initialization
76   RenderItem& item = renderList.GetNextFreeItem();
77   const Render::Renderer& renderer = renderable.GetRenderer();
78   item.SetRenderer( const_cast< Render::Renderer* >( &renderer ) );
79   item.SetNode( const_cast< Node* >( &parentNode ) );
80
81   item.SetIsOpaque( renderable.IsFullyOpaque(updateBufferIndex) );
82   if( isLayer3d )
83   {
84     item.SetDepthIndex( renderable.GetDepthIndex() );
85   }
86   else
87   {
88     item.SetDepthIndex( renderable.GetDepthIndex() + static_cast<int>( parentNode.GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER );
89   }
90
91   // save MV matrix onto the item
92   Matrix::Multiply( item.GetModelViewMatrix(), worldMatrix, viewMatrix );
93 }
94
95 /**
96  * Add a renderer to the list
97  * @param updateBufferIndex to read the model matrix from
98  * @param renderList to add the item to
99  * @param NodeRenderer NodeRenderer pair
100  * @param viewMatrix used to calculate modelview matrix for the item
101  * @param cameraAttachment The camera used to render
102  * @param isLayer3d Whether we are processing a 3D layer or not
103  */
104 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
105                                      RenderList& renderList,
106                                      NodeRenderer& renderable,
107                                      const Matrix& viewMatrix,
108                                      SceneGraph::CameraAttachment& cameraAttachment,
109                                      bool isLayer3d )
110 {
111   // Check for cull against view frustum
112   const Matrix& worldMatrix = renderable.mNode->GetWorldMatrix( updateBufferIndex );
113   bool inside = true;
114
115   if ( renderable.mRenderer->GetMaterial().GetShader()->GeometryHintEnabled( Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY ) )
116   {
117     const Vector3& position = worldMatrix.GetTranslation3();
118     const Vector3& scale = renderable.mNode->GetScale( updateBufferIndex );
119     const Vector3& halfSize = renderable.mNode->GetSize( updateBufferIndex ) * scale * 0.5f;
120
121     // Do a fast sphere check
122     if ( cameraAttachment.CheckSphereInFrustum( updateBufferIndex, position, halfSize.Length() ) )
123     {
124       // Check geometry AABB
125       //TODO: Take into account orientation
126       if ( !cameraAttachment.CheckAABBInFrustum( updateBufferIndex, position, halfSize ) )
127       {
128         inside = false;
129       }
130     }
131     else
132     {
133       inside = false;
134     }
135   }
136
137   if ( inside )
138   {
139     // Get the next free RenderItem
140     RenderItem& item = renderList.GetNextFreeItem();
141     item.SetRenderer( &renderable.mRenderer->GetRenderer() );
142     item.SetNode( renderable.mNode );
143     item.SetIsOpaque( renderable.mRenderer->IsFullyOpaque(updateBufferIndex, *renderable.mNode ) );
144
145     if( isLayer3d )
146     {
147       item.SetDepthIndex( renderable.mRenderer->GetDepthIndex() );
148     }
149     else
150     {
151       item.SetDepthIndex( renderable.mRenderer->GetDepthIndex() + static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER );
152     }
153
154     // save MV matrix onto the item
155     Matrix::Multiply( item.GetModelViewMatrix(), worldMatrix, viewMatrix );
156   }
157 }
158
159 /**
160  * Add all renderers to the list
161  * @param updateBufferIndex to read the model matrix from
162  * @param renderList to add the items to
163  * @param renderable attachments
164  * NodeRendererContainer Node-Renderer pairs
165  * @param viewMatrix used to calculate modelview matrix for the items
166  * @param cameraAttachment The camera used to render
167  * @param isLayer3d Whether we are processing a 3D layer or not
168  */
169 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
170                                       RenderList& renderList,
171                                       RenderableAttachmentContainer& attachments,
172                                       NodeRendererContainer& renderers,
173                                       const Matrix& viewMatrix,
174                                       SceneGraph::CameraAttachment& cameraAttachment,
175                                       bool isLayer3d )
176 {
177   DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
178
179   // Add renderer for each attachment
180   unsigned int index(0);
181   const RenderableAttachmentIter endIter = attachments.end();
182   for ( RenderableAttachmentIter iter = attachments.begin(); iter != endIter; ++iter )
183   {
184     RenderableAttachment& attachment = **iter;
185     AddRendererToRenderList( updateBufferIndex, renderList, attachment, viewMatrix, cameraAttachment, isLayer3d );
186
187     DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "  List[%d].renderer = %p\n", index, &(attachment.GetRenderer()));
188     ++index;
189   }
190
191   unsigned int rendererCount( renderers.Size() );
192   for( unsigned int i(0); i<rendererCount; ++i )
193   {
194     AddRendererToRenderList( updateBufferIndex, renderList, renderers[i], viewMatrix, cameraAttachment, isLayer3d );
195   }
196 }
197
198 /**
199  * Try to reuse cached renderitems from the renderlist
200  * This avoids recalculating the model view matrices in case this part of the scene was static
201  * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
202  * @param layer that is being processed
203  * @param renderList that is cached from frame N-1
204  * @param attachmentList that is being used
205  */
206 inline bool TryReuseCachedRenderers( Layer& layer,
207                                      RenderList& renderList,
208                                      RenderableAttachmentContainer& attachmentList )
209 {
210   bool retValue = false;
211   size_t renderableCount = attachmentList.size();
212   // check that the cached list originates from this layer and that the counts match
213   if( ( renderList.GetSourceLayer() == &layer )&&
214       ( renderList.GetCachedItemCount() == renderableCount ) )
215   {
216     // check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong attachments
217     // Attachments are not sorted, but render list is so at this stage renderers may be in different order
218     // therefore we check a combined sum of all renderer addresses
219     size_t checkSumNew = 0;
220     size_t checkSumOld = 0;
221     for( size_t index = 0; index < renderableCount; ++index )
222     {
223       RenderableAttachment* attachment = attachmentList[ index ];
224       const Render::Renderer& renderer = attachment->GetRenderer();
225       checkSumNew += size_t( &renderer );
226       checkSumOld += size_t( &renderList.GetRenderer( index ) );
227     }
228     if( checkSumNew == checkSumOld )
229     {
230       // tell list to reuse its existing items
231       renderList.ReuseCachedItems();
232       retValue = true;
233     }
234   }
235   return retValue;
236 }
237
238
239 /**
240  * Function which sorts render items by depth index then by instance
241  * ptrs of shader/geometry/material.
242  * @param lhs item
243  * @param rhs item
244  * @return true if left item is greater than right
245  */
246 bool CompareItems( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
247 {
248   // @todo MESH_REWORK Consider replacing all these sortAttributes with a single long int that
249   // encapsulates the same data (e.g. the middle-order bits of the ptrs)
250   if( lhs.renderItem->GetDepthIndex() == rhs.renderItem->GetDepthIndex() )
251   {
252     if( lhs.shader == rhs.shader )
253     {
254       if( lhs.textureResourceId == rhs.textureResourceId )
255       {
256         return lhs.geometry < rhs.geometry;
257       }
258       return lhs.textureResourceId < rhs.textureResourceId;
259     }
260     return lhs.shader < rhs.shader;
261   }
262   return lhs.renderItem->GetDepthIndex() < rhs.renderItem->GetDepthIndex();
263 }
264 /**
265  * Function which sorts the render items by Z function, then
266  * by instance ptrs of shader/geometry/material.
267  * @param lhs item
268  * @param rhs item
269  * @return true if left item is greater than right
270  */
271 bool CompareItems3D( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
272 {
273   bool lhsIsOpaque = lhs.renderItem->IsOpaque();
274   if( lhsIsOpaque ==  rhs.renderItem->IsOpaque())
275   {
276     if( lhsIsOpaque )
277     {
278       //If both RenderItems are opaque, sort using shader, then material then geometry
279       if( lhs.shader == rhs.shader )
280       {
281         if( lhs.textureResourceId == rhs.textureResourceId )
282         {
283           return lhs.geometry < rhs.geometry;
284         }
285         return lhs.textureResourceId < rhs.textureResourceId;
286       }
287       return lhs.shader < rhs.shader;
288     }
289     else
290     {
291       //If both RenderItems are transparent, sort using z,then shader, then material, then geometry
292       if( Equals(lhs.zValue, rhs.zValue) )
293       {
294         if( lhs.shader == rhs.shader )
295         {
296           if( lhs.textureResourceId == rhs.textureResourceId )
297           {
298             return lhs.geometry < rhs.geometry;
299           }
300           return lhs.textureResourceId < rhs.textureResourceId;
301         }
302         return lhs.shader < rhs.shader;
303       }
304       return lhs.zValue > rhs.zValue;
305     }
306   }
307   else
308   {
309     return lhsIsOpaque;
310   }
311 }
312
313 /**
314  * Sort color render items
315  * @param colorRenderList to sort
316  * @param layer where the renderers are from
317  * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
318  */
319 inline void SortColorRenderItems( BufferIndex bufferIndex, RenderList& renderList, Layer& layer, RendererSortingHelper& sortingHelper )
320 {
321   const size_t renderableCount = renderList.Count();
322   // reserve space if needed
323   const unsigned int oldcapacity = sortingHelper.size();
324   if( oldcapacity < renderableCount )
325   {
326     sortingHelper.reserve( renderableCount );
327     // add real objects (reserve does not construct objects)
328     sortingHelper.insert( sortingHelper.begin() + oldcapacity,
329                           (renderableCount - oldcapacity),
330                           RendererWithSortAttributes() );
331   }
332   else
333   {
334     // clear extra elements from helper, does not decrease capability
335     sortingHelper.resize( renderableCount );
336   }
337
338   // calculate the sorting value, once per item by calling the layers sort function
339   // Using an if and two for-loops rather than if inside for as its better for branch prediction
340   if( layer.UsesDefaultSortFunction() )
341   {
342     for( size_t index = 0; index < renderableCount; ++index )
343     {
344       RenderItem& item = renderList.GetItem( index );
345
346       item.GetRenderer().SetSortAttributes( bufferIndex, sortingHelper[ index ] );
347
348       // the default sorting function should get inlined here
349       sortingHelper[ index ].zValue = Internal::Layer::ZValue( item.GetModelViewMatrix().GetTranslation3() ) - item.GetDepthIndex();
350
351       // keep the renderitem pointer in the helper so we can quickly reorder items after sort
352       sortingHelper[ index ].renderItem = &item;
353     }
354   }
355   else
356   {
357     const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
358     for( size_t index = 0; index < renderableCount; ++index )
359     {
360       RenderItem& item = renderList.GetItem( index );
361
362       item.GetRenderer().SetSortAttributes( bufferIndex, sortingHelper[ index ] );
363       sortingHelper[ index ].zValue = (*sortFunction)( item.GetModelViewMatrix().GetTranslation3() ) - item.GetDepthIndex();
364
365       // keep the renderitem pointer in the helper so we can quickly reorder items after sort
366       sortingHelper[ index ].renderItem = &item;
367     }
368   }
369
370   if( layer.GetBehavior() ==  Dali::Layer::LAYER_3D)
371   {
372     // sort the renderers back to front, Z Axis point from near plane to far plane
373     std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems3D );
374   }
375   else
376   {
377     // sort the renderers based on DepthIndex
378     std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems );
379   }
380
381   // reorder/repopulate the renderitems in renderlist to correct order based on sortinghelper
382   DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Transparent List:\n");
383   RenderItemContainer::Iterator renderListIter = renderList.GetContainer().Begin();
384   for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter )
385   {
386     *renderListIter = sortingHelper[ index ].renderItem;
387     DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "  sortedList[%d] = %p\n", index, &sortingHelper[ index ].renderItem->GetRenderer() );
388   }
389 }
390
391 /**
392  * Add color renderers from the layer onto the next free render list
393  * @param updateBufferIndex to use
394  * @param layer to get the renderers from
395  * @param viewmatrix for the camera from rendertask
396  * @param cameraAttachment to use the view frustum
397  * @param stencilRenderablesExist is true if there are stencil renderers on this layer
398  * @param instruction to fill in
399  * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
400  * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
401  */
402 inline void AddColorRenderers( BufferIndex updateBufferIndex,
403                                Layer& layer,
404                                const Matrix& viewMatrix,
405                                SceneGraph::CameraAttachment& cameraAttachment,
406                                bool stencilRenderablesExist,
407                                RenderInstruction& instruction,
408                                RendererSortingHelper& sortingHelper,
409                                bool tryReuseRenderList )
410 {
411   RenderList& renderList = instruction.GetNextFreeRenderList( layer.colorRenderables.size() );
412   renderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
413   renderList.SetHasColorRenderItems( true );
414
415   // try to reuse cached renderitems from last time around
416   if( tryReuseRenderList )
417   {
418     if( TryReuseCachedRenderers( layer, renderList, layer.colorRenderables ) )
419     {
420       return;
421     }
422   }
423
424   AddRenderersToRenderList( updateBufferIndex, renderList, layer.colorRenderables, layer.colorRenderers, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D );
425   SortColorRenderItems( updateBufferIndex, renderList, layer, sortingHelper );
426
427   //Set render flags
428   unsigned int flags = 0u;
429   if( stencilRenderablesExist )
430   {
431     flags = RenderList::STENCIL_BUFFER_ENABLED;
432   }
433
434   // Special optimization if depth test is disabled or if only one opaque rendered in the layer (for example background image)
435   // and this renderer does not need depth test against itself (e.g. mesh)
436   // and if this layer has got exactly one opaque renderer
437   // and this renderer is not interested in depth testing
438   // (i.e. is an image and not a mesh)
439
440   if ( ( renderList.Count() == 1 ) &&
441        ( !renderList.GetRenderer( 0 ).RequiresDepthTest() ) &&
442        ( !renderList.GetItem(0).IsOpaque() ) )
443   {
444     //Nothing to do here
445   }
446   else if( !layer.IsDepthTestDisabled())
447   {
448     flags |= RenderList::DEPTH_BUFFER_ENABLED;
449     flags |= RenderList::DEPTH_CLEAR;
450   }
451
452   renderList.ClearFlags();
453   renderList.SetFlags( flags );
454 }
455
456 /**
457  * Add overlay renderers from the layer onto the next free render list
458  * @param updateBufferIndex to use
459  * @param layer to get the renderers from
460  * @param viewmatrix for the camera from rendertask
461  * @param stencilRenderablesExist is true if there are stencil renderers on this layer
462  * @param instruction to fill in
463  * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
464  */
465 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
466                                  Layer& layer,
467                                  const Matrix& viewMatrix,
468                                  SceneGraph::CameraAttachment& cameraAttachment,
469                                  bool stencilRenderablesExist,
470                                  RenderInstruction& instruction,
471                                  bool tryReuseRenderList )
472 {
473   RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.size() );
474   overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
475   overlayRenderList.SetHasColorRenderItems( false );
476
477   //Set render flags
478   overlayRenderList.ClearFlags();
479   if(stencilRenderablesExist)
480   {
481     overlayRenderList.SetFlags(RenderList::STENCIL_BUFFER_ENABLED);
482   }
483
484   // try to reuse cached renderitems from last time around
485   if( tryReuseRenderList )
486   {
487     if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
488     {
489       return;
490     }
491   }
492   AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, layer.overlayRenderers, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D );
493 }
494
495 /**
496  * Add stencil renderers from the layer onto the next free render list
497  * @param updateBufferIndex to use
498  * @param layer to get the renderers from
499  * @param viewmatrix for the camera from rendertask
500  * @param instruction to fill in
501  * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
502  */
503 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
504                                  Layer& layer,
505                                  const Matrix& viewMatrix,
506                                  SceneGraph::CameraAttachment& cameraAttachment,
507                                  RenderInstruction& instruction,
508                                  bool tryReuseRenderList )
509 {
510   RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.size() );
511   stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
512   stencilRenderList.SetHasColorRenderItems( false );
513
514   //Set render flags
515   stencilRenderList.ClearFlags();
516   stencilRenderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_BUFFER_ENABLED );
517
518   // try to reuse cached renderitems from last time around
519   if( tryReuseRenderList )
520   {
521     if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
522     {
523       return;
524     }
525   }
526   AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, layer.stencilRenderers, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D );
527 }
528
529 /**
530  * Prepare a single render instruction
531  * @param updateBufferIndex to use
532  * @param sortedLayers to prepare the instruction from
533  * @param renderTask to get the view matrix
534  * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
535  * @param renderTracker An optional render tracker object
536  * @param instructions container
537  */
538 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
539                                SortedLayerPointers& sortedLayers,
540                                RenderTask& renderTask,
541                                RendererSortingHelper& sortingHelper,
542                                RenderTracker* renderTracker,
543                                RenderInstructionContainer& instructions )
544 {
545   // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
546   // then populate with instructions.
547   RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
548   renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
549   bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
550
551   const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
552   SceneGraph::CameraAttachment& cameraAttachment = renderTask.GetCameraAttachment();
553
554   const SortedLayersIter endIter = sortedLayers.end();
555   for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
556   {
557     Layer& layer = **iter;
558
559     const bool stencilRenderablesExist( !layer.stencilRenderables.empty() || !layer.stencilRenderers.Empty() );
560     const bool colorRenderablesExist( !layer.colorRenderables.empty() || !layer.colorRenderers.Empty() );
561     const bool overlayRenderablesExist( !layer.overlayRenderables.empty() || !layer.overlayRenderers.Empty() );
562     const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers(renderTask.GetCamera()) );
563
564     // Ignore stencils if there's nothing to test
565     if( stencilRenderablesExist &&
566         ( colorRenderablesExist || overlayRenderablesExist ) )
567     {
568       AddStencilRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, instruction, tryReuseRenderList );
569     }
570
571     if ( colorRenderablesExist )
572     {
573       AddColorRenderers( updateBufferIndex,
574                          layer,
575                          viewMatrix,
576                          cameraAttachment,
577                          stencilRenderablesExist,
578                          instruction,
579                          sortingHelper,
580                          tryReuseRenderList );
581     }
582
583     if ( overlayRenderablesExist )
584     {
585       AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, stencilRenderablesExist,
586                            instruction, tryReuseRenderList );
587     }
588   }
589
590   instruction.mRenderTracker = renderTracker;
591   instruction.mCullMode = renderTask.GetCullMode();
592
593   // inform the render instruction that all renderers have been added and this frame is complete
594   instruction.UpdateCompleted();
595 }
596
597 } // SceneGraph
598
599 } // Internal
600
601 } // Dali