[Tizen] Implement partial update
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / render-instruction-processor.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/manager/render-instruction-processor.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/internal/event/actors/layer-impl.h> // for the default sorting function
25 #include <dali/internal/update/manager/sorted-layers.h>
26 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
27 #include <dali/internal/update/rendering/scene-graph-texture-set.h>
28 #include <dali/internal/render/common/render-item.h>
29 #include <dali/internal/render/common/render-tracker.h>
30 #include <dali/internal/render/common/render-instruction.h>
31 #include <dali/internal/render/common/render-instruction-container.h>
32 #include <dali/internal/render/shaders/scene-graph-shader.h>
33 #include <dali/internal/render/renderers/render-renderer.h>
34 #include <dali/internal/render/renderers/render-property-buffer.h>
35 #include <dali/internal/update/nodes/scene-graph-layer.h>
36 #include <dali/internal/common/math.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 namespace
55 {
56
57 /**
58  * Function which compares render items by shader/textureSet/geometry
59  * @param[in] lhs Left hand side item
60  * @param[in] rhs Right hand side item
61  * @return True if left item is greater than right
62  */
63 inline bool PartialCompareItems( const RenderInstructionProcessor::SortAttributes& lhs,
64                                  const RenderInstructionProcessor::SortAttributes& rhs )
65 {
66   if( lhs.shader == rhs.shader )
67   {
68     if( lhs.textureSet == rhs.textureSet )
69     {
70       return lhs.geometry < rhs.geometry;
71     }
72     return lhs.textureSet < rhs.textureSet;
73   }
74   return lhs.shader < rhs.shader;
75 }
76
77 /**
78  * Function which sorts render items by depth index then by instance
79  * ptrs of shader/textureSet/geometry.
80  * @param[in] lhs Left hand side item
81  * @param[in] rhs Right hand side item
82  * @return True if left item is greater than right
83  */
84 bool CompareItems( const RenderInstructionProcessor::SortAttributes& lhs, const RenderInstructionProcessor::SortAttributes& rhs )
85 {
86   // @todo Consider replacing all these sortAttributes with a single long int that
87   // encapsulates the same data (e.g. the middle-order bits of the ptrs).
88   if( lhs.renderItem->mDepthIndex == rhs.renderItem->mDepthIndex )
89   {
90     return PartialCompareItems( lhs, rhs );
91   }
92   return lhs.renderItem->mDepthIndex < rhs.renderItem->mDepthIndex;
93 }
94
95 /**
96  * Function which sorts the render items by Z function, then
97  * by instance ptrs of shader / geometry / material.
98  * @param[in] lhs Left hand side item
99  * @param[in] rhs Right hand side item
100  * @return True if left item is greater than right
101  */
102 bool CompareItems3D( const RenderInstructionProcessor::SortAttributes& lhs, const RenderInstructionProcessor::SortAttributes& rhs )
103 {
104   const bool lhsIsOpaque = lhs.renderItem->mIsOpaque;
105   if( lhsIsOpaque == rhs.renderItem->mIsOpaque )
106   {
107     if( lhsIsOpaque )
108     {
109       // If both RenderItems are opaque, sort using shader, then material then geometry.
110       return PartialCompareItems( lhs, rhs );
111     }
112     else
113     {
114       // If both RenderItems are transparent, sort using Z, then shader, then material, then geometry.
115       if( Equals( lhs.zValue, rhs.zValue ) )
116       {
117         return PartialCompareItems( lhs, rhs );
118       }
119       return lhs.zValue > rhs.zValue;
120     }
121   }
122   else
123   {
124     return lhsIsOpaque;
125   }
126 }
127
128 /**
129  * Function which sorts render items by clipping hierarchy, then Z function and instance ptrs of shader / geometry / material.
130  * @param[in] lhs Left hand side item
131  * @param[in] rhs Right hand side item
132  * @return True if left item is greater than right
133  */
134 bool CompareItems3DWithClipping( const RenderInstructionProcessor::SortAttributes& lhs, const RenderInstructionProcessor::SortAttributes& rhs )
135 {
136   // Items must be sorted in order of clipping first, otherwise incorrect clipping regions could be used.
137   if( lhs.renderItem->mNode->mClippingSortModifier == rhs.renderItem->mNode->mClippingSortModifier )
138   {
139     return CompareItems3D( lhs, rhs );
140   }
141
142   return lhs.renderItem->mNode->mClippingSortModifier < rhs.renderItem->mNode->mClippingSortModifier;
143 }
144
145 /**
146  * Add a renderer to the list
147  * @param updateBufferIndex to read the model matrix from
148  * @param renderList to add the item to
149  * @param renderable Node-Renderer pair
150  * @param viewMatrix used to calculate modelview matrix for the item
151  * @param camera The camera used to render
152  * @param isLayer3d Whether we are processing a 3D layer or not
153  * @param cull Whether frustum culling is enabled or not
154  */
155 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
156                                      RenderList& renderList,
157                                      Renderable& renderable,
158                                      const Matrix& viewMatrix,
159                                      SceneGraph::Camera& camera,
160                                      bool isLayer3d,
161                                      bool cull )
162 {
163   bool inside( true );
164   Node* node = renderable.mNode;
165   bool geomertryModified = false;
166   if( cull && renderable.mRenderer && !( geomertryModified = renderable.mRenderer->GetShader().HintEnabled( Dali::Shader::Hint::MODIFIES_GEOMETRY ) ) )
167   {
168     const Vector4& boundingSphere = node->GetBoundingSphere();
169     inside = ( boundingSphere.w > Math::MACHINE_EPSILON_1000 ) &&
170              ( camera.CheckSphereInFrustum( updateBufferIndex, Vector3( boundingSphere ), boundingSphere.w ) );
171   }
172
173   if( inside )
174   {
175     Renderer::OpacityType opacityType = renderable.mRenderer ? renderable.mRenderer->GetOpacityType( updateBufferIndex, *renderable.mNode ) : Renderer::OPAQUE;
176     if( opacityType != Renderer::TRANSPARENT || node->GetClippingMode() == ClippingMode::CLIP_CHILDREN )
177     {
178       // Get the next free RenderItem.
179       RenderItem& item = renderList.GetNextFreeItem();
180
181       item.mNode = renderable.mNode;
182       item.mIsOpaque = ( opacityType == Renderer::OPAQUE );
183       item.mDepthIndex = 0;
184       item.mPartialUpdateEnabled = false;
185
186       if( !isLayer3d )
187       {
188         item.mDepthIndex = renderable.mNode->GetDepthIndex();
189       }
190       if( isLayer3d || geomertryModified )
191       {
192         renderList.SetPartialUpdateEnabled( false );
193       }
194
195       if( DALI_LIKELY( renderable.mRenderer ) )
196       {
197         item.mRenderer =   &renderable.mRenderer->GetRenderer();
198         item.mTextureSet =  renderable.mRenderer->GetTextures();
199         item.mDepthIndex += renderable.mRenderer->GetDepthIndex();
200
201         if( FaceCullingMode::NONE != renderable.mRenderer->GetFaceCullingMode() )
202         {
203           renderList.SetPartialUpdateEnabled( false );
204         }
205       }
206       else
207       {
208         item.mRenderer = nullptr;
209       }
210
211       // Save ModelView matrix onto the item.
212       node->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize );
213
214       Matrix::Multiply( item.mModelViewMatrix, item.mModelMatrix, viewMatrix );
215
216       if( node->IsPartialUpdateAvailable() && DALI_LIKELY( item.mRenderer ) && renderList.IsPartialUpdateEnabled() )
217       {
218         if( node->IsComponentChanged() || node->IsPropertyDirty() )
219         {
220           item.mPartialUpdateEnabled = true;
221
222           item.mUpdateSizeHint = item.mSize;
223           Vector3 updateSizeHint = Vector3::ZERO;
224           node->GetUpdateSizeHint( updateBufferIndex, updateSizeHint );
225           if( updateSizeHint != Vector3::ZERO )
226           {
227             item.mUpdateSizeHint = updateSizeHint;
228           }
229         }
230       }
231     }
232     node->SetCulled( updateBufferIndex, false );
233   }
234   else
235   {
236     node->SetCulled( updateBufferIndex, true );
237   }
238 }
239
240 /**
241  * Add all renderers to the list
242  * @param updateBufferIndex to read the model matrix from
243  * @param renderList to add the items to
244  * @param renderers to render
245  * NodeRendererContainer Node-Renderer pairs
246  * @param viewMatrix used to calculate modelview matrix for the items
247  * @param camera The camera used to render
248  * @param isLayer3d Whether we are processing a 3D layer or not
249  * @param cull Whether frustum culling is enabled or not
250  */
251 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
252                                       RenderList& renderList,
253                                       RenderableContainer& renderers,
254                                       const Matrix& viewMatrix,
255                                       SceneGraph::Camera& camera,
256                                       bool isLayer3d,
257                                       bool cull )
258 {
259   DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
260
261   for( auto&& renderer : renderers )
262   {
263     AddRendererToRenderList( updateBufferIndex,
264                              renderList,
265                              renderer,
266                              viewMatrix,
267                              camera,
268                              isLayer3d,
269                              cull );
270   }
271 }
272
273 /**
274  * Try to reuse cached RenderItems from the RenderList
275  * This avoids recalculating the model view matrices in case this part of the scene was static
276  * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
277  * @param layer that is being processed
278  * @param renderList that is cached from frame N-1
279  * @param renderables list of renderables
280  */
281 inline bool TryReuseCachedRenderers( Layer& layer,
282                                      RenderList& renderList,
283                                      RenderableContainer& renderables )
284 {
285   bool retValue = false;
286   uint32_t renderableCount = static_cast<uint32_t>( renderables.Size() );
287   // Check that the cached list originates from this layer and that the counts match
288   if( ( renderList.GetSourceLayer() == &layer )&&
289       ( renderList.GetCachedItemCount() == renderableCount ) )
290   {
291     // Check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong things.
292     // Render list is sorted so at this stage renderers may be in different order.
293     // Therefore we check a combined sum of all renderer addresses.
294     size_t checkSumNew = 0;
295     size_t checkSumOld = 0;
296     for( uint32_t index = 0; index < renderableCount; ++index )
297     {
298       const Render::Renderer& renderer = renderables[index].mRenderer->GetRenderer();
299       checkSumNew += reinterpret_cast<std::size_t>( &renderer );
300       checkSumOld += reinterpret_cast<std::size_t>( &renderList.GetRenderer( index ) );
301     }
302     if( checkSumNew == checkSumOld )
303     {
304       // tell list to reuse its existing items
305       renderList.ReuseCachedItems();
306       retValue = true;
307     }
308   }
309   return retValue;
310 }
311
312 inline bool SetupRenderList( RenderableContainer& renderables,
313                              Layer& layer,
314                              RenderInstruction& instruction,
315                              bool tryReuseRenderList,
316                              RenderList** renderList )
317 {
318   *renderList = &( instruction.GetNextFreeRenderList( renderables.Size() ) );
319   ( *renderList )->SetClipping( layer.IsClipping(), layer.GetClippingBox() );
320   ( *renderList )->SetSourceLayer( &layer );
321
322   // Try to reuse cached RenderItems from last time around.
323   return ( tryReuseRenderList && TryReuseCachedRenderers( layer, **renderList, renderables ) );
324 }
325
326 } // Anonymous namespace.
327
328
329 RenderInstructionProcessor::RenderInstructionProcessor()
330 : mSortingHelper()
331 {
332   // Set up a container of comparators for fast run-time selection.
333   mSortComparitors.Reserve( 3u );
334
335   mSortComparitors.PushBack( CompareItems );
336   mSortComparitors.PushBack( CompareItems3D );
337   mSortComparitors.PushBack( CompareItems3DWithClipping );
338 }
339
340 RenderInstructionProcessor::~RenderInstructionProcessor()
341 {
342 }
343
344 inline void RenderInstructionProcessor::SortRenderItems( BufferIndex bufferIndex, RenderList& renderList, Layer& layer, bool respectClippingOrder )
345 {
346   const uint32_t renderableCount = static_cast<uint32_t>( renderList.Count() );
347   // Reserve space if needed.
348   const uint32_t oldcapacity = static_cast<uint32_t>( mSortingHelper.size() );
349   if( oldcapacity < renderableCount )
350   {
351     mSortingHelper.reserve( renderableCount );
352     // Add real objects (reserve does not construct objects).
353     mSortingHelper.insert( mSortingHelper.begin() + oldcapacity,
354                           (renderableCount - oldcapacity),
355                           RenderInstructionProcessor::SortAttributes() );
356   }
357   else
358   {
359     // Clear extra elements from helper, does not decrease capability.
360     mSortingHelper.resize( renderableCount );
361   }
362
363   // Calculate the sorting value, once per item by calling the layers sort function.
364   // Using an if and two for-loops rather than if inside for as its better for branch prediction.
365   if( layer.UsesDefaultSortFunction() )
366   {
367     for( uint32_t index = 0; index < renderableCount; ++index )
368     {
369       RenderItem& item = renderList.GetItem( index );
370
371       if( item.mRenderer )
372       {
373         item.mRenderer->SetSortAttributes( bufferIndex, mSortingHelper[ index ] );
374       }
375
376       // texture set
377       mSortingHelper[ index ].textureSet = item.mTextureSet;
378
379       // The default sorting function should get inlined here.
380       mSortingHelper[ index ].zValue = Internal::Layer::ZValue( item.mModelViewMatrix.GetTranslation3() ) - static_cast<float>( item.mDepthIndex );
381
382       // Keep the renderitem pointer in the helper so we can quickly reorder items after sort.
383       mSortingHelper[ index ].renderItem = &item;
384     }
385   }
386   else
387   {
388     const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
389     for( uint32_t index = 0; index < renderableCount; ++index )
390     {
391       RenderItem& item = renderList.GetItem( index );
392
393       item.mRenderer->SetSortAttributes( bufferIndex, mSortingHelper[ index ] );
394
395       // texture set
396       mSortingHelper[ index ].textureSet = item.mTextureSet;
397
398
399       mSortingHelper[ index ].zValue = (*sortFunction)( item.mModelViewMatrix.GetTranslation3() ) - static_cast<float>( item.mDepthIndex );
400
401       // Keep the RenderItem pointer in the helper so we can quickly reorder items after sort.
402       mSortingHelper[ index ].renderItem = &item;
403     }
404   }
405
406   // Here we determine which comparitor (of the 3) to use.
407   //   0 is LAYER_UI
408   //   1 is LAYER_3D
409   //   2 is LAYER_3D + Clipping
410   const unsigned int comparitorIndex = layer.GetBehavior() == Dali::Layer::LAYER_3D ? respectClippingOrder ? 2u : 1u : 0u;
411
412   std::stable_sort( mSortingHelper.begin(), mSortingHelper.end(), mSortComparitors[ comparitorIndex ] );
413
414   // Reorder / re-populate the RenderItems in the RenderList to correct order based on the sortinghelper.
415   DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Transparent List:\n");
416   RenderItemContainer::Iterator renderListIter = renderList.GetContainer().Begin();
417   for( uint32_t index = 0; index < renderableCount; ++index, ++renderListIter )
418   {
419     *renderListIter = mSortingHelper[ index ].renderItem;
420     DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "  sortedList[%d] = %p\n", index, mSortingHelper[ index ].renderItem->mRenderer);
421   }
422 }
423
424 void RenderInstructionProcessor::Prepare( BufferIndex updateBufferIndex,
425                                           SortedLayerPointers& sortedLayers,
426                                           RenderTask& renderTask,
427                                           bool cull,
428                                           bool hasClippingNodes,
429                                           RenderInstructionContainer& instructions )
430 {
431   // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
432   // then populate with instructions.
433   RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
434   renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
435   bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
436   bool isRenderListAdded = false;
437   bool isRootLayerDirty = false;
438
439   const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
440   SceneGraph::Camera& camera = renderTask.GetCamera();
441
442   const SortedLayersIter endIter = sortedLayers.end();
443   for( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
444   {
445     Layer& layer = **iter;
446     const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers( &renderTask.GetCamera() ) );
447     const bool isLayer3D = layer.GetBehavior() == Dali::Layer::LAYER_3D;
448     RenderList* renderList = NULL;
449
450     if( layer.IsRoot() && ( layer.GetDirtyFlags() != NodePropertyFlags::NOTHING ) )
451     {
452       // If root-layer & dirty, i.e. a property has changed or a child has been deleted, then we need to ensure we render once more
453       isRootLayerDirty = true;
454     }
455
456     if( !layer.colorRenderables.Empty() )
457     {
458       RenderableContainer& renderables = layer.colorRenderables;
459
460       if( !SetupRenderList( renderables, layer, instruction, tryReuseRenderList, &renderList ) )
461       {
462         renderList->SetHasColorRenderItems( true );
463         if( !isLayer3D )
464         {
465           renderList->SetPartialUpdateEnabled( true );
466         }
467         AddRenderersToRenderList( updateBufferIndex,
468                                   *renderList,
469                                   renderables,
470                                   viewMatrix,
471                                   camera,
472                                   isLayer3D,
473                                   cull );
474
475         // We only use the clipping version of the sort comparitor if any clipping nodes exist within the RenderList.
476         SortRenderItems( updateBufferIndex, *renderList, layer, hasClippingNodes );
477       }
478
479       isRenderListAdded = true;
480     }
481
482     if( !layer.overlayRenderables.Empty() )
483     {
484       RenderableContainer& renderables = layer.overlayRenderables;
485
486       if( !SetupRenderList( renderables, layer, instruction, tryReuseRenderList, &renderList ) )
487       {
488         renderList->SetHasColorRenderItems( false );
489         if( !isLayer3D )
490         {
491           renderList->SetPartialUpdateEnabled( true );
492         }
493         AddRenderersToRenderList( updateBufferIndex,
494                                   *renderList,
495                                   renderables,
496                                   viewMatrix,
497                                   camera,
498                                   isLayer3D,
499                                   cull );
500
501         // Clipping hierarchy is irrelevant when sorting overlay items, so we specify using the non-clipping version of the sort comparitor.
502         SortRenderItems( updateBufferIndex, *renderList, layer, false );
503       }
504
505       isRenderListAdded = true;
506     }
507   }
508
509   // Inform the render instruction that all renderers have been added and this frame is complete.
510   instruction.UpdateCompleted();
511
512   if( !isRenderListAdded && !instruction.mIsClearColorSet && !isRootLayerDirty )
513   {
514     instructions.DiscardCurrentInstruction( updateBufferIndex );
515   }
516 }
517
518 } // SceneGraph
519
520 } // Internal
521
522 } // Dali