2 * Copyright (c) 2015 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/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>
41 #if defined(DEBUG_ENABLED)
42 Debug::Filter* gRenderListLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_LISTS");
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
65 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
66 RenderList& renderList,
67 Renderable& renderable,
68 const Matrix& viewMatrix,
69 SceneGraph::CameraAttachment& cameraAttachment,
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 ) )
79 const Vector3& position = worldMatrix.GetTranslation3();
80 float radius( size.Length() * 0.5f );
82 inside = (radius > Math::MACHINE_EPSILON_1000) &&
83 (cameraAttachment.CheckSphereInFrustum( updateBufferIndex, position, radius ) );
88 Renderer::Opacity opacity = renderable.mRenderer->GetOpacity( updateBufferIndex, *renderable.mNode );
89 if( opacity != Renderer::TRANSPARENT )
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 );
99 item.SetDepthIndex( renderable.mRenderer->GetDepthIndex() );
103 item.SetDepthIndex( renderable.mRenderer->GetDepthIndex() + static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER );
105 // save MV matrix onto the item
106 Matrix::Multiply( item.GetModelViewMatrix(), worldMatrix, viewMatrix );
107 item.SetSize( size );
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
123 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
124 RenderList& renderList,
125 RenderableContainer& renderables,
126 const Matrix& viewMatrix,
127 SceneGraph::CameraAttachment& cameraAttachment,
131 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
133 unsigned int rendererCount( renderables.Size() );
134 for( unsigned int i(0); i<rendererCount; ++i )
136 AddRendererToRenderList( updateBufferIndex, renderList, renderables[i], viewMatrix, cameraAttachment, isLayer3d, cull );
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
148 inline bool TryReuseCachedRenderers( Layer& layer,
149 RenderList& renderList,
150 RenderableContainer& renderables )
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 ) )
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 )
165 const Render::Renderer& renderer = renderables[index].mRenderer->GetRenderer();
166 checkSumNew += size_t( &renderer );
167 checkSumOld += size_t( &renderList.GetRenderer( index ) );
169 if( checkSumNew == checkSumOld )
171 // tell list to reuse its existing items
172 renderList.ReuseCachedItems();
180 * Function which sorts render items by depth index then by instance
181 * ptrs of shader/texture/geometry.
184 * @return true if left item is greater than right
186 bool CompareItems( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
188 if( lhs.renderItem->GetDepthIndex() == rhs.renderItem->GetDepthIndex() )
190 if( lhs.shader == rhs.shader )
192 if( lhs.textureResourceId == rhs.textureResourceId )
194 return lhs.geometry < rhs.geometry;
196 return lhs.textureResourceId < rhs.textureResourceId;
198 return lhs.shader < rhs.shader;
200 return lhs.renderItem->GetDepthIndex() < rhs.renderItem->GetDepthIndex();
203 * Function which sorts the render items by Z function, then
204 * by instance ptrs of shader/texture/geometry.
207 * @return true if left item is greater than right
209 bool CompareItems3D( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
211 bool lhsIsOpaque = lhs.renderItem->IsOpaque();
212 if( lhsIsOpaque == rhs.renderItem->IsOpaque())
216 //If both RenderItems are opaque, sort using shader, then texture then geometry
217 if( lhs.shader == rhs.shader )
219 if( lhs.textureResourceId == rhs.textureResourceId )
221 return lhs.geometry < rhs.geometry;
223 return lhs.textureResourceId < rhs.textureResourceId;
225 return lhs.shader < rhs.shader;
229 //If both RenderItems are transparent, sort using z,then shader, then texture, then geometry
230 if( Equals(lhs.zValue, rhs.zValue) )
232 if( lhs.shader == rhs.shader )
234 if( lhs.textureResourceId == rhs.textureResourceId )
236 return lhs.geometry < rhs.geometry;
238 return lhs.textureResourceId < rhs.textureResourceId;
240 return lhs.shader < rhs.shader;
242 return lhs.zValue > rhs.zValue;
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)
258 inline void SortRenderItems( BufferIndex bufferIndex, RenderList& renderList, Layer& layer, RendererSortingHelper& sortingHelper )
260 const size_t renderableCount = renderList.Count();
261 // reserve space if needed
262 const unsigned int oldcapacity = sortingHelper.size();
263 if( oldcapacity < renderableCount )
265 sortingHelper.reserve( renderableCount );
266 // add real objects (reserve does not construct objects)
267 sortingHelper.insert( sortingHelper.begin() + oldcapacity,
268 (renderableCount - oldcapacity),
269 RendererWithSortAttributes() );
273 // clear extra elements from helper, does not decrease capability
274 sortingHelper.resize( renderableCount );
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() )
281 for( size_t index = 0; index < renderableCount; ++index )
283 RenderItem& item = renderList.GetItem( index );
285 item.GetRenderer().SetSortAttributes( bufferIndex, sortingHelper[ index ] );
287 // the default sorting function should get inlined here
288 sortingHelper[ index ].zValue = Internal::Layer::ZValue( item.GetModelViewMatrix().GetTranslation3() ) - item.GetDepthIndex();
290 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
291 sortingHelper[ index ].renderItem = &item;
296 const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
297 for( size_t index = 0; index < renderableCount; ++index )
299 RenderItem& item = renderList.GetItem( index );
301 item.GetRenderer().SetSortAttributes( bufferIndex, sortingHelper[ index ] );
302 sortingHelper[ index ].zValue = (*sortFunction)( item.GetModelViewMatrix().GetTranslation3() ) - item.GetDepthIndex();
304 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
305 sortingHelper[ index ].renderItem = &item;
309 if( layer.GetBehavior() == Dali::Layer::LAYER_3D)
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 );
316 // sort the renderers based on DepthIndex
317 std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems );
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 )
325 *renderListIter = sortingHelper[ index ].renderItem;
326 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " sortedList[%d] = %p\n", index, &sortingHelper[ index ].renderItem->GetRenderer() );
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
342 inline void AddColorRenderers( BufferIndex updateBufferIndex,
344 const Matrix& viewMatrix,
345 SceneGraph::CameraAttachment& cameraAttachment,
346 bool stencilRenderablesExist,
347 RenderInstruction& instruction,
348 RendererSortingHelper& sortingHelper,
349 bool tryReuseRenderList,
352 RenderList& renderList = instruction.GetNextFreeRenderList( layer.colorRenderables.Size() );
353 renderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
354 renderList.SetHasColorRenderItems( true );
356 // try to reuse cached renderitems from last time around
357 if( tryReuseRenderList )
359 if( TryReuseCachedRenderers( layer, renderList, layer.colorRenderables ) )
365 AddRenderersToRenderList( updateBufferIndex, renderList, layer.colorRenderables, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
366 SortRenderItems( updateBufferIndex, renderList, layer, sortingHelper );
369 unsigned int flags = 0u;
370 if( stencilRenderablesExist )
372 flags = RenderList::STENCIL_BUFFER_ENABLED;
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)
381 if ( ( renderList.Count() == 1 ) &&
382 ( !renderList.GetRenderer( 0 ).RequiresDepthTest() ) &&
383 ( !renderList.GetItem(0).IsOpaque() ) )
387 else if( !layer.IsDepthTestDisabled())
389 flags |= RenderList::DEPTH_BUFFER_ENABLED;
390 flags |= RenderList::DEPTH_CLEAR;
393 renderList.ClearFlags();
394 renderList.SetFlags( flags );
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
407 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
409 const Matrix& viewMatrix,
410 SceneGraph::CameraAttachment& cameraAttachment,
411 bool stencilRenderablesExist,
412 RenderInstruction& instruction,
413 RendererSortingHelper& sortingHelper,
414 bool tryReuseRenderList,
417 RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.Size() );
418 overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
419 overlayRenderList.SetHasColorRenderItems( false );
422 overlayRenderList.ClearFlags();
423 if(stencilRenderablesExist)
425 overlayRenderList.SetFlags(RenderList::STENCIL_BUFFER_ENABLED);
428 // try to reuse cached renderitems from last time around
429 if( tryReuseRenderList )
431 if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
436 AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
437 SortRenderItems( updateBufferIndex, overlayRenderList, layer, sortingHelper );
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
449 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
451 const Matrix& viewMatrix,
452 SceneGraph::CameraAttachment& cameraAttachment,
453 RenderInstruction& instruction,
454 bool tryReuseRenderList,
457 RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.Size() );
458 stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
459 stencilRenderList.SetHasColorRenderItems( false );
462 stencilRenderList.ClearFlags();
463 stencilRenderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_BUFFER_ENABLED );
465 // try to reuse cached renderitems from last time around
466 if( tryReuseRenderList )
468 if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
473 AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
476 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
477 SortedLayerPointers& sortedLayers,
478 RenderTask& renderTask,
479 RendererSortingHelper& sortingHelper,
481 RenderInstructionContainer& instructions )
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();
489 const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
490 SceneGraph::CameraAttachment& cameraAttachment = renderTask.GetCameraAttachment();
492 const SortedLayersIter endIter = sortedLayers.end();
493 for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
495 Layer& layer = **iter;
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()) );
502 // Ignore stencils if there's nothing to test
503 if( stencilRenderablesExist &&
504 ( colorRenderablesExist || overlayRenderablesExist ) )
506 AddStencilRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, instruction, tryReuseRenderList, cull );
509 if ( colorRenderablesExist )
511 AddColorRenderers( updateBufferIndex,
515 stencilRenderablesExist,
522 if ( overlayRenderablesExist )
524 AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, stencilRenderablesExist,
525 instruction, sortingHelper, tryReuseRenderList, cull );
529 // inform the render instruction that all renderers have been added and this frame is complete
530 instruction.UpdateCompleted();