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/node-attachments/scene-graph-renderable-attachment.h>
27 #include <dali/internal/update/nodes/scene-graph-layer.h>
28 #include <dali/internal/update/manager/sorted-layers.h>
29 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
30 #include <dali/internal/update/rendering/scene-graph-material.h>
31 #include <dali/internal/update/rendering/scene-graph-geometry.h>
32 #include <dali/internal/update/resources/resource-manager-declarations.h>
33 #include <dali/internal/render/common/render-item.h>
34 #include <dali/internal/render/common/render-tracker.h>
35 #include <dali/internal/render/common/render-instruction.h>
36 #include <dali/internal/render/common/render-instruction-container.h>
37 #include <dali/internal/render/shaders/scene-graph-shader.h>
38 #include <dali/internal/render/renderers/render-renderer.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 attachment
61 * @param viewMatrix used to calculate modelview matrix for the item
62 * @param cameraAttachment The camera used to render
63 * @param isLayer3d Whether we are processing a 3D layer or not
65 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
66 RenderList& renderList,
67 RenderableAttachment& renderable,
68 const Matrix& viewMatrix,
69 SceneGraph::CameraAttachment& cameraAttachment,
72 const Node& parentNode = renderable.GetParent();
73 const Matrix& worldMatrix = parentNode.GetWorldMatrix( updateBufferIndex );
75 // Get the next free RenderItem and initialization
76 RenderItem& item = renderList.GetNextFreeItem();
77 const Render::Renderer& renderer = renderable.GetRenderer();
78 item.SetRenderer( const_cast< Render::Renderer* >( &renderer ) );
79 item.SetNode( const_cast< Node* >( &parentNode ) );
81 item.SetIsOpaque( renderable.IsFullyOpaque(updateBufferIndex) );
84 item.SetDepthIndex( renderable.GetDepthIndex() );
88 item.SetDepthIndex( renderable.GetDepthIndex() + static_cast<int>( parentNode.GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER );
91 // save MV matrix onto the item
92 Matrix::Multiply( item.GetModelViewMatrix(), worldMatrix, viewMatrix );
96 * Add a renderer to the list
97 * @param updateBufferIndex to read the model matrix from
98 * @param renderList to add the item to
99 * @param NodeRenderer NodeRenderer pair
100 * @param viewMatrix used to calculate modelview matrix for the item
101 * @param cameraAttachment The camera used to render
102 * @param isLayer3d Whether we are processing a 3D layer or not
104 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
105 RenderList& renderList,
106 NodeRenderer& renderable,
107 const Matrix& viewMatrix,
108 SceneGraph::CameraAttachment& cameraAttachment,
111 // Check for cull against view frustum
112 const Matrix& worldMatrix = renderable.mNode->GetWorldMatrix( updateBufferIndex );
115 if ( renderable.mRenderer->GetMaterial().GetShader()->GeometryHintEnabled( Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY ) )
117 const Vector3& position = worldMatrix.GetTranslation3();
118 const Vector3& scale = renderable.mNode->GetScale( updateBufferIndex );
119 const Vector3& halfSize = renderable.mNode->GetSize( updateBufferIndex ) * scale * 0.5f;
121 // Do a fast sphere check
122 if ( cameraAttachment.CheckSphereInFrustum( updateBufferIndex, position, halfSize.Length() ) )
124 // Check geometry AABB
125 //TODO: Take into account orientation
126 if ( !cameraAttachment.CheckAABBInFrustum( updateBufferIndex, position, halfSize ) )
139 // Get the next free RenderItem
140 RenderItem& item = renderList.GetNextFreeItem();
141 item.SetRenderer( &renderable.mRenderer->GetRenderer() );
142 item.SetNode( renderable.mNode );
143 item.SetIsOpaque( renderable.mRenderer->IsFullyOpaque(updateBufferIndex, *renderable.mNode ) );
147 item.SetDepthIndex( renderable.mRenderer->GetDepthIndex() );
151 item.SetDepthIndex( renderable.mRenderer->GetDepthIndex() + static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER );
154 // save MV matrix onto the item
155 Matrix::Multiply( item.GetModelViewMatrix(), worldMatrix, viewMatrix );
160 * Add all renderers to the list
161 * @param updateBufferIndex to read the model matrix from
162 * @param renderList to add the items to
163 * @param renderable attachments
164 * NodeRendererContainer Node-Renderer pairs
165 * @param viewMatrix used to calculate modelview matrix for the items
166 * @param cameraAttachment The camera used to render
167 * @param isLayer3d Whether we are processing a 3D layer or not
169 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
170 RenderList& renderList,
171 RenderableAttachmentContainer& attachments,
172 NodeRendererContainer& renderers,
173 const Matrix& viewMatrix,
174 SceneGraph::CameraAttachment& cameraAttachment,
177 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
179 // Add renderer for each attachment
180 unsigned int index(0);
181 const RenderableAttachmentIter endIter = attachments.end();
182 for ( RenderableAttachmentIter iter = attachments.begin(); iter != endIter; ++iter )
184 RenderableAttachment& attachment = **iter;
185 AddRendererToRenderList( updateBufferIndex, renderList, attachment, viewMatrix, cameraAttachment, isLayer3d );
187 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " List[%d].renderer = %p\n", index, &(attachment.GetRenderer()));
191 unsigned int rendererCount( renderers.Size() );
192 for( unsigned int i(0); i<rendererCount; ++i )
194 AddRendererToRenderList( updateBufferIndex, renderList, renderers[i], viewMatrix, cameraAttachment, isLayer3d );
199 * Try to reuse cached renderitems from the renderlist
200 * This avoids recalculating the model view matrices in case this part of the scene was static
201 * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
202 * @param layer that is being processed
203 * @param renderList that is cached from frame N-1
204 * @param attachmentList that is being used
206 inline bool TryReuseCachedRenderers( Layer& layer,
207 RenderList& renderList,
208 RenderableAttachmentContainer& attachmentList )
210 bool retValue = false;
211 size_t renderableCount = attachmentList.size();
212 // check that the cached list originates from this layer and that the counts match
213 if( ( renderList.GetSourceLayer() == &layer )&&
214 ( renderList.GetCachedItemCount() == renderableCount ) )
216 // check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong attachments
217 // Attachments are not sorted, but render list is so at this stage renderers may be in different order
218 // therefore we check a combined sum of all renderer addresses
219 size_t checkSumNew = 0;
220 size_t checkSumOld = 0;
221 for( size_t index = 0; index < renderableCount; ++index )
223 RenderableAttachment* attachment = attachmentList[ index ];
224 const Render::Renderer& renderer = attachment->GetRenderer();
225 checkSumNew += size_t( &renderer );
226 checkSumOld += size_t( &renderList.GetRenderer( index ) );
228 if( checkSumNew == checkSumOld )
230 // tell list to reuse its existing items
231 renderList.ReuseCachedItems();
240 * Function which sorts render items by depth index then by instance
241 * ptrs of shader/geometry/material.
244 * @return true if left item is greater than right
246 bool CompareItems( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
248 // @todo MESH_REWORK Consider replacing all these sortAttributes with a single long int that
249 // encapsulates the same data (e.g. the middle-order bits of the ptrs)
250 if( lhs.renderItem->GetDepthIndex() == rhs.renderItem->GetDepthIndex() )
252 if( lhs.shader == rhs.shader )
254 if( lhs.textureResourceId == rhs.textureResourceId )
256 return lhs.geometry < rhs.geometry;
258 return lhs.textureResourceId < rhs.textureResourceId;
260 return lhs.shader < rhs.shader;
262 return lhs.renderItem->GetDepthIndex() < rhs.renderItem->GetDepthIndex();
265 * Function which sorts the render items by Z function, then
266 * by instance ptrs of shader/geometry/material.
269 * @return true if left item is greater than right
271 bool CompareItems3D( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
273 bool lhsIsOpaque = lhs.renderItem->IsOpaque();
274 if( lhsIsOpaque == rhs.renderItem->IsOpaque())
278 //If both RenderItems are opaque, sort using shader, then material then geometry
279 if( lhs.shader == rhs.shader )
281 if( lhs.textureResourceId == rhs.textureResourceId )
283 return lhs.geometry < rhs.geometry;
285 return lhs.textureResourceId < rhs.textureResourceId;
287 return lhs.shader < rhs.shader;
291 //If both RenderItems are transparent, sort using z,then shader, then material, then geometry
292 if( Equals(lhs.zValue, rhs.zValue) )
294 if( lhs.shader == rhs.shader )
296 if( lhs.textureResourceId == rhs.textureResourceId )
298 return lhs.geometry < rhs.geometry;
300 return lhs.textureResourceId < rhs.textureResourceId;
302 return lhs.shader < rhs.shader;
304 return lhs.zValue > rhs.zValue;
314 * Sort color render items
315 * @param colorRenderList to sort
316 * @param layer where the renderers are from
317 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
319 inline void SortColorRenderItems( BufferIndex bufferIndex, RenderList& renderList, Layer& layer, RendererSortingHelper& sortingHelper )
321 const size_t renderableCount = renderList.Count();
322 // reserve space if needed
323 const unsigned int oldcapacity = sortingHelper.size();
324 if( oldcapacity < renderableCount )
326 sortingHelper.reserve( renderableCount );
327 // add real objects (reserve does not construct objects)
328 sortingHelper.insert( sortingHelper.begin() + oldcapacity,
329 (renderableCount - oldcapacity),
330 RendererWithSortAttributes() );
334 // clear extra elements from helper, does not decrease capability
335 sortingHelper.resize( renderableCount );
338 // calculate the sorting value, once per item by calling the layers sort function
339 // Using an if and two for-loops rather than if inside for as its better for branch prediction
340 if( layer.UsesDefaultSortFunction() )
342 for( size_t index = 0; index < renderableCount; ++index )
344 RenderItem& item = renderList.GetItem( index );
346 item.GetRenderer().SetSortAttributes( bufferIndex, sortingHelper[ index ] );
348 // the default sorting function should get inlined here
349 sortingHelper[ index ].zValue = Internal::Layer::ZValue( item.GetModelViewMatrix().GetTranslation3() ) - item.GetDepthIndex();
351 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
352 sortingHelper[ index ].renderItem = &item;
357 const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
358 for( size_t index = 0; index < renderableCount; ++index )
360 RenderItem& item = renderList.GetItem( index );
362 item.GetRenderer().SetSortAttributes( bufferIndex, sortingHelper[ index ] );
363 sortingHelper[ index ].zValue = (*sortFunction)( item.GetModelViewMatrix().GetTranslation3() ) - item.GetDepthIndex();
365 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
366 sortingHelper[ index ].renderItem = &item;
370 if( layer.GetBehavior() == Dali::Layer::LAYER_3D)
372 // sort the renderers back to front, Z Axis point from near plane to far plane
373 std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems3D );
377 // sort the renderers based on DepthIndex
378 std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems );
381 // reorder/repopulate the renderitems in renderlist to correct order based on sortinghelper
382 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Transparent List:\n");
383 RenderItemContainer::Iterator renderListIter = renderList.GetContainer().Begin();
384 for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter )
386 *renderListIter = sortingHelper[ index ].renderItem;
387 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " sortedList[%d] = %p\n", index, &sortingHelper[ index ].renderItem->GetRenderer() );
392 * Add color renderers from the layer onto the next free render list
393 * @param updateBufferIndex to use
394 * @param layer to get the renderers from
395 * @param viewmatrix for the camera from rendertask
396 * @param cameraAttachment to use the view frustum
397 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
398 * @param instruction to fill in
399 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
400 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
402 inline void AddColorRenderers( BufferIndex updateBufferIndex,
404 const Matrix& viewMatrix,
405 SceneGraph::CameraAttachment& cameraAttachment,
406 bool stencilRenderablesExist,
407 RenderInstruction& instruction,
408 RendererSortingHelper& sortingHelper,
409 bool tryReuseRenderList )
411 RenderList& renderList = instruction.GetNextFreeRenderList( layer.colorRenderables.size() );
412 renderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
413 renderList.SetHasColorRenderItems( true );
415 // try to reuse cached renderitems from last time around
416 if( tryReuseRenderList )
418 if( TryReuseCachedRenderers( layer, renderList, layer.colorRenderables ) )
424 AddRenderersToRenderList( updateBufferIndex, renderList, layer.colorRenderables, layer.colorRenderers, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D );
425 SortColorRenderItems( updateBufferIndex, renderList, layer, sortingHelper );
428 unsigned int flags = 0u;
429 if( stencilRenderablesExist )
431 flags = RenderList::STENCIL_BUFFER_ENABLED;
434 // Special optimization if depth test is disabled or if only one opaque rendered in the layer (for example background image)
435 // and this renderer does not need depth test against itself (e.g. mesh)
436 // and if this layer has got exactly one opaque renderer
437 // and this renderer is not interested in depth testing
438 // (i.e. is an image and not a mesh)
440 if ( ( renderList.Count() == 1 ) &&
441 ( !renderList.GetRenderer( 0 ).RequiresDepthTest() ) &&
442 ( !renderList.GetItem(0).IsOpaque() ) )
446 else if( !layer.IsDepthTestDisabled())
448 flags |= RenderList::DEPTH_BUFFER_ENABLED;
449 flags |= RenderList::DEPTH_CLEAR;
452 renderList.ClearFlags();
453 renderList.SetFlags( flags );
457 * Add overlay renderers from the layer onto the next free render list
458 * @param updateBufferIndex to use
459 * @param layer to get the renderers from
460 * @param viewmatrix for the camera from rendertask
461 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
462 * @param instruction to fill in
463 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
465 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
467 const Matrix& viewMatrix,
468 SceneGraph::CameraAttachment& cameraAttachment,
469 bool stencilRenderablesExist,
470 RenderInstruction& instruction,
471 bool tryReuseRenderList )
473 RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.size() );
474 overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
475 overlayRenderList.SetHasColorRenderItems( false );
478 overlayRenderList.ClearFlags();
479 if(stencilRenderablesExist)
481 overlayRenderList.SetFlags(RenderList::STENCIL_BUFFER_ENABLED);
484 // try to reuse cached renderitems from last time around
485 if( tryReuseRenderList )
487 if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
492 AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, layer.overlayRenderers, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D );
496 * Add stencil renderers from the layer onto the next free render list
497 * @param updateBufferIndex to use
498 * @param layer to get the renderers from
499 * @param viewmatrix for the camera from rendertask
500 * @param instruction to fill in
501 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
503 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
505 const Matrix& viewMatrix,
506 SceneGraph::CameraAttachment& cameraAttachment,
507 RenderInstruction& instruction,
508 bool tryReuseRenderList )
510 RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.size() );
511 stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
512 stencilRenderList.SetHasColorRenderItems( false );
515 stencilRenderList.ClearFlags();
516 stencilRenderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_BUFFER_ENABLED );
518 // try to reuse cached renderitems from last time around
519 if( tryReuseRenderList )
521 if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
526 AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, layer.stencilRenderers, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D );
530 * Prepare a single render instruction
531 * @param updateBufferIndex to use
532 * @param sortedLayers to prepare the instruction from
533 * @param renderTask to get the view matrix
534 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
535 * @param renderTracker An optional render tracker object
536 * @param instructions container
538 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
539 SortedLayerPointers& sortedLayers,
540 RenderTask& renderTask,
541 RendererSortingHelper& sortingHelper,
542 RenderTracker* renderTracker,
543 RenderInstructionContainer& instructions )
545 // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
546 // then populate with instructions.
547 RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
548 renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
549 bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
551 const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
552 SceneGraph::CameraAttachment& cameraAttachment = renderTask.GetCameraAttachment();
554 const SortedLayersIter endIter = sortedLayers.end();
555 for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
557 Layer& layer = **iter;
559 const bool stencilRenderablesExist( !layer.stencilRenderables.empty() || !layer.stencilRenderers.Empty() );
560 const bool colorRenderablesExist( !layer.colorRenderables.empty() || !layer.colorRenderers.Empty() );
561 const bool overlayRenderablesExist( !layer.overlayRenderables.empty() || !layer.overlayRenderers.Empty() );
562 const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers(renderTask.GetCamera()) );
564 // Ignore stencils if there's nothing to test
565 if( stencilRenderablesExist &&
566 ( colorRenderablesExist || overlayRenderablesExist ) )
568 AddStencilRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, instruction, tryReuseRenderList );
571 if ( colorRenderablesExist )
573 AddColorRenderers( updateBufferIndex,
577 stencilRenderablesExist,
580 tryReuseRenderList );
583 if ( overlayRenderablesExist )
585 AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, stencilRenderablesExist,
586 instruction, tryReuseRenderList );
590 instruction.mRenderTracker = renderTracker;
591 instruction.mCullMode = renderTask.GetCullMode();
593 // inform the render instruction that all renderers have been added and this frame is complete
594 instruction.UpdateCompleted();