350d66e910df204b2a6a2e93a4536be2088069ca
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / prepare-render-instructions.cpp
1 /*
2  * Copyright (c) 2016 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/nodes/scene-graph-layer.h>
27 #include <dali/internal/update/manager/sorted-layers.h>
28 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
29 #include <dali/internal/update/rendering/scene-graph-texture-set.h>
30 #include <dali/internal/update/resources/resource-manager-declarations.h>
31 #include <dali/internal/render/common/render-item.h>
32 #include <dali/internal/render/common/render-tracker.h>
33 #include <dali/internal/render/common/render-instruction.h>
34 #include <dali/internal/render/common/render-instruction-container.h>
35 #include <dali/internal/render/shaders/scene-graph-shader.h>
36 #include <dali/internal/render/renderers/render-renderer.h>
37 #include <dali/internal/render/renderers/render-property-buffer.h>
38 #include <dali/internal/update/manager/geometry-batcher.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 Node-Renderer pair
61  * @param viewMatrix used to calculate modelview matrix for the item
62  * @param camera The camera used to render
63  * @param geometryBatcher The instance of the geometry batcher
64  * @param isLayer3d Whether we are processing a 3D layer or not
65  * @param cull Whether frustum culling is enabled or not
66  */
67 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
68                                      RenderList& renderList,
69                                      Renderable& renderable,
70                                      const Matrix& viewMatrix,
71                                      SceneGraph::Camera& camera,
72                                      GeometryBatcher& geometryBatcher,
73                                      bool isLayer3d,
74                                      bool cull )
75 {
76   // discard renderable early if it belongs to the batch which has been consumed in during frame
77   Node* renderableNode = renderable.mNode;
78   const bool batchingValid( renderable.mRenderer->IsBatchingEnabled() && renderableNode->mBatchIndex != BATCH_NULL_HANDLE );
79   if( batchingValid && geometryBatcher.HasRendered( renderableNode->mBatchIndex ) )
80   {
81     return;
82   }
83
84   bool inside( true );
85   const Node* batchParentNode = renderable.mNode->GetBatchParent();
86   const Node* node = ( renderable.mRenderer->IsBatchingEnabled() && batchParentNode ) ?
87         batchParentNode : renderableNode;
88
89   if ( cull && !renderable.mRenderer->GetShader().HintEnabled( Dali::Shader::Hint::MODIFIES_GEOMETRY ) )
90   {
91     const Vector4& boundingSphere = node->GetBoundingSphere();
92     inside = (boundingSphere.w > Math::MACHINE_EPSILON_1000) &&
93              (camera.CheckSphereInFrustum( updateBufferIndex, Vector3(boundingSphere), boundingSphere.w ) );
94   }
95
96   if( inside )
97   {
98     if( batchingValid )
99     {
100       geometryBatcher.SetRendered( renderableNode->mBatchIndex );
101     }
102
103     Renderer::Opacity opacity = renderable.mRenderer->GetOpacity( updateBufferIndex, *renderable.mNode );
104     if( opacity != Renderer::TRANSPARENT )
105     {
106       // Get the next free RenderItem
107       RenderItem& item = renderList.GetNextFreeItem();
108       item.mRenderer = &renderable.mRenderer->GetRenderer();
109       item.mNode = renderable.mNode;
110       item.mIsOpaque = (opacity == Renderer::OPAQUE);
111
112       if( isLayer3d )
113       {
114         item.mDepthIndex = renderable.mRenderer->GetDepthIndex();
115       }
116       else
117       {
118         item.mDepthIndex = renderable.mRenderer->GetDepthIndex() + static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER;
119       }
120       // save MV matrix onto the item
121       node->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize );
122       Matrix::Multiply( item.mModelViewMatrix, item.mModelMatrix, viewMatrix );
123     }
124   }
125 }
126
127 /**
128  * Add all renderers to the list
129  * @param updateBufferIndex to read the model matrix from
130  * @param renderList to add the items to
131  * @param renderers to render
132  * NodeRendererContainer Node-Renderer pairs
133  * @param viewMatrix used to calculate modelview matrix for the items
134  * @param camera The camera used to render
135  * @param geometryBatcher The instance of the geometry batcher
136  * @param isLayer3d Whether we are processing a 3D layer or not
137  * @param cull Whether frustum culling is enabled or not
138  */
139 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
140                                       RenderList& renderList,
141                                       RenderableContainer& renderers,
142                                       const Matrix& viewMatrix,
143                                       SceneGraph::Camera& camera,
144                                       GeometryBatcher* geometryBatcher,
145                                       bool isLayer3d,
146                                       bool cull)
147 {
148   DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
149
150   unsigned int rendererCount( renderers.Size() );
151   for( unsigned int i(0); i<rendererCount; ++i )
152   {
153     AddRendererToRenderList( updateBufferIndex, renderList, renderers[i], viewMatrix, camera, *geometryBatcher, isLayer3d, cull );
154   }
155 }
156
157 /**
158  * Try to reuse cached renderitems from the renderlist
159  * This avoids recalculating the model view matrices in case this part of the scene was static
160  * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
161  * @param layer that is being processed
162  * @param renderList that is cached from frame N-1
163  * @param renderables list of renderables
164  */
165 inline bool TryReuseCachedRenderers( Layer& layer,
166                                      RenderList& renderList,
167                                      RenderableContainer& renderables )
168 {
169   bool retValue = false;
170   size_t renderableCount = renderables.Size();
171   // check that the cached list originates from this layer and that the counts match
172   if( ( renderList.GetSourceLayer() == &layer )&&
173       ( renderList.GetCachedItemCount() == renderableCount ) )
174   {
175     // check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong things
176     // Render list is sorted so at this stage renderers may be in different order
177     // therefore we check a combined sum of all renderer addresses
178     size_t checkSumNew = 0;
179     size_t checkSumOld = 0;
180     for( size_t index = 0; index < renderableCount; ++index )
181     {
182       const Render::Renderer& renderer = renderables[index].mRenderer->GetRenderer();
183       checkSumNew += size_t( &renderer );
184       checkSumOld += size_t( &renderList.GetRenderer( index ) );
185     }
186     if( checkSumNew == checkSumOld )
187     {
188       // tell list to reuse its existing items
189       renderList.ReuseCachedItems();
190       retValue = true;
191     }
192   }
193   return retValue;
194 }
195
196 /**
197  * Function which sorts render items by depth index then by instance
198  * ptrs of shader/texture/geometry.
199  * @param lhs item
200  * @param rhs item
201  * @return true if left item is greater than right
202  */
203 bool CompareItems( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
204 {
205   if( lhs.renderItem->mDepthIndex == rhs.renderItem->mDepthIndex )
206   {
207     if( lhs.shader == rhs.shader )
208     {
209       if( lhs.textureResourceId == rhs.textureResourceId )
210       {
211         return lhs.geometry < rhs.geometry;
212       }
213       return lhs.textureResourceId < rhs.textureResourceId;
214     }
215     return lhs.shader < rhs.shader;
216   }
217   return lhs.renderItem->mDepthIndex < rhs.renderItem->mDepthIndex;
218 }
219 /**
220  * Function which sorts the render items by Z function, then
221  * by instance ptrs of shader/texture/geometry.
222  * @param lhs item
223  * @param rhs item
224  * @return true if left item is greater than right
225  */
226 bool CompareItems3D( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
227 {
228   bool lhsIsOpaque = lhs.renderItem->mIsOpaque;
229   if( lhsIsOpaque ==  rhs.renderItem->mIsOpaque )
230   {
231     if( lhsIsOpaque )
232     {
233       //If both RenderItems are opaque, sort using shader, then texture then geometry
234       if( lhs.shader == rhs.shader )
235       {
236         if( lhs.textureResourceId == rhs.textureResourceId )
237         {
238           return lhs.geometry < rhs.geometry;
239         }
240         return lhs.textureResourceId < rhs.textureResourceId;
241       }
242       return lhs.shader < rhs.shader;
243     }
244     else
245     {
246       //If both RenderItems are transparent, sort using z,then shader, then texture, then geometry
247       if( Equals(lhs.zValue, rhs.zValue) )
248       {
249         if( lhs.shader == rhs.shader )
250         {
251           if( lhs.textureResourceId == rhs.textureResourceId )
252           {
253             return lhs.geometry < rhs.geometry;
254           }
255           return lhs.textureResourceId < rhs.textureResourceId;
256         }
257         return lhs.shader < rhs.shader;
258       }
259       return lhs.zValue > rhs.zValue;
260     }
261   }
262   else
263   {
264     return lhsIsOpaque;
265   }
266 }
267
268 /**
269  * Sort render items
270  * @param bufferIndex The buffer to read from
271  * @param renderList to sort
272  * @param layer where the renderers are from
273  * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
274  */
275 inline void SortRenderItems( BufferIndex bufferIndex, RenderList& renderList, Layer& layer, RendererSortingHelper& sortingHelper )
276 {
277   const size_t renderableCount = renderList.Count();
278   // reserve space if needed
279   const unsigned int oldcapacity = sortingHelper.size();
280   if( oldcapacity < renderableCount )
281   {
282     sortingHelper.reserve( renderableCount );
283     // add real objects (reserve does not construct objects)
284     sortingHelper.insert( sortingHelper.begin() + oldcapacity,
285                           (renderableCount - oldcapacity),
286                           RendererWithSortAttributes() );
287   }
288   else
289   {
290     // clear extra elements from helper, does not decrease capability
291     sortingHelper.resize( renderableCount );
292   }
293
294   // calculate the sorting value, once per item by calling the layers sort function
295   // Using an if and two for-loops rather than if inside for as its better for branch prediction
296   if( layer.UsesDefaultSortFunction() )
297   {
298     for( size_t index = 0; index < renderableCount; ++index )
299     {
300       RenderItem& item = renderList.GetItem( index );
301
302       item.mRenderer->SetSortAttributes( bufferIndex, sortingHelper[ index ] );
303
304       // the default sorting function should get inlined here
305       sortingHelper[ index ].zValue = Internal::Layer::ZValue( item.mModelViewMatrix.GetTranslation3() ) - item.mDepthIndex;
306
307       // keep the renderitem pointer in the helper so we can quickly reorder items after sort
308       sortingHelper[ index ].renderItem = &item;
309     }
310   }
311   else
312   {
313     const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
314     for( size_t index = 0; index < renderableCount; ++index )
315     {
316       RenderItem& item = renderList.GetItem( index );
317
318       item.mRenderer->SetSortAttributes( bufferIndex, sortingHelper[ index ] );
319       sortingHelper[ index ].zValue = (*sortFunction)( item.mModelViewMatrix.GetTranslation3() ) - item.mDepthIndex;
320
321       // keep the renderitem pointer in the helper so we can quickly reorder items after sort
322       sortingHelper[ index ].renderItem = &item;
323     }
324   }
325
326   if( layer.GetBehavior() ==  Dali::Layer::LAYER_3D)
327   {
328     // sort the renderers back to front, Z Axis point from near plane to far plane
329     std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems3D );
330   }
331   else
332   {
333     // sort the renderers based on DepthIndex
334     std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems );
335   }
336
337   // reorder/repopulate the renderitems in renderlist to correct order based on sortinghelper
338   DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Transparent List:\n");
339   RenderItemContainer::Iterator renderListIter = renderList.GetContainer().Begin();
340   for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter )
341   {
342     *renderListIter = sortingHelper[ index ].renderItem;
343     DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "  sortedList[%d] = %p\n", index, sortingHelper[ index ].renderItem->mRenderer);
344   }
345 }
346
347 /**
348  * Add color renderers from the layer onto the next free render list
349  * @param updateBufferIndex to use
350  * @param layer to get the renderers from
351  * @param viewmatrix for the camera from rendertask
352  * @param camera to use the view frustum
353  * @param stencilRenderablesExist is true if there are stencil renderers on this layer
354  * @param instruction to fill in
355  * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
356  * @param geometryBatcher the instance of the geometry batcher
357  * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
358  * @param cull Whether frustum culling is enabled or not
359  */
360 inline void AddColorRenderers( BufferIndex updateBufferIndex,
361                                Layer& layer,
362                                const Matrix& viewMatrix,
363                                SceneGraph::Camera& camera,
364                                bool stencilRenderablesExist,
365                                RenderInstruction& instruction,
366                                RendererSortingHelper& sortingHelper,
367                                GeometryBatcher& geometryBatcher,
368                                bool tryReuseRenderList,
369                                bool cull)
370 {
371   RenderList& renderList = instruction.GetNextFreeRenderList( layer.colorRenderables.Size() );
372   renderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
373   renderList.SetSourceLayer( &layer );
374   renderList.SetHasColorRenderItems( true );
375
376   // try to reuse cached renderitems from last time around
377   if( tryReuseRenderList )
378   {
379     if( TryReuseCachedRenderers( layer, renderList, layer.colorRenderables ) )
380     {
381       return;
382     }
383   }
384
385   AddRenderersToRenderList( updateBufferIndex, renderList, layer.colorRenderables, viewMatrix, camera, &geometryBatcher, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
386   SortRenderItems( updateBufferIndex, renderList, layer, sortingHelper );
387
388   // Setup the render flags for stencil.
389   renderList.ClearFlags();
390   if( stencilRenderablesExist )
391   {
392     // Note: SetFlags does not overwrite, it ORs, so ClearFlags() is also required.
393     renderList.SetFlags( RenderList::STENCIL_BUFFER_ENABLED );
394   }
395 }
396
397 /**
398  * Add overlay renderers from the layer onto the next free render list
399  * @param updateBufferIndex to use
400  * @param layer to get the renderers from
401  * @param viewmatrix for the camera from rendertask
402  * @param camera to use
403  * @param stencilRenderablesExist is true if there are stencil renderers on this layer
404  * @param instruction to fill in
405  * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
406  * @param cull Whether frustum culling is enabled or not
407  */
408 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
409                                  Layer& layer,
410                                  const Matrix& viewMatrix,
411                                  SceneGraph::Camera& camera,
412                                  bool stencilRenderablesExist,
413                                  RenderInstruction& instruction,
414                                  RendererSortingHelper& sortingHelper,
415                                  bool tryReuseRenderList,
416                                  bool cull )
417 {
418   RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.Size() );
419   overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
420   overlayRenderList.SetSourceLayer( &layer );
421   overlayRenderList.SetHasColorRenderItems( false );
422
423   //Set render flags
424   overlayRenderList.ClearFlags();
425   if(stencilRenderablesExist)
426   {
427     overlayRenderList.SetFlags(RenderList::STENCIL_BUFFER_ENABLED);
428   }
429
430   // try to reuse cached renderitems from last time around
431   if( tryReuseRenderList )
432   {
433     if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
434     {
435       return;
436     }
437   }
438   AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix, camera, NULL, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
439   SortRenderItems( updateBufferIndex, overlayRenderList, layer, sortingHelper );
440 }
441
442 /**
443  * Add stencil renderers from the layer onto the next free render list
444  * @param updateBufferIndex to use
445  * @param layer to get the renderers from
446  * @param viewmatrix for the camera from rendertask
447  * @param camera to use
448  * @param instruction to fill in
449  * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
450  * @param cull Whether frustum culling is enabled or not
451  */
452 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
453                                  Layer& layer,
454                                  const Matrix& viewMatrix,
455                                  SceneGraph::Camera& camera,
456                                  RenderInstruction& instruction,
457                                  bool tryReuseRenderList,
458                                  bool cull )
459 {
460   RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.Size() );
461   stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
462   stencilRenderList.SetSourceLayer( &layer );
463   stencilRenderList.SetHasColorRenderItems( false );
464
465   //Set render flags
466   stencilRenderList.ClearFlags();
467   stencilRenderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_BUFFER_ENABLED );
468
469   // try to reuse cached renderitems from last time around
470   if( tryReuseRenderList )
471   {
472     if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
473     {
474       return;
475     }
476   }
477   AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix, camera, NULL, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
478 }
479
480 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
481                                SortedLayerPointers& sortedLayers,
482                                RenderTask& renderTask,
483                                RendererSortingHelper& sortingHelper,
484                                bool cull,
485                                RenderInstructionContainer& instructions,
486                                GeometryBatcher& geometryBatcher )
487 {
488   // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
489   // then populate with instructions.
490   RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
491   renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
492   bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
493
494   const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
495   SceneGraph::Camera& camera = renderTask.GetCamera();
496
497   const SortedLayersIter endIter = sortedLayers.end();
498   for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
499   {
500     Layer& layer = **iter;
501
502     const bool stencilRenderablesExist( !layer.stencilRenderables.Empty() );
503     const bool colorRenderablesExist( !layer.colorRenderables.Empty() );
504     const bool overlayRenderablesExist( !layer.overlayRenderables.Empty() );
505     const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers( &renderTask.GetCamera() ) );
506
507     // Ignore stencils if there's nothing to test
508     if( stencilRenderablesExist &&
509         ( colorRenderablesExist || overlayRenderablesExist ) )
510     {
511       AddStencilRenderers( updateBufferIndex, layer, viewMatrix, camera, instruction, tryReuseRenderList, cull );
512     }
513
514     if ( colorRenderablesExist )
515     {
516       AddColorRenderers( updateBufferIndex,
517                          layer,
518                          viewMatrix,
519                          camera,
520                          stencilRenderablesExist,
521                          instruction,
522                          sortingHelper,
523                          geometryBatcher,
524                          tryReuseRenderList,
525                          cull );
526     }
527
528     if ( overlayRenderablesExist )
529     {
530       AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, camera, stencilRenderablesExist,
531                            instruction, sortingHelper, tryReuseRenderList, cull );
532     }
533   }
534
535   // inform the render instruction that all renderers have been added and this frame is complete
536   instruction.UpdateCompleted();
537 }
538
539 } // SceneGraph
540
541 } // Internal
542
543 } // Dali