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