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