2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/update/manager/prepare-render-instructions.h>
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>
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gRenderListLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_LISTS");
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
67 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
68 RenderList& renderList,
69 Renderable& renderable,
70 const Matrix& viewMatrix,
71 SceneGraph::Camera& camera,
72 GeometryBatcher& geometryBatcher,
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 ) )
85 const Node* batchParentNode = renderable.mNode->GetBatchParent();
86 const Node* node = ( renderable.mRenderer->IsBatchingEnabled() && batchParentNode ) ?
87 batchParentNode : renderableNode;
89 if ( cull && !renderable.mRenderer->GetShader().HintEnabled( Dali::Shader::Hint::MODIFIES_GEOMETRY ) )
91 const Vector4& boundingSphere = node->GetBoundingSphere();
92 inside = (boundingSphere.w > Math::MACHINE_EPSILON_1000) &&
93 (camera.CheckSphereInFrustum( updateBufferIndex, Vector3(boundingSphere), boundingSphere.w ) );
100 geometryBatcher.SetRendered( renderableNode->mBatchIndex );
103 Renderer::Opacity opacity = renderable.mRenderer->GetOpacity( updateBufferIndex, *renderable.mNode );
104 if( opacity != Renderer::TRANSPARENT )
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);
114 item.mDepthIndex = renderable.mRenderer->GetDepthIndex();
118 item.mDepthIndex = renderable.mRenderer->GetDepthIndex() + static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER;
120 // save MV matrix onto the item
121 node->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize );
122 Matrix::Multiply( item.mModelViewMatrix, item.mModelMatrix, viewMatrix );
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
139 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
140 RenderList& renderList,
141 RenderableContainer& renderers,
142 const Matrix& viewMatrix,
143 SceneGraph::Camera& camera,
144 GeometryBatcher* geometryBatcher,
148 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
150 unsigned int rendererCount( renderers.Size() );
151 for( unsigned int i(0); i<rendererCount; ++i )
153 AddRendererToRenderList( updateBufferIndex, renderList, renderers[i], viewMatrix, camera, *geometryBatcher, isLayer3d, cull );
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
165 inline bool TryReuseCachedRenderers( Layer& layer,
166 RenderList& renderList,
167 RenderableContainer& renderables )
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 ) )
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 )
182 const Render::Renderer& renderer = renderables[index].mRenderer->GetRenderer();
183 checkSumNew += size_t( &renderer );
184 checkSumOld += size_t( &renderList.GetRenderer( index ) );
186 if( checkSumNew == checkSumOld )
188 // tell list to reuse its existing items
189 renderList.ReuseCachedItems();
197 * Function which sorts render items by depth index then by instance
198 * ptrs of shader/texture/geometry.
201 * @return true if left item is greater than right
203 bool CompareItems( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
205 if( lhs.renderItem->mDepthIndex == rhs.renderItem->mDepthIndex )
207 if( lhs.shader == rhs.shader )
209 if( lhs.textureResourceId == rhs.textureResourceId )
211 return lhs.geometry < rhs.geometry;
213 return lhs.textureResourceId < rhs.textureResourceId;
215 return lhs.shader < rhs.shader;
217 return lhs.renderItem->mDepthIndex < rhs.renderItem->mDepthIndex;
220 * Function which sorts the render items by Z function, then
221 * by instance ptrs of shader/texture/geometry.
224 * @return true if left item is greater than right
226 bool CompareItems3D( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
228 bool lhsIsOpaque = lhs.renderItem->mIsOpaque;
229 if( lhsIsOpaque == rhs.renderItem->mIsOpaque )
233 //If both RenderItems are opaque, sort using shader, then texture then geometry
234 if( lhs.shader == rhs.shader )
236 if( lhs.textureResourceId == rhs.textureResourceId )
238 return lhs.geometry < rhs.geometry;
240 return lhs.textureResourceId < rhs.textureResourceId;
242 return lhs.shader < rhs.shader;
246 //If both RenderItems are transparent, sort using z,then shader, then texture, then geometry
247 if( Equals(lhs.zValue, rhs.zValue) )
249 if( lhs.shader == rhs.shader )
251 if( lhs.textureResourceId == rhs.textureResourceId )
253 return lhs.geometry < rhs.geometry;
255 return lhs.textureResourceId < rhs.textureResourceId;
257 return lhs.shader < rhs.shader;
259 return lhs.zValue > rhs.zValue;
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)
275 inline void SortRenderItems( BufferIndex bufferIndex, RenderList& renderList, Layer& layer, RendererSortingHelper& sortingHelper )
277 const size_t renderableCount = renderList.Count();
278 // reserve space if needed
279 const unsigned int oldcapacity = sortingHelper.size();
280 if( oldcapacity < renderableCount )
282 sortingHelper.reserve( renderableCount );
283 // add real objects (reserve does not construct objects)
284 sortingHelper.insert( sortingHelper.begin() + oldcapacity,
285 (renderableCount - oldcapacity),
286 RendererWithSortAttributes() );
290 // clear extra elements from helper, does not decrease capability
291 sortingHelper.resize( renderableCount );
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() )
298 for( size_t index = 0; index < renderableCount; ++index )
300 RenderItem& item = renderList.GetItem( index );
302 item.mRenderer->SetSortAttributes( bufferIndex, sortingHelper[ index ] );
304 // the default sorting function should get inlined here
305 sortingHelper[ index ].zValue = Internal::Layer::ZValue( item.mModelViewMatrix.GetTranslation3() ) - item.mDepthIndex;
307 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
308 sortingHelper[ index ].renderItem = &item;
313 const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
314 for( size_t index = 0; index < renderableCount; ++index )
316 RenderItem& item = renderList.GetItem( index );
318 item.mRenderer->SetSortAttributes( bufferIndex, sortingHelper[ index ] );
319 sortingHelper[ index ].zValue = (*sortFunction)( item.mModelViewMatrix.GetTranslation3() ) - item.mDepthIndex;
321 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
322 sortingHelper[ index ].renderItem = &item;
326 if( layer.GetBehavior() == Dali::Layer::LAYER_3D)
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 );
333 // sort the renderers based on DepthIndex
334 std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems );
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 )
342 *renderListIter = sortingHelper[ index ].renderItem;
343 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " sortedList[%d] = %p\n", index, sortingHelper[ index ].renderItem->mRenderer);
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
360 inline void AddColorRenderers( BufferIndex updateBufferIndex,
362 const Matrix& viewMatrix,
363 SceneGraph::Camera& camera,
364 bool stencilRenderablesExist,
365 RenderInstruction& instruction,
366 RendererSortingHelper& sortingHelper,
367 GeometryBatcher& geometryBatcher,
368 bool tryReuseRenderList,
371 RenderList& renderList = instruction.GetNextFreeRenderList( layer.colorRenderables.Size() );
372 renderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
373 renderList.SetSourceLayer( &layer );
374 renderList.SetHasColorRenderItems( true );
376 // try to reuse cached renderitems from last time around
377 if( tryReuseRenderList )
379 if( TryReuseCachedRenderers( layer, renderList, layer.colorRenderables ) )
385 AddRenderersToRenderList( updateBufferIndex, renderList, layer.colorRenderables, viewMatrix, camera, &geometryBatcher, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
386 SortRenderItems( updateBufferIndex, renderList, layer, sortingHelper );
388 // Setup the render flags for stencil.
389 renderList.ClearFlags();
390 if( stencilRenderablesExist )
392 // Note: SetFlags does not overwrite, it ORs, so ClearFlags() is also required.
393 renderList.SetFlags( RenderList::STENCIL_BUFFER_ENABLED );
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
408 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
410 const Matrix& viewMatrix,
411 SceneGraph::Camera& camera,
412 bool stencilRenderablesExist,
413 RenderInstruction& instruction,
414 RendererSortingHelper& sortingHelper,
415 bool tryReuseRenderList,
418 RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.Size() );
419 overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
420 overlayRenderList.SetSourceLayer( &layer );
421 overlayRenderList.SetHasColorRenderItems( false );
424 overlayRenderList.ClearFlags();
425 if(stencilRenderablesExist)
427 overlayRenderList.SetFlags(RenderList::STENCIL_BUFFER_ENABLED);
430 // try to reuse cached renderitems from last time around
431 if( tryReuseRenderList )
433 if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
438 AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix, camera, NULL, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
439 SortRenderItems( updateBufferIndex, overlayRenderList, layer, sortingHelper );
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
452 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
454 const Matrix& viewMatrix,
455 SceneGraph::Camera& camera,
456 RenderInstruction& instruction,
457 bool tryReuseRenderList,
460 RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.Size() );
461 stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
462 stencilRenderList.SetSourceLayer( &layer );
463 stencilRenderList.SetHasColorRenderItems( false );
466 stencilRenderList.ClearFlags();
467 stencilRenderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_BUFFER_ENABLED );
469 // try to reuse cached renderitems from last time around
470 if( tryReuseRenderList )
472 if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
477 AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix, camera, NULL, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
480 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
481 SortedLayerPointers& sortedLayers,
482 RenderTask& renderTask,
483 RendererSortingHelper& sortingHelper,
485 RenderInstructionContainer& instructions,
486 GeometryBatcher& geometryBatcher )
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();
494 const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
495 SceneGraph::Camera& camera = renderTask.GetCamera();
497 const SortedLayersIter endIter = sortedLayers.end();
498 for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
500 Layer& layer = **iter;
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() ) );
507 // Ignore stencils if there's nothing to test
508 if( stencilRenderablesExist &&
509 ( colorRenderablesExist || overlayRenderablesExist ) )
511 AddStencilRenderers( updateBufferIndex, layer, viewMatrix, camera, instruction, tryReuseRenderList, cull );
514 if ( colorRenderablesExist )
516 AddColorRenderers( updateBufferIndex,
520 stencilRenderablesExist,
528 if ( overlayRenderablesExist )
530 AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, camera, stencilRenderablesExist,
531 instruction, sortingHelper, tryReuseRenderList, cull );
535 // inform the render instruction that all renderers have been added and this frame is complete
536 instruction.UpdateCompleted();