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/integration-api/debug.h>
23 #include <dali/internal/event/actors/layer-impl.h> // for the default sorting function
24 #include <dali/internal/update/resources/resource-manager-declarations.h>
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/node-attachments/scene-graph-renderable-attachment.h>
28 #include <dali/internal/update/nodes/scene-graph-layer.h>
29 #include <dali/internal/render/common/render-item.h>
30 #include <dali/internal/render/common/render-tracker.h>
31 #include <dali/internal/render/common/render-instruction.h>
32 #include <dali/internal/render/common/render-instruction-container.h>
33 #include <dali/internal/render/renderers/scene-graph-renderer.h>
37 #if defined(DEBUG_ENABLED)
38 Debug::Filter* gRenderListLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_LISTS");
52 * Set flags for opaque renderlist
53 * @param renderList to set the flags to
54 * @param transparentRenderersExist is true if there is transparent renderers in this layer
55 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
56 * @param depthTestDisabled whether depth test is disabled.
58 inline void SetOpaqueRenderFlags( RenderList& renderList, bool transparentRenderersExist, bool stencilRenderablesExist, bool depthTestDisabled )
60 //@todo MESH_REWORK Move RequiresDepthTest from render thread object to update thread object
62 renderList.SetInterleave(transparentRenderersExist);
64 // Special optimization if depth test is disabled or if only one opaque rendered in the layer (for example background image)
65 // and this renderer does not need depth test against itself (e.g. mesh)
66 // and if this layer has got exactly one opaque renderer
67 // and this renderer is not interested in depth testing
68 // (i.e. is an image and not a mesh)
69 if ( ( renderList.Count() == 1 ) &&
70 ( !transparentRenderersExist ) &&
71 ( !renderList.GetRenderer( 0 )->RequiresDepthTest() ) )
73 // no need to enable depth test or clear depth buffer
74 // if there's something transparent already rendered by previous layers,
75 // this opaque renderer will correctly draw on top of them since no depth test
76 renderList.ClearFlags();
77 renderList.SetInterleave(false);
79 else if( depthTestDisabled )
81 renderList.ClearFlags();
85 // Prepare for rendering multiple opaque objects
86 unsigned int flags = RenderList::DEPTH_BUFFER_ENABLED | RenderList::DEPTH_WRITE | RenderList::DEPTH_CLEAR; // clear depth buffer, draw over the previously rendered layers;
88 renderList.ClearFlags();
89 renderList.SetFlags(flags);
92 if( stencilRenderablesExist )
94 renderList.SetFlags( RenderList::STENCIL_BUFFER_ENABLED );
99 * Set the transparent flags on the renderlist
100 * @param renderList to set the flags on
101 * @param opaqueRenderersExist is true if there are opaque renderers on this layer
102 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
103 * @param depthTestDisabled whether depth test is disabled.
105 inline void SetTransparentRenderFlags( RenderList& renderList, bool opaqueRenderersExist, bool stencilRenderablesExist, bool depthTestDisabled )
107 renderList.ClearFlags();
108 // We don't need to write to the depth buffer, as transparent objects
109 // don't obscure each other.
111 renderList.SetInterleave(opaqueRenderersExist);
112 if ( opaqueRenderersExist && !depthTestDisabled )
114 // If there are a mix of opaque and transparent objects, the transparent
115 // objects should be rendered with depth test on to avoid background objects
116 // appearing in front of opaque foreground objects.
117 renderList.SetFlags( RenderList::DEPTH_BUFFER_ENABLED );
120 if( stencilRenderablesExist )
122 renderList.SetFlags( RenderList::STENCIL_BUFFER_ENABLED );
128 * Set flags for overlay renderlist
129 * @param renderList to set the flags for
130 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
132 inline void SetOverlayRenderFlags( RenderList& renderList, bool stencilRenderablesExist )
134 if(stencilRenderablesExist)
136 renderList.SetFlags(RenderList::STENCIL_BUFFER_ENABLED);
141 * Set flags for stencil renderlist
142 * @param renderList to set the flags for
144 inline void SetStencilRenderFlags( RenderList& renderList )
146 renderList.ClearFlags();
147 renderList.SetFlags(RenderList::STENCIL_CLEAR | RenderList::STENCIL_WRITE | RenderList::STENCIL_BUFFER_ENABLED );
151 * Add a renderer to the list
152 * @param updateBufferIndex to read the model matrix from
153 * @param renderList to add the item to
154 * @param renderable attachment
155 * @param viewMatrix used to calculate modelview matrix for the item
157 inline void AddRendererToRenderList( BufferIndex updateBufferIndex,
158 RenderList& renderList,
159 RenderableAttachment& renderable,
160 const Matrix& viewMatrix )
162 const Renderer& renderer = renderable.GetRenderer();
164 // Get the next free RenderItem
165 RenderItem& item = renderList.GetNextFreeItem();
166 item.SetRenderer( const_cast< Renderer* >( &renderer ) );
167 item.SetDepthIndex( renderable.GetDepthIndex(updateBufferIndex) );
169 // calculate MV matrix onto the item
170 Matrix& modelViewMatrix = item.GetModelViewMatrix();
171 const Matrix& worldMatrix = renderable.GetParent().GetWorldMatrix( updateBufferIndex );
173 Matrix::Multiply( modelViewMatrix, worldMatrix, viewMatrix );
177 * Add all renderers to the list
178 * @param updateBufferIndex to read the model matrix from
179 * @param renderList to add the items to
180 * @param renderable attachments
181 * @param viewMatrix used to calculate modelview matrix for the items
183 inline void AddRenderersToRenderList( BufferIndex updateBufferIndex,
184 RenderList& renderList,
185 RenderableAttachmentContainer& attachments,
186 const Matrix& viewMatrix )
188 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "AddRenderersToRenderList()\n");
190 // Add renderer for each attachment
192 const RenderableAttachmentIter endIter = attachments.end();
193 for ( RenderableAttachmentIter iter = attachments.begin(); iter != endIter; ++iter )
195 RenderableAttachment& attachment = **iter;
196 AddRendererToRenderList( updateBufferIndex, renderList, attachment, viewMatrix );
198 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " List[%d].renderer = %p\n", index, &(attachment.GetRenderer()));
204 * Try to reuse cached renderitems from the renderlist
205 * This avoids recalculating the model view matrices in case this part of the scene was static
206 * An example case is a toolbar layer that rarely changes or a popup on top of the rest of the stage
207 * @param layer that is being processed
208 * @param renderList that is cached from frame N-1
209 * @param attachmentList that is being used
211 inline bool TryReuseCachedRenderers( Layer& layer,
212 RenderList& renderList,
213 RenderableAttachmentContainer& attachmentList )
215 bool retValue = false;
216 size_t renderableCount = attachmentList.size();
217 // check that the cached list originates from this layer and that the counts match
218 if( ( renderList.GetSourceLayer() == &layer )&&
219 ( renderList.GetCachedItemCount() == renderableCount ) )
221 // check that all the same renderers are there. This gives us additional security in avoiding rendering the wrong attachments
222 // Attachments are not sorted, but render list is so at this stage renderers may be in different order
223 // therefore we check a combined sum of all renderer addresses
224 size_t checkSumNew = 0;
225 size_t checkSumOld = 0;
226 for( size_t index = 0; index < renderableCount; ++index )
228 RenderableAttachment* attachment = attachmentList[ index ];
229 const Renderer& renderer = attachment->GetRenderer();
230 checkSumNew += size_t( &renderer );
231 checkSumOld += size_t( renderList.GetRenderer( index ) );
233 if( checkSumNew == checkSumOld )
235 // tell list to reuse its existing items
236 renderList.ReuseCachedItems();
245 * Function which sorts render items by depth index then by instance
246 * ptrs of shader/geometry/material.
249 * @return true if left item is greater than right
251 bool CompareItems( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
253 // @todo MESH_REWORK Consider replacing all these sortAttributes with a single long int that
254 // encapsulates the same data (e.g. the middle-order bits of the ptrs)
255 if( lhs.renderItem->GetDepthIndex() == rhs.renderItem->GetDepthIndex() )
257 if( lhs.shader == rhs.shader )
259 if( lhs.material == rhs.material )
261 return lhs.geometry < lhs.geometry;
263 return lhs.material < rhs.material;
265 return lhs.shader < rhs.shader;;
267 return lhs.renderItem->GetDepthIndex() < rhs.renderItem->GetDepthIndex();
270 * Function which sorts the render items by depth index then by Z function,
271 * then by instance ptrs of shader/geometry/material.
274 * @return true if left item is greater than right
276 bool CompareItemsWithZValue( const RendererWithSortAttributes& lhs, const RendererWithSortAttributes& rhs )
278 // @todo MESH_REWORK Consider replacing all these sortAttributes with a single long int that
279 // encapsulates the same data (e.g. the middle-order bits of the ptrs)
281 if( lhs.renderItem->GetDepthIndex() == rhs.renderItem->GetDepthIndex() )
283 if( Equals(lhs.zValue, rhs.zValue) )
285 if( lhs.shader == rhs.shader )
287 if( lhs.material == rhs.material )
289 return lhs.geometry < lhs.geometry;
291 return lhs.material < rhs.material;
293 return lhs.shader < rhs.shader;;
295 return lhs.zValue > rhs.zValue;
297 return lhs.renderItem->GetDepthIndex() < rhs.renderItem->GetDepthIndex();
300 inline void SortOpaqueRenderItems(
301 BufferIndex bufferIndex,
302 RenderList& opaqueRenderList,
304 RenderItemSortingHelper& sortingHelper )
306 const size_t renderableCount = opaqueRenderList.Count();
307 // reserve space if needed
308 const unsigned int oldcapacity = sortingHelper.size();
309 if( oldcapacity < renderableCount )
311 sortingHelper.reserve( renderableCount );
312 // add real objects (reserve does not construct objects)
313 sortingHelper.insert( sortingHelper.begin() + oldcapacity,
314 (renderableCount - oldcapacity),
315 RendererWithSortAttributes() );
319 // clear extra elements from helper, does not decrease capability
320 sortingHelper.resize( renderableCount );
323 for( size_t index = 0; index < renderableCount; ++index )
325 RenderItem& item = opaqueRenderList.GetItem( index );
327 //@todo MESH_REWORK After merge of RenderableAttachment and RendererAttachment, should instead store the renderable ptr and get the fields directly
328 layer.opaqueRenderables[index]->SetSortAttributes( bufferIndex, sortingHelper[ index ] );
330 sortingHelper[ index ].zValue = 0;
331 sortingHelper[ index ].renderItem = &item;
334 // Sort the renderers by depth index, then by instance
335 std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItems );
337 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Opaque List:\n");
339 // Repopulate the render items in the render list based on the sorting helper
340 RenderItemContainer::Iterator renderListIter = opaqueRenderList.GetContainer().Begin();
341 for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter )
343 *renderListIter = sortingHelper[ index ].renderItem;
344 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " sortedList[%d] = %p\n", sortingHelper[ index ].renderItem->GetRenderer() );
349 * Add opaque renderers from the layer onto the next free render list
350 * @param updateBufferIndex to use
351 * @param layer to get the renderers from
352 * @param viewmatrix for the camera from rendertask
353 * @param transparentRenderersExist is true if there is transparent renderers in this layer
354 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
355 * @param instruction to fill in
356 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
358 inline void AddOpaqueRenderers( BufferIndex updateBufferIndex,
360 const Matrix& viewMatrix,
361 bool transparentRenderablesExist,
362 bool stencilRenderablesExist,
363 RenderInstruction& instruction,
364 RendererSortingHelper& sortingHelper,
365 bool tryReuseRenderList )
367 const size_t renderableCount = layer.opaqueRenderables.size();
368 RenderList& opaqueRenderList = instruction.GetNextFreeRenderList( layer.opaqueRenderables.size() );
369 opaqueRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
371 // try to reuse cached renderitems from last time around
372 if( tryReuseRenderList )
374 if( TryReuseCachedRenderers( layer, opaqueRenderList, layer.opaqueRenderables ) )
376 // reset the flags as other layers might have changed
377 // opaque flags can only be set after renderers are added
378 SetOpaqueRenderFlags(opaqueRenderList, transparentRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
382 AddRenderersToRenderList( updateBufferIndex, opaqueRenderList, layer.opaqueRenderables, viewMatrix );
384 // opaque flags can only be set after renderers are added
385 SetOpaqueRenderFlags(opaqueRenderList, transparentRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
387 // sorting is only needed if more than 1 item
388 if( renderableCount > 1 )
390 SortOpaqueRenderItems( updateBufferIndex, opaqueRenderList, layer, sortingHelper.opaque );
396 * Sort transparent render items
397 * @param transparentRenderList to sort
398 * @param layer where the renderers are from
399 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
401 inline void SortTransparentRenderItems( BufferIndex bufferIndex, RenderList& transparentRenderList, Layer& layer, RenderItemSortingHelper& sortingHelper )
403 const size_t renderableCount = transparentRenderList.Count();
404 // reserve space if needed
405 const unsigned int oldcapacity = sortingHelper.size();
406 if( oldcapacity < renderableCount )
408 sortingHelper.reserve( renderableCount );
409 // add real objects (reserve does not construct objects)
410 sortingHelper.insert( sortingHelper.begin() + oldcapacity,
411 (renderableCount - oldcapacity),
412 RendererWithSortAttributes() );
416 // clear extra elements from helper, does not decrease capability
417 sortingHelper.resize( renderableCount );
420 // calculate the sorting value, once per item by calling the layers sort function
421 // Using an if and two for-loops rather than if inside for as its better for branch prediction
422 if( layer.UsesDefaultSortFunction() )
424 for( size_t index = 0; index < renderableCount; ++index )
426 RenderItem& item = transparentRenderList.GetItem( index );
428 //@todo MESH_REWORK After merge of RenderableAttachment and RendererAttachment, should instead store the renderable ptr and get the fields directly
429 layer.transparentRenderables[index]->SetSortAttributes( bufferIndex, sortingHelper[ index ] );
431 // the default sorting function should get inlined here
432 sortingHelper[ index ].zValue = Internal::Layer::ZValue( item.GetModelViewMatrix().GetTranslation3() );
434 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
435 sortingHelper[ index ].renderItem = &item;
440 const Dali::Layer::SortFunctionType sortFunction = layer.GetSortFunction();
441 for( size_t index = 0; index < renderableCount; ++index )
443 RenderItem& item = transparentRenderList.GetItem( index );
445 layer.transparentRenderables[index]->SetSortAttributes( bufferIndex, sortingHelper[ index ] );
446 sortingHelper[ index ].zValue = (*sortFunction)( item.GetModelViewMatrix().GetTranslation3() );
448 // keep the renderitem pointer in the helper so we can quickly reorder items after sort
449 sortingHelper[ index ].renderItem = &item;
453 // sort the renderers back to front, Z Axis point from near plane to far plane
454 std::stable_sort( sortingHelper.begin(), sortingHelper.end(), CompareItemsWithZValue );
456 // reorder/repopulate the renderitems in renderlist to correct order based on sortinghelper
457 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, "Sorted Transparent List:\n");
458 RenderItemContainer::Iterator renderListIter = transparentRenderList.GetContainer().Begin();
459 for( unsigned int index = 0; index < renderableCount; ++index, ++renderListIter )
461 *renderListIter = sortingHelper[ index ].renderItem;
462 DALI_LOG_INFO( gRenderListLogFilter, Debug::Verbose, " sortedList[%d] = %p\n", index, sortingHelper[ index ].renderItem->GetRenderer() );
467 * Add transparent renderers from the layer onto the next free render list
468 * @param updateBufferIndex to use
469 * @param layer to get the renderers from
470 * @param viewmatrix for the camera from rendertask
471 * @param opaqueRenderablesExist is true if there are opaque renderers on this layer
472 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
473 * @param instruction to fill in
474 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
475 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
477 inline void AddTransparentRenderers( BufferIndex updateBufferIndex,
479 const Matrix& viewMatrix,
480 bool opaqueRenderablesExist,
481 bool stencilRenderablesExist,
482 RenderInstruction& instruction,
483 RendererSortingHelper& sortingHelper,
484 bool tryReuseRenderList )
486 const size_t renderableCount = layer.transparentRenderables.size();
487 RenderList& transparentRenderList = instruction.GetNextFreeRenderList( renderableCount );
488 transparentRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
490 // transparent flags are independent of the amount of transparent renderers
491 SetTransparentRenderFlags( transparentRenderList, opaqueRenderablesExist, stencilRenderablesExist, layer.IsDepthTestDisabled() );
493 // try to reuse cached renderitems from last time around
494 if( tryReuseRenderList )
496 if( TryReuseCachedRenderers( layer, transparentRenderList, layer.transparentRenderables ) )
501 transparentRenderList.SetSourceLayer( &layer );
503 AddRenderersToRenderList( updateBufferIndex, transparentRenderList, layer.transparentRenderables, viewMatrix );
505 // sorting is only needed if more than 1 item
506 if( renderableCount > 1 )
508 SortTransparentRenderItems( updateBufferIndex, transparentRenderList, layer, sortingHelper.transparent );
513 * Add overlay renderers from the layer onto the next free render list
514 * @param updateBufferIndex to use
515 * @param layer to get the renderers from
516 * @param viewmatrix for the camera from rendertask
517 * @param stencilRenderablesExist is true if there are stencil renderers on this layer
518 * @param instruction to fill in
519 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
521 inline void AddOverlayRenderers( BufferIndex updateBufferIndex,
523 const Matrix& viewMatrix,
524 bool stencilRenderablesExist,
525 RenderInstruction& instruction,
526 bool tryReuseRenderList )
528 RenderList& overlayRenderList = instruction.GetNextFreeRenderList( layer.overlayRenderables.size() );
529 overlayRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
530 SetOverlayRenderFlags( overlayRenderList, stencilRenderablesExist );
532 // try to reuse cached renderitems from last time around
533 if( tryReuseRenderList )
535 if( TryReuseCachedRenderers( layer, overlayRenderList, layer.overlayRenderables ) )
540 AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix );
544 * Add stencil renderers from the layer onto the next free render list
545 * @param updateBufferIndex to use
546 * @param layer to get the renderers from
547 * @param viewmatrix for the camera from rendertask
548 * @param instruction to fill in
549 * @param tryReuseRenderList whether to try to reuse the cached items from the instruction
551 inline void AddStencilRenderers( BufferIndex updateBufferIndex,
553 const Matrix& viewMatrix,
554 RenderInstruction& instruction,
555 bool tryReuseRenderList )
557 RenderList& stencilRenderList = instruction.GetNextFreeRenderList( layer.stencilRenderables.size() );
558 stencilRenderList.SetClipping( layer.IsClipping(), layer.GetClippingBox() );
559 SetStencilRenderFlags( stencilRenderList );
561 // try to reuse cached renderitems from last time around
562 if( tryReuseRenderList )
564 if( TryReuseCachedRenderers( layer, stencilRenderList, layer.stencilRenderables ) )
569 AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix );
573 * Prepare a single render instruction
574 * @param updateBufferIndex to use
575 * @param sortedLayers to prepare the instruction from
576 * @param renderTask to get the view matrix
577 * @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
578 * @param renderTracker An optional render tracker object
579 * @param instructions container
581 void PrepareRenderInstruction( BufferIndex updateBufferIndex,
582 SortedLayerPointers& sortedLayers,
583 RenderTask& renderTask,
584 RendererSortingHelper& sortingHelper,
585 RenderTracker* renderTracker,
586 RenderInstructionContainer& instructions )
588 // Retrieve the RenderInstruction buffer from the RenderInstructionContainer
589 // then populate with instructions.
590 RenderInstruction& instruction = instructions.GetNextInstruction( updateBufferIndex );
591 renderTask.PrepareRenderInstruction( instruction, updateBufferIndex );
592 bool viewMatrixHasNotChanged = !renderTask.ViewMatrixUpdated();
594 const Matrix& viewMatrix = renderTask.GetViewMatrix( updateBufferIndex );
596 const SortedLayersIter endIter = sortedLayers.end();
597 for ( SortedLayersIter iter = sortedLayers.begin(); iter != endIter; ++iter )
599 Layer& layer = **iter;
601 const bool stencilRenderablesExist( !layer.stencilRenderables.empty() );
602 const bool opaqueRenderablesExist( !layer.opaqueRenderables.empty() );
603 const bool transparentRenderablesExist( !layer.transparentRenderables.empty() );
604 const bool overlayRenderablesExist( !layer.overlayRenderables.empty() );
605 const bool tryReuseRenderList( viewMatrixHasNotChanged && layer.CanReuseRenderers(renderTask.GetCamera()) );
607 // Ignore stencils if there's nothing to test
608 if( stencilRenderablesExist &&
609 ( opaqueRenderablesExist || transparentRenderablesExist || overlayRenderablesExist ) )
611 AddStencilRenderers( updateBufferIndex, layer, viewMatrix, instruction, tryReuseRenderList );
614 if ( opaqueRenderablesExist )
616 AddOpaqueRenderers( updateBufferIndex,
619 transparentRenderablesExist,
620 stencilRenderablesExist,
623 tryReuseRenderList );
626 if ( transparentRenderablesExist )
628 AddTransparentRenderers( updateBufferIndex,
631 opaqueRenderablesExist,
632 stencilRenderablesExist,
635 tryReuseRenderList );
638 // @todo MESH_REWORK Mark opaque and transparent render lists as interleaveable.
639 // ( Saves having to have a pair of lists for each depth index )
641 if ( overlayRenderablesExist )
643 AddOverlayRenderers( updateBufferIndex, layer, viewMatrix, stencilRenderablesExist,
644 instruction, tryReuseRenderList );
648 instruction.mRenderTracker = renderTracker;
649 instruction.mCullMode = renderTask.GetCullMode();
651 // inform the render instruction that all renderers have been added and this frame is complete
652 instruction.UpdateCompleted();