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/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>
40 #if defined(DEBUG_ENABLED)
41 Debug::Filter* gRenderListLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_LISTS");
55 * Add a renderer to the list
56 * @param updateBufferIndex to read the model matrix from
57 * @param renderList to add the item to
58 * @param renderable Node-Renderer pair
59 * @param viewMatrix used to calculate modelview matrix for the item
60 * @param cameraAttachment The camera used to render
61 * @param isLayer3d Whether we are processing a 3D layer or not
62 * @param cull Whether frustum culling is enabled or not
64 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
65 RenderList& renderList,
66 Renderable& renderable,
67 const Matrix& viewMatrix,
68 SceneGraph::CameraAttachment& cameraAttachment,
74 const Matrix& worldMatrix = renderable.mNode->GetWorldMatrix( updateBufferIndex );
75 const Vector3& size = renderable.mNode->GetSize( updateBufferIndex );
76 if ( cull && renderable.mRenderer->GetShader().GeometryHintEnabled( Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY ) )
78 const Vector3& position = worldMatrix.GetTranslation3();
79 float radius( size.Length() * 0.5f );
81 inside = (radius > Math::MACHINE_EPSILON_1000) &&
82 (cameraAttachment.CheckSphereInFrustum( updateBufferIndex, position, radius ) );
87 Renderer::Opacity opacity = renderable.mRenderer->GetOpacity( updateBufferIndex, *renderable.mNode );
88 if( opacity != Renderer::TRANSPARENT )
90 // Get the next free RenderItem
91 RenderItem& item = renderList.GetNextFreeItem();
92 item.SetRenderer( &renderable.mRenderer->GetRenderer() );
93 item.SetNode( renderable.mNode );
94 item.SetIsOpaque( opacity == Renderer::OPAQUE );
98 item.SetDepthIndex( renderable.mRenderer->GetDepthIndex() );
102 item.SetDepthIndex( renderable.mRenderer->GetDepthIndex() + static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER );
104 // save MV matrix onto the item
105 Matrix::Multiply( item.GetModelViewMatrix(), worldMatrix, viewMatrix );
106 item.SetSize( size );
112 * Add all renderers to the list
113 * @param updateBufferIndex to read the model matrix from
114 * @param renderList to add the items to
115 * @param renderable attachments
116 * NodeRendererContainer Node-Renderer pairs
117 * @param viewMatrix used to calculate modelview matrix for the items
118 * @param cameraAttachment The camera used to render
119 * @param isLayer3d Whether we are processing a 3D layer or not
120 * @param cull Whether frustum culling is enabled or not
122 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
123 RenderList& renderList,
124 RenderableContainer& renderables,
125 const Matrix& viewMatrix,
126 SceneGraph::CameraAttachment& cameraAttachment,
130 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
132 unsigned int rendererCount( renderables.Size() );
133 for( unsigned int i(0); i<rendererCount; ++i )
135 AddRendererToRenderList( updateBufferIndex, renderList, renderables[i], viewMatrix, cameraAttachment, isLayer3d, cull );
140 * Try to reuse cached renderitems from the renderlist
141 * This avoids recalculating the model view matrices in case this part of the scene was static
142 * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
143 * @param layer that is being processed
144 * @param renderList that is cached from frame N-1
145 * @param renderables list of renderables
147 inline bool TryReuseCachedRenderers( Layer& layer,
148 RenderList& renderList,
149 RenderableContainer& renderables )
151 bool retValue = false;
152 size_t renderableCount = renderables.Size();
153 // check that the cached list originates from this layer and that the counts match
154 if( ( renderList.GetSourceLayer() == &layer )&&
155 ( renderList.GetCachedItemCount() == renderableCount ) )
157 // check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong attachments
158 // Attachments are not sorted, but render list is so at this stage renderers may be in different order
159 // therefore we check a combined sum of all renderer addresses
160 size_t checkSumNew = 0;
161 size_t checkSumOld = 0;
162 for( size_t index = 0; index < renderableCount; ++index )
164 const Render::Renderer& renderer = renderables[index].mRenderer->GetRenderer();
165 checkSumNew += size_t( &renderer );
166 checkSumOld += size_t( &renderList.GetRenderer( index ) );
168 if( checkSumNew == checkSumOld )
170 // tell list to reuse its existing items
171 renderList.ReuseCachedItems();
179 * Function which sorts render items by depth index then by instance
180 * ptrs of shader/texture/geometry.
183 * @return true if left item is greater than right
185 bool CompareItems( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
187 if( lhs.renderItem->GetDepthIndex() == rhs.renderItem->GetDepthIndex() )
189 if( lhs.shader == rhs.shader )
191 if( lhs.textureResourceId == rhs.textureResourceId )
193 return lhs.geometry < rhs.geometry;
195 return lhs.textureResourceId < rhs.textureResourceId;
197 return lhs.shader < rhs.shader;
199 return lhs.renderItem->GetDepthIndex() < rhs.renderItem->GetDepthIndex();
202 * Function which sorts the render items by Z function, then
203 * by instance ptrs of shader/texture/geometry.
206 * @return true if left item is greater than right
208 bool CompareItems3D( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
210 bool lhsIsOpaque = lhs.renderItem->IsOpaque();
211 if( lhsIsOpaque == rhs.renderItem->IsOpaque())
215 //If both RenderItems are opaque, sort using shader, then texture then geometry
216 if( lhs.shader == rhs.shader )
218 if( lhs.textureResourceId == rhs.textureResourceId )
220 return lhs.geometry < rhs.geometry;
222 return lhs.textureResourceId < rhs.textureResourceId;
224 return lhs.shader < rhs.shader;
228 //If both RenderItems are transparent, sort using z,then shader, then texture, then geometry
229 if( Equals(lhs.zValue, rhs.zValue) )
231 if( lhs.shader == rhs.shader )
233 if( lhs.textureResourceId == rhs.textureResourceId )
235 return lhs.geometry < rhs.geometry;
237 return lhs.textureResourceId < rhs.textureResourceId;
239 return lhs.shader < rhs.shader;
241 return lhs.zValue > rhs.zValue;
252 * @param bufferIndex The buffer to read from
253 * @param renderList to sort
254 * @param layer where the renderers are from
255 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
257 inline void SortRenderItems( BufferIndex bufferIndex, RenderList& renderList, Layer& layer, RendererSortingHelper& sortingHelper )
259 const size_t renderableCount = renderList.Count();
260 // reserve space if needed
261 const unsigned int oldcapacity = sortingHelper.size();
262 if( oldcapacity < renderableCount )
264 sortingHelper.reserve( renderableCount );
265 // add real objects (reserve does not construct objects)
266 sortingHelper.insert( sortingHelper.begin() + oldcapacity,
267 (renderableCount - oldcapacity),
268 RendererWithSortAttributes() );
272 // clear extra elements from helper, does not decrease capability
273 sortingHelper.resize( renderableCount );
276 // calculate the sorting value, once per item by calling the layers sort function
277 // Using an if and two for-loops rather than if inside for as its better for branch prediction
278 if( layer.UsesDefaultSortFunction() )
280 for( size_t index = 0; index < renderableCount; ++index )
282 RenderItem& item = renderList.GetItem( index );
284 item.GetRenderer().SetSortAttributes( bufferIndex, sortingHelper[ index ] );
286 // the default sorting function should get inlined here
287 sortingHelper[ index ].zValue = Internal::Layer::ZValue( item.GetModelViewMatrix().GetTranslation3() ) - item.GetDepthIndex();
289 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
290 sortingHelper[ index ].renderItem = &item;
295 const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
296 for( size_t index = 0; index < renderableCount; ++index )
298 RenderItem& item = renderList.GetItem( index );
300 item.GetRenderer().SetSortAttributes( bufferIndex, sortingHelper[ index ] );
301 sortingHelper[ index ].zValue = (*sortFunction)( item.GetModelViewMatrix().GetTranslation3() ) - item.GetDepthIndex();
303 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
304 sortingHelper[ index ].renderItem = &item;
308 if( layer.GetBehavior() == Dali::Layer::LAYER_3D)
310 // sort the renderers back to front, Z Axis point from near plane to far plane
311 std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems3D );
315 // sort the renderers based on DepthIndex
316 std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems );
319 // reorder/repopulate the renderitems in renderlist to correct order based on sortinghelper
320 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Transparent List:\n");
321 RenderItemContainer::Iterator renderListIter = renderList.GetContainer().Begin();
322 for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter )
324 *renderListIter = sortingHelper[ index ].renderItem;
325 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " sortedList[%d] = %p\n", index, &sortingHelper[ index ].renderItem->GetRenderer() );
330 * Add color renderers from the layer onto the next free render list
331 * @param updateBufferIndex to use
332 * @param layer to get the renderers from
333 * @param viewmatrix for the camera from rendertask
334 * @param cameraAttachment to use the view frustum
335 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
336 * @param instruction to fill in
337 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
338 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
339 * @param cull Whether frustum culling is enabled or not
341 inline void AddColorRenderers( BufferIndex updateBufferIndex,
343 const Matrix& viewMatrix,
344 SceneGraph::CameraAttachment& cameraAttachment,
345 bool stencilRenderablesExist,
346 RenderInstruction& instruction,
347 RendererSortingHelper& sortingHelper,
348 bool tryReuseRenderList,
351 RenderList& renderList = instruction.GetNextFreeRenderList( layer.colorRenderables.Size() );
352 renderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
353 renderList.SetHasColorRenderItems( true );
355 // try to reuse cached renderitems from last time around
356 if( tryReuseRenderList )
358 if( TryReuseCachedRenderers( layer, renderList, layer.colorRenderables ) )
364 AddRenderersToRenderList( updateBufferIndex, renderList, layer.colorRenderables, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
365 SortRenderItems( updateBufferIndex, renderList, layer, sortingHelper );
368 unsigned int flags = 0u;
369 if( stencilRenderablesExist )
371 flags = RenderList::STENCIL_BUFFER_ENABLED;
374 // Special optimization if depth test is disabled or if only one opaque rendered in the layer (for example background image)
375 // and this renderer does not need depth test against itself (e.g. mesh)
376 // and if this layer has got exactly one opaque renderer
377 // and this renderer is not interested in depth testing
378 // (i.e. is an image and not a mesh)
380 if ( ( renderList.Count() == 1 ) &&
381 ( !renderList.GetRenderer( 0 ).RequiresDepthTest() ) &&
382 ( !renderList.GetItem(0).IsOpaque() ) )
386 else if( !layer.IsDepthTestDisabled())
388 flags |= RenderList::DEPTH_BUFFER_ENABLED;
389 flags |= RenderList::DEPTH_CLEAR;
392 renderList.ClearFlags();
393 renderList.SetFlags( flags );
397 * Add overlay renderers from the layer onto the next free render list
398 * @param updateBufferIndex to use
399 * @param layer to get the renderers from
400 * @param viewmatrix for the camera from rendertask
401 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
402 * @param instruction to fill in
403 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
404 * @param cull Whether frustum culling is enabled or not
406 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
408 const Matrix& viewMatrix,
409 SceneGraph::CameraAttachment& cameraAttachment,
410 bool stencilRenderablesExist,
411 RenderInstruction& instruction,
412 RendererSortingHelper& sortingHelper,
413 bool tryReuseRenderList,
416 RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.Size() );
417 overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
418 overlayRenderList.SetHasColorRenderItems( false );
421 overlayRenderList.ClearFlags();
422 if(stencilRenderablesExist)
424 overlayRenderList.SetFlags(RenderList::STENCIL_BUFFER_ENABLED);
427 // try to reuse cached renderitems from last time around
428 if( tryReuseRenderList )
430 if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
435 AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
436 SortRenderItems( updateBufferIndex, overlayRenderList, layer, sortingHelper );
440 * Add stencil renderers from the layer onto the next free render list
441 * @param updateBufferIndex to use
442 * @param layer to get the renderers from
443 * @param viewmatrix for the camera from rendertask
444 * @param instruction to fill in
445 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
446 * @param cull Whether frustum culling is enabled or not
448 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
450 const Matrix& viewMatrix,
451 SceneGraph::CameraAttachment& cameraAttachment,
452 RenderInstruction& instruction,
453 bool tryReuseRenderList,
456 RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.Size() );
457 stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
458 stencilRenderList.SetHasColorRenderItems( false );
461 stencilRenderList.ClearFlags();
462 stencilRenderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_BUFFER_ENABLED );
464 // try to reuse cached renderitems from last time around
465 if( tryReuseRenderList )
467 if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
472 AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix, cameraAttachment, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
475 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
476 SortedLayerPointers& sortedLayers,
477 RenderTask& renderTask,
478 RendererSortingHelper& sortingHelper,
480 RenderInstructionContainer& instructions )
482 // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
483 // then populate with instructions.
484 RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
485 renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
486 bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
488 const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
489 SceneGraph::CameraAttachment& cameraAttachment = renderTask.GetCameraAttachment();
491 const SortedLayersIter endIter = sortedLayers.end();
492 for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
494 Layer& layer = **iter;
496 const bool stencilRenderablesExist( !layer.stencilRenderables.Empty() );
497 const bool colorRenderablesExist( !layer.colorRenderables.Empty() );
498 const bool overlayRenderablesExist( !layer.overlayRenderables.Empty() );
499 const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers(renderTask.GetCamera()) );
501 // Ignore stencils if there's nothing to test
502 if( stencilRenderablesExist &&
503 ( colorRenderablesExist || overlayRenderablesExist ) )
505 AddStencilRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, instruction, tryReuseRenderList, cull );
508 if ( colorRenderablesExist )
510 AddColorRenderers( updateBufferIndex,
514 stencilRenderablesExist,
521 if ( overlayRenderablesExist )
523 AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, cameraAttachment, stencilRenderablesExist,
524 instruction, sortingHelper, tryReuseRenderList, cull );
528 // inform the render instruction that all renderers have been added and this frame is complete
529 instruction.UpdateCompleted();