[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 isModifiesGeometryHint = false;
166   if( cull && renderable.mRenderer && !( isModifiesGeometryHint = 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 || isModifiesGeometryHint )
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( DALI_LIKELY( item.mRenderer ) && renderList.IsPartialUpdateEnabled() )
217       {
218         if( node->IsPropertyDirty() || node->IsComponentChanged() )
219         {
220           item.mPartialUpdateEnabled = true;
221
222           item.mUpdateSizeHint = item.mSize;
223           Vector3 updateSizeHint = node->GetUpdateSizeHint( updateBufferIndex );
224           if( updateSizeHint != Vector3::ZERO )
225           {
226             item.mUpdateSizeHint = updateSizeHint;
227           }
228         }
229       }
230     }
231     node->SetCulled( updateBufferIndex, false );
232   }
233   else
234   {
235     node->SetCulled( updateBufferIndex, true );
236   }
237 }
238
239 /**
240  * Add all renderers to the list
241  * @param updateBufferIndex to read the model matrix from
242  * @param renderList to add the items to
243  * @param renderers to render
244  * NodeRendererContainer Node-Renderer pairs
245  * @param viewMatrix used to calculate modelview matrix for the items
246  * @param camera The camera used to render
247  * @param isLayer3d Whether we are processing a 3D layer or not
248  * @param cull Whether frustum culling is enabled or not
249  */
250 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
251                                       RenderList& renderList,
252                                       RenderableContainer& renderers,
253                                       const Matrix& viewMatrix,
254                                       SceneGraph::Camera& camera,
255                                       bool isLayer3d,
256                                       bool cull )
257 {
258   DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
259
260   for( auto&& renderer : renderers )
261   {
262     AddRendererToRenderList( updateBufferIndex,
263                              renderList,
264                              renderer,
265                              viewMatrix,
266                              camera,
267                              isLayer3d,
268                              cull );
269   }
270 }
271
272 /**
273  * Try to reuse cached RenderItems from the RenderList
274  * This avoids recalculating the model view matrices in case this part of the scene was static
275  * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
276  * @param layer that is being processed
277  * @param renderList that is cached from frame N-1
278  * @param renderables list of renderables
279  */
280 inline bool TryReuseCachedRenderers( Layer& layer,
281                                      RenderList& renderList,
282                                      RenderableContainer& renderables )
283 {
284   bool retValue = false;
285   uint32_t renderableCount = static_cast<uint32_t>( renderables.Size() );
286   // Check that the cached list originates from this layer and that the counts match
287   if( ( renderList.GetSourceLayer() == &layer )&&
288       ( renderList.GetCachedItemCount() == renderableCount ) )
289   {
290     // Check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong things.
291     // Render list is sorted so at this stage renderers may be in different order.
292     // Therefore we check a combined sum of all renderer addresses.
293     size_t checkSumNew = 0;
294     size_t checkSumOld = 0;
295     for( uint32_t index = 0; index < renderableCount; ++index )
296     {
297       const Render::Renderer& renderer = renderables[index].mRenderer->GetRenderer();
298       checkSumNew += reinterpret_cast<std::size_t>( &renderer );
299       checkSumOld += reinterpret_cast<std::size_t>( &renderList.GetRenderer( index ) );
300     }
301     if( checkSumNew == checkSumOld )
302     {
303       // tell list to reuse its existing items
304       renderList.ReuseCachedItems();
305       retValue = true;
306     }
307   }
308   return retValue;
309 }
310
311 inline bool SetupRenderList( RenderableContainer& renderables,
312                              Layer& layer,
313                              RenderInstruction& instruction,
314                              bool tryReuseRenderList,
315                              RenderList** renderList )
316 {
317   *renderList = &( instruction.GetNextFreeRenderList( renderables.Size() ) );
318   ( *renderList )->SetClipping( layer.IsClipping(), layer.GetClippingBox() );
319   ( *renderList )->SetSourceLayer( &layer );
320
321   // Try to reuse cached RenderItems from last time around.
322   return ( tryReuseRenderList && TryReuseCachedRenderers( layer, **renderList, renderables ) );
323 }
324
325 } // Anonymous namespace.
326
327
328 RenderInstructionProcessor::RenderInstructionProcessor()
329 : mSortingHelper()
330 {
331   // Set up a container of comparators for fast run-time selection.
332   mSortComparitors.Reserve( 3u );
333
334   mSortComparitors.PushBack( CompareItems );
335   mSortComparitors.PushBack( CompareItems3D );
336   mSortComparitors.PushBack( CompareItems3DWithClipping );
337 }
338
339 RenderInstructionProcessor::~RenderInstructionProcessor()
340 {
341 }
342
343 inline void RenderInstructionProcessor::SortRenderItems( BufferIndex bufferIndex, RenderList& renderList, Layer& layer, bool respectClippingOrder )
344 {
345   const uint32_t renderableCount = static_cast<uint32_t>( renderList.Count() );
346   // Reserve space if needed.
347   const uint32_t oldcapacity = static_cast<uint32_t>( mSortingHelper.size() );
348   if( oldcapacity < renderableCount )
349   {
350     mSortingHelper.reserve( renderableCount );
351     // Add real objects (reserve does not construct objects).
352     mSortingHelper.insert( mSortingHelper.begin() + oldcapacity,
353                           (renderableCount - oldcapacity),
354                           RenderInstructionProcessor::SortAttributes() );
355   }
356   else
357   {
358     // Clear extra elements from helper, does not decrease capability.
359     mSortingHelper.resize( renderableCount );
360   }
361
362   // Calculate the sorting value, once per item by calling the layers sort function.
363   // Using an if and two for-loops rather than if inside for as its better for branch prediction.
364   if( layer.UsesDefaultSortFunction() )
365   {
366     for( uint32_t index = 0; index < renderableCount; ++index )
367     {
368       RenderItem& item = renderList.GetItem( index );
369
370       if( item.mRenderer )
371       {
372         item.mRenderer->SetSortAttributes( bufferIndex, mSortingHelper[ index ] );
373       }
374
375       // texture set
376       mSortingHelper[ index ].textureSet = item.mTextureSet;
377
378       // The default sorting function should get inlined here.
379       mSortingHelper[ index ].zValue = Internal::Layer::ZValue( item.mModelViewMatrix.GetTranslation3() ) - static_cast<float>( item.mDepthIndex );
380
381       // Keep the renderitem pointer in the helper so we can quickly reorder items after sort.
382       mSortingHelper[ index ].renderItem = &item;
383     }
384   }
385   else
386   {
387     const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
388     for( uint32_t index = 0; index < renderableCount; ++index )
389     {
390       RenderItem& item = renderList.GetItem( index );
391
392       item.mRenderer->SetSortAttributes( bufferIndex, mSortingHelper[ index ] );
393
394       // texture set
395       mSortingHelper[ index ].textureSet = item.mTextureSet;
396
397
398       mSortingHelper[ index ].zValue = (*sortFunction)( item.mModelViewMatrix.GetTranslation3() ) - static_cast<float>( item.mDepthIndex );
399
400       // Keep the RenderItem pointer in the helper so we can quickly reorder items after sort.
401       mSortingHelper[ index ].renderItem = &item;
402     }
403   }
404
405   // Here we determine which comparitor (of the 3) to use.
406   //   0 is LAYER_UI
407   //   1 is LAYER_3D
408   //   2 is LAYER_3D + Clipping
409   const unsigned int comparitorIndex = layer.GetBehavior() == Dali::Layer::LAYER_3D ? respectClippingOrder ? 2u : 1u : 0u;
410
411   std::stable_sort( mSortingHelper.begin(), mSortingHelper.end(), mSortComparitors[ comparitorIndex ] );
412
413   // Reorder / re-populate the RenderItems in the RenderList to correct order based on the sortinghelper.
414   DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Transparent List:\n");
415   RenderItemContainer::Iterator renderListIter = renderList.GetContainer().Begin();
416   for( uint32_t index = 0; index < renderableCount; ++index, ++renderListIter )
417   {
418     *renderListIter = mSortingHelper[ index ].renderItem;
419     DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "  sortedList[%d] = %p\n", index, mSortingHelper[ index ].renderItem->mRenderer);
420   }
421 }
422
423 void RenderInstructionProcessor::Prepare( BufferIndex updateBufferIndex,
424                                           SortedLayerPointers& sortedLayers,
425                                           RenderTask& renderTask,
426                                           bool cull,
427                                           bool hasClippingNodes,
428                                           RenderInstructionContainer& instructions )
429 {
430   // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
431   // then populate with instructions.
432   RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
433   renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
434   bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
435   bool isRenderListAdded = false;
436   bool isRootLayerDirty = false;
437
438   const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
439   SceneGraph::Camera& camera = renderTask.GetCamera();
440
441   const SortedLayersIter endIter = sortedLayers.end();
442   for( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
443   {
444     Layer& layer = **iter;
445     const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers( &renderTask.GetCamera() ) );
446     const bool isLayer3D = layer.GetBehavior() == Dali::Layer::LAYER_3D;
447     RenderList* renderList = NULL;
448
449     if( layer.IsRoot() && ( layer.GetDirtyFlags() != NodePropertyFlags::NOTHING ) )
450     {
451       // 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
452       isRootLayerDirty = true;
453     }
454
455     if( !layer.colorRenderables.Empty() )
456     {
457       RenderableContainer& renderables = layer.colorRenderables;
458
459       if( !SetupRenderList( renderables, layer, instruction, tryReuseRenderList, &renderList ) )
460       {
461         renderList->SetHasColorRenderItems( true );
462         if( !isLayer3D )
463         {
464           renderList->SetPartialUpdateEnabled( true );
465         }
466         AddRenderersToRenderList( updateBufferIndex,
467                                   *renderList,
468                                   renderables,
469                                   viewMatrix,
470                                   camera,
471                                   isLayer3D,
472                                   cull );
473
474         // We only use the clipping version of the sort comparitor if any clipping nodes exist within the RenderList.
475         SortRenderItems( updateBufferIndex, *renderList, layer, hasClippingNodes );
476       }
477
478       isRenderListAdded = true;
479     }
480
481     if( !layer.overlayRenderables.Empty() )
482     {
483       RenderableContainer& renderables = layer.overlayRenderables;
484
485       if( !SetupRenderList( renderables, layer, instruction, tryReuseRenderList, &renderList ) )
486       {
487         renderList->SetHasColorRenderItems( false );
488         if( !isLayer3D )
489         {
490           renderList->SetPartialUpdateEnabled( true );
491         }
492         AddRenderersToRenderList( updateBufferIndex,
493                                   *renderList,
494                                   renderables,
495                                   viewMatrix,
496                                   camera,
497                                   isLayer3D,
498                                   cull );
499
500         // Clipping hierarchy is irrelevant when sorting overlay items, so we specify using the non-clipping version of the sort comparitor.
501         SortRenderItems( updateBufferIndex, *renderList, layer, false );
502       }
503
504       isRenderListAdded = true;
505     }
506   }
507
508   // Inform the render instruction that all renderers have been added and this frame is complete.
509   instruction.UpdateCompleted();
510
511   if( !isRenderListAdded && !instruction.mIsClearColorSet && !isRootLayerDirty )
512   {
513     instructions.DiscardCurrentInstruction( updateBufferIndex );
514   }
515 }
516
517 } // SceneGraph
518
519 } // Internal
520
521 } // Dali